1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1991, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)old.bin.grep.c	8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17 
18 /*
19  * grep -- print lines matching (or not matching) a pattern
20  *
21  *	status returns:
22  *		0 - ok, and some matches
23  *		1 - ok, but no matches
24  *		2 - some error
25  */
26 
27 #include <stdio.h>
28 #include <ctype.h>
29 
30 #define	CBRA	1
31 #define	CCHR	2
32 #define	CDOT	4
33 #define	CCL	6
34 #define	NCCL	8
35 #define	CDOL	10
36 #define	CEOF	11
37 #define	CKET	12
38 #define	CBRC	14
39 #define	CLET	15
40 #define	CBACK	18
41 
42 #define	STAR	01
43 
44 #define	LBSIZE	BUFSIZ
45 #define	ESIZE	256
46 #define	NBRA	9
47 
48 char	expbuf[ESIZE];
49 long	lnum;
50 char	linebuf[LBSIZE+1];
51 char	ybuf[ESIZE];
52 int	bflag;
53 int	lflag;
54 int	nflag;
55 int	cflag;
56 int	vflag;
57 int	nfile;
58 int	hflag	= 1;
59 int	oflag;
60 int	sflag;
61 int	yflag;
62 int	wflag;
63 int	retcode = 0;
64 int	circf;
65 int	blkno;
66 long	tln;
67 int	nsucc;
68 char	*braslist[NBRA];
69 char	*braelist[NBRA];
70 char	bittab[] = {
71 	1,
72 	2,
73 	4,
74 	8,
75 	16,
76 	32,
77 	64,
78 	128
79 };
80 
81 main(argc, argv)
82 	int argc;
83 	char **argv;
84 {
85 	extern char *optarg;
86 	extern int optind;
87 	int ch;
88 
89 	while ((ch = getopt(argc, argv, "iywohsvblcne:")) != EOF)
90 		switch((char)ch) {
91 		case 'i':
92 		case 'y':
93 			yflag++;
94 			break;
95 		case 'w':
96 			wflag++;
97 			break;
98 		case 'o':
99 			oflag++;
100 			break;
101 		case 'h':
102 			hflag = 0;
103 			break;
104 		case 's':
105 			sflag++;
106 			break;
107 		case 'v':
108 			vflag++;
109 			break;
110 		case 'b':
111 			bflag++;
112 			break;
113 		case 'l':
114 			lflag++;
115 			break;
116 		case 'c':
117 			cflag++;
118 			break;
119 		case 'n':
120 			nflag++;
121 			break;
122 		case 'e':
123 			argv += optind - 1;
124 			argc -= optind - 1;
125 			*argv = optarg;
126 			goto out;
127 		case '?':
128 		default:
129 			errexit("grep: unknown flag\n", (char *)NULL);
130 		}
131 	argv += optind;
132 	argc -= optind;
133 
134 out:
135 	if (argc<=0)
136 		exit(2);
137 	if (yflag) {
138 		register char *p, *s;
139 		for (s = ybuf, p = *argv; *p; ) {
140 			if (*p == '\\') {
141 				*s++ = *p++;
142 				if (*p)
143 					*s++ = *p++;
144 			} else if (*p == '[') {
145 				while (*p != '\0' && *p != ']')
146 					*s++ = *p++;
147 			} else if (islower(*p)) {
148 				*s++ = '[';
149 				*s++ = toupper(*p);
150 				*s++ = *p++;
151 				*s++ = ']';
152 			} else
153 				*s++ = *p++;
154 			if (s >= ybuf+ESIZE-5)
155 				errexit("grep: argument too long\n", (char *)NULL);
156 		}
157 		*s = '\0';
158 		*argv = ybuf;
159 	}
160 	compile(*argv);
161 	nfile = --argc;
162 	if (argc<=0) {
163 		if (lflag)
164 			exit(1);
165 		execute((char *)NULL);
166 	} else while (--argc >= 0) {
167 		argv++;
168 		execute(*argv);
169 	}
170 	exit(retcode != 0 ? retcode : nsucc == 0);
171 }
172 
173 compile(astr)
174 char *astr;
175 {
176 	register c;
177 	register char *ep, *sp;
178 	char *cstart;
179 	char *lastep;
180 	int cclcnt;
181 	char bracket[NBRA], *bracketp;
182 	int closed;
183 	char numbra;
184 	char neg;
185 
186 	ep = expbuf;
187 	sp = astr;
188 	lastep = 0;
189 	bracketp = bracket;
190 	closed = numbra = 0;
191 	if (*sp == '^') {
192 		circf++;
193 		sp++;
194 	}
195 	if (wflag)
196 		*ep++ = CBRC;
197 	for (;;) {
198 		if (ep >= &expbuf[ESIZE])
199 			goto cerror;
200 		if ((c = *sp++) != '*')
201 			lastep = ep;
202 		switch (c) {
203 
204 		case '\0':
205 			if (wflag)
206 				*ep++ = CLET;
207 			*ep++ = CEOF;
208 			return;
209 
210 		case '.':
211 			*ep++ = CDOT;
212 			continue;
213 
214 		case '*':
215 			if (lastep==0 || *lastep==CBRA || *lastep==CKET ||
216 			    *lastep == CBRC || *lastep == CLET)
217 				goto defchar;
218 			*lastep |= STAR;
219 			continue;
220 
221 		case '$':
222 			if (*sp != '\0')
223 				goto defchar;
224 			*ep++ = CDOL;
225 			continue;
226 
227 		case '[':
228 			if(&ep[17] >= &expbuf[ESIZE])
229 				goto cerror;
230 			*ep++ = CCL;
231 			neg = 0;
232 			if((c = *sp++) == '^') {
233 				neg = 1;
234 				c = *sp++;
235 			}
236 			cstart = sp;
237 			do {
238 				if (c=='\0')
239 					goto cerror;
240 				if (c=='-' && sp>cstart && *sp!=']') {
241 					for (c = sp[-2]; c<*sp; c++)
242 						ep[c>>3] |= bittab[c&07];
243 					sp++;
244 				}
245 				ep[c>>3] |= bittab[c&07];
246 			} while((c = *sp++) != ']');
247 			if(neg) {
248 				for(cclcnt = 0; cclcnt < 16; cclcnt++)
249 					ep[cclcnt] ^= -1;
250 				ep[0] &= 0376;
251 			}
252 
253 			ep += 16;
254 
255 			continue;
256 
257 		case '\\':
258 			if((c = *sp++) == 0)
259 				goto cerror;
260 			if(c == '<') {
261 				*ep++ = CBRC;
262 				continue;
263 			}
264 			if(c == '>') {
265 				*ep++ = CLET;
266 				continue;
267 			}
268 			if(c == '(') {
269 				if(numbra >= NBRA) {
270 					goto cerror;
271 				}
272 				*bracketp++ = numbra;
273 				*ep++ = CBRA;
274 				*ep++ = numbra++;
275 				continue;
276 			}
277 			if(c == ')') {
278 				if(bracketp <= bracket) {
279 					goto cerror;
280 				}
281 				*ep++ = CKET;
282 				*ep++ = *--bracketp;
283 				closed++;
284 				continue;
285 			}
286 
287 			if(c >= '1' && c <= '9') {
288 				if((c -= '1') >= closed)
289 					goto cerror;
290 				*ep++ = CBACK;
291 				*ep++ = c;
292 				continue;
293 			}
294 
295 		defchar:
296 		default:
297 			*ep++ = CCHR;
298 			*ep++ = c;
299 		}
300 	}
301     cerror:
302 	errexit("grep: RE error\n", (char *)NULL);
303 }
304 
305 execute(file)
306 char *file;
307 {
308 	register char *p1, *p2;
309 	register c;
310 
311 	if (file) {
312 		if (freopen(file, "r", stdin) == NULL) {
313 			perror(file);
314 			retcode = 2;
315 		}
316 	}
317 	lnum = 0;
318 	tln = 0;
319 	for (;;) {
320 		lnum++;
321 		p1 = linebuf;
322 		while ((c = getchar()) != '\n') {
323 			if (c == EOF) {
324 				if (cflag) {
325 					if (nfile>1)
326 						printf("%s:", file);
327 					printf("%D\n", tln);
328 					fflush(stdout);
329 				}
330 				return;
331 			}
332 			*p1++ = c;
333 			if (p1 >= &linebuf[LBSIZE-1])
334 				break;
335 		}
336 		*p1++ = '\0';
337 		p1 = linebuf;
338 		p2 = expbuf;
339 		if (circf) {
340 			if (advance(p1, p2))
341 				goto found;
342 			goto nfound;
343 		}
344 		/* fast check for first character */
345 		if (*p2==CCHR) {
346 			c = p2[1];
347 			do {
348 				if (*p1!=c)
349 					continue;
350 				if (advance(p1, p2))
351 					goto found;
352 			} while (*p1++);
353 			goto nfound;
354 		}
355 		/* regular algorithm */
356 		do {
357 			if (advance(p1, p2))
358 				goto found;
359 		} while (*p1++);
360 	nfound:
361 		if (vflag)
362 			succeed(file);
363 		continue;
364 	found:
365 		if (vflag==0)
366 			succeed(file);
367 	}
368 }
369 
370 advance(lp, ep)
371 register char *lp, *ep;
372 {
373 	register char *curlp;
374 	char c;
375 	char *bbeg;
376 	int ct;
377 
378 	for (;;) switch (*ep++) {
379 
380 	case CCHR:
381 		if (*ep++ == *lp++)
382 			continue;
383 		return(0);
384 
385 	case CDOT:
386 		if (*lp++)
387 			continue;
388 		return(0);
389 
390 	case CDOL:
391 		if (*lp==0)
392 			continue;
393 		return(0);
394 
395 	case CEOF:
396 		return(1);
397 
398 	case CCL:
399 		c = *lp++ & 0177;
400 		if(ep[c>>3] & bittab[c & 07]) {
401 			ep += 16;
402 			continue;
403 		}
404 		return(0);
405 	case CBRA:
406 		braslist[*ep++] = lp;
407 		continue;
408 
409 	case CKET:
410 		braelist[*ep++] = lp;
411 		continue;
412 
413 	case CBACK:
414 		bbeg = braslist[*ep];
415 		if (braelist[*ep]==0)
416 			return(0);
417 		ct = braelist[*ep++] - bbeg;
418 		if(ecmp(bbeg, lp, ct)) {
419 			lp += ct;
420 			continue;
421 		}
422 		return(0);
423 
424 	case CBACK|STAR:
425 		bbeg = braslist[*ep];
426 		if (braelist[*ep]==0)
427 			return(0);
428 		ct = braelist[*ep++] - bbeg;
429 		curlp = lp;
430 		while(ecmp(bbeg, lp, ct))
431 			lp += ct;
432 		while(lp >= curlp) {
433 			if(advance(lp, ep))	return(1);
434 			lp -= ct;
435 		}
436 		return(0);
437 
438 
439 	case CDOT|STAR:
440 		curlp = lp;
441 		while (*lp++);
442 		goto star;
443 
444 	case CCHR|STAR:
445 		curlp = lp;
446 		while (*lp++ == *ep);
447 		ep++;
448 		goto star;
449 
450 	case CCL|STAR:
451 		curlp = lp;
452 		do {
453 			c = *lp++ & 0177;
454 		} while(ep[c>>3] & bittab[c & 07]);
455 		ep += 16;
456 		goto star;
457 
458 	star:
459 		if(--lp == curlp) {
460 			continue;
461 		}
462 
463 		if(*ep == CCHR) {
464 			c = ep[1];
465 			do {
466 				if(*lp != c)
467 					continue;
468 				if(advance(lp, ep))
469 					return(1);
470 			} while(lp-- > curlp);
471 			return(0);
472 		}
473 
474 		do {
475 			if (advance(lp, ep))
476 				return(1);
477 		} while (lp-- > curlp);
478 		return(0);
479 
480 	case CBRC:
481 		if (lp == expbuf)
482 			continue;
483 #define	uletter(c)	(isalpha(c) || (c) == '_')
484 		if (uletter(*lp) || isdigit(*lp))
485 			if (!uletter(lp[-1]) && !isdigit(lp[-1]))
486 				continue;
487 		return (0);
488 
489 	case CLET:
490 		if (!uletter(*lp) && !isdigit(*lp))
491 			continue;
492 		return (0);
493 
494 	default:
495 		errexit("grep RE botch\n", (char *)NULL);
496 	}
497 }
498 
499 succeed(f)
500 char *f;
501 {
502 	nsucc = 1;
503 	if (sflag)
504 		return;
505 	if (cflag) {
506 		tln++;
507 		return;
508 	}
509 	if (lflag) {
510 		printf("%s\n", f);
511 		fflush(stdout);
512 		fseek(stdin, 0l, 2);
513 		return;
514 	}
515 	if (nfile > 1 && hflag || oflag)
516 		printf("%s:", f);
517 	if (bflag)
518 		printf("%u:", blkno);
519 	if (nflag)
520 		printf("%ld:", lnum);
521 	printf("%s\n", linebuf);
522 	fflush(stdout);
523 }
524 
525 ecmp(a, b, count)
526 char	*a, *b;
527 {
528 	register cc = count;
529 	while(cc--)
530 		if(*a++ != *b++)	return(0);
531 	return(1);
532 }
533 
534 errexit(s, f)
535 char *s, *f;
536 {
537 	fprintf(stderr, s, f);
538 	exit(2);
539 }
540