xref: /original-bsd/usr.bin/tail/tail.c (revision bff54947)
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