948
|
1 /* grep.c - print lines what match given regular expression
|
|
2 *
|
|
3 * Copyright 2013 CE Strake <strake888 at gmail.com>
|
|
4 *
|
|
5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
|
|
6 * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
|
|
7
|
|
8 USE_GREP(NEWTOY(grep, "EFhinovclqe*f*m#", TOYFLAG_BIN))
|
|
9
|
|
10 config GREP
|
|
11 bool "grep"
|
|
12 default n
|
|
13 help
|
|
14 usage: grep [-clq] [-EFhinov] (-e RE | -f REfile | RE) [file...]
|
|
15
|
|
16 modes:
|
|
17 default: print lines from each file what match regular expression RE.
|
|
18 -c: print the number of matching lines in each file.
|
|
19 -l: print all matching file names.
|
|
20 -q: print nil; quit with code 0 when match found.
|
|
21
|
|
22 flags:
|
|
23 -E: extended RE syntax
|
|
24 -F: fixed RE syntax, i.e. all characters literal
|
|
25 -h: not print file name
|
|
26 -i: case insensitive
|
|
27 -n: print line numbers
|
|
28 -o: print only matching part
|
|
29 -v: invert match
|
|
30 */
|
|
31
|
|
32 #define FOR_grep
|
|
33 #include "toys.h"
|
|
34 #include <regex.h>
|
|
35 #include <err.h>
|
|
36
|
|
37 /* could be in GLOBALS but so need initialization code */
|
|
38 static int c = 1;
|
|
39
|
|
40 static regex_t re; /* fails in GLOBALS */
|
|
41
|
|
42 GLOBALS(
|
|
43 long mArgu;
|
|
44 struct arg_list *fArgu, *eArgu;
|
|
45 char mode;
|
|
46 )
|
|
47
|
|
48 static void do_grep (int fd, char *name) {
|
|
49 int n = 0, nMatch = 0;
|
|
50
|
|
51 for (;;) {
|
|
52 char *x, *y;
|
|
53 regmatch_t match;
|
|
54 int atBOL = 1;
|
|
55
|
|
56 x = get_rawline (fd, 0, '\n');
|
|
57 if (!x) break;
|
|
58 y = x;
|
|
59 n++; /* start at 1 */
|
|
60
|
|
61 while (regexec (&re, y, 1, &match, atBOL ? 0 : REG_NOTBOL) == 0) {
|
|
62 if (atBOL) nMatch++;
|
|
63 c = 0; atBOL = 0;
|
|
64 switch (TT.mode) {
|
|
65 case 'q':
|
|
66 exit (0);
|
|
67 case 'l':
|
|
68 if (!(toys.optflags & FLAG_h)) printf ("%s\n", name);
|
|
69 free (x);
|
|
70 return;
|
|
71 case 'c':
|
|
72 break;
|
|
73 default:
|
|
74 if (!(toys.optflags & FLAG_h)) printf ("%s:", name);
|
|
75 if ( (toys.optflags & FLAG_n)) printf ("%d:", n);
|
|
76 if (!(toys.optflags & FLAG_o)) fputs (x, stdout);
|
|
77 else {
|
|
78 y += match.rm_so;
|
|
79 printf ("%.*s\n", match.rm_eo - match.rm_so, y++);
|
|
80 }
|
|
81 }
|
|
82 if (!(toys.optflags & FLAG_o)) break;
|
|
83 }
|
|
84
|
|
85 free (x);
|
|
86
|
|
87 if ((toys.optflags & FLAG_m) && nMatch >= TT.mArgu) break;
|
|
88 }
|
|
89
|
|
90 if (TT.mode == 'c') printf ("%s:%d\n", name, nMatch);
|
|
91 }
|
|
92
|
|
93 char *regfix (char *re_xs) {
|
|
94 char *re_ys;
|
|
95 int ii, jj = 0;
|
|
96 re_ys = xmalloc (2*strlen (re_xs) + 1);
|
|
97 for (ii = 0; re_xs[ii]; ii++) {
|
|
98 if (strchr ("^.[]$()|*+?{}\\", re_xs[ii])) re_ys[jj++] = '\\';
|
|
99 re_ys[jj++] = re_xs[ii];
|
|
100 }
|
|
101 re_ys[jj] = 0;
|
|
102 return re_ys;
|
|
103 }
|
|
104
|
|
105 void buildRE (void) {
|
|
106 char *re_xs;
|
|
107
|
|
108 re_xs = 0;
|
|
109 for (; TT.eArgu; TT.eArgu = TT.eArgu -> next) {
|
|
110 if (toys.optflags & FLAG_F) TT.eArgu -> arg = regfix (TT.eArgu -> arg);
|
|
111 if (re_xs) re_xs = xastrcat (re_xs, "|");
|
|
112 re_xs = xastrcat (re_xs, TT.eArgu -> arg);
|
|
113 }
|
|
114 for (; TT.fArgu; TT.fArgu = TT.fArgu -> next) {
|
|
115 FILE *f;
|
|
116 char *x, *y;
|
|
117 size_t l;
|
|
118
|
|
119 f = xfopen (TT.fArgu -> arg, "r");
|
|
120 x = 0;
|
|
121 for (;;) {
|
|
122 if (getline (&x, &l, f) < 0) {
|
|
123 if (feof (f)) break;
|
|
124 err (2, "failed to read");
|
|
125 }
|
|
126 y = x + strlen (x) - 1;
|
|
127 if (y[0] == '\n') y[0] = 0;
|
|
128
|
|
129 y = toys.optflags & FLAG_F ? regfix (x) : x;
|
|
130 if (re_xs) re_xs = xastrcat (re_xs, "|");
|
|
131 re_xs = xastrcat (re_xs, y);
|
|
132 free (y);
|
|
133 }
|
|
134 free (x);
|
|
135 fclose (f);
|
|
136 }
|
|
137
|
|
138 if (!re_xs) {
|
|
139 if (toys.optc < 1) errx (2, "no RE");
|
|
140 re_xs = toys.optflags & FLAG_F ? regfix (toys.optargs[0]) : toys.optargs[0];
|
|
141 toys.optc--; toys.optargs++;
|
|
142 }
|
|
143
|
|
144 if (regcomp (&re, re_xs,
|
|
145 (toys.optflags & (FLAG_E | FLAG_F) ? REG_EXTENDED : 0) |
|
|
146 (toys.optflags & FLAG_i ? REG_ICASE : 0)) != 0) {
|
|
147 errx (2, "bad RE");
|
|
148 }
|
|
149 }
|
|
150
|
|
151 void grep_main (void) {
|
|
152 buildRE ();
|
|
153
|
|
154 if (toys.optflags & FLAG_c) TT.mode = 'c';
|
|
155 if (toys.optflags & FLAG_l) TT.mode = 'l';
|
|
156 if (toys.optflags & FLAG_q) TT.mode = 'q';
|
|
157
|
|
158 if (toys.optc > 0) loopfiles (toys.optargs, do_grep);
|
|
159 else do_grep (0, "-");
|
|
160
|
|
161 exit (c);
|
|
162 }
|