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