D 1.5 90/06/24 18:32:22 trent 5 4 00001/00001/00272 MRs: COMMENTS: signal int to void D 1.4 86/06/05 23:06:42 lepreau 4 3 00011/00011/00262 MRs: COMMENTS: lint D 1.3 86/06/05 22:59:31 lepreau 3 2 00167/00101/00106 MRs: COMMENTS: handle stdin via temp file. This code needlessly uses temp file in case 'tac 1.1 #include 1.1 #include 1.3 #include 1.1 1.1 /* 1.1 * This should be defined for BSD releases later than 4.2 and for Sys V.2, 1.1 * at least. fwrite is faster than putc only if you have a new speedy fwrite. 1.1 */ 1.1 #define FAST_FWRITE 1.1 1.1 #ifdef DEBUG /* dbx can't handle registers */ 1.1 #include 1.1 # define register 1.1 #endif 1.1 1.1 /* Default target string and bound */ 1.1 int right = 1; /* right or left bounded segments? */ 1.1 char *targ = "\n"; 1.1 1.3 char *tfile; 1.3 char *buf; 1.3 1.1 int readsize = 4096; /* significantly faster than 1024 */ 1.1 int bufsize; 1.1 int targlen; 1.1 int numerr; 1.1 1.3 int cleanup(); 1.1 extern off_t lseek(); 1.4 extern char *strcpy(), *malloc(), *realloc(), *mktemp(); 1.1 1.1 main(argc, argv) 1.1 int argc; 1.1 char **argv; 1.1 { 1.1 1.1 #ifdef DEBUG 1.3 if (argc > 1 && isdigit(*argv[1])) { 1.1 readsize = atoi(argv[1]); 1.1 argc--, argv++; 1.1 } 1.1 #endif 1.1 1.3 if (argc > 1 && (argv[1][0] == '+' || argv[1][0] == '-') && argv[1][1]) { 1.1 targ = &argv[1][1]; 1.1 right = (argv[1][0] == '+'); 1.1 argc--; argv++; 1.1 } 1.1 targlen = strlen(targ); 1.1 1.1 bufsize = (readsize << 1) + targlen + 2; 1.1 if ((buf = malloc((unsigned) bufsize)) == NULL) { 1.1 perror("tac: initial malloc"); 1.1 exit(1); 1.1 } 1.1 1.1 (void) strcpy(buf, targ); /* stop string at beginning */ 1.1 buf += targlen; 1.1 1.3 if (argc == 1) 1.3 tacstdin(); 1.1 while (--argc) { 1.3 if (strcmp(*++argv, "-") == 0) 1.3 tacstdin(); 1.3 else 1.3 tacit(*argv); 1.3 } 1.3 exit(numerr > 0 ? 1 : 0); 1.3 } 1.1 1.3 tacstdin() 1.3 { 1.1 1.5 void (*sigint)(), (*sighup)(), (*sigterm)(); 1.3 1.3 if ((sigint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 1.4 (void) signal(SIGINT, cleanup); 1.3 if ((sighup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 1.4 (void) signal(SIGHUP, cleanup); 1.3 if ((sigterm = signal(SIGTERM, SIG_IGN)) != SIG_IGN) 1.4 (void) signal(SIGTERM, cleanup); 1.3 1.3 savestdin(); 1.3 tacit(tfile); 1.4 (void) unlink(tfile); 1.3 1.4 (void) signal(SIGINT, sigint); 1.4 (void) signal(SIGHUP, sighup); 1.4 (void) signal(SIGTERM, sigterm); 1.3 } 1.3 1.3 char template[] = "/tmp/tacXXXXXX"; 1.3 char workplate[sizeof template]; 1.3 1.3 savestdin() 1.3 { 1.3 int fd; 1.3 register int n; 1.3 1.4 (void) strcpy(workplate, template); 1.3 tfile = mktemp(workplate); 1.3 if ((fd = creat(tfile, 0600)) < 0) { 1.3 prterr(tfile); 1.3 cleanup(); 1.3 } 1.3 while ((n = read(0, buf, readsize)) > 0) 1.3 if (write(fd, buf, n) != n) { 1.3 prterr(tfile); 1.3 cleanup(); 1.1 } 1.4 (void) close(fd); 1.3 if (n < 0) { 1.3 prterr("stdin read"); 1.3 cleanup(); 1.3 } 1.3 } 1.1 1.3 tacit(name) 1.3 char *name; 1.3 { 1.3 register char *p, *pastend; 1.3 register int firstchar, targm1len; /* target length minus 1 */ 1.3 struct stat st; 1.3 off_t off; 1.3 int fd, i; 1.3 1.3 firstchar = *targ; 1.3 targm1len = targlen - 1; 1.3 1.3 if (stat(name, &st) < 0) { 1.3 prterr(name); 1.3 numerr++; 1.3 return; 1.3 } 1.3 if ((off = st.st_size) == 0) 1.3 return; 1.3 if ((fd = open(name, 0)) < 0) { 1.3 prterr(name); 1.3 numerr++; 1.3 return; 1.3 } 1.3 1.3 /* 1.3 * Arrange for the first read to lop off enough to 1.3 * leave the rest of the file a multiple of readsize. 1.3 * Since readsize can change, this may not always hold during 1.3 * the pgm run, but since it usually will, leave it here 1.3 * for i/o efficiency (page/sector boundaries and all that). 1.3 * Note: the efficiency gain has not been verified. 1.3 */ 1.3 if ((i = off % readsize) == 0) 1.3 i = readsize; 1.3 off -= i; 1.3 1.3 (void) lseek(fd, off, 0); 1.3 if (read(fd, buf, i) != i) { 1.3 prterr(name); 1.3 (void) close(fd); 1.3 numerr++; 1.3 return; 1.3 } 1.3 p = pastend = buf + i; /* pastend always points to end+1 */ 1.3 p -= targm1len; 1.3 1.3 for (;;) { 1.3 while ( *--p != firstchar || 1.3 (targm1len && strncmp(p+1, targ+1, targm1len)) ) 1.3 continue; 1.3 if (p < buf) { /* backed off front of buffer */ 1.3 if (off == 0) { 1.3 /* beginning of file: dump last segment */ 1.3 output(p + targlen, pastend); 1.3 (void) close(fd); 1.3 break; 1.3 } 1.3 if ((i = pastend - buf) > readsize) { 1.3 char *tbuf; 1.3 int newbufsize = (readsize << 2) + targlen + 2; 1.3 1.3 if ((tbuf = realloc(buf-targlen, (unsigned) newbufsize)) == NULL) { 1.3 /* If realloc fails, old buf contents may be lost. */ 1.3 perror("tac: segment too long; may have garbage here"); 1.1 numerr++; 1.3 i = readsize; 1.1 } 1.3 else { 1.3 tbuf += targlen; /* skip over the stop string */ 1.3 p += tbuf - buf; 1.3 pastend += tbuf - buf; 1.3 buf = tbuf; 1.3 bufsize = newbufsize; 1.3 readsize = readsize << 1; 1.3 /* guaranteed to fit now (I think!) */ 1.3 } 1.1 } 1.3 if (off - readsize < 0) { 1.3 readsize = off; 1.3 off = 0; 1.3 } 1.3 else 1.3 off -= readsize; 1.3 (void) lseek(fd, off, 0); /* back up */ 1.3 /* Shift pending old data right to make room for new */ 1.3 bcopy(buf, p = buf + readsize, i); 1.3 pastend = p + i; 1.3 if (read(fd, buf, readsize) != readsize) { 1.3 prterr(name); 1.3 numerr++; 1.3 (void) close(fd); 1.3 break; 1.3 } 1.3 continue; 1.1 } 1.3 /* Found a real instance of the target string */ 1.3 output(right ? p + targlen : p, pastend); 1.3 pastend = p; 1.3 p -= targm1len; 1.1 } 1.1 } 1.1 1.1 /* 1.1 * Dump chars from p to pastend-1. If right-bounded by target 1.1 * and not the first time through, append the target string. 1.1 */ 1.1 output(p, pastend) 1.1 register char *p; 1.1 char *pastend; 1.1 { 1.1 static short first = 1; 1.1 1.1 #ifdef FAST_FWRITE 1.1 (void) fwrite(p, 1, pastend - p, stdout); 1.1 #else 1.1 while (p < pastend) 1.1 (void) putc(*p++, stdout); 1.1 #endif 1.1 if (right && !first) 1.1 (void) fwrite(targ, 1, targlen, stdout); 1.1 first = 0; 1.1 if ferror(stdout) { 1.1 perror("tac: fwrite/putc"); 1.1 exit(++numerr > 1 ? numerr : 1); 1.1 } 1.1 } 1.1 1.1 prterr(s) 1.1 char *s; 1.1 { 1.1 1.1 fprintf(stderr, "tac: "); 1.1 perror(s); 1.3 } 1.3 1.3 cleanup() 1.3 { 1.3 1.4 (void) unlink(tfile); 1.3 exit(1); 1.1 }