BSD 3 development
[unix-history] / usr / src / cmd / tail.c
CommitLineData
ef7ca5f4
BJ
1/* tail command
2 *
3 * tail where [file]
4 * where is +\b_n[type]
5 * - means n lines before end
6 * + means nth line from beginning
7 * type 'b' means tail n blocks, not lines
8 * type 'c' means tail n characters
9*/
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <errno.h>
13#include <pagsiz.h>
14#define BUFSIZ BSIZE
15#define LBIN 4097
16struct stat statb;
17char bin[LBIN];
18int errno;
19
20main(argc,argv)
21char **argv;
22{
23 long n,di;
24 int fromend;
25 register i,j,k;
26 char *p;
27 int partial,piped,bylines;
28 char *arg;
29 lseek(0,(long)0,1);
30 piped = errno==ESPIPE;
31 arg = argv[1];
32 if(argc<=1 || *arg!='-'&&*arg!='+') {
33 arg = "-10l";
34 argc++;
35 argv--;
36 }
37 fromend = *arg=='-';
38 arg++;
39 if(!digit(*arg))
40 goto errcom;
41 n = 0;
42 while(digit(*arg))
43 n = n*10 + *arg++ - '0';
44 if(!fromend&&n>0)
45 n--;
46 if(argc>2) {
47 close(0);
48 if(open(argv[2],0)!=0) {
49 write(2,"tail: can't open ",17);
50 write(2,argv[2],strlen(argv[2]));
51 write(2,"\n",1);
52 exit(1);
53 }
54 }
55 bylines = 0;
56 switch(*arg) {
57 case 'b':
58 n <<= 9;
59 break;
60 case 'c':
61 break;
62 case '\0':
63 case 'l':
64 bylines = 1;
65 break;
66 default:
67 goto errcom;
68 }
69 if(fromend)
70 goto keep;
71
72 /*seek from beginning */
73
74 if(bylines) {
75 j = 0;
76 while(n-->0) {
77 do {
78 if(j--<=0) {
79 p = bin;
80 j = read(0,p,BUFSIZ);
81 if(j--<=0) exit(0);
82 }
83 } while(*p++ != '\n');
84 }
85 write(1,p,j);
86 } else if(n>0) {
87 if(!piped)
88 fstat(0,&statb);
89 if(piped||(statb.st_mode&S_IFMT)==S_IFCHR)
90 while(n>0) {
91 i = n>BUFSIZ?BUFSIZ:n;
92 i = read(0,bin,i);
93 if(i<=0) exit(0);
94 n -= i;
95 }
96 else
97 lseek(0,n,0);
98 }
99 while((i=read(0,bin,BUFSIZ))>0)
100 write(1,bin,i);
101 exit(0);
102
103 /*seek from end*/
104
105keep:
106 if(n<=0) exit(0);
107 if(!piped) {
108 fstat(0,&statb);
109 di = !bylines&&n<LBIN?n:LBIN-1;
110 if(statb.st_size > di)
111 lseek(0,-di,2);
112 }
113 partial = 1;
114 for(;;) {
115 i = 0;
116 do {
117 j = read(0,&bin[i],LBIN-i);
118 if(j<=0)
119 goto brka;
120 i += j;
121 } while(i<LBIN);
122 partial = 0;
123 }
124brka:
125 if(!bylines) {
126 k =
127 n<=i ? i-n:
128 partial ? 0:
129 n>=LBIN ? i+1:
130 i-n+LBIN;
131 k--;
132 } else {
133 k = i;
134 j = 0;
135 do {
136 do {
137 if(--k<0) {
138 if(partial)
139 goto brkb;
140 k = LBIN -1;
141 }
142 } while(bin[k]!='\n'&&k!=i);
143 } while(j++<n&&k!=i);
144brkb:
145 if(k==i) do {
146 if(++k>=LBIN)
147 k = 0;
148 } while(bin[k]!='\n'&&k!=i);
149 }
150 if(k<i)
151 write(1,&bin[k+1],i-k-1);
152 else {
153 write(1,&bin[k+1],LBIN-k-1);
154 write(1,bin,i);
155 }
156 exit(0);
157errcom:
158 write(2,"usage: tail +\b_n[lbc] [file]\n",29);
159 exit(1);
160}
161
162digit(c)
163{
164 return(c>='0'&&c<='9');
165}