Annotation of 43BSD/contrib/tac/tac.c, revision 1.1

1.1     ! root        1: #ifndef lint
        !             2: static char sccsid[] = "@(#)tac.c      1.4 6/5/86";
        !             3: #endif
        !             4: 
        !             5: /*
        !             6:  * tac.c - Print file segments in reverse order
        !             7:  *
        !             8:  * Original line-only version by unknown author off the net.
        !             9:  * Rewritten in 1985 by Jay Lepreau, Univ of Utah, to allocate memory
        !            10:  * dynamically, handle string bounded segments (suggested by Rob Pike),
        !            11:  * and handle pipes.
        !            12:  */
        !            13: 
        !            14: #include <sys/types.h>
        !            15: #include <sys/stat.h>
        !            16: #include <stdio.h>
        !            17: #include <signal.h>
        !            18: 
        !            19: /*
        !            20:  * This should be defined for BSD releases later than 4.2 and for Sys V.2,
        !            21:  * at least.  fwrite is faster than putc only if you have a new speedy fwrite.
        !            22:  */
        !            23: #define FAST_FWRITE
        !            24: 
        !            25: #ifdef DEBUG                           /* dbx can't handle registers */
        !            26: #include <ctype.h>
        !            27: # define register
        !            28: #endif
        !            29: 
        !            30: /* Default target string and bound */
        !            31: int right = 1;                         /* right or left bounded segments? */
        !            32: char *targ = "\n";
        !            33: 
        !            34: char *tfile;
        !            35: char *buf;
        !            36: 
        !            37: int readsize = 4096;                   /* significantly faster than 1024 */
        !            38: int bufsize;
        !            39: int targlen;
        !            40: int numerr;
        !            41: 
        !            42: int cleanup();
        !            43: extern off_t lseek();
        !            44: extern char *strcpy(), *malloc(), *realloc(), *mktemp();
        !            45: 
        !            46: main(argc, argv)
        !            47:     int argc;
        !            48:     char **argv;
        !            49: {
        !            50: 
        !            51: #ifdef DEBUG
        !            52:     if (argc > 1 && isdigit(*argv[1])) {
        !            53:        readsize = atoi(argv[1]);
        !            54:        argc--, argv++;
        !            55:     }
        !            56: #endif
        !            57:     
        !            58:     if (argc > 1 && (argv[1][0] == '+' || argv[1][0] == '-') && argv[1][1]) {
        !            59:        targ = &argv[1][1];
        !            60:        right = (argv[1][0] == '+');
        !            61:        argc--; argv++;
        !            62:     }
        !            63:     targlen = strlen(targ);
        !            64: 
        !            65:     bufsize = (readsize << 1) + targlen + 2;
        !            66:     if ((buf = malloc((unsigned) bufsize)) == NULL) {
        !            67:        perror("tac: initial malloc");
        !            68:        exit(1);
        !            69:     }
        !            70: 
        !            71:     (void) strcpy(buf, targ);          /* stop string at beginning */
        !            72:     buf += targlen;
        !            73: 
        !            74:     if (argc == 1)
        !            75:        tacstdin();
        !            76:     while (--argc) {
        !            77:        if (strcmp(*++argv, "-") == 0)
        !            78:            tacstdin();
        !            79:        else
        !            80:            tacit(*argv);
        !            81:     }
        !            82:     exit(numerr > 0 ? 1 : 0);
        !            83: }
        !            84: 
        !            85: tacstdin()
        !            86: {
        !            87: 
        !            88:     int (*sigint)(), (*sighup)(), (*sigterm)();
        !            89: 
        !            90:     if ((sigint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
        !            91:        (void) signal(SIGINT, cleanup);
        !            92:     if ((sighup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
        !            93:        (void) signal(SIGHUP, cleanup);
        !            94:     if ((sigterm = signal(SIGTERM, SIG_IGN)) != SIG_IGN)
        !            95:        (void) signal(SIGTERM, cleanup);
        !            96: 
        !            97:     savestdin();
        !            98:     tacit(tfile);
        !            99:     (void) unlink(tfile);
        !           100: 
        !           101:     (void) signal(SIGINT, sigint);
        !           102:     (void) signal(SIGHUP, sighup);
        !           103:     (void) signal(SIGTERM, sigterm);
        !           104: }
        !           105: 
        !           106: char template[] = "/tmp/tacXXXXXX";
        !           107: char workplate[sizeof template];
        !           108: 
        !           109: savestdin()
        !           110: {
        !           111:     int fd;
        !           112:     register int n;
        !           113: 
        !           114:     (void) strcpy(workplate, template);
        !           115:     tfile = mktemp(workplate);
        !           116:     if ((fd = creat(tfile, 0600)) < 0) {
        !           117:        prterr(tfile);
        !           118:        cleanup();
        !           119:     }
        !           120:     while ((n = read(0, buf, readsize)) > 0)
        !           121:        if (write(fd, buf, n) != n) {
        !           122:            prterr(tfile);
        !           123:            cleanup();
        !           124:        }
        !           125:     (void) close(fd);
        !           126:     if (n < 0) {
        !           127:        prterr("stdin read");
        !           128:        cleanup();
        !           129:     }
        !           130: }
        !           131: 
        !           132: tacit(name)
        !           133:     char *name;
        !           134: {
        !           135:     register char *p, *pastend;
        !           136:     register int firstchar, targm1len; /* target length minus 1 */
        !           137:     struct stat st;
        !           138:     off_t off;
        !           139:     int fd, i;
        !           140: 
        !           141:     firstchar = *targ;
        !           142:     targm1len = targlen - 1;
        !           143: 
        !           144:     if (stat(name, &st) < 0) {
        !           145:        prterr(name);
        !           146:        numerr++;
        !           147:        return;
        !           148:     }
        !           149:     if ((off = st.st_size) == 0)
        !           150:        return;
        !           151:     if ((fd = open(name, 0)) < 0) {
        !           152:        prterr(name);
        !           153:        numerr++;
        !           154:        return;
        !           155:     }
        !           156: 
        !           157:     /*
        !           158:      * Arrange for the first read to lop off enough to
        !           159:      * leave the rest of the file a multiple of readsize.
        !           160:      * Since readsize can change, this may not always hold during
        !           161:      * the pgm run, but since it usually will, leave it here
        !           162:      * for i/o efficiency (page/sector boundaries and all that).
        !           163:      * Note: the efficiency gain has not been verified.
        !           164:      */
        !           165:     if ((i = off % readsize) == 0)
        !           166:        i = readsize;
        !           167:     off -= i;
        !           168: 
        !           169:     (void) lseek(fd, off, 0);
        !           170:     if (read(fd, buf, i) != i) {
        !           171:        prterr(name);
        !           172:        (void) close(fd);
        !           173:        numerr++;
        !           174:        return;
        !           175:     }
        !           176:     p = pastend = buf + i;             /* pastend always points to end+1 */
        !           177:     p -= targm1len;
        !           178: 
        !           179:     for (;;) {
        !           180:        while ( *--p != firstchar ||
        !           181:          (targm1len && strncmp(p+1, targ+1, targm1len)) )
        !           182:            continue;
        !           183:        if (p < buf) {          /* backed off front of buffer */
        !           184:            if (off == 0) {
        !           185:                /* beginning of file: dump last segment */
        !           186:                output(p + targlen, pastend);
        !           187:                (void) close(fd);
        !           188:                break;
        !           189:            }
        !           190:            if ((i = pastend - buf) > readsize) {
        !           191:                char *tbuf;
        !           192:                int newbufsize = (readsize << 2) + targlen + 2;
        !           193:                
        !           194:                if ((tbuf = realloc(buf-targlen, (unsigned) newbufsize)) == NULL) {
        !           195:                    /* If realloc fails, old buf contents may be lost. */
        !           196:                    perror("tac: segment too long; may have garbage here");
        !           197:                    numerr++;
        !           198:                    i = readsize;
        !           199:                }
        !           200:                else {
        !           201:                    tbuf += targlen;    /* skip over the stop string */
        !           202:                    p += tbuf - buf;
        !           203:                    pastend += tbuf - buf;
        !           204:                    buf = tbuf;
        !           205:                    bufsize = newbufsize;
        !           206:                    readsize = readsize << 1;
        !           207:                    /* guaranteed to fit now (I think!) */
        !           208:                }
        !           209:            }
        !           210:            if (off - readsize < 0) {
        !           211:                readsize = off;
        !           212:                off = 0;
        !           213:            }
        !           214:            else
        !           215:                off -= readsize;
        !           216:            (void) lseek(fd, off, 0);   /* back up */
        !           217:            /* Shift pending old data right to make room for new */
        !           218:            bcopy(buf, p = buf + readsize, i);
        !           219:            pastend = p + i;
        !           220:            if (read(fd, buf, readsize) != readsize) {
        !           221:                prterr(name);
        !           222:                numerr++;
        !           223:                (void) close(fd);
        !           224:                break;
        !           225:            }
        !           226:            continue;
        !           227:        }
        !           228:        /* Found a real instance of the target string */
        !           229:        output(right ? p + targlen : p, pastend);
        !           230:        pastend = p;
        !           231:        p -= targm1len;
        !           232:     }
        !           233: }
        !           234: 
        !           235: /*
        !           236:  * Dump chars from p to pastend-1.  If right-bounded by target
        !           237:  * and not the first time through, append the target string.
        !           238:  */
        !           239: output(p, pastend)
        !           240:     register char *p;
        !           241:     char *pastend;
        !           242: {
        !           243:     static short first = 1;
        !           244: 
        !           245: #ifdef FAST_FWRITE
        !           246:     (void) fwrite(p, 1, pastend - p, stdout);
        !           247: #else
        !           248:     while (p < pastend)
        !           249:        (void) putc(*p++, stdout);
        !           250: #endif
        !           251:     if (right && !first)
        !           252:        (void) fwrite(targ, 1, targlen, stdout);
        !           253:     first = 0;
        !           254:     if ferror(stdout) {
        !           255:        perror("tac: fwrite/putc");
        !           256:        exit(++numerr > 1 ? numerr : 1);
        !           257:     }
        !           258: }
        !           259: 
        !           260: prterr(s)
        !           261:     char *s;
        !           262: {
        !           263: 
        !           264:     fprintf(stderr, "tac: ");
        !           265:     perror(s);
        !           266: }
        !           267: 
        !           268: cleanup()
        !           269: {
        !           270: 
        !           271:     (void) unlink(tfile);
        !           272:     exit(1);
        !           273: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.