date and time created 83/02/11 15:44:35 by rrh
[unix-history] / usr / src / usr.bin / tail / tail.c
CommitLineData
15dbf57f
BJ
1static char *sccsid = "@(#)tail.c 4.1 (Berkeley) %G%";
2/* tail command
3 *
4 * tail where [file]
5 * where is +\b_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
24struct stat statb;
25int follow;
26int piped;
27char bin[LBIN];
28int errno;
29
30main(argc,argv)
31char **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 }
123copy:
124 while((i=read(0,bin,BUFSIZ))>0)
125 write(1,bin,i);
126 fexit();
127
128 /*seek from end*/
129
130keep:
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 }
152brka:
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);
186brkb:
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();
200errcom:
201 fprintf(stderr, "usage: tail [+\b_[n][lbc][rf]] [file]\n");
202 exit(2);
203}
204
205fexit()
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}