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