|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.