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