|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.