grep.c revision b97d8211fa5c382f32e9a9f606a8566bd2ec09fb
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
673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley *
773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley * TODO: -ABC
8e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
9b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob LandleyUSE_GREP(NEWTOY(grep, "A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
10c49b9a97559d2009e9076e063b2e9acbc13fb9efRob LandleyUSE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
11c49b9a97559d2009e9076e063b2e9acbc13fb9efRob LandleyUSE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
12e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
13e999ca008416e3d41c1079bcb4d151b43c95dc3aStrakeconfig GREP
14e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  bool "grep"
15205b496e42ceb72bf0755fec4f4675a467c401e1Rob Landley  default y
16e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  help
17b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley    usage: grep [-EFivwcloqsHbhn] [-A NUM] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]...
18f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
19f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    Show lines matching regular expressions. If no -e, first argument is
20f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    regular expression to match. With no files (or "-" filename) read stdin.
21f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    Returns 0 if matched, 1 if no match found.
22f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
23f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -e  Regex to match. (May be repeated.)
24f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -f  File containing regular expressions to match.
25f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
26f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    match type:
27b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley    -A  NUM lines after match
28f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -E  extended regex syntax    -F  fixed (match literal string)
29fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    -i  case insensitive         -m  stop after this many lines matched
30fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    -r  recursive (on dir)       -v  invert match
31fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    -w  whole word (implies -E)  -x  whole line
32d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    -z  input NUL terminated
33f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
34f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    display modes: (default: matched line)
35f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -c  count of matching lines  -l  show matching filenames
36f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -o  only matching part       -q  quiet (errors only)
37d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    -s  silent (no error msg)    -Z  output NUL terminated
38f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
39d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    output prefix (default: filename if checking more than 1 file)
40f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -H  force filename           -b  byte offset of match
41f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley    -h  hide filename            -n  line number of match
42c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley
43c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landleyconfig EGREP
44c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  bool
45c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  default y
46c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  depends on GREP
47c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley
48c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landleyconfig FGREP
49c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  bool
50c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  default y
51c49b9a97559d2009e9076e063b2e9acbc13fb9efRob Landley  depends on GREP
52e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake*/
53e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
54e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#define FOR_grep
55e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#include "toys.h"
56e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake#include <regex.h>
57e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
58e999ca008416e3d41c1079bcb4d151b43c95dc3aStrakeGLOBALS(
59dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  long m;
60dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  struct arg_list *f;
61dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  struct arg_list *e;
62b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley  long a;
63e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake)
64e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
6573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley// Show matches in one file
66f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landleystatic void do_grep(int fd, char *name)
67f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{
68dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  FILE *file = fdopen(fd, "r");
69b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley  long offset = 0, after = 0;
7073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley  int lcount = 0, mcount = 0;
71b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley  char *bars = 0, indelim = '\n' * !(toys.optflags&FLAG_z),
72d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley       outdelim = '\n' * !(toys.optflags&FLAG_Z);
73e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
7431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  if (!fd) name = "(standard input)";
7531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley
76dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  if (!file) {
77d3a435e53c94ec25b4ae5fa2614f49ef8884e08aRob Landley    perror_msg_raw(name);
78dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    return;
79dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  }
80dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
8173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley  // Loop through lines of input
82e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  for (;;) {
836c64f5f186d26d4c95d408979d33831935e026f1Rob Landley    char *line = 0, *start;
8473e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    regmatch_t matches;
85dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    size_t unused;
86dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    long len;
87030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley    int mmatch = 0;
88e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
89dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    lcount++;
90d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    if (0 > (len = getdelim(&line, &unused, indelim, file))) break;
91d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    if (line[len-1] == indelim) line[len-1] = 0;
92dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
93dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    start = line;
94e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
9573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    // Loop through matches in this line
9673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    do {
97dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      int rc = 0, skip = 0;
98dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
9973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley      // Handle non-regex matches
100dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      if (toys.optflags & FLAG_F) {
101fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley        struct arg_list *seek, fseek;
102dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        char *s = 0;
103dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
104dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        for (seek = TT.e; seek; seek = seek->next) {
105e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley          if (toys.optflags & FLAG_x) {
106e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley            int i = (toys.optflags & FLAG_i);
107e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley
108e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley            if ((i ? strcasecmp : strcmp)(seek->arg, line)) s = line;
109e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley          } else if (!*seek->arg) {
110fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley            seek = &fseek;
111fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley            fseek.arg = s = line;
112fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley            break;
113fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley          }
114dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          if (toys.optflags & FLAG_i) {
115dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            long ll = strlen(seek->arg);;
116dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
117dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            // Alas, posix hasn't got strcasestr()
118dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            for (s = line; *s; s++) if (!strncasecmp(s, seek->arg, ll)) break;
119dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley            if (!*s) s = 0;
120dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          } else s = strstr(line, seek->arg);
121dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley          if (s) break;
122dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        }
123dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
124dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        if (s) {
12573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          matches.rm_so = (s-line);
12673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          skip = matches.rm_eo = (s-line)+strlen(seek->arg);
127dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley        } else rc = 1;
128dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      } else {
12973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        rc = regexec((regex_t *)toybuf, start, 1, &matches,
130dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley                     start==line ? 0 : REG_NOTBOL);
13173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        skip = matches.rm_eo;
132dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      }
133dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
134dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      if (toys.optflags & FLAG_x)
13573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        if (matches.rm_so || line[matches.rm_eo]) rc = 1;
13673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley
13773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley      if (!rc && (toys.optflags & FLAG_w)) {
13873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        char c = 0;
13973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley
14073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        if ((start+matches.rm_so)!=line) {
14173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          c = start[matches.rm_so-1];
14273e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          if (!isalnum(c) && c != '_') c = 0;
14373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        }
14473e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        if (!c) {
14573e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          c = start[matches.rm_eo];
14673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          if (!isalnum(c) && c != '_') c = 0;
14773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        }
14873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        if (c) {
14973e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          start += matches.rm_so+1;
15073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley
15173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          continue;
15273e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        }
15373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley      }
154dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
155dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      if (toys.optflags & FLAG_v) {
156dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        if (toys.optflags & FLAG_o) {
15773e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          if (rc) skip = matches.rm_eo = strlen(start);
15873e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          else if (!matches.rm_so) {
159dad378bb17f1910014383bf196e87028e98d81d6Rob Landley            start += skip;
160dad378bb17f1910014383bf196e87028e98d81d6Rob Landley            continue;
16173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          } else matches.rm_eo = matches.rm_so;
162dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        } else {
163dad378bb17f1910014383bf196e87028e98d81d6Rob Landley          if (!rc) break;
16473e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley          matches.rm_eo = strlen(start);
165dad378bb17f1910014383bf196e87028e98d81d6Rob Landley        }
16673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        matches.rm_so = 0;
167dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      } else if (rc) break;
1686c64f5f186d26d4c95d408979d33831935e026f1Rob Landley
169b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley      if (bars) {
170b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley        xputs(bars);
171b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley        bars = 0;
172b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley      }
173030970bd70e14849b0f2598bfa0982402fc7e2e7Rob Landley      mmatch++;
174e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley      toys.exitval = 0;
175e6e685cdb8f6e30607c25dcac5f8dc93d4230c20Rob Landley      if (toys.optflags & FLAG_q) xexit();
176dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      if (toys.optflags & FLAG_l) {
177d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley        printf("%s%c", name, outdelim);
1786c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        free(line);
1796c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        fclose(file);
1806c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        return;
181dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      }
182fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley      if (toys.optflags & FLAG_o)
18373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley        if (matches.rm_eo == matches.rm_so)
184fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley          break;
185fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
1866c64f5f186d26d4c95d408979d33831935e026f1Rob Landley      if (!(toys.optflags & FLAG_c)) {
1876c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (toys.optflags & FLAG_H) printf("%s:", name);
1886c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (toys.optflags & FLAG_n) printf("%d:", lcount);
1896c64f5f186d26d4c95d408979d33831935e026f1Rob Landley        if (toys.optflags & FLAG_b)
1906c64f5f186d26d4c95d408979d33831935e026f1Rob Landley          printf("%ld:", offset + (start-line) +
19173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley              ((toys.optflags & FLAG_o) ? matches.rm_so : 0));
192b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley        if (!(toys.optflags & FLAG_o)) {
193b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley          xprintf("%s%c", line, outdelim);
194b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley          if (TT.a) after = TT.a;
195b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley        } else {
196b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley          xprintf("%.*s%c", (int)(matches.rm_eo-matches.rm_so),
197b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley                  start+matches.rm_so, outdelim);
198e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake        }
199e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake      }
200dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
201dad378bb17f1910014383bf196e87028e98d81d6Rob Landley      start += skip;
20273e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley      if (!(toys.optflags & FLAG_o)) break;
20373e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    } while (*start);
204dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    offset += len;
2056c64f5f186d26d4c95d408979d33831935e026f1Rob Landley
206b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley    if (mmatch) mcount++;
207b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley    else if (after) {
208b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley      if (after>0) {
209b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley        xprintf("%s%c", line, outdelim);
210b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley        if (!--after) after = -1;
211b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley      } else bars = "--";
212b97d8211fa5c382f32e9a9f606a8566bd2ec09fbRob Landley    }
213dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    free(line);
214dad378bb17f1910014383bf196e87028e98d81d6Rob Landley
215dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    if ((toys.optflags & FLAG_m) && mcount >= TT.m) break;
216dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  }
217e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
218dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (toys.optflags & FLAG_c) {
219fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    if (toys.optflags & FLAG_H) printf("%s:", name);
220d3657e9e8846e11f376fcb6fae60b15dae853479Rob Landley    xprintf("%d%c", mcount, outdelim);
221e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  }
222e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
223dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  // loopfiles will also close the fd, but this frees an (opaque) struct.
224dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  fclose(file);
225e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake}
226e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
227dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landleystatic void parse_regex(void)
228f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{
22931f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  struct arg_list *al, *new, *list = NULL;
230dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  long len = 0;
231dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  char *s, *ss;
232dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
233dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  // Add all -f lines to -e list. (Yes, this is leaking allocation context for
234dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  // exit to free. Not supporting nofork for this command any time soon.)
23531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  al = TT.f ? TT.f : TT.e;
23631f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  while (al) {
237dc3731783ead154d5a0d8d318566468474b43013Rob Landley    if (TT.f) s = ss = xreadfile(al->arg, 0, 0);
23831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    else s = ss = al->arg;
239dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
24073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    // Split lines at \n, add individual lines to new list.
241fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    do {
242dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      ss = strchr(s, '\n');
24331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      if (ss) *(ss++) = 0;
24431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      new = xmalloc(sizeof(struct arg_list));
24531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      new->next = list;
24631f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      new->arg = s;
24731f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      list = new;
248dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      s = ss;
249fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    } while (ss && *s);
25073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley
25173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    // Advance, when we run out of -f switch to -e.
25231f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    al = al->next;
25331f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    if (!al && TT.f) {
25431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      TT.f = 0;
25531f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      al = TT.e;
25631f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    }
257e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  }
25831f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley  TT.e = list;
259f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley
260dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  if (!(toys.optflags & FLAG_F)) {
261fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    char *regstr;
26273e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    int i;
263e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
26431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    // Convert strings to one big regex
2653ad73e1344afa7812671d08456591b8cde952775William Haddon    for (al = TT.e; al; al = al->next)
2663ad73e1344afa7812671d08456591b8cde952775William Haddon      len += strlen(al->arg)+1+!(toys.optflags & FLAG_E);
267e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
268fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    regstr = s = xmalloc(len);
269dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    for (al = TT.e; al; al = al->next) {
270dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      s = stpcpy(s, al->arg);
27131f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley      if (!(toys.optflags & FLAG_E)) *(s++) = '\\';
272dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      *(s++) = '|';
273e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake    }
27431f07104445bc0c0cbc942d86ee9d31d08c344d8Rob Landley    *(s-=(1+!(toys.optflags & FLAG_E))) = 0;
275e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
27673e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    i = regcomp((regex_t *)toybuf, regstr,
277dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley                ((toys.optflags & FLAG_E) ? REG_EXTENDED : 0) |
278dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley                ((toys.optflags & FLAG_i) ? REG_ICASE    : 0));
2797b7b284ce4c1bd53d442927d9a570fcf84e0187cStrake
28073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    if (i) {
28173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley      regerror(i, (regex_t *)toybuf, toybuf+sizeof(regex_t),
282dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley               sizeof(toybuf)-sizeof(regex_t));
283dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley      error_exit("bad REGEX: %s", toybuf);
284dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    }
285e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake  }
286e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake}
287e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
288fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landleystatic int do_grep_r(struct dirtree *new)
289fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley{
290fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  char *name;
291fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
292fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (new->parent && !dirtree_notdotdot(new)) return 0;
293fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (S_ISDIR(new->st.st_mode)) return DIRTREE_RECURSE;
294fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
295fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  // "grep -r onefile" doesn't show filenames, but "grep -r onedir" should.
296fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (new->parent && !(toys.optflags & FLAG_h)) toys.optflags |= FLAG_H;
297fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
298fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  name = dirtree_path(new, 0);
299fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  do_grep(openat(dirtree_parentfd(new), new->name, 0), name);
300fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  free(name);
301fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
302fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  return 0;
303fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley}
304fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
305f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landleyvoid grep_main(void)
306f97eaf158aa0baf868f0b19d192f7d302c1484e9Rob Landley{
307adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley  char **ss = toys.optargs;
308fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
309dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  // Handle egrep and fgrep
31073e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley  if (*toys.which->name == 'e') toys.optflags |= FLAG_E;
311dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (*toys.which->name == 'f') toys.optflags |= FLAG_F;
3121fa68247345fa6e2cefe4fb4d88ef75f614b18c4M. Farkas-Dyck
313dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  if (!TT.e && !TT.f) {
314adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley    if (!*ss) error_exit("no REGEX");
315dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    TT.e = xzalloc(sizeof(struct arg_list));
316adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley    TT.e->arg = *(ss++);
317dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley    toys.optc--;
318dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  }
319dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley
320dd2d23930241a30a8eb4f0fc9d70bc86c4a6cb6eRob Landley  parse_regex();
321e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
322fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (!(toys.optflags & FLAG_h) && toys.optc>1) toys.optflags |= FLAG_H;
323e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake
324174ba2bed2f33fe90926b08a3e9ec4e3ce7febabStrake  toys.exitval = 1;
325dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  if (toys.optflags & FLAG_s) {
326dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    close(2);
327dad378bb17f1910014383bf196e87028e98d81d6Rob Landley    xopen("/dev/null", O_RDWR);
328dad378bb17f1910014383bf196e87028e98d81d6Rob Landley  }
329fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley
330fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley  if (toys.optflags & FLAG_r) {
33173e3a644c1af8e28ca45c3b5169dee8acc06b179Rob Landley    // Iterate through -r arguments. Use "." as default if none provided.
332adcbaf530f3ec351ec2932ebe9b77140f79eda4aRob Landley    for (ss = *ss ? ss : (char *[]){".", 0}; *ss; ss++) {
333fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley      if (!strcmp(*ss, "-")) do_grep(0, *ss);
334fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley      else dirtree_read(*ss, do_grep_r);
335fce85e9d287cef03777d3c2d97b2a0b43242ee21Rob Landley    }
33694983f2dddde86e8f121abe97a28aa1f6c87a3dbRob Landley  } else loopfiles_rw(ss, O_RDONLY, 0, 1, do_grep);
337e999ca008416e3d41c1079bcb4d151b43c95dc3aStrake}
338