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