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