1 #define	EXTERN
2 #include	"grep.h"
3 
4 char *validflags = "bchiLlnsv";
5 void
usage(void)6 usage(void)
7 {
8 	fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
9 	exits("usage");
10 }
11 
12 void
main(int argc,char * argv[])13 main(int argc, char *argv[])
14 {
15 	int i, status;
16 
17 	ARGBEGIN {
18 	default:
19 		if(utfrune(validflags, ARGC()) == nil)
20 			usage();
21 		flags[ARGC()]++;
22 		break;
23 
24 	case 'q':	/* gnu grep -q means plan 9 grep -s */
25 		flags['s']++;
26 		break;
27 
28 	case 'E':	/* ignore, turns gnu grep into egrep */
29 		break;
30 
31 	case 'e':
32 		flags['e']++;
33 		lineno = 0;
34 		str2top(ARGF());
35 		break;
36 
37 	case 'f':
38 		flags['f']++;
39 		filename = ARGF();
40 		rein = Bopen(filename, OREAD);
41 		if(rein == 0) {
42 			fprint(2, "grep: can't open %s: %r\n", filename);
43 			exits("open");
44 		}
45 		lineno = 1;
46 		str2top(filename);
47 		break;
48 	} ARGEND
49 
50 	if(flags['f'] == 0 && flags['e'] == 0) {
51 		if(argc <= 0)
52 			usage();
53 		str2top(argv[0]);
54 		argc--;
55 		argv++;
56 	}
57 
58 	follow = mal(maxfollow*sizeof(*follow));
59 	state0 = initstate(topre.beg);
60 
61 	Binit(&bout, 1, OWRITE);
62 	switch(argc) {
63 	case 0:
64 		status = search(0, 0);
65 		break;
66 	case 1:
67 		status = search(argv[0], 0);
68 		break;
69 	default:
70 		status = 0;
71 		for(i=0; i<argc; i++)
72 			status |= search(argv[i], Hflag);
73 		break;
74 	}
75 	if(status)
76 		exits(0);
77 	exits("no matches");
78 }
79 
80 int
search(char * file,int flag)81 search(char *file, int flag)
82 {
83 	State *s, *ns;
84 	int c, fid, eof, nl, empty;
85 	long count, lineno, n;
86 	uchar *elp, *lp, *bol;
87 
88 	if(file == 0) {
89 		file = "stdin";
90 		fid = 0;
91 		flag |= Bflag;
92 	} else
93 		fid = open(file, OREAD);
94 
95 	if(fid < 0) {
96 		fprint(2, "grep: can't open %s: %r\n", file);
97 		return 0;
98 	}
99 
100 	if(flags['b'])
101 		flag ^= Bflag;		/* dont buffer output */
102 	if(flags['c'])
103 		flag |= Cflag;		/* count */
104 	if(flags['h'])
105 		flag &= ~Hflag;		/* do not print file name in output */
106 	if(flags['i'])
107 		flag |= Iflag;		/* fold upper-lower */
108 	if(flags['l'])
109 		flag |= Llflag;		/* print only name of file if any match */
110 	if(flags['L'])
111 		flag |= LLflag;		/* print only name of file if any non match */
112 	if(flags['n'])
113 		flag |= Nflag;		/* count only */
114 	if(flags['s'])
115 		flag |= Sflag;		/* status only */
116 	if(flags['v'])
117 		flag |= Vflag;		/* inverse match */
118 
119 	s = state0;
120 	lineno = 0;
121 	count = 0;
122 	eof = 0;
123 	empty = 1;
124 	nl = 0;
125 	lp = u.u.buf;
126 	bol = lp;
127 
128 loop0:
129 	n = lp-bol;
130 	if(n > sizeof(u.u.pre))
131 		n = sizeof(u.u.pre);
132 	memmove(u.u.buf-n, bol, n);
133 	bol = u.u.buf-n;
134 	n = read(fid, u.u.buf, sizeof(u.u.buf));
135 	/* if file has no final newline, simulate one to emit matches to last line */
136 	if(n > 0) {
137 		empty = 0;
138 		nl = u.u.buf[n-1]=='\n';
139 	} else {
140 		if(n < 0){
141 			fprint(2, "grep: read error on %s: %r\n", file);
142 			return count != 0;
143 		}
144 		if(!eof && !nl && !empty) {
145 			u.u.buf[0] = '\n';
146 			n = 1;
147 			eof = 1;
148 		}
149 	}
150 	if(n <= 0) {
151 		close(fid);
152 		if(flag & Cflag) {
153 			if(flag & Hflag)
154 				Bprint(&bout, "%s:", file);
155 			Bprint(&bout, "%ld\n", count);
156 		}
157 		if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
158 			Bprint(&bout, "%s\n", file);
159 		Bflush(&bout);
160 		return count != 0;
161 	}
162 	lp = u.u.buf;
163 	elp = lp+n;
164 	if(flag & Iflag)
165 		goto loopi;
166 
167 /*
168  * normal character loop
169  */
170 loop:
171 	c = *lp;
172 	ns = s->next[c];
173 	if(ns == 0) {
174 		increment(s, c);
175 		goto loop;
176 	}
177 /*	if(flags['2']) */
178 /*		if(s->match) */
179 /*			print("%d: %.2x**\n", s, c); */
180 /*		else */
181 /*			print("%d: %.2x\n", s, c); */
182 	lp++;
183 	s = ns;
184 	if(c == '\n') {
185 		lineno++;
186 		if(!!s->match == !(flag&Vflag)) {
187 			count++;
188 			if(flag & (Cflag|Sflag|Llflag|LLflag))
189 				goto cont;
190 			if(flag & Hflag)
191 				Bprint(&bout, "%s:", file);
192 			if(flag & Nflag)
193 				Bprint(&bout, "%ld: ", lineno);
194 			/* suppress extra newline at EOF unless we are labeling matches with file name */
195 			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
196 			if(flag & Bflag)
197 				Bflush(&bout);
198 		}
199 		if((lineno & Flshcnt) == 0)
200 			Bflush(&bout);
201 	cont:
202 		bol = lp;
203 	}
204 	if(lp != elp)
205 		goto loop;
206 	goto loop0;
207 
208 /*
209  * character loop for -i flag
210  * for speed
211  */
212 loopi:
213 	c = *lp;
214 	if(c >= 'A' && c <= 'Z')
215 		c += 'a'-'A';
216 	ns = s->next[c];
217 	if(ns == 0) {
218 		increment(s, c);
219 		goto loopi;
220 	}
221 	lp++;
222 	s = ns;
223 	if(c == '\n') {
224 		lineno++;
225 		if(!!s->match == !(flag&Vflag)) {
226 			count++;
227 			if(flag & (Cflag|Sflag|Llflag|LLflag))
228 				goto conti;
229 			if(flag & Hflag)
230 				Bprint(&bout, "%s:", file);
231 			if(flag & Nflag)
232 				Bprint(&bout, "%ld: ", lineno);
233 			/* suppress extra newline at EOF unless we are labeling matches with file name */
234 			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
235 			if(flag & Bflag)
236 				Bflush(&bout);
237 		}
238 		if((lineno & Flshcnt) == 0)
239 			Bflush(&bout);
240 	conti:
241 		bol = lp;
242 	}
243 	if(lp != elp)
244 		goto loopi;
245 	goto loop0;
246 }
247 
248 State*
initstate(Re * r)249 initstate(Re *r)
250 {
251 	State *s;
252 	int i;
253 
254 	addcase(r);
255 	if(flags['1'])
256 		reprint("r", r);
257 	nfollow = 0;
258 	gen++;
259 	fol1(r, Cbegin);
260 	follow[nfollow++] = r;
261 	qsort(follow, nfollow, sizeof(*follow), fcmp);
262 
263 	s = sal(nfollow);
264 	for(i=0; i<nfollow; i++)
265 		s->re[i] = follow[i];
266 	return s;
267 }
268