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.5 (Berkeley) 03/01/91";
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 	char *file;
236 {
237 	register char *p1, *p2;
238 	register c;
239 	int f;
240 	char *ebp, *cbp;
241 	static char *buf;
242 	static int blksize;
243 	struct stat stb;
244 
245 	if (file) {
246 		if ((f = open(file, 0)) < 0) {
247 			perror(file);
248 			retcode = 2;
249 		}
250 	} else
251 		f = 0;
252 	if (buf == NULL) {
253 		if (fstat(f, &stb) > 0 && stb.st_blksize > 0)
254 			blksize = stb.st_blksize;
255 		else
256 			blksize = BLKSIZE;
257 		buf = (char *)malloc(blksize);
258 		if (buf == NULL) {
259 			fprintf(stderr, "grep: no memory for %s\n", file);
260 			retcode = 2;
261 			return;
262 		}
263 	}
264 	ebp = buf;
265 	cbp = buf;
266 	lnum = 0;
267 	tln = 0;
268 	blkno = -1;
269 	for (;;) {
270 		lnum++;
271 		if((lnum&0377) == 0)
272 			fflush(stdout);
273 		p1 = linebuf;
274 		p2 = cbp;
275 		for (;;) {
276 			if (p2 >= ebp) {
277 				if ((c = read(f, buf, blksize)) <= 0) {
278 					close(f);
279 					if (cflag) {
280 						if (lflag) {
281 							if (tln)
282 							printf("%s\n", file);
283 						} else {
284 							if (nfile > 1)
285 								printf("%s:", file);
286 							printf("%ld\n", tln);
287 						}
288 					}
289 					return;
290 				}
291 				blkno++;
292 				p2 = buf;
293 				ebp = buf+c;
294 			}
295 			if ((c = *p2++) == '\n')
296 				break;
297 			if(c)
298 			if (p1 < &linebuf[BUFSIZ-1])
299 				*p1++ = c;
300 		}
301 		*p1++ = 0;
302 		cbp = p2;
303 		p1 = linebuf;
304 		p2 = expbuf;
305 		if (circf) {
306 			if (advance(p1, p2))
307 				goto found;
308 			goto nfound;
309 		}
310 		/* fast check for first character */
311 		if (*p2==CCHR) {
312 			c = p2[1];
313 			do {
314 				if (*p1!=c && (!iflag || (c ^ *p1) != ' '
315 					|| letter(c) != letter(*p1)))
316 					continue;
317 				if (advance(p1, p2))
318 					goto found;
319 			} while (*p1++);
320 			goto nfound;
321 		}
322 		/* regular algorithm */
323 		do {
324 			if (advance(p1, p2))
325 				goto found;
326 		} while (*p1++);
327 	nfound:
328 		if (vflag)
329 			succeed(file);
330 		continue;
331 	found:
332 		if (vflag==0)
333 			succeed(file);
334 	}
335 }
336 
337 advance(alp, aep)
338 	char *alp, *aep;
339 {
340 	register char *lp, *ep, *curlp;
341 	char *nextep;
342 
343 	lp = alp;
344 	ep = aep;
345 	for (;;) switch (*ep++) {
346 
347 	case CCHR:
348 		if (!same(*ep, *lp))
349 			return (0);
350 		ep++, lp++;
351 		continue;
352 
353 	case CDOT:
354 		if (*lp++)
355 			continue;
356 		return(0);
357 
358 	case CDOL:
359 		if (*lp==0)
360 			continue;
361 		return(0);
362 
363 	case CEOF:
364 		return(1);
365 
366 	case CCL:
367 		if (cclass(ep, *lp++, 1)) {
368 			ep += *ep;
369 			continue;
370 		}
371 		return(0);
372 
373 	case NCCL:
374 		if (cclass(ep, *lp++, 0)) {
375 			ep += *ep;
376 			continue;
377 		}
378 		return(0);
379 
380 	case CDOT|STAR:
381 		curlp = lp;
382 		while (*lp++);
383 		goto star;
384 
385 	case CCHR|STAR:
386 		curlp = lp;
387 		while (same(*lp, *ep))
388 			lp++;
389 		lp++;
390 		ep++;
391 		goto star;
392 
393 	case CCL|STAR:
394 	case NCCL|STAR:
395 		curlp = lp;
396 		while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
397 		ep += *ep;
398 		goto star;
399 
400 	star:
401 		do {
402 			lp--;
403 			if (advance(lp, ep))
404 				return(1);
405 		} while (lp > curlp);
406 		return(0);
407 
408 	case CBRC:
409 		if (lp == expbuf)
410 			continue;
411 #define	uletter(c)	(letter(c) || c == '_')
412 		if ( ( uletter(*lp) || digit ( * lp ) )  && !uletter(lp[-1]) && !digit(lp[-1]))
413 			continue;
414 		return (0);
415 
416 	case CLET:
417 		if (!uletter(*lp) && !digit(*lp))
418 			continue;
419 		return (0);
420 
421 	default:
422 		fprintf(stderr, "grep: RE botch\n");
423 		exit(2);
424 	}
425 }
426 
427 cclass(aset, ac, af)
428 	char *aset;
429 {
430 	register char *set, c;
431 	register n;
432 
433 	set = aset;
434 	if ((c = ac) == 0)
435 		return(0);
436 	n = *set++;
437 	while (--n)
438 		if (n > 2 && set[1] == '-') {
439 			if (c >= (set[0] & 0177) && c <= (set[2] & 0177))
440 				return (af);
441 			set += 3;
442 			n -= 2;
443 		} else
444 			if ((*set++ & 0177) == c)
445 				return(af);
446 	return(!af);
447 }
448 
449 succeed(f)
450 {
451 	nsucc = 1;
452 	if (sflag)
453 		return;
454 	if (cflag) {
455 		tln++;
456 		return;
457 	}
458 	if (oflag || !hflag && nfile > 1)
459 		printf("%s:", f);
460 	if (bflag)
461 		printf("%d:", blkno);
462 	if (nflag)
463 		printf("%ld:", lnum);
464 	printf("%s\n", linebuf);
465 }
466 
467 digit(c)
468 	char c;
469 {
470 	return (c>='0' && c<='9');
471 }
472