fix sccsid to use keywords and modern initialization syntax
[unix-history] / usr / src / usr.bin / tail / tail.c
CommitLineData
22e155fc
DF
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
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
c9e4db79 13#ifndef lint
cff15a56 14static char sccsid[] = "@(#)tail.c 5.3 (Berkeley) %G%";
22e155fc
DF
15#endif not lint
16
15dbf57f
BJ
17/* tail command
18 *
19 * tail where [file]
bf98c161 20 * where is +/-n[type]
15dbf57f
BJ
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>
c9e4db79 36#include <sys/file.h>
15dbf57f
BJ
37#include <errno.h>
38
eaea2641 39#define LBIN 32769
683b5107 40#undef BUFSIZ
eaea2641 41#define BUFSIZ 8192
15dbf57f
BJ
42struct stat statb;
43int follow;
44int piped;
45char bin[LBIN];
46int errno;
47
48main(argc,argv)
49char **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
15dbf57f
BJ
57 arg = argv[1];
58 if(argc<=1 || *arg!='-'&&*arg!='+') {
59 arg = "-10l";
60 argc++;
61 argv--;
62 }
63 fromend = *arg=='-';
64 arg++;
2b63311e
MK
65 if (isdigit(*arg)) {
66 n = 0;
67 while(isdigit(*arg))
68 n = n*10 + *arg++ - '0';
69 } else
70 n = -1;
15dbf57f
BJ
71 if(!fromend&&n>0)
72 n--;
73 if(argc>2) {
c9e4db79 74 (void)close(0);
15dbf57f
BJ
75 if(open(argv[2],0)!=0) {
76 perror(argv[2]);
77 exit(1);
78 }
79 }
c9e4db79 80 (void)lseek(0,(off_t)0,L_INCR);
76c3d437 81 piped = errno==ESPIPE;
15dbf57f
BJ
82 bylines = -1; bkwds = 0;
83 while(*arg)
84 switch(*arg++) {
85
86 case 'b':
683b5107 87 if (n == -1) n = 1;
15dbf57f
BJ
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':
2b63311e 100 if(n==-1) n = LBIN;
15dbf57f
BJ
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 }
2b63311e 110 if (n==-1) n = 10;
15dbf57f
BJ
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 }
c9e4db79 130 (void)write(1,p,j);
15dbf57f
BJ
131 } else if(n>0) {
132 if(!piped)
c9e4db79 133 (void)fstat(0,&statb);
15dbf57f
BJ
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
c9e4db79 143 (void)lseek(0,(off_t)n,L_SET);
15dbf57f
BJ
144 }
145copy:
146 while((i=read(0,bin,BUFSIZ))>0)
c9e4db79 147 (void)write(1,bin,i);
15dbf57f
BJ
148 fexit();
149
150 /*seek from end*/
151
152keep:
153 if(n <= 0)
154 fexit();
155 if(!piped) {
c9e4db79 156 (void)fstat(0,&statb);
683b5107 157 /* If by lines, back up 1 buffer: else back up as needed */
eaea2641 158 di = bylines?LBIN-1:n;
15dbf57f 159 if(statb.st_size > di)
c9e4db79 160 (void)lseek(0,(off_t)-di,L_XTND);
15dbf57f
BJ
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 }
175brka:
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) {
c9e4db79
JB
195 if(bkwds)
196 (void)write(1,bin,lastnl+1);
15dbf57f
BJ
197 goto brkb;
198 }
199 k = LBIN -1;
200 }
201 } while(bin[k]!='\n'&&k!=i);
202 if(bkwds && j>0){
c9e4db79 203 if(k<lastnl) (void)write(1,&bin[k+1],lastnl-k);
15dbf57f 204 else {
c9e4db79
JB
205 (void)write(1,&bin[k+1],LBIN-k-1);
206 (void)write(1,bin,lastnl+1);
15dbf57f
BJ
207 }
208 }
209 } while(j++<n&&k!=i);
210brkb:
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)
c9e4db79 218 (void)write(1,&bin[k+1],i-k-1);
15dbf57f 219 else {
c9e4db79
JB
220 (void)write(1,&bin[k+1],LBIN-k-1);
221 (void)write(1,bin,i);
15dbf57f
BJ
222 }
223 fexit();
224errcom:
225 fprintf(stderr, "usage: tail [+\b_[n][lbc][rf]] [file]\n");
226 exit(2);
227}
228
229fexit()
230{ register int n;
231 if (!follow || piped) exit(0);
232 for (;;)
233 { sleep(1);
234 while ((n = read (0, bin, BUFSIZ)) > 0)
cff15a56
MK
235 if (write (1, bin, n) < 0)
236 exit(1);
15dbf57f
BJ
237 }
238}