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.3 (Berkeley) 11/13/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 if (write (1, bin, n) < 0) 236 exit(1); 237 } 238 } 239