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