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