BSD 2 development
[unix-history] / src / grep.c
CommitLineData
cc6679ee
BJ
1/* Copyright (c) 1979 Regents of the University of California */
2#include <stdio.h>
3/*
4 * grep -- print lines matching (or not matching) a pattern
5 */
6
7#define CCHR 2
8#define CDOT 4
9#define CCL 6
10#define NCCL 8
11#define CDOL 10
12#define CEOF 11
13
14#define CBRC 14
15#define CLET 15
16#define STAR 01
17
18#define LBSIZE 256
19#define ESIZE 256
20
21char expbuf[ESIZE];
22long lnum;
23char linebuf[LBSIZE+1];
24int bflag;
25int nflag;
26int cflag;
27int vflag;
28int nfile;
29int iflag;
30int lflag;
31int wflag;
32int circf;
33int blkno;
34char ibuf[512];
35long tln;
36
37main(argc, argv)
38char **argv;
39{
40 char obuf[BUFSIZ];
41
42 setbuf(stdout, obuf);
43 while (--argc > 0 && (++argv)[0][0]=='-') {
44 char *cp = argv[0] + 1;
45 while (*cp) switch (*cp++) {
46
47 case 'v':
48 vflag++;
49 continue;
50
51 case 'b':
52 bflag++;
53 continue;
54
55 case 'i':
56 iflag++;
57 continue;
58
59 case 'l':
60 lflag++;
61 case 'c':
62 cflag++;
63 continue;
64
65 case 'w':
66 wflag++;
67 continue;
68
69 case 'n':
70 nflag++;
71 continue;
72
73 default:
74 fprintf(stderr, "Unknown flag\n");
75 continue;
76 }
77 }
78 if (argc<=0)
79 exit(2);
80 compile(*argv);
81 nfile = --argc;
82 if (argc<=0)
83 execute(0);
84 else while (--argc >= 0) {
85 argv++;
86 execute(*argv);
87 }
88 exit(0);
89}
90
91compile(astr)
92char *astr;
93{
94 register c;
95 register char *ep, *sp;
96 char *lastep;
97 int cclcnt;
98
99 ep = expbuf;
100 sp = astr;
101 if (*sp == '^') {
102 circf++;
103 sp++;
104 }
105 if (wflag)
106 *ep++ = CBRC;
107 for (;;) {
108 if (ep >= &expbuf[ESIZE])
109 goto cerror;
110 if ((c = *sp++) != '*')
111 lastep = ep;
112 switch (c) {
113
114 case '\0':
115 if (wflag)
116 *ep++ = CLET;
117 *ep++ = CEOF;
118 return;
119
120 case '.':
121 *ep++ = CDOT;
122 continue;
123
124 case '*':
125 if (lastep==0)
126 goto defchar;
127 *lastep =| STAR;
128 continue;
129
130 case '$':
131 if (*sp != '\0')
132 goto defchar;
133 *ep++ = CDOL;
134 continue;
135
136 case '[':
137 *ep++ = CCL;
138 *ep++ = 0;
139 cclcnt = 1;
140 if ((c = *sp++) == '^') {
141 c = *sp++;
142 ep[-2] = NCCL;
143 }
144 do {
145 *ep++ = c;
146 cclcnt++;
147 if (c=='\0' || ep >= &expbuf[ESIZE])
148 goto cerror;
149 } while ((c = *sp++) != ']');
150 lastep[1] = cclcnt;
151 continue;
152
153 case '\\':
154 if ((c = *sp++) == '\0')
155 goto cerror;
156 if (c == '<') {
157 *ep++ = CBRC;
158 continue;
159 }
160 if (c == '>') {
161 *ep++ = CLET;
162 continue;
163 }
164 defchar:
165 default:
166 *ep++ = CCHR;
167 *ep++ = c;
168 }
169 }
170 cerror:
171 fprintf(stderr, "RE error\n");
172}
173
174same(a, b)
175 register int a, b;
176{
177
178 return (a == b || iflag && (a ^ b) == ' ' && letter(a) == letter(b));
179}
180
181letter(c)
182 register int c;
183{
184
185 if (c >= 'a' && c <= 'z')
186 return (c);
187 if (c >= 'A' && c <= 'Z')
188 return (c + 'a' - 'A');
189 return (0);
190}
191
192execute(file)
193{
194 register char *p1, *p2;
195 register c;
196 int f;
197 char *ebp, *cbp;
198
199 if (file) {
200 if ((f = open(file, 0)) < 0) {
201 fprintf(stderr, "Can't open %s\n", file);
202 }
203 } else
204 f = 0;
205 ebp = ibuf;
206 cbp = ibuf;
207 lnum = 0;
208 tln = 0;
209 blkno = -1;
210 for (;;) {
211 lnum++;
212 if((lnum&0377) == 0)
213 fflush(stdout);
214 p1 = linebuf;
215 p2 = cbp;
216 for (;;) {
217 if (p2 >= ebp) {
218 if ((c = read(f, ibuf, 512)) <= 0) {
219 close(f);
220 if (cflag) {
221 if (lflag) {
222 if (tln)
223 printf("%s\n", file);
224 } else {
225 if (nfile > 1)
226 printf("%s:", file);
227 printf("%ld\n", tln);
228 }
229 }
230 return;
231 }
232 blkno++;
233 p2 = ibuf;
234 ebp = ibuf+c;
235 }
236 if ((c = *p2++) == '\n')
237 break;
238 if(c)
239 if (p1 < &linebuf[LBSIZE-1])
240 *p1++ = c;
241 }
242 *p1++ = 0;
243 cbp = p2;
244 p1 = linebuf;
245 p2 = expbuf;
246 if (circf) {
247 if (advance(p1, p2))
248 goto found;
249 goto nfound;
250 }
251 /* fast check for first character */
252 if (*p2==CCHR) {
253 c = p2[1];
254 do {
255 if (*p1!=c && (!iflag || (c ^ *p1) != ' '
256 || letter(c) != letter(*p1)))
257 continue;
258 if (advance(p1, p2))
259 goto found;
260 } while (*p1++);
261 goto nfound;
262 }
263 /* regular algorithm */
264 do {
265 if (advance(p1, p2))
266 goto found;
267 } while (*p1++);
268 nfound:
269 if (vflag)
270 succeed(file);
271 continue;
272 found:
273 if (vflag==0)
274 succeed(file);
275 }
276}
277
278advance(alp, aep)
279{
280 register char *lp, *ep, *curlp;
281 char *nextep;
282
283 lp = alp;
284 ep = aep;
285 for (;;) switch (*ep++) {
286
287 case CCHR:
288 if (!same(*ep, *lp))
289 return (0);
290 ep++, lp++;
291 continue;
292
293 case CDOT:
294 if (*lp++)
295 continue;
296 return(0);
297
298 case CDOL:
299 if (*lp==0)
300 continue;
301 return(0);
302
303 case CEOF:
304 return(1);
305
306 case CCL:
307 if (cclass(ep, *lp++, 1)) {
308 ep =+ *ep;
309 continue;
310 }
311 return(0);
312
313 case NCCL:
314 if (cclass(ep, *lp++, 0)) {
315 ep =+ *ep;
316 continue;
317 }
318 return(0);
319
320 case CDOT|STAR:
321 curlp = lp;
322 while (*lp++);
323 goto star;
324
325 case CCHR|STAR:
326 curlp = lp;
327 while (same(*lp, *ep))
328 lp++;
329 lp++;
330 ep++;
331 goto star;
332
333 case CCL|STAR:
334 case NCCL|STAR:
335 curlp = lp;
336 while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
337 ep =+ *ep;
338 goto star;
339
340 star:
341 do {
342 lp--;
343 if (advance(lp, ep))
344 return(1);
345 } while (lp > curlp);
346 return(0);
347
348 case CBRC:
349 if (lp == expbuf)
350 continue;
351#define uletter(c) (letter(c) || c == '_')
352 if (uletter(*lp) && !uletter(lp[-1]) && !digit(lp[-1]))
353 continue;
354 return (0);
355
356 case CLET:
357 if (!uletter(*lp) && !digit(*lp))
358 continue;
359 return (0);
360
361 default:
362 fprintf(stderr, "RE botch\n");
363 }
364}
365
366cclass(aset, ac, af)
367{
368 register char *set, c;
369 register n;
370
371 set = aset;
372 if ((c = ac) == 0)
373 return(0);
374 n = *set++;
375 while (--n)
376 if (n > 2 && set[1] == '-') {
377 if (c >= (set[0] & 0177) && c <= (set[2] & 0177))
378 return (af);
379 set =+ 3;
380 n -= 2;
381 } else
382 if ((*set++ & 0177) == c)
383 return(af);
384 return(!af);
385}
386
387succeed(f)
388{
389 if (cflag) {
390 tln++;
391 return;
392 }
393 if (nfile > 1)
394 printf("%s:", f);
395 if (bflag)
396 printf("%l:", blkno);
397 if (nflag)
398 printf("%ld:", lnum);
399 printf("%s\n", linebuf);
400}
401
402digit(c)
403 char c;
404{
405 return (c>='0' && c<='9');
406}