1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if defined(DOSCCS) && !defined(lint) 8: char copyright[] = 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: 12: static char sccsid[] = "@(#)tail.c 5.2.1 (2.11BSD GTE) 1/1/94"; 13: #endif 14: 15: /* tail command 16: * 17: * tail where [file] 18: * where is +/-n[type] 19: * - means n lines before end 20: * + means nth line from beginning 21: * type 'b' means tail n blocks, not lines 22: * type 'c' means tail n characters 23: * Type 'r' means in lines in reverse order from end 24: * (for -r, default is entire buffer ) 25: * option 'f' means loop endlessly trying to read more 26: * characters after the end of file, on the assumption 27: * that the file is growing 28: */ 29: 30: #include <stdio.h> 31: #include <ctype.h> 32: #include <sys/types.h> 33: #include <sys/stat.h> 34: #include <sys/file.h> 35: #include <errno.h> 36: 37: #ifdef pdp11 38: #define LBIN 16385 39: #else 40: #define LBIN 32769 41: #endif 42: #undef BUFSIZ 43: #define BUFSIZ 8192 44: struct stat statb; 45: int follow; 46: int piped; 47: char bin[LBIN]; 48: int errno; 49: 50: main(argc,argv) 51: char **argv; 52: { 53: long n,di; 54: register i,j,k; 55: char *arg; 56: int partial,bylines,bkwds,fromend,lastnl; 57: char *p; 58: 59: arg = argv[1]; 60: if(argc<=1 || *arg!='-'&&*arg!='+') { 61: arg = "-10l"; 62: argc++; 63: argv--; 64: } 65: fromend = *arg=='-'; 66: arg++; 67: if (isdigit(*arg)) { 68: n = 0; 69: while(isdigit(*arg)) 70: n = n*10 + *arg++ - '0'; 71: } else 72: n = -1; 73: if(!fromend&&n>0) 74: n--; 75: if(argc>2) { 76: (void)close(0); 77: if(open(argv[2],0)!=0) { 78: perror(argv[2]); 79: exit(1); 80: } 81: } 82: (void)lseek(0,(off_t)0,L_INCR); 83: piped = errno==ESPIPE; 84: bylines = -1; bkwds = 0; 85: while(*arg) 86: switch(*arg++) { 87: 88: case 'b': 89: if (n == -1) n = 1; 90: n <<= 9; 91: if(bylines!=-1) goto errcom; 92: bylines=0; 93: break; 94: case 'c': 95: if(bylines!=-1) goto errcom; 96: bylines=0; 97: break; 98: case 'f': 99: follow = 1; 100: break; 101: case 'r': 102: if(n==-1) n = LBIN; 103: bkwds = 1; fromend = 1; bylines = 1; 104: break; 105: case 'l': 106: if(bylines!=-1) goto errcom; 107: bylines = 1; 108: break; 109: default: 110: goto errcom; 111: } 112: if (n==-1) n = 10; 113: if(bylines==-1) bylines = 1; 114: if(bkwds) follow=0; 115: if(fromend) 116: goto keep; 117: 118: /*seek from beginning */ 119: 120: if(bylines) { 121: j = 0; 122: while(n-->0) { 123: do { 124: if(j--<=0) { 125: p = bin; 126: j = read(0,p,BUFSIZ); 127: if(j--<=0) 128: fexit(); 129: } 130: } while(*p++ != '\n'); 131: } 132: (void)write(1,p,j); 133: } else if(n>0) { 134: if(!piped) 135: (void)fstat(0,&statb); 136: if(piped||(statb.st_mode&S_IFMT)==S_IFCHR) 137: while(n>0) { 138: i = n>BUFSIZ?BUFSIZ:n; 139: i = read(0,bin,i); 140: if(i<=0) 141: fexit(); 142: n -= i; 143: } 144: else 145: (void)lseek(0,(off_t)n,L_SET); 146: } 147: copy: 148: while((i=read(0,bin,BUFSIZ))>0) 149: (void)write(1,bin,i); 150: fexit(); 151: 152: /*seek from end*/ 153: 154: keep: 155: if(n <= 0) 156: fexit(); 157: if(!piped) { 158: (void)fstat(0,&statb); 159: /* If by lines, back up 1 buffer: else back up as needed */ 160: di = bylines?LBIN-1:n; 161: if(statb.st_size > di) 162: (void)lseek(0,(off_t)-di,L_XTND); 163: if(!bylines) 164: goto copy; 165: } 166: partial = 1; 167: for(;;) { 168: i = 0; 169: do { 170: j = read(0,&bin[i],LBIN-i); 171: if(j<=0) 172: goto brka; 173: i += j; 174: } while(i<LBIN); 175: partial = 0; 176: } 177: brka: 178: if(!bylines) { 179: k = 180: n<=i ? i-n: 181: partial ? 0: 182: n>=LBIN ? i+1: 183: i-n+LBIN; 184: k--; 185: } else { 186: if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */ 187: bin[i]='\n'; 188: if(++i>=LBIN) {i = 0; partial = 0;} 189: } 190: k = i; 191: j = 0; 192: do { 193: lastnl = k; 194: do { 195: if(--k<0) { 196: if(partial) { 197: if(bkwds) 198: (void)write(1,bin,lastnl+1); 199: goto brkb; 200: } 201: k = LBIN -1; 202: } 203: } while(bin[k]!='\n'&&k!=i); 204: if(bkwds && j>0){ 205: if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k); 206: else { 207: (void)write(1,&bin[k+1],LBIN-k-1); 208: (void)write(1,bin,lastnl+1); 209: } 210: } 211: } while(j++<n&&k!=i); 212: brkb: 213: if(bkwds) exit(0); 214: if(k==i) do { 215: if(++k>=LBIN) 216: k = 0; 217: } while(bin[k]!='\n'&&k!=i); 218: } 219: if(k<i) 220: (void)write(1,&bin[k+1],i-k-1); 221: else { 222: (void)write(1,&bin[k+1],LBIN-k-1); 223: (void)write(1,bin,i); 224: } 225: fexit(); 226: errcom: 227: fprintf(stderr, "usage: tail [+_[n][lbc][rf]] [file]\n"); 228: exit(2); 229: } 230: 231: fexit() 232: { register int n; 233: if (!follow || piped) exit(0); 234: for (;;) 235: { sleep(1); 236: while ((n = read (0, bin, BUFSIZ)) > 0) 237: (void)write (1, bin, n); 238: } 239: }