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