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