date and time created 85/06/09 01:42:35 by lepreau
authorJay Lepreau <lepreau@ucbvax.Berkeley.EDU>
Sun, 9 Jun 1985 16:42:35 +0000 (08:42 -0800)
committerJay Lepreau <lepreau@ucbvax.Berkeley.EDU>
Sun, 9 Jun 1985 16:42:35 +0000 (08:42 -0800)
SCCS-vsn: local/tac/tac.c 1.1

usr/src/local/tac/tac.c [new file with mode: 0644]

diff --git a/usr/src/local/tac/tac.c b/usr/src/local/tac/tac.c
new file mode 100644 (file)
index 0000000..ef506e1
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef lint
+static char sccsid[] = "@(#)tac.c      1.1 %G%";
+#endif
+
+/*
+ * tac.c - Print file segments in reverse order
+ *
+ * Original line-only version by unknown author off the net.
+ * 1985 mods by Jay Lepreau, Univ of Utah, to allocate memory dynamically
+ * and handle string bounded segments.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+/*
+ * This should be defined for BSD releases later than 4.2 and for Sys V.2,
+ * at least.  fwrite is faster than putc only if you have a new speedy fwrite.
+ */
+#define FAST_FWRITE
+
+#ifdef DEBUG                           /* dbx can't handle registers */
+#include <ctype.h>
+# define register
+#endif
+
+/* Default target string and bound */
+int right = 1;                         /* right or left bounded segments? */
+char *targ = "\n";
+
+int readsize = 4096;                   /* significantly faster than 1024 */
+int bufsize;
+int targlen;
+int numerr;
+
+extern off_t lseek();
+extern char *malloc(), *realloc();
+
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    register char *p, *pastend;
+    register int firstchar, targm1len; /* target length minus 1 */
+    int fd, i;
+    off_t off;
+    char *buf;
+    struct stat st;
+
+    if (argc < 2) {
+       (void) fprintf(stderr, "Usage: tac [-string | +string] file ...\n");
+       exit(1);
+    }
+
+#ifdef DEBUG
+    if (isdigit(*argv[1])) {
+       readsize = atoi(argv[1]);
+       argc--, argv++;
+    }
+#endif
+    
+    if (argv[1][0] == '+' || argv[1][0] == '-') {
+       targ = &argv[1][1];
+       right = (argv[1][0] == '+');
+       argc--; argv++;
+    }
+    firstchar = *targ;
+    targlen = strlen(targ);
+    targm1len = targlen - 1;
+
+    bufsize = (readsize << 1) + targlen + 2;
+    if ((buf = malloc((unsigned) bufsize)) == NULL) {
+       perror("tac: initial malloc");
+       exit(1);
+    }
+
+    (void) strcpy(buf, targ);          /* stop string at beginning */
+    buf += targlen;
+
+    while (--argc) {
+       if (stat(p = *++argv, &st) < 0) {
+           prterr(p);
+           numerr++;
+           continue;
+       }
+       if ((off = st.st_size) == 0)
+           continue;
+       if ((fd = open(p, 0)) < 0) {
+           prterr(p);
+           numerr++;
+           continue;
+       }
+
+       /*
+        * Arrange for the first read to lop off enough to
+        * leave the rest of the file a multiple of readsize.
+        * Since readsize can change, this may not always hold during
+        * the pgm run, but since it usually will, leave it here
+        * for i/o efficiency (page/sector boundaries and all that).
+        * Note: Above statement has never been verified!
+        */
+       if ((i = off % readsize) == 0)
+           i = readsize;
+       off -= i;
+
+       (void) lseek(fd, off, 0);
+       if (read(fd, buf, i) != i) {
+           prterr(p);
+           (void) close(fd);
+           numerr++;
+           continue;
+       }
+       p = pastend = buf + i;          /* pastend always points to end+1 */
+       p -= targm1len;
+
+       for (;;) {
+           while ( *--p != firstchar ||
+             (targm1len && strncmp(p+1, targ+1, targm1len)) )
+               continue;
+           if (p < buf) {              /* backed off front of buffer */
+               if (off == 0) {
+                   /* beginning of file: dump last segment */
+                   output(p + targlen, pastend);
+                   (void) close(fd);
+                   break;
+               }
+               if ((i = pastend - buf) > readsize) {
+                   char *tbuf;
+                   int newbufsize = (readsize << 2) + targlen + 2;
+                   
+                   if ((tbuf = realloc(buf-targlen, (unsigned) newbufsize)) == NULL) {
+                       /* If realloc fails, old buf contents may be lost. */
+                       perror("tac: segment too long; may have garbage here");
+                       numerr++;
+                       i = readsize;
+                   }
+                   else {
+                       tbuf += targlen;        /* skip over the stop string */
+                       p += tbuf - buf;
+                       pastend += tbuf - buf;
+                       buf = tbuf;
+                       bufsize = newbufsize;
+                       readsize = readsize << 1;
+                       /* guaranteed to fit now (I think!) */
+                   }
+               }
+               if (off - readsize < 0) {
+                   readsize = off;
+                   off = 0;
+               }
+               else
+                   off -= readsize;
+               (void) lseek(fd, off, 0);       /* back up */
+               /* Shift pending old data right to make room for new */
+               bcopy(buf, p = buf + readsize, i);
+               pastend = p + i;
+               if (read(fd, buf, readsize) != readsize) {
+                   prterr(*argv);
+                   numerr++;
+                   (void) close(fd);
+                   break;
+               }
+               continue;
+           }
+           /* Found a real instance of the target string */
+           output(right ? p + targlen : p, pastend);
+           pastend = p;
+           p -= targm1len;
+       }
+    }
+    exit(numerr);
+}
+
+/*
+ * Dump chars from p to pastend-1.  If right-bounded by target
+ * and not the first time through, append the target string.
+ */
+output(p, pastend)
+    register char *p;
+    char *pastend;
+{
+    static short first = 1;
+
+#ifdef FAST_FWRITE
+    (void) fwrite(p, 1, pastend - p, stdout);
+#else
+    while (p < pastend)
+       (void) putc(*p++, stdout);
+#endif
+    if (right && !first)
+       (void) fwrite(targ, 1, targlen, stdout);
+    first = 0;
+    if ferror(stdout) {
+       perror("tac: fwrite/putc");
+       exit(++numerr > 1 ? numerr : 1);
+    }
+}
+
+prterr(s)
+    char *s;
+{
+
+    fprintf(stderr, "tac: ");
+    perror(s);
+}