xref: /plan9/sys/src/cmd/grep/main.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1 #define	EXTERN
2 #include	"grep.h"
3 
4 char *validflags = "bchiLlnsv";
5 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
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(ARGF());
28 		break;
29 
30 	case 'f':
31 		flags['f']++;
32 		filename = ARGF();
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
74 search(char *file, int flag)
75 {
76 	State *s, *ns;
77 	int c, fid;
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 	lp = u.buf;
116 	bol = lp;
117 
118 loop0:
119 	n = lp-bol;
120 	if(n > sizeof(u.pre))
121 		n = sizeof(u.pre);
122 	memmove(u.buf-n, bol, n);
123 	bol = u.buf-n;
124 	n = read(fid, u.buf, sizeof(u.buf));
125 	if(n <= 0) {
126 		close(fid);
127 		if(flag & Cflag) {
128 			if(flag & Hflag)
129 				Bprint(&bout, "%s:", file);
130 			Bprint(&bout, "%ld\n", count);
131 		}
132 		if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
133 			Bprint(&bout, "%s\n", file);
134 		Bflush(&bout);
135 		return count != 0;
136 	}
137 	lp = u.buf;
138 	elp = lp+n;
139 	if(flag & Iflag)
140 		goto loopi;
141 
142 /*
143  * normal character loop
144  */
145 loop:
146 	c = *lp;
147 	ns = s->next[c];
148 	if(ns == 0) {
149 		increment(s, c);
150 		goto loop;
151 	}
152 //	if(flags['2'])
153 //		if(s->match)
154 //			print("%d: %.2x**\n", s, c);
155 //		else
156 //			print("%d: %.2x\n", s, c);
157 	lp++;
158 	s = ns;
159 	if(c == '\n') {
160 		lineno++;
161 		if(!!s->match == !(flag&Vflag)) {
162 			count++;
163 			if(flag & (Cflag|Sflag|Llflag|LLflag))
164 				goto cont;
165 			if(flag & Hflag)
166 				Bprint(&bout, "%s:", file);
167 			if(flag & Nflag)
168 				Bprint(&bout, "%ld: ", lineno);
169 			Bwrite(&bout, bol, lp-bol);
170 			if(flag & Bflag)
171 				Bflush(&bout);
172 		}
173 		if((lineno & Flshcnt) == 0)
174 			Bflush(&bout);
175 	cont:
176 		bol = lp;
177 	}
178 	if(lp != elp)
179 		goto loop;
180 	goto loop0;
181 
182 /*
183  * character loop for -i flag
184  * for speed
185  */
186 loopi:
187 	c = *lp;
188 	if(c >= 'A' && c <= 'Z')
189 		c += 'a'-'A';
190 	ns = s->next[c];
191 	if(ns == 0) {
192 		increment(s, c);
193 		goto loopi;
194 	}
195 	lp++;
196 	s = ns;
197 	if(c == '\n') {
198 		lineno++;
199 		if(!!s->match == !(flag&Vflag)) {
200 			count++;
201 			if(flag & (Cflag|Sflag|Llflag|LLflag))
202 				goto conti;
203 			if(flag & Hflag)
204 				Bprint(&bout, "%s:", file);
205 			if(flag & Nflag)
206 				Bprint(&bout, "%ld: ", lineno);
207 			Bwrite(&bout, bol, lp-bol);
208 			if(flag & Bflag)
209 				Bflush(&bout);
210 		}
211 		if((lineno & Flshcnt) == 0)
212 			Bflush(&bout);
213 	conti:
214 		bol = lp;
215 	}
216 	if(lp != elp)
217 		goto loopi;
218 	goto loop0;
219 }
220 
221 State*
222 initstate(Re *r)
223 {
224 	State *s;
225 	int i;
226 
227 	addcase(r);
228 	if(flags['1'])
229 		reprint("r", r);
230 	nfollow = 0;
231 	gen++;
232 	fol1(r, Cbegin);
233 	follow[nfollow++] = r;
234 	qsort(follow, nfollow, sizeof(*follow), fcmp);
235 
236 	s = sal(nfollow);
237 	for(i=0; i<nfollow; i++)
238 		s->re[i] = follow[i];
239 	return s;
240 }
241