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