BSD 4_4 release
[unix-history] / usr / src / usr.bin / tail / tail.c
index 1efe18f..cc8ea14 100644 (file)
@@ -1,21 +1,47 @@
 /*-
 /*-
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Edward Sze-Tyan Wang.
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Edward Sze-Tyan Wang.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)tail.c     5.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)tail.c     8.1 (Berkeley) 6/6/93";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -33,48 +59,66 @@ char *fname;
 static void obsolete __P((char **));
 static void usage __P((void));
 
 static void obsolete __P((char **));
 static void usage __P((void));
 
+int
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
        struct stat sb;
        FILE *fp;
        long off;
        enum STYLE style;
 {
        struct stat sb;
        FILE *fp;
        long off;
        enum STYLE style;
-       int ch;
-       char *p, *num;
+       int ch, first;
+       char *p;
 
 
-       obsolete(argv);
+       /*
+        * Tail's options are weird.  First, -n10 is the same as -n-10, not
+        * -n+10.  Second, the number options are 1 based and not offsets,
+        * so -n+1 is the first line, and -c-1 is the last byte.  Third, the
+        * number options for the -r option specify the number of things that
+        * get displayed, not the starting point in the file.  The one major
+        * incompatibility in this version as compared to historical versions
+        * is that the 'r' option couldn't be modified by the -lbc options,
+        * i.e. it was always done in lines.  This version treats -rc as a
+        * number of characters in reverse order.  Finally, the default for
+        * -r is the entire file, not 10 lines.
+        */
+#define        ARG(units, forward, backward) {                                 \
+       if (style)                                                      \
+               usage();                                                \
+       off = strtol(optarg, &p, 10) * (units);                         \
+       if (*p)                                                         \
+               err(1, "illegal offset -- %s", optarg);                 \
+       switch(optarg[0]) {                                             \
+       case '+':                                                       \
+               if (off)                                                \
+                       off -= (units);                                 \
+                       style = (forward);                              \
+               break;                                                  \
+       case '-':                                                       \
+               off = -off;                                             \
+               /* FALLTHROUGH */                                       \
+       default:                                                        \
+               style = (backward);                                     \
+               break;                                                  \
+       }                                                               \
+}
 
 
+       obsolete(argv);
        style = NOTSET;
        while ((ch = getopt(argc, argv, "b:c:fn:r")) != EOF)
                switch(ch) {
                case 'b':
        style = NOTSET;
        while ((ch = getopt(argc, argv, "b:c:fn:r")) != EOF)
                switch(ch) {
                case 'b':
-                       if (style)
-                               usage();
-                       off = strtol(num = optarg, &p, 10) * 512;
-                       if (*p)
-                               err("illegal offset -- %s", optarg);
-                       style = *num == '+' ? FBYTES : RBYTES;
+                       ARG(512, FBYTES, RBYTES);
                        break;
                case 'c':
                        break;
                case 'c':
-                       if (style)
-                               usage();
-                       off = strtol(num = optarg, &p, 10);
-                       if (*p)
-                               err("illegal offset -- %s", optarg);
-                       style = *num == '+' ? FBYTES : RBYTES;
+                       ARG(1, FBYTES, RBYTES);
                        break;
                case 'f':
                        fflag = 1;
                        break;
                case 'n':
                        break;
                case 'f':
                        fflag = 1;
                        break;
                case 'n':
-                       if (style)
-                               usage();
-                       off = strtol(num = optarg, &p, 10);
-                       if (*p)
-                               err("illegal offset -- %s", optarg);
-                       style = *num == '+' ? FLINES : RLINES;
+                       ARG(1, FLINES, RLINES);
                        break;
                case 'r':
                        rflag = 1;
                        break;
                case 'r':
                        rflag = 1;
@@ -86,49 +130,27 @@ main(argc, argv)
        argc -= optind;
        argv += optind;
 
        argc -= optind;
        argv += optind;
 
+       if (fflag && argc > 1)
+               err(1, "-f option only appropriate for a single file");
+
        /*
        /*
-        * Don't permit follow option if displaying in reverse.  An offset
-        * with an explicit leading minus is meaningless.
+        * If displaying in reverse, don't permit follow option, and convert
+        * style values.
         */
        if (rflag) {
                if (fflag)
                        usage();
         */
        if (rflag) {
                if (fflag)
                        usage();
-               if (style && *num == '-')
-                       err("illegal offset for -r option -- %s", num);
                if (style == FBYTES)
                        style = RBYTES;
                if (style == FBYTES)
                        style = RBYTES;
-               if (style == FLINES)
+               else if (style == FLINES)
                        style = RLINES;
        }
 
                        style = RLINES;
        }
 
-       if (fname = *argv) {
-               if ((fp = fopen(fname, "r")) == NULL)
-                       ierr();
-       } else {
-               fp = stdin;
-               fname = "stdin";
-       }
-
-       if (fstat(fileno(fp), &sb))
-               ierr();
-
        /*
        /*
-        * Determine if input is a pipe.  4.4BSD will set the SOCKET
-        * bit in the st_mode field for pipes.  Fix this then.
+        * If style not specified, the default is the whole file for -r, and
+        * the last 10 lines if not -r.
         */
         */
-       if (lseek(fileno(fp), 0L, SEEK_CUR) == -1 && errno == ESPIPE) {
-               errno = 0;
-               fflag = 0;              /* POSIX.2 requires this. */
-       }
-
-       /*
-        * Tail's options are weird.  First, -n10 is the same as -n-10, not
-        * -n+10.  Second, the number options for the -r option specify the
-        * number of bytes/chars/lines that get displayed, not the offset from
-        * the beginning/end of the file.  Finally, the default for -r is the
-        * entire file, not 10 lines.
-        */
-       if (!style)
+       if (style == NOTSET)
                if (rflag) {
                        off = 0;
                        style = REVERSE;
                if (rflag) {
                        off = 0;
                        style = REVERSE;
@@ -136,13 +158,50 @@ main(argc, argv)
                        off = 10;
                        style = RLINES;
                }
                        off = 10;
                        style = RLINES;
                }
-       else if (off < 0)
-               off = -off;
 
 
-       if (rflag)
-               reverse(fp, style, off, &sb);
-       else
-               forward(fp, style, off, &sb);
+       if (*argv)
+               for (first = 1; fname = *argv++;) {
+                       if ((fp = fopen(fname, "r")) == NULL ||
+                           fstat(fileno(fp), &sb)) {
+                               ierr();
+                               continue;
+                       }
+                       if (argc > 1) {
+                               (void)printf("%s==> %s <==\n",
+                                   first ? "" : "\n", fname);
+                               first = 0;
+                               (void)fflush(stdout);
+                       }
+
+                       if (rflag)
+                               reverse(fp, style, off, &sb);
+                       else
+                               forward(fp, style, off, &sb);
+                       (void)fclose(fp);
+               }
+       else {
+               fname = "stdin";
+
+               if (fstat(fileno(stdin), &sb)) {
+                       ierr();
+                       exit(1);
+               }
+
+               /*
+                * Determine if input is a pipe.  4.4BSD will set the SOCKET
+                * bit in the st_mode field for pipes.  Fix this then.
+                */
+               if (lseek(fileno(stdin), (off_t)0, SEEK_CUR) == -1 &&
+                   errno == ESPIPE) {
+                       errno = 0;
+                       fflag = 0;              /* POSIX.2 requires this. */
+               }
+
+               if (rflag)
+                       reverse(stdin, style, off, &sb);
+               else
+                       forward(stdin, style, off, &sb);
+       }
        exit(rval);
 }
 
        exit(rval);
 }
 
@@ -153,7 +212,7 @@ main(argc, argv)
  */
 static void
 obsolete(argv)
  */
 static void
 obsolete(argv)
-       char **argv;
+       char *argv[];
 {
        register char *ap, *p, *t;
        int len;
 {
        register char *ap, *p, *t;
        int len;
@@ -175,7 +234,7 @@ obsolete(argv)
                        /* Malloc space for dash, new option and argument. */
                        len = strlen(*argv);
                        if ((start = p = malloc(len + 3)) == NULL)
                        /* Malloc space for dash, new option and argument. */
                        len = strlen(*argv);
                        if ((start = p = malloc(len + 3)) == NULL)
-                               err("%s", strerror(errno));
+                               err(1, "%s", strerror(errno));
                        *p++ = '-';
 
                        /*
                        *p++ = '-';
 
                        /*
@@ -184,8 +243,10 @@ obsolete(argv)
                         * output style characters.
                         */
                        t = *argv + len - 1;
                         * output style characters.
                         */
                        t = *argv + len - 1;
-                       if (*t == 'f' || *t == 'r')
-                               *p++ = *t--;
+                       if (*t == 'f' || *t == 'r') {
+                               *p++ = *t;
+                               *t-- = '\0';
+                       }
                        switch(*t) {
                        case 'b':
                                *p++ = 'b';
                        switch(*t) {
                        case 'b':
                                *p++ = 'b';
@@ -203,7 +264,7 @@ obsolete(argv)
                                *p++ = 'n';
                                break;
                        default:
                                *p++ = 'n';
                                break;
                        default:
-                               err("illegal option -- %s", *argv);
+                               err(1, "illegal option -- %s", *argv);
                        }
                        *p++ = *argv[0];
                        (void)strcpy(p, ap);
                        }
                        *p++ = *argv[0];
                        (void)strcpy(p, ap);
@@ -236,6 +297,6 @@ static void
 usage()
 {
        (void)fprintf(stderr,
 usage()
 {
        (void)fprintf(stderr,
-           "usage: tail [-f | -r] [-b # | -c # | -n #] [file]\n");
+           "usage: tail [-f | -r] [-b # | -c # | -n #] [file ...]\n");
        exit(1);
 }
        exit(1);
 }