From e8419c90f1f3880f96ff335c4ee0bdd7a86ab0c6 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 19 Feb 2008 00:38:10 +0000 Subject: tail: fix "tail -c 20 /dev/huge_disk" (was taking ages) tail: a few variables renamed wc: tiny optimization. --- coreutils/tail.c | 79 ++++++++++++++++++++++++++++++-------------------------- coreutils/wc.c | 2 +- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/coreutils/tail.c b/coreutils/tail.c index beecbaedf..340697f88 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c @@ -74,7 +74,7 @@ static unsigned eat_num(const char *p) p++; else if (*p == '+') { p++; - G.status = EXIT_FAILURE; + G.status = 1; /* mark that we saw "+" */ } return xatou_sfx(p, tail_suffixes); } @@ -92,7 +92,7 @@ int tail_main(int argc, char **argv) char *tailbuf; size_t tailbufsize; int taillen = 0; - int newline = 0; + int newlines_seen = 0; int nfiles, nread, nwrite, seen, i, opt; int *fds; @@ -128,12 +128,12 @@ int tail_main(int argc, char **argv) #endif argc -= optind; argv += optind; - from_top = G.status; + from_top = G.status; /* 1 if there was "-c +N" or "-n +N" */ + G.status = EXIT_SUCCESS; /* open all the files */ fds = xmalloc(sizeof(int) * (argc + 1)); nfiles = i = 0; - G.status = EXIT_SUCCESS; if (argc == 0) { struct stat statbuf; @@ -155,39 +155,49 @@ int tail_main(int argc, char **argv) if (!nfiles) bb_error_msg_and_die("no files"); + /* prepare the buffer */ tailbufsize = BUFSIZ; - - /* tail the files */ if (!from_top && COUNT_BYTES) { - if (tailbufsize < count) { + if (tailbufsize < count + BUFSIZ) { tailbufsize = count + BUFSIZ; } } + tailbuf = xmalloc(tailbufsize); - buf = tailbuf = xmalloc(tailbufsize); - + /* tail the files */ fmt = header_fmt + 1; /* Skip header leading newline on first output. */ i = 0; do { - /* Be careful. It would be possible to optimize the count-bytes - * case if the file is seekable. If you do though, remember that - * starting file position may not be the beginning of the file. - * Beware of backing up too far. See example in wc.c. - */ - if (!(count | from_top) && lseek(fds[i], 0, SEEK_END) >= 0) { - continue; - } + off_t current; if (nfiles > header_threshhold) { tail_xprint_header(fmt, argv[i]); fmt = header_fmt; } + /* Optimizing count-bytes case if the file is seekable. + * Beware of backing up too far. + * Also we exclude files with size 0 (because of /proc/xxx) */ + current = lseek(fds[i], 0, SEEK_END); + if (current > 0) { + if (!from_top) { + if (count == 0) + continue; /* showing zero lines is easy :) */ + if (COUNT_BYTES) { + current -= count; + if (current < 0) + current = 0; + xlseek(fds[i], current, SEEK_SET); + bb_copyfd_size(fds[i], STDOUT_FILENO, count); + continue; + } + } + } + buf = tailbuf; taillen = 0; seen = 1; - newline = 0; - + newlines_seen = 0; while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) { if (from_top) { nwrite = nread; @@ -215,34 +225,32 @@ int tail_main(int argc, char **argv) } } else { int k = nread; - int nbuf = 0; + int newlines_in_buf = 0; - while (k) { - --k; + do { /* count '\n' in last read */ + k--; if (buf[k] == '\n') { - ++nbuf; + newlines_in_buf++; } - } + } while (k); - if (newline + nbuf < count) { - newline += nbuf; + if (newlines_seen + newlines_in_buf < count) { + newlines_seen += newlines_in_buf; taillen += nread; } else { - int extra = 0; + int extra = (buf[nread-1] != '\n'); - if (buf[nread-1] != '\n') - extra = 1; - k = newline + nbuf + extra - count; + k = newlines_seen + newlines_in_buf + extra - count; s = tailbuf; while (k) { if (*s == '\n') { - --k; + k--; } - ++s; + s++; } taillen += nread - (s - tailbuf); memmove(tailbuf, s, taillen); - newline = count - extra; + newlines_seen = count - extra; } if (tailbufsize < taillen + BUFSIZ) { tailbufsize = taillen + BUFSIZ; @@ -251,13 +259,10 @@ int tail_main(int argc, char **argv) } buf = tailbuf + taillen; } - } - + } /* while (tail_read() > 0) */ if (!from_top) { xwrite(STDOUT_FILENO, tailbuf, taillen); } - - taillen = 0; } while (++i < nfiles); buf = xrealloc(tailbuf, BUFSIZ); diff --git a/coreutils/wc.c b/coreutils/wc.c index 291af411f..58ea1c7db 100644 --- a/coreutils/wc.c +++ b/coreutils/wc.c @@ -73,7 +73,7 @@ int wc_main(int argc, char **argv) { FILE *fp; const char *s, *arg; - const char *start_fmt = "%9"COUNT_FMT; + const char *start_fmt = " %9"COUNT_FMT + 1; const char *fname_fmt = " %s\n"; COUNT_T *pcounts; COUNT_T counts[4]; -- cgit v1.2.3