xref: /csrg-svn/usr.bin/tail/tail.c (revision 1214)
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