aboutsummaryrefslogtreecommitdiff
path: root/coreutils/tail.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>1999-12-09 06:11:36 +0000
committerEric Andersen <andersen@codepoet.org>1999-12-09 06:11:36 +0000
commit1792f8c48926450501e19d32e78e140bcb9661c6 (patch)
tree14d0304ebb774077e696a9c86117bf43d935d8bb /coreutils/tail.c
parentc24db7b591870978fdd2cec8995728d1520c2fa9 (diff)
downloadbusybox-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.c176
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
58static void error(int i, int errnum, char* fmt, const char *msg) 44static 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
112char *xmalloc (); 102char *xmalloc ();
113int safe_read ();
114 103
115/* The name this program was run with. */ 104/* The name this program was run with. */
116char *program_name; 105char *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. */
119static int have_read_stdin; 108static int have_read_stdin;
120 109
121/* If nonzero, display usage information and exit. */
122static int show_help;
123
124/* If nonzero, print the version on standard output then exit. */
125static int show_version;
126 110
127static const char tail_usage[] = 111static const char tail_usage[] =
128"tail [OPTION]... [FILE]...\n\ 112"tail [OPTION]... [FILE]...\n\
113\n\
129Print last 10 lines of each FILE to standard output.\n\ 114Print last 10 lines of each FILE to standard output.\n\
130With more than one FILE, precede each with a header giving the file name.\n\ 115With more than one FILE, precede each with a header giving the file name.\n\
131With no FILE, or when FILE is -, read standard input.\n\ 116With 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\
141If the first character of N (the number of bytes or lines) is a `+',\n\ 125If the first character of N (bytes or lines) is a `+', output begins with \n\
142print beginning with the Nth item from the start of each file, otherwise,\n\ 126the Nth item from the start of each file, otherwise, print the last N items\n\
143print the last N items in the file. N may have a multiplier suffix:\n\ 127in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
144b for 512, k for 1024, m for 1048576 (1 Meg). A first OPTION of -VALUE\n\
145or +VALUE is treated like -n VALUE or -n +VALUE unless VALUE has one of\n\
146the [bkm] suffix multipliers, in which case it is treated like -c VALUE\n\
147or -c +VALUE.\n";
148 128
149static void 129static void
150write_header (const char *filename, const char *comment) 130write_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;
511output: 491output:
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
817extern int 797extern int
818tai_main (int argc, char **argv) 798tail_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 {