tail: fix "tail -c 20 /dev/huge_disk" (was taking ages)
authorDenis Vlasenko <vda.linux@googlemail.com>
Tue, 19 Feb 2008 00:38:10 +0000 (00:38 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Tue, 19 Feb 2008 00:38:10 +0000 (00:38 -0000)
tail: a few variables renamed
wc: tiny optimization.

coreutils/tail.c
coreutils/wc.c

index beecbaedfaab9529366e147bf64a773829d15d81..340697f888576cc8a551e48c0431d53f577b3a75 100644 (file)
@@ -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);
index 291af411fb8b5f88d63a77741004855233eabad6..58ea1c7db2262cd65ef59e2aaa261f4b0e81ab6a 100644 (file)
@@ -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];