1: /* tail command 2: * 3: * tail where [file] 4: * where is +_n[type] 5: * - means n lines before end 6: * + means nth line from beginning 7: * type 'b' means tail n blocks, not lines 8: * type 'c' means tail n characters 9: * Type 'r' means in lines in reverse order from end 10: * (for -r, default is entire buffer ) 11: */ 12: #include <sys/types.h> 13: #include <sys/stat.h> 14: #include <errno.h> 15: #define LBIN 4097 16: struct stat statb; 17: char bin[LBIN]; 18: int errno; 19: 20: main(argc,argv) 21: char **argv; 22: { 23: long n,di; 24: register i,j,k; 25: char *p; 26: int partial,piped,bylines,bkwds,fromend,lastnl; 27: char *arg; 28: lseek(0,(long)0,1); 29: piped = errno==ESPIPE; 30: arg = argv[1]; 31: if(argc<=1 || *arg!='-'&&*arg!='+') { 32: arg = "-10l"; 33: argc++; 34: argv--; 35: } 36: fromend = *arg=='-'; 37: arg++; 38: n = 0; 39: while(digit(*arg)) 40: n = n*10 + *arg++ - '0'; 41: if(!fromend&&n>0) 42: n--; 43: if(argc>2) { 44: close(0); 45: if(open(argv[2],0)!=0) { 46: write(2,"tail: can't open ",17); 47: write(2,argv[2],strlen(argv[2])); 48: write(2,"\n",1); 49: exit(1); 50: } 51: } 52: bylines = 0; bkwds = 0; 53: switch(*arg) { 54: case 'b': 55: n <<= 9; 56: break; 57: case 'c': 58: break; 59: case 'r': 60: if(n==0) n = LBIN; 61: bkwds = 1; fromend = 1; bylines = 1; 62: break; 63: case '\0': 64: case 'l': 65: bylines = 1; 66: break; 67: default: 68: goto errcom; 69: } 70: if(fromend) 71: goto keep; 72: 73: /*seek from beginning */ 74: 75: if(bylines) { 76: j = 0; 77: while(n-->0) { 78: do { 79: if(j--<=0) { 80: p = bin; 81: j = read(0,p,512); 82: if(j--<=0) exit(0); 83: } 84: } while(*p++ != '\n'); 85: } 86: write(1,p,j); 87: } else if(n>0) { 88: if(!piped) 89: fstat(0,&statb); 90: if(piped||(statb.st_mode&S_IFMT)==S_IFCHR) 91: while(n>0) { 92: i = n>512?512:n; 93: i = read(0,bin,i); 94: if(i<=0) exit(0); 95: n -= i; 96: } 97: else 98: lseek(0,n,0); 99: } 100: copy: 101: while((i=read(0,bin,512))>0) 102: write(1,bin,i); 103: exit(0); 104: 105: /*seek from end*/ 106: 107: keep: 108: if(n<=0) exit(0); 109: if(!piped) { 110: fstat(0,&statb); 111: di = !bylines? n: LBIN-1; 112: if(statb.st_size > di) 113: lseek(0,-di,2); 114: if(!bylines) 115: goto copy; 116: } 117: partial = 1; 118: for(;;) { 119: i = 0; 120: do { 121: j = read(0,&bin[i],LBIN-i); 122: if(j<=0) 123: goto brka; 124: i += j; 125: } while(i<LBIN); 126: partial = 0; 127: } 128: brka: 129: if(!bylines) { 130: k = 131: n<=i ? i-n: 132: partial ? 0: 133: n>=LBIN ? i+1: 134: i-n+LBIN; 135: k--; 136: } else { 137: if(bkwds && bin[i==0?LBIN-1:i-1]!='\n'){ /* force trailing newline */ 138: bin[i]='\n'; 139: if(++i>=LBIN) {i = 0; partial = 0;} 140: } 141: k = i; 142: j = 0; 143: do { 144: lastnl = k; 145: do { 146: if(--k<0) { 147: if(partial) { 148: if(bkwds) write(1,bin,lastnl+1); 149: goto brkb; 150: } 151: k = LBIN -1; 152: } 153: } while(bin[k]!='\n'&&k!=i); 154: if(bkwds && j>0){ 155: if(k<lastnl) write(1,&bin[k+1],lastnl-k); 156: else { 157: write(1,&bin[k+1],LBIN-k-1); 158: write(1,bin,lastnl+1); 159: } 160: } 161: } while(j++<n&&k!=i); 162: brkb: 163: if(bkwds) exit(0); 164: if(k==i) do { 165: if(++k>=LBIN) 166: k = 0; 167: } while(bin[k]!='\n'&&k!=i); 168: } 169: if(k<i) 170: write(1,&bin[k+1],i-k-1); 171: else { 172: write(1,&bin[k+1],LBIN-k-1); 173: write(1,bin,i); 174: } 175: exit(0); 176: errcom: 177: write(2,"usage: tail +_n[lbcr] [file]\n",30); 178: exit(1); 179: } 180: 181: digit(c) 182: { 183: return(c>='0'&&c<='9'); 184: }