grep.c revision adcbaf530f3ec351ec2932ebe9b77140f79eda4a
1e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake/* grep.c - print lines what match given regular expression
2e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake *
3e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake * Copyright 2013 CE Strake <strake888 at gmail.com>
4e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake *
5dad378bb17f1910014383bf196e87028e98d81d6Rob Landley * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html
6e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
76c64f5f186d26d4c95d408979d33831935e026f1Rob LandleyUSE_GREP(NEWTOY(grep, "ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
8c49b9a97559d2009e9076e063b2e9acbc13fb9efRob LandleyUSE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
9c49b9a97559d2009e9076e063b2e9acbc13fb9efRob LandleyUSE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
10e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
11e999ca008416e3d41c1079bcb4d151b43c95dc3aStrakeconfig GREP
12e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  bool "grep"
13205b496e42ceb72bf0755fec4f4675a467c401e1Rob Landley  default y
14e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  help
15dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    usage: grep [-EFivwcloqsHbhn] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]...
16f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
17f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    Show lines matching regular expressions. If no -e, first argument is
18f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    regular expression to match. With no files (or "-" filename) read stdin.
19f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    Returns 0 if matched, 1 if no match found.
20f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
21f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -e  Regex to match. (May be repeated.)
22f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -f  File containing regular expressions to match.
23f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
24f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    match type:
25f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -E  extended regex syntax    -F  fixed (match literal string)
26fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    -i  case insensitive         -m  stop after this many lines matched
27fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    -r  recursive (on dir)       -v  invert match
28fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    -w  whole word (implies -E)  -x  whole line
29d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    -z  input NUL terminated
30f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
31f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    display modes: (default: matched line)
32f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -c  count of matching lines  -l  show matching filenames
33f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -o  only matching part       -q  quiet (errors only)
34d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    -s  silent (no error msg)    -Z  output NUL terminated
35f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
36d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    output prefix (default: filename if checking more than 1 file)
37f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -H  force filename           -b  byte offset of match
38f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -h  hide filename            -n  line number of match
39c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley
40c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landleyconfig EGREP
41c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  bool
42c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  default y
43c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  depends on GREP
44c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley
45c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landleyconfig FGREP
46c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  bool
47c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  default y
48c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  depends on GREP
49e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake*/
50e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
51e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#define FOR_grep
52e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#include "toys.h"
53e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#include <regex.h>
54e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
55e999ca008416e3d41c1079bcb4d151b43c95dc3aStrakeGLOBALS(
56dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  long m;
57dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  struct arg_list *f;
58dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  struct arg_list *e;
59dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
60fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  struct arg_list *regex;
61e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake)
62e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
63f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landleystatic void do_grep(int fd, char *name)
64f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{
65dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  FILE *file = fdopen(fd, "r");
66dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  long offset = 0;
676c64f5f186d26d4c95d408979d33831935e026f1Rob Landley  int lcount = 0, mcount = 0, which = toys.optflags & FLAG_w ? 2 : 0;
68d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley  char indelim = '\n' * !(toys.optflags&FLAG_z),
69d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley       outdelim = '\n' * !(toys.optflags&FLAG_Z);
70e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
7131f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  if (!fd) name = "(standard input)";
7231f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley
73dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  if (!file) {
74dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    perror_msg("%s", name);
75dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    return;
76dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  }
77dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
78e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  for (;;) {
796c64f5f186d26d4c95d408979d33831935e026f1Rob Landley    char *line = 0, *start;
807b7b284ce4c1bd53d442927d9a570fcf84e0187cStrake    regmatch_t matches[3];
81dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    size_t unused;
82dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    long len;
83030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley    int mmatch = 0;
84e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
85dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    lcount++;
86d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    if (0 > (len = getdelim(&line, &unused, indelim, file))) break;
87d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    if (line[len-1] == indelim) line[len-1] = 0;
88dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
89dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    start = line;
90e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
916c64f5f186d26d4c95d408979d33831935e026f1Rob Landley    for (;;)
926c64f5f186d26d4c95d408979d33831935e026f1Rob Landley    {
93dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      int rc = 0, skip = 0;
94dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
95dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      if (toys.optflags & FLAG_F) {
96fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley        struct arg_list *seek, fseek;
97dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        char *s = 0;
98dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
99dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        for (seek = TT.e; seek; seek = seek->next) {
100e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley          if (toys.optflags & FLAG_x) {
101e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley            int i = (toys.optflags & FLAG_i);
102e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley
103e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley            if ((i ? strcasecmp : strcmp)(seek->arg, line)) s = line;
104e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley          } else if (!*seek->arg) {
105fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley            seek = &fseek;
106fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley            fseek.arg = s = line;
107fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley            break;
108fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley          }
109dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          if (toys.optflags & FLAG_i) {
110dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            long ll = strlen(seek->arg);;
111dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
112dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            // Alas, posix hasn't got strcasestr()
113dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            for (s = line; *s; s++) if (!strncasecmp(s, seek->arg, ll)) break;
114dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            if (!*s) s = 0;
115dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          } else s = strstr(line, seek->arg);
116dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          if (s) break;
117dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        }
118dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
119dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        if (s) {
120dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          matches[which].rm_so = (s-line);
121dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          skip = matches[which].rm_eo = (s-line)+strlen(seek->arg);
122dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        } else rc = 1;
123dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      } else {
124dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        rc = regexec((regex_t *)toybuf, start, 3, matches,
125dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley                     start==line ? 0 : REG_NOTBOL);
126dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        skip = matches[which].rm_eo;
127dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      }
128dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
129dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      if (toys.optflags & FLAG_x)
130dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        if (matches[which].rm_so || line[matches[which].rm_eo]) rc = 1;
131dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
132dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      if (toys.optflags & FLAG_v) {
133dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        if (toys.optflags & FLAG_o) {
134dad378bb17f1910014383bf196e87028e98d81d6Rob Landley          if (rc) skip = matches[which].rm_eo = strlen(start);
135dad378bb17f1910014383bf196e87028e98d81d6Rob Landley          else if (!matches[which].rm_so) {
136dad378bb17f1910014383bf196e87028e98d81d6Rob Landley            start += skip;
137dad378bb17f1910014383bf196e87028e98d81d6Rob Landley            continue;
138dad378bb17f1910014383bf196e87028e98d81d6Rob Landley          } else matches[which].rm_eo = matches[which].rm_so;
139dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        } else {
140dad378bb17f1910014383bf196e87028e98d81d6Rob Landley          if (!rc) break;
141dad378bb17f1910014383bf196e87028e98d81d6Rob Landley          matches[which].rm_eo = strlen(start);
142dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        }
143dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        matches[which].rm_so = 0;
144dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      } else if (rc) break;
1456c64f5f186d26d4c95d408979d33831935e026f1Rob Landley
146030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley      mmatch++;
147e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley      toys.exitval = 0;
148e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley      if (toys.optflags & FLAG_q) xexit();
149dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      if (toys.optflags & FLAG_l) {
150d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley        printf("%s%c", name, outdelim);
1516c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        free(line);
1526c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        fclose(file);
1536c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        return;
154dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      }
155fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley      if (toys.optflags & FLAG_o)
156fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley        if (matches[which].rm_eo == matches[which].rm_so)
157fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley          break;
158fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
1596c64f5f186d26d4c95d408979d33831935e026f1Rob Landley      if (!(toys.optflags & FLAG_c)) {
1606c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (toys.optflags & FLAG_H) printf("%s:", name);
1616c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (toys.optflags & FLAG_n) printf("%d:", lcount);
1626c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (toys.optflags & FLAG_b)
1636c64f5f186d26d4c95d408979d33831935e026f1Rob Landley          printf("%ld:", offset + (start-line) +
1646c64f5f186d26d4c95d408979d33831935e026f1Rob Landley              ((toys.optflags & FLAG_o) ? matches[which].rm_so : 0));
1656c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (!(toys.optflags & FLAG_o)) xprintf("%s%c", line, outdelim);
166e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake        else {
1676c64f5f186d26d4c95d408979d33831935e026f1Rob Landley          xprintf("%.*s%c", matches[which].rm_eo - matches[which].rm_so,
1686c64f5f186d26d4c95d408979d33831935e026f1Rob Landley                  start + matches[which].rm_so, outdelim);
169e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake        }
170e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake      }
171dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
172dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      start += skip;
173dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      if (!(toys.optflags & FLAG_o) || !*start) break;
174e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake    }
175dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    offset += len;
1766c64f5f186d26d4c95d408979d33831935e026f1Rob Landley
177dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    free(line);
178dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
179030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley    if (mmatch) mcount++;
180dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    if ((toys.optflags & FLAG_m) && mcount >= TT.m) break;
181dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  }
182e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
183dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (toys.optflags & FLAG_c) {
184fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    if (toys.optflags & FLAG_H) printf("%s:", name);
185d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    xprintf("%d%c", mcount, outdelim);
186e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  }
187e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
188dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  // loopfiles will also close the fd, but this frees an (opaque) struct.
189dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  fclose(file);
190e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake}
191e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
192dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landleystatic void parse_regex(void)
193f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{
19431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  struct arg_list *al, *new, *list = NULL;
195dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  long len = 0;
196dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  char *s, *ss;
197dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
198dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  // Add all -f lines to -e list. (Yes, this is leaking allocation context for
199dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  // exit to free. Not supporting nofork for this command any time soon.)
20031f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  al = TT.f ? TT.f : TT.e;
20131f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  while (al) {
202dc3731783ead154d5a0d8d318566468474b43013Rob Landley    if (TT.f) s = ss = xreadfile(al->arg, 0, 0);
20331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    else s = ss = al->arg;
204dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
205fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    do {
206dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      ss = strchr(s, '\n');
20731f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      if (ss) *(ss++) = 0;
20831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      new = xmalloc(sizeof(struct arg_list));
20931f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      new->next = list;
21031f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      new->arg = s;
21131f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      list = new;
212dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      s = ss;
213fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    } while (ss && *s);
21431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    al = al->next;
21531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    if (!al && TT.f) {
21631f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      TT.f = 0;
21731f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      al = TT.e;
21831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    }
219e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  }
22031f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  TT.e = list;
221f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
222dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  if (!(toys.optflags & FLAG_F)) {
223dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    int w = toys.optflags & FLAG_w;
224fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    char *regstr;
225e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
22631f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    // Convert strings to one big regex
227dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    if (w) len = 36;
2283ad73e1344afa7812671d08456591b8cde952775William Haddon    for (al = TT.e; al; al = al->next)
2293ad73e1344afa7812671d08456591b8cde952775William Haddon      len += strlen(al->arg)+1+!(toys.optflags & FLAG_E);
230e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
231fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    regstr = s = xmalloc(len);
232dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    if (w) s = stpcpy(s, "(^|[^_[:alnum:]])(");
233dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    for (al = TT.e; al; al = al->next) {
234dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      s = stpcpy(s, al->arg);
23531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      if (!(toys.optflags & FLAG_E)) *(s++) = '\\';
236dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      *(s++) = '|';
237e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake    }
23831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    *(s-=(1+!(toys.optflags & FLAG_E))) = 0;
239dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    if (w) strcpy(s, ")($|[^_[:alnum:]])");
240e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
241fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    w = regcomp((regex_t *)toybuf, regstr,
242dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley                ((toys.optflags & FLAG_E) ? REG_EXTENDED : 0) |
243dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley                ((toys.optflags & FLAG_i) ? REG_ICASE    : 0));
2447b7b284ce4c1bd53d442927d9a570fcf84e0187cStrake
245dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    if (w) {
246dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      regerror(w, (regex_t *)toybuf, toybuf+sizeof(regex_t),
247dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley               sizeof(toybuf)-sizeof(regex_t));
248dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      error_exit("bad REGEX: %s", toybuf);
249dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    }
250e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  }
251e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake}
252e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
253fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landleystatic int do_grep_r(struct dirtree *new)
254fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley{
255fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  char *name;
256fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
257fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (new->parent && !dirtree_notdotdot(new)) return 0;
258fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (S_ISDIR(new->st.st_mode)) return DIRTREE_RECURSE;
259fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
260fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  // "grep -r onefile" doesn't show filenames, but "grep -r onedir" should.
261fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (new->parent && !(toys.optflags & FLAG_h)) toys.optflags |= FLAG_H;
262fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
263fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  name = dirtree_path(new, 0);
264fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  do_grep(openat(dirtree_parentfd(new), new->name, 0), name);
265fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  free(name);
266fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
267fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  return 0;
268fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley}
269fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
270f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landleyvoid grep_main(void)
271f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{
272adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley  char **ss = toys.optargs;
273fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
274dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  // Handle egrep and fgrep
275dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (*toys.which->name == 'e' || (toys.optflags & FLAG_w))
276dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    toys.optflags |= FLAG_E;
277dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (*toys.which->name == 'f') toys.optflags |= FLAG_F;
2781fa68247345fa6e2cefe4fb4d88ef75f614b18c4M. Farkas-Dyck
279dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  if (!TT.e && !TT.f) {
280adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley    if (!*ss) error_exit("no REGEX");
281dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    TT.e = xzalloc(sizeof(struct arg_list));
282adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley    TT.e->arg = *(ss++);
283dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    toys.optc--;
284dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  }
285dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
286dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  parse_regex();
287e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
288fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (!(toys.optflags & FLAG_h) && toys.optc>1) toys.optflags |= FLAG_H;
289e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
290174ba2bed2f33fe90926b08a3e9ec4e3ce7febabStrake  toys.exitval = 1;
291dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (toys.optflags & FLAG_s) {
292dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    close(2);
293dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    xopen("/dev/null", O_RDWR);
294dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  }
295fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
296fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (toys.optflags & FLAG_r) {
297adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley    for (ss = *ss ? ss : (char *[]){".", 0}; *ss; ss++) {
298fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley      if (!strcmp(*ss, "-")) do_grep(0, *ss);
299fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley      else dirtree_read(*ss, do_grep_r);
300fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    }
301fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  } else loopfiles_rw(toys.optargs, O_RDONLY, 0, 1, do_grep);
302e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake}
303