tail: fix "tail -c 20 /dev/huge_disk" (was taking ages)

tail: a few variables renamed
wc: tiny optimization.
This commit is contained in:
Denis Vlasenko 2008-02-19 00:38:10 +00:00
parent 5233cd3800
commit e8419c90f1
2 changed files with 43 additions and 38 deletions

View File

@ -74,7 +74,7 @@ static unsigned eat_num(const char *p)
p++; p++;
else if (*p == '+') { else if (*p == '+') {
p++; p++;
G.status = EXIT_FAILURE; G.status = 1; /* mark that we saw "+" */
} }
return xatou_sfx(p, tail_suffixes); return xatou_sfx(p, tail_suffixes);
} }
@ -92,7 +92,7 @@ int tail_main(int argc, char **argv)
char *tailbuf; char *tailbuf;
size_t tailbufsize; size_t tailbufsize;
int taillen = 0; int taillen = 0;
int newline = 0; int newlines_seen = 0;
int nfiles, nread, nwrite, seen, i, opt; int nfiles, nread, nwrite, seen, i, opt;
int *fds; int *fds;
@ -128,12 +128,12 @@ int tail_main(int argc, char **argv)
#endif #endif
argc -= optind; argc -= optind;
argv += 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 */ /* open all the files */
fds = xmalloc(sizeof(int) * (argc + 1)); fds = xmalloc(sizeof(int) * (argc + 1));
nfiles = i = 0; nfiles = i = 0;
G.status = EXIT_SUCCESS;
if (argc == 0) { if (argc == 0) {
struct stat statbuf; struct stat statbuf;
@ -155,39 +155,49 @@ int tail_main(int argc, char **argv)
if (!nfiles) if (!nfiles)
bb_error_msg_and_die("no files"); bb_error_msg_and_die("no files");
/* prepare the buffer */
tailbufsize = BUFSIZ; tailbufsize = BUFSIZ;
/* tail the files */
if (!from_top && COUNT_BYTES) { if (!from_top && COUNT_BYTES) {
if (tailbufsize < count) { if (tailbufsize < count + BUFSIZ) {
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. */ fmt = header_fmt + 1; /* Skip header leading newline on first output. */
i = 0; i = 0;
do { do {
/* Be careful. It would be possible to optimize the count-bytes off_t current;
* 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;
}
if (nfiles > header_threshhold) { if (nfiles > header_threshhold) {
tail_xprint_header(fmt, argv[i]); tail_xprint_header(fmt, argv[i]);
fmt = header_fmt; 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; buf = tailbuf;
taillen = 0; taillen = 0;
seen = 1; seen = 1;
newline = 0; newlines_seen = 0;
while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) { while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
if (from_top) { if (from_top) {
nwrite = nread; nwrite = nread;
@ -215,34 +225,32 @@ int tail_main(int argc, char **argv)
} }
} else { } else {
int k = nread; int k = nread;
int nbuf = 0; int newlines_in_buf = 0;
while (k) { do { /* count '\n' in last read */
--k; k--;
if (buf[k] == '\n') { if (buf[k] == '\n') {
++nbuf; newlines_in_buf++;
} }
} } while (k);
if (newline + nbuf < count) { if (newlines_seen + newlines_in_buf < count) {
newline += nbuf; newlines_seen += newlines_in_buf;
taillen += nread; taillen += nread;
} else { } else {
int extra = 0; int extra = (buf[nread-1] != '\n');
if (buf[nread-1] != '\n') k = newlines_seen + newlines_in_buf + extra - count;
extra = 1;
k = newline + nbuf + extra - count;
s = tailbuf; s = tailbuf;
while (k) { while (k) {
if (*s == '\n') { if (*s == '\n') {
--k; k--;
} }
++s; s++;
} }
taillen += nread - (s - tailbuf); taillen += nread - (s - tailbuf);
memmove(tailbuf, s, taillen); memmove(tailbuf, s, taillen);
newline = count - extra; newlines_seen = count - extra;
} }
if (tailbufsize < taillen + BUFSIZ) { if (tailbufsize < taillen + BUFSIZ) {
tailbufsize = taillen + BUFSIZ; tailbufsize = taillen + BUFSIZ;
@ -251,13 +259,10 @@ int tail_main(int argc, char **argv)
} }
buf = tailbuf + taillen; buf = tailbuf + taillen;
} }
} } /* while (tail_read() > 0) */
if (!from_top) { if (!from_top) {
xwrite(STDOUT_FILENO, tailbuf, taillen); xwrite(STDOUT_FILENO, tailbuf, taillen);
} }
taillen = 0;
} while (++i < nfiles); } while (++i < nfiles);
buf = xrealloc(tailbuf, BUFSIZ); buf = xrealloc(tailbuf, BUFSIZ);

View File

@ -73,7 +73,7 @@ int wc_main(int argc, char **argv)
{ {
FILE *fp; FILE *fp;
const char *s, *arg; 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"; const char *fname_fmt = " %s\n";
COUNT_T *pcounts; COUNT_T *pcounts;
COUNT_T counts[4]; COUNT_T counts[4];