diff options
author | Eric Andersen <andersen@codepoet.org> | 1999-12-09 06:11:36 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 1999-12-09 06:11:36 +0000 |
commit | 1792f8c48926450501e19d32e78e140bcb9661c6 (patch) | |
tree | 14d0304ebb774077e696a9c86117bf43d935d8bb /coreutils/tail.c | |
parent | c24db7b591870978fdd2cec8995728d1520c2fa9 (diff) | |
download | busybox-w32-1792f8c48926450501e19d32e78e140bcb9661c6.tar.gz busybox-w32-1792f8c48926450501e19d32e78e140bcb9661c6.tar.bz2 busybox-w32-1792f8c48926450501e19d32e78e140bcb9661c6.zip |
Tail now works (costs 6k). Several other updates.
-Erik
Diffstat (limited to 'coreutils/tail.c')
-rw-r--r-- | coreutils/tail.c | 176 |
1 files changed, 65 insertions, 111 deletions
diff --git a/coreutils/tail.c b/coreutils/tail.c index 058d462a5..7a64c4ca3 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c | |||
@@ -13,35 +13,16 @@ | |||
13 | 13 | ||
14 | You should have received a copy of the GNU General Public License | 14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software | 15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 | |||
18 | /* Can display any amount of data, unlike the Unix version, which uses | ||
19 | a fixed size buffer and therefore can only deliver a limited number | ||
20 | of lines. | ||
21 | |||
22 | Options: | ||
23 | -b Tail by N 512-byte blocks. | ||
24 | -c, --bytes=N[bkm] Tail by N bytes | ||
25 | [or 512-byte blocks, kilobytes, or megabytes]. | ||
26 | -f, --follow Loop forever trying to read more characters at the | ||
27 | end of the file, on the assumption that the file | ||
28 | is growing. Ignored if reading from a pipe. | ||
29 | -n, --lines=N Tail by N lines. | ||
30 | -q, --quiet, --silent Never print filename headers. | ||
31 | -v, --verbose Always print filename headers. | ||
32 | |||
33 | If a number (N) starts with a `+', begin printing with the Nth item | ||
34 | from the start of each file, instead of from the end. | ||
35 | |||
36 | Reads from standard input if no files are given or when a filename of | ||
37 | ``-'' is encountered. | ||
38 | By default, filename headers are printed only more than one file | ||
39 | is given. | ||
40 | By default, prints the last 10 lines (tail -n 10). | ||
41 | 17 | ||
42 | Original version by Paul Rubin <phr@ocf.berkeley.edu>. | 18 | Original version by Paul Rubin <phr@ocf.berkeley.edu>. |
43 | Extensions by David MacKenzie <djm@gnu.ai.mit.edu>. | 19 | Extensions by David MacKenzie <djm@gnu.ai.mit.edu>. |
44 | tail -f for multiple files by Ian Lance Taylor <ian@airs.com>. */ | 20 | tail -f for multiple files by Ian Lance Taylor <ian@airs.com>. |
21 | |||
22 | Rewrote the option parser, removed locales support, | ||
23 | and generally busyboxed, Erik Andersen <andersen@lineo.com> | ||
24 | |||
25 | */ | ||
45 | 26 | ||
46 | #include "internal.h" | 27 | #include "internal.h" |
47 | 28 | ||
@@ -49,16 +30,25 @@ | |||
49 | #include <assert.h> | 30 | #include <assert.h> |
50 | #include <errno.h> | 31 | #include <errno.h> |
51 | #include <sys/types.h> | 32 | #include <sys/types.h> |
33 | #include <sys/types.h> | ||
34 | #include <sys/stat.h> | ||
35 | #include <fcntl.h> | ||
36 | #include <ctype.h> | ||
37 | |||
52 | 38 | ||
53 | 39 | ||
54 | /* Disable assertions. Some systems have broken assert macros. */ | 40 | /* Disable assertions. Some systems have broken assert macros. */ |
55 | #define NDEBUG 1 | 41 | #define NDEBUG 1 |
56 | 42 | ||
57 | 43 | ||
58 | static void error(int i, int errnum, char* fmt, const char *msg) | 44 | static void error(int i, int errnum, char* fmt, ...) |
59 | { | 45 | { |
60 | fprintf(stderr, fmt, msg); | 46 | va_list arguments; |
61 | perror( errnum); | 47 | |
48 | va_start(arguments, fmt); | ||
49 | vfprintf(stderr, fmt, arguments); | ||
50 | fprintf(stderr, "\n%s\n", strerror( errnum)); | ||
51 | va_end(arguments); | ||
62 | exit(i); | 52 | exit(i); |
63 | } | 53 | } |
64 | 54 | ||
@@ -69,7 +59,7 @@ static void error(int i, int errnum, char* fmt, const char *msg) | |||
69 | assert ((fd) == 1); \ | 59 | assert ((fd) == 1); \ |
70 | assert ((n_bytes) >= 0); \ | 60 | assert ((n_bytes) >= 0); \ |
71 | if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \ | 61 | if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \ |
72 | error (EXIT_FAILURE, errno, "write error", NULL); \ | 62 | error (EXIT_FAILURE, errno, "write error"); \ |
73 | } \ | 63 | } \ |
74 | while (0) | 64 | while (0) |
75 | 65 | ||
@@ -110,7 +100,6 @@ enum header_mode | |||
110 | }; | 100 | }; |
111 | 101 | ||
112 | char *xmalloc (); | 102 | char *xmalloc (); |
113 | int safe_read (); | ||
114 | 103 | ||
115 | /* The name this program was run with. */ | 104 | /* The name this program was run with. */ |
116 | char *program_name; | 105 | char *program_name; |
@@ -118,33 +107,24 @@ char *program_name; | |||
118 | /* Nonzero if we have ever read standard input. */ | 107 | /* Nonzero if we have ever read standard input. */ |
119 | static int have_read_stdin; | 108 | static int have_read_stdin; |
120 | 109 | ||
121 | /* If nonzero, display usage information and exit. */ | ||
122 | static int show_help; | ||
123 | |||
124 | /* If nonzero, print the version on standard output then exit. */ | ||
125 | static int show_version; | ||
126 | 110 | ||
127 | static const char tail_usage[] = | 111 | static const char tail_usage[] = |
128 | "tail [OPTION]... [FILE]...\n\ | 112 | "tail [OPTION]... [FILE]...\n\ |
113 | \n\ | ||
129 | Print last 10 lines of each FILE to standard output.\n\ | 114 | Print last 10 lines of each FILE to standard output.\n\ |
130 | With more than one FILE, precede each with a header giving the file name.\n\ | 115 | With more than one FILE, precede each with a header giving the file name.\n\ |
131 | With no FILE, or when FILE is -, read standard input.\n\ | 116 | With no FILE, or when FILE is -, read standard input.\n\ |
132 | \n\ | 117 | \n\ |
133 | -c, --bytes=N output the last N bytes\n\ | 118 | -c=N[kbm] output the last N bytes\n\ |
134 | -f, --follow output appended data as the file grows\n\ | 119 | -f output appended data as the file grows\n\ |
135 | -n, --lines=N output the last N lines, instead of last 10\n\ | 120 | -n=N output the last N lines, instead of last 10\n\ |
136 | -q, --quiet, --silent never output headers giving file names\n\ | 121 | -q never output headers giving file names\n\ |
137 | -v, --verbose always output headers giving file names\n\ | 122 | -v always output headers giving file names\n\ |
138 | --help display this help and exit\n\ | 123 | --help display this help and exit\n\ |
139 | --version output version information and exit\n\ | ||
140 | \n\ | 124 | \n\ |
141 | If the first character of N (the number of bytes or lines) is a `+',\n\ | 125 | If the first character of N (bytes or lines) is a `+', output begins with \n\ |
142 | print beginning with the Nth item from the start of each file, otherwise,\n\ | 126 | the Nth item from the start of each file, otherwise, print the last N items\n\ |
143 | print the last N items in the file. N may have a multiplier suffix:\n\ | 127 | in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n"; |
144 | b for 512, k for 1024, m for 1048576 (1 Meg). A first OPTION of -VALUE\n\ | ||
145 | or +VALUE is treated like -n VALUE or -n +VALUE unless VALUE has one of\n\ | ||
146 | the [bkm] suffix multipliers, in which case it is treated like -c VALUE\n\ | ||
147 | or -c +VALUE.\n"; | ||
148 | 128 | ||
149 | static void | 129 | static void |
150 | write_header (const char *filename, const char *comment) | 130 | write_header (const char *filename, const char *comment) |
@@ -184,7 +164,7 @@ file_lines (const char *filename, int fd, long int n_lines, off_t pos) | |||
184 | reads will be on block boundaries, which might increase efficiency. */ | 164 | reads will be on block boundaries, which might increase efficiency. */ |
185 | pos -= bytes_read; | 165 | pos -= bytes_read; |
186 | lseek (fd, pos, SEEK_SET); | 166 | lseek (fd, pos, SEEK_SET); |
187 | bytes_read = safe_read (fd, buffer, bytes_read); | 167 | bytes_read = fullRead (fd, buffer, bytes_read); |
188 | if (bytes_read == -1) | 168 | if (bytes_read == -1) |
189 | { | 169 | { |
190 | error (0, errno, "%s", filename); | 170 | error (0, errno, "%s", filename); |
@@ -220,7 +200,7 @@ file_lines (const char *filename, int fd, long int n_lines, off_t pos) | |||
220 | pos -= BUFSIZ; | 200 | pos -= BUFSIZ; |
221 | lseek (fd, pos, SEEK_SET); | 201 | lseek (fd, pos, SEEK_SET); |
222 | } | 202 | } |
223 | while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0); | 203 | while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0); |
224 | if (bytes_read == -1) | 204 | if (bytes_read == -1) |
225 | { | 205 | { |
226 | error (0, errno, "%s", filename); | 206 | error (0, errno, "%s", filename); |
@@ -255,7 +235,7 @@ pipe_lines (const char *filename, int fd, long int n_lines) | |||
255 | tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER)); | 235 | tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER)); |
256 | 236 | ||
257 | /* Input is always read into a fresh buffer. */ | 237 | /* Input is always read into a fresh buffer. */ |
258 | while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0) | 238 | while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0) |
259 | { | 239 | { |
260 | tmp->nlines = 0; | 240 | tmp->nlines = 0; |
261 | tmp->next = NULL; | 241 | tmp->next = NULL; |
@@ -374,7 +354,7 @@ pipe_bytes (const char *filename, int fd, off_t n_bytes) | |||
374 | tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER)); | 354 | tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER)); |
375 | 355 | ||
376 | /* Input is always read into a fresh buffer. */ | 356 | /* Input is always read into a fresh buffer. */ |
377 | while ((tmp->nbytes = safe_read (fd, tmp->buffer, BUFSIZ)) > 0) | 357 | while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0) |
378 | { | 358 | { |
379 | tmp->next = NULL; | 359 | tmp->next = NULL; |
380 | 360 | ||
@@ -453,7 +433,7 @@ start_bytes (const char *filename, int fd, off_t n_bytes) | |||
453 | char buffer[BUFSIZ]; | 433 | char buffer[BUFSIZ]; |
454 | int bytes_read = 0; | 434 | int bytes_read = 0; |
455 | 435 | ||
456 | while (n_bytes > 0 && (bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0) | 436 | while (n_bytes > 0 && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0) |
457 | n_bytes -= bytes_read; | 437 | n_bytes -= bytes_read; |
458 | if (bytes_read == -1) | 438 | if (bytes_read == -1) |
459 | { | 439 | { |
@@ -476,7 +456,7 @@ start_lines (const char *filename, int fd, long int n_lines) | |||
476 | int bytes_read = 0; | 456 | int bytes_read = 0; |
477 | int bytes_to_skip = 0; | 457 | int bytes_to_skip = 0; |
478 | 458 | ||
479 | while (n_lines && (bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0) | 459 | while (n_lines && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0) |
480 | { | 460 | { |
481 | bytes_to_skip = 0; | 461 | bytes_to_skip = 0; |
482 | while (bytes_to_skip < bytes_read) | 462 | while (bytes_to_skip < bytes_read) |
@@ -509,7 +489,7 @@ dump_remainder (const char *filename, int fd) | |||
509 | 489 | ||
510 | total = 0; | 490 | total = 0; |
511 | output: | 491 | output: |
512 | while ((bytes_read = safe_read (fd, buffer, BUFSIZ)) > 0) | 492 | while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0) |
513 | { | 493 | { |
514 | XWRITE (STDOUT_FILENO, buffer, bytes_read); | 494 | XWRITE (STDOUT_FILENO, buffer, bytes_read); |
515 | total += bytes_read; | 495 | total += bytes_read; |
@@ -731,7 +711,7 @@ tail_file (const char *filename, off_t n_units, int filenum) | |||
731 | int fd, errors; | 711 | int fd, errors; |
732 | struct stat stats; | 712 | struct stat stats; |
733 | 713 | ||
734 | if (!strcmp (filename, "-") | 714 | if (!strcmp (filename, "-")) |
735 | { | 715 | { |
736 | have_read_stdin = 1; | 716 | have_read_stdin = 1; |
737 | filename = "standard input"; | 717 | filename = "standard input"; |
@@ -815,16 +795,15 @@ tail_file (const char *filename, off_t n_units, int filenum) | |||
815 | } | 795 | } |
816 | 796 | ||
817 | extern int | 797 | extern int |
818 | tai_main (int argc, char **argv) | 798 | tail_main (int argc, char **argv) |
819 | { | 799 | { |
800 | int stopit = 0; | ||
820 | enum header_mode header_mode = multiple_files; | 801 | enum header_mode header_mode = multiple_files; |
821 | int exit_status = 0; | 802 | int exit_status = 0; |
822 | /* If from_start, the number of items to skip before printing; otherwise, | 803 | /* If from_start, the number of items to skip before printing; otherwise, |
823 | the number of items at the end of the file to print. Initially, -1 | 804 | the number of items at the end of the file to print. Initially, -1 |
824 | means the value has not been set. */ | 805 | means the value has not been set. */ |
825 | off_t n_units = -1; | 806 | off_t n_units = -1; |
826 | long int tmp_long; | ||
827 | int c; /* Option character. */ | ||
828 | int n_files; | 807 | int n_files; |
829 | char **file; | 808 | char **file; |
830 | 809 | ||
@@ -832,48 +811,38 @@ tai_main (int argc, char **argv) | |||
832 | have_read_stdin = 0; | 811 | have_read_stdin = 0; |
833 | count_lines = 1; | 812 | count_lines = 1; |
834 | forever = forever_multiple = from_start = print_headers = 0; | 813 | forever = forever_multiple = from_start = print_headers = 0; |
835 | 814 | ||
836 | if (argc > 1 | 815 | /* Parse any options */ |
837 | && ((argv[1][0] == '-' && ISDIGIT (argv[1][1])) | 816 | //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv); |
838 | || (argv[1][0] == '+' && (ISDIGIT (argv[1][1]) | 817 | while (--argc > 0 && ( **(++argv) == '-' || **argv == '+' )) { |
839 | || argv[1][1] == 0)))) | 818 | if (**argv == '+') { |
840 | { | 819 | from_start = 1; |
841 | /* Old option syntax: a dash or plus, one or more digits (zero digits | 820 | } |
842 | are acceptable with a plus), and one or more option letters. */ | 821 | stopit = 0; |
843 | if (argv[1][0] == '+') | 822 | while (stopit == 0 && *(++(*argv))) { |
844 | from_start = 1; | 823 | switch (**argv) { |
845 | if (argv[1][1] != '\0') | ||
846 | { | ||
847 | strtol_error s_err; | ||
848 | char *p; | ||
849 | |||
850 | s_err = xstrtol (++argv[1], &p, 0, &tmp_long, "bkm"); | ||
851 | n_units = tmp_long; | ||
852 | if (s_err == LONGINT_OVERFLOW) | ||
853 | { | ||
854 | STRTOL_FATAL_ERROR (argv[1], "argument", s_err); | ||
855 | } | ||
856 | |||
857 | /* If a [bkm] suffix was given then count bytes, not lines. */ | ||
858 | if (p[-1] == 'b' || p[-1] == 'k' || p[-1] == 'm') | ||
859 | count_lines = 0; | ||
860 | |||
861 | /* Parse any appended option letters. */ | ||
862 | while (*p) | ||
863 | { | ||
864 | switch (*p) | ||
865 | { | ||
866 | case 'c': | 824 | case 'c': |
867 | /* Interpret N_UNITS as # of bytes. */ | ||
868 | count_lines = 0; | 825 | count_lines = 0; |
826 | |||
827 | if (--argc < 1) { | ||
828 | usage(tail_usage); | ||
829 | } | ||
830 | n_units = getNum(*(++argv)); | ||
831 | stopit = 1; | ||
869 | break; | 832 | break; |
870 | 833 | ||
871 | case 'f': | 834 | case 'f': |
872 | forever = 1; | 835 | forever = 1; |
873 | break; | 836 | break; |
874 | 837 | ||
875 | case 'l': | 838 | case 'n': |
876 | count_lines = 1; | 839 | count_lines = 1; |
840 | |||
841 | if (--argc < 1) { | ||
842 | usage(tail_usage); | ||
843 | } | ||
844 | n_units = atol(*(++argv)); | ||
845 | stopit = 1; | ||
877 | break; | 846 | break; |
878 | 847 | ||
879 | case 'q': | 848 | case 'q': |
@@ -885,26 +854,11 @@ tai_main (int argc, char **argv) | |||
885 | break; | 854 | break; |
886 | 855 | ||
887 | default: | 856 | default: |
888 | error (0, 0, "unrecognized option '%c'", *p); | ||
889 | usage (tail_usage); | 857 | usage (tail_usage); |
890 | } | ||
891 | ++p; | ||
892 | } | 858 | } |
893 | } | 859 | } |
894 | /* Make the options we just parsed invisible to getopt. */ | ||
895 | argv[1] = argv[0]; | ||
896 | argv++; | ||
897 | argc--; | ||
898 | } | ||
899 | |||
900 | if (show_version) | ||
901 | { | ||
902 | printf ("tail - %s\n", PACKAGE_VERSION); | ||
903 | exit (EXIT_SUCCESS); | ||
904 | } | 860 | } |
905 | 861 | ||
906 | if (show_help) | ||
907 | usage (tail_usage); | ||
908 | 862 | ||
909 | if (n_units == -1) | 863 | if (n_units == -1) |
910 | n_units = DEFAULT_N_LINES; | 864 | n_units = DEFAULT_N_LINES; |
@@ -918,8 +872,8 @@ tai_main (int argc, char **argv) | |||
918 | --n_units; | 872 | --n_units; |
919 | } | 873 | } |
920 | 874 | ||
921 | n_files = argc - optind; | 875 | n_files = argc; |
922 | file = argv + optind; | 876 | file = argv; |
923 | 877 | ||
924 | if (n_files > 1 && forever) | 878 | if (n_files > 1 && forever) |
925 | { | 879 | { |