Annotation of 43BSD/contrib/tac/tac.c, revision 1.1.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.