1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62#define FOR_grep
63#include "toys.h"
64#include <regex.h>
65
66GLOBALS(
67 long m;
68 struct arg_list *f;
69 struct arg_list *e;
70 long a;
71 long b;
72 long c;
73 struct arg_list *M;
74 struct arg_list *S;
75
76 char indelim, outdelim;
77 int found;
78)
79
80
81static void outline(char *line, char dash, char *name, long lcount, long bcount,
82 int trim)
83{
84 if (name && (toys.optflags&FLAG_H)) printf("%s%c", name, dash);
85 if (!line || (lcount && (toys.optflags&FLAG_n)))
86 printf("%ld%c", lcount, line ? dash : TT.outdelim);
87 if (bcount && (toys.optflags&FLAG_b)) printf("%ld%c", bcount-1, dash);
88 if (line) xprintf("%.*s%c", trim, line, TT.outdelim);
89}
90
91
92static void do_grep(int fd, char *name)
93{
94 long lcount = 0, mcount = 0, offset = 0, after = 0, before = 0;
95 struct double_list *dlb = 0;
96 char *bars = 0;
97 FILE *file;
98 int bin = 0;
99
100 if (!fd) name = "(standard input)";
101
102
103 if (!(toys.optflags&FLAG_a) && !lseek(fd, 0, SEEK_CUR)) {
104 char buf[256];
105 int len, i = 0;
106 wchar_t wc;
107
108
109 if (0<(len = read(fd, buf, 256))) {
110 lseek(fd, -len, SEEK_CUR);
111 while (i<len) {
112 bin = utf8towc(&wc, buf+i, len-i);
113 if (bin == -2) i = len;
114 if (bin<1) break;
115 i += bin;
116 }
117 bin = i!=len;
118 }
119 if (bin && (toys.optflags&FLAG_I)) return;
120 }
121
122 if (!(file = fdopen(fd, "r"))) return perror_msg("%s", name);
123
124
125 for (;;) {
126 char *line = 0, *start;
127 regmatch_t matches;
128 size_t ulen;
129 long len;
130 int mmatch = 0;
131
132 lcount++;
133 errno = 0;
134 ulen = len = getdelim(&line, &ulen, TT.indelim, file);
135 if (errno) perror_msg("%s", name);
136 if (len<1) break;
137 if (line[ulen-1] == TT.indelim) line[--ulen] = 0;
138
139 start = line;
140
141
142 do {
143 int rc = 0, skip = 0;
144
145
146 if (toys.optflags & FLAG_F) {
147 struct arg_list *seek, fseek;
148 char *s = 0;
149
150 for (seek = TT.e; seek; seek = seek->next) {
151 if (toys.optflags & FLAG_x) {
152 int i = (toys.optflags & FLAG_i);
153
154 if ((i ? strcasecmp : strcmp)(seek->arg, line)) s = line;
155 } else if (!*seek->arg) {
156 seek = &fseek;
157 fseek.arg = s = line;
158 break;
159 }
160 if (toys.optflags & FLAG_i) s = strnstr(line, seek->arg);
161 else s = strstr(line, seek->arg);
162 if (s) break;
163 }
164
165 if (s) {
166 matches.rm_so = (s-line);
167 skip = matches.rm_eo = (s-line)+strlen(seek->arg);
168 } else rc = 1;
169
170
171 } else {
172 rc = regexec0((void *)toybuf, start, ulen-(start-line), 1, &matches,
173 start==line ? 0 : REG_NOTBOL);
174 skip = matches.rm_eo;
175 }
176
177 if (toys.optflags & FLAG_x)
178 if (matches.rm_so || line[matches.rm_eo]) rc = 1;
179
180 if (!rc && (toys.optflags & FLAG_w)) {
181 char c = 0;
182
183 if ((start+matches.rm_so)!=line) {
184 c = start[matches.rm_so-1];
185 if (!isalnum(c) && c != '_') c = 0;
186 }
187 if (!c) {
188 c = start[matches.rm_eo];
189 if (!isalnum(c) && c != '_') c = 0;
190 }
191 if (c) {
192 start += matches.rm_so+1;
193
194 continue;
195 }
196 }
197
198 if (toys.optflags & FLAG_v) {
199 if (toys.optflags & FLAG_o) {
200 if (rc) skip = matches.rm_eo = strlen(start);
201 else if (!matches.rm_so) {
202 start += skip;
203 continue;
204 } else matches.rm_eo = matches.rm_so;
205 } else {
206 if (!rc) break;
207 matches.rm_eo = strlen(start);
208 }
209 matches.rm_so = 0;
210 } else if (rc) break;
211
212
213 if (bars) {
214 xputs(bars);
215 bars = 0;
216 }
217 mmatch++;
218 TT.found = 1;
219 if (toys.optflags & FLAG_q) {
220 toys.exitval = 0;
221 xexit();
222 }
223 if (toys.optflags & FLAG_l) {
224 xprintf("%s%c", name, TT.outdelim);
225 free(line);
226 fclose(file);
227 return;
228 }
229 if (toys.optflags & FLAG_o)
230 if (matches.rm_eo == matches.rm_so)
231 break;
232
233 if (!(toys.optflags & FLAG_c)) {
234 long bcount = 1 + offset + (start-line) +
235 ((toys.optflags & FLAG_o) ? matches.rm_so : 0);
236
237 if (bin) printf("Binary file %s matches\n", name);
238 else if (!(toys.optflags & FLAG_o)) {
239 while (dlb) {
240 struct double_list *dl = dlist_pop(&dlb);
241
242 outline(dl->data, '-', name, lcount-before, 0, -1);
243 free(dl->data);
244 free(dl);
245 before--;
246 }
247
248 outline(line, ':', name, lcount, bcount, -1);
249 if (TT.a) after = TT.a+1;
250 } else outline(start+matches.rm_so, ':', name, lcount, bcount,
251 matches.rm_eo-matches.rm_so);
252 }
253
254 start += skip;
255 if (!(toys.optflags & FLAG_o)) break;
256 } while (*start);
257 offset += len;
258
259 if (mmatch) mcount++;
260 else {
261 int discard = (after || TT.b);
262
263 if (after && --after) {
264 outline(line, '-', name, lcount, 0, -1);
265 discard = 0;
266 }
267 if (discard && TT.b) {
268 dlist_add(&dlb, line);
269 line = 0;
270 if (++before>TT.b) {
271 struct double_list *dl;
272
273 dl = dlist_pop(&dlb);
274 free(dl->data);
275 free(dl);
276 before--;
277 } else discard = 0;
278 }
279
280
281 if (discard && mcount) bars = "--";
282 }
283 free(line);
284
285 if ((toys.optflags & FLAG_m) && mcount >= TT.m) break;
286 }
287
288 if (toys.optflags & FLAG_c) outline(0, ':', name, mcount, 0, -1);
289
290
291 fclose(file);
292}
293
294static void parse_regex(void)
295{
296 struct arg_list *al, *new, *list = NULL;
297 long len = 0;
298 char *s, *ss;
299
300
301
302 al = TT.f ? TT.f : TT.e;
303 while (al) {
304 if (TT.f) s = ss = xreadfile(al->arg, 0, 0);
305 else s = ss = al->arg;
306
307
308 do {
309 ss = strchr(s, '\n');
310 if (ss) *(ss++) = 0;
311 new = xmalloc(sizeof(struct arg_list));
312 new->next = list;
313 new->arg = s;
314 list = new;
315 s = ss;
316 } while (ss && *s);
317
318
319 al = al->next;
320 if (!al && TT.f) {
321 TT.f = 0;
322 al = TT.e;
323 }
324 }
325 TT.e = list;
326
327 if (!(toys.optflags & FLAG_F)) {
328 char *regstr;
329 int i;
330
331
332 for (al = TT.e; al; al = al->next)
333 len += strlen(al->arg)+1+!(toys.optflags & FLAG_E);
334
335 regstr = s = xmalloc(len);
336 for (al = TT.e; al; al = al->next) {
337 s = stpcpy(s, al->arg);
338 if (!(toys.optflags & FLAG_E)) *(s++) = '\\';
339 *(s++) = '|';
340 }
341 *(s-=(1+!(toys.optflags & FLAG_E))) = 0;
342
343 i = regcomp((regex_t *)toybuf, regstr,
344 ((toys.optflags & FLAG_E) ? REG_EXTENDED : 0) |
345 ((toys.optflags & FLAG_i) ? REG_ICASE : 0));
346
347 if (i) {
348 regerror(i, (regex_t *)toybuf, toybuf+sizeof(regex_t),
349 sizeof(toybuf)-sizeof(regex_t));
350 error_exit("bad REGEX: %s", toybuf);
351 }
352 }
353}
354
355static int do_grep_r(struct dirtree *new)
356{
357 char *name;
358
359 if (!dirtree_notdotdot(new)) return 0;
360 if (S_ISDIR(new->st.st_mode)) return DIRTREE_RECURSE;
361 if (TT.S || TT.M) {
362 struct arg_list *al;
363
364 for (al = TT.S; al; al = al->next)
365 if (!fnmatch(al->arg, new->name, 0)) return 0;
366
367 if (TT.M) {
368 for (al = TT.M; al; al = al->next)
369 if (!fnmatch(al->arg, new->name, 0)) break;
370
371 if (!al) return 0;
372 }
373 }
374
375
376 if (new->parent && !(toys.optflags & FLAG_h)) toys.optflags |= FLAG_H;
377
378 name = dirtree_path(new, 0);
379 do_grep(openat(dirtree_parentfd(new), new->name, 0), name);
380 free(name);
381
382 return 0;
383}
384
385void grep_main(void)
386{
387 char **ss = toys.optargs;
388
389
390 toys.exitval = 2;
391
392 if (!TT.a) TT.a = TT.c;
393 if (!TT.b) TT.b = TT.c;
394
395 TT.indelim = '\n' * !(toys.optflags&FLAG_z);
396 TT.outdelim = '\n' * !(toys.optflags&FLAG_Z);
397
398
399 if (*toys.which->name == 'e') toys.optflags |= FLAG_E;
400 if (*toys.which->name == 'f') toys.optflags |= FLAG_F;
401
402 if (!TT.e && !TT.f) {
403 if (!*ss) error_exit("no REGEX");
404 TT.e = xzalloc(sizeof(struct arg_list));
405 TT.e->arg = *(ss++);
406 toys.optc--;
407 }
408
409 parse_regex();
410
411 if (!(toys.optflags & FLAG_h) && toys.optc>1) toys.optflags |= FLAG_H;
412
413 if (toys.optflags & FLAG_s) {
414 close(2);
415 xopen_stdio("/dev/null", O_RDWR);
416 }
417
418 if (toys.optflags & FLAG_r) {
419
420 for (ss = *ss ? ss : (char *[]){".", 0}; *ss; ss++) {
421 if (!strcmp(*ss, "-")) do_grep(0, *ss);
422 else dirtree_read(*ss, do_grep_r);
423 }
424 } else loopfiles_rw(ss, O_RDONLY|WARN_ONLY, 0, do_grep);
425 toys.exitval = !TT.found;
426}
427