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