sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 006c9739b3cff20a660fe15ffeb30be02a8fde5f
parent 989127e525794da87629287a26553f212e3a7388
Author: FRIGN <dev@frign.de>
Date:   Mon Feb  9 18:38:41 +0100

Add c-flag to tail(1) and refactor manpage

and mark it as finished in README.

Diffstat:
README | 2+-
tail.1 | 25+++++++++++++++++--------
tail.c | 56++++++++++++++++++++++++++++++++++++++------------------
3 files changed, 56 insertions(+), 27 deletions(-)
diff --git a/README b/README @@ -64,7 +64,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support, =* sponge non-posix none strings no -a, -n, -t =* sync non-posix none -= tail no -c +=* tail yes none =* tar non-posix none =* tee yes none test yes none diff --git a/tail.1 b/tail.1 @@ -7,7 +7,7 @@ .Sh SYNOPSIS .Nm .Op Fl f -.Op Fl n Ar num +.Op Fl c Ar num | Fl n Ar num .Op Ar file ... .Sh DESCRIPTION .Nm @@ -20,19 +20,28 @@ is given, reads from stdin. .Sh OPTIONS .Bl -tag -width Ds +.It Fl c Ar num | Fl n Ar num +Display +.Ar num +last characters | lines. If +.Ar num +begins with '+' it is used as an offset from the beginning of each +.Ar file . +If +.Ar num +begins with '-' it is handled the same as if no sign was given. .It Fl f If one .Ar file is specified, append lines to output as .Ar file grows. -.It Fl n Ar lines -Display -.Ar num -lines. If -.Ar num -begins with '+' it is used as an offset from the beginning of each -.Ar file . .El .Sh SEE ALSO .Xr head 1 +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2008 +specification. diff --git a/tail.c b/tail.c @@ -9,43 +9,61 @@ #include <unistd.h> #include "text.h" +#include "utf.h" #include "util.h" static int fflag = 0; static void -dropinit(FILE *fp, const char *str, size_t n) +dropinit(FILE *fp, const char *str, size_t n, char mode) { + Rune r; char *buf = NULL; size_t size = 0, i = 0; ssize_t len; - while (i < n && (len = getline(&buf, &size, fp)) != -1) - if (len > 0 && buf[len - 1] == '\n') + if (mode == 'n') { + while (i < n && (len = getline(&buf, &size, fp)) != -1) + if (len > 0 && buf[len - 1] == '\n') + i++; + } else { + while (i < n && (len = readrune(str, fp, &r))) i++; + } free(buf); concat(fp, str, stdout, "<stdout>"); } static void -taketail(FILE *fp, const char *str, size_t n) +taketail(FILE *fp, const char *str, size_t n, char mode) { + Rune *r = NULL; char **ring = NULL; size_t i, j, *size = NULL; - ring = ecalloc(n, sizeof *ring); - size = ecalloc(n, sizeof *size); + if (mode == 'n') { + ring = ecalloc(n, sizeof *ring); + size = ecalloc(n, sizeof *size); + + for (i = j = 0; getline(&ring[i], &size[i], fp) != -1; ) + i = j = (i + 1) % n; + } else { + r = ecalloc(n, sizeof *r); - for (i = j = 0; getline(&ring[i], &size[i], fp) != -1; ) - i = j = (i + 1) % n; + for (i = j = 0; readrune(str, fp, &r[i]); ) + i = j = (i + 1) % n; + } if (ferror(fp)) eprintf("%s: read error:", str); do { - if (ring[j]) { + if (ring && ring[j]) { fputs(ring[j], stdout); free(ring[j]); } + if (r) { + writerune("<stdout>", stdout, &r[j]); + } } while ((j = (j + 1) % n) != i); free(ring); @@ -63,30 +81,32 @@ main(int argc, char *argv[]) { struct stat st1, st2; FILE *fp; - size_t n = 10, tmpsize; + size_t num = 10, tmpsize; int ret = 0, newline, many; - char *lines, *tmp; - void (*tail)(FILE *, const char *, size_t) = taketail; + char mode = 'n', *numstr, *tmp; + void (*tail)(FILE *, const char *, size_t, char) = taketail; ARGBEGIN { case 'f': fflag = 1; break; + case 'c': case 'n': - lines = EARGF(usage()); - n = MIN(llabs(estrtonum(lines, LLONG_MIN + 1, MIN(LLONG_MAX, SIZE_MAX))), SIZE_MAX); - if (strchr(lines, '+')) + mode = ARGC(); + numstr = EARGF(usage()); + num = MIN(llabs(estrtonum(numstr, LLONG_MIN + 1, MIN(LLONG_MAX, SIZE_MAX))), SIZE_MAX); + if (strchr(numstr, '+')) tail = dropinit; break; ARGNUM: - n = ARGNUMF(); + num = ARGNUMF(); break; default: usage(); } ARGEND; if (argc == 0) - tail(stdin, "<stdin>", n); + tail(stdin, "<stdin>", num, mode); else { if ((many = argc > 1) && fflag) usage(); @@ -104,7 +124,7 @@ main(int argc, char *argv[]) if (!(S_ISFIFO(st1.st_mode) || S_ISREG(st1.st_mode))) fflag = 0; newline = 1; - tail(fp, argv[0], n); + tail(fp, argv[0], num, mode); if (fflag && argc == 1) { tmp = NULL;