Commit | Line | Data |
---|---|---|
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 | |
16 | struct stat statb; | |
17 | char bin[LBIN]; | |
18 | int errno; | |
19 | ||
20 | main(argc,argv) | |
21 | char **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 | ||
105 | keep: | |
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 | } | |
124 | brka: | |
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); | |
144 | brkb: | |
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); | |
157 | errcom: | |
158 | write(2,"usage: tail +\b_n[lbc] [file]\n",29); | |
159 | exit(1); | |
160 | } | |
161 | ||
162 | digit(c) | |
163 | { | |
164 | return(c>='0'&&c<='9'); | |
165 | } |