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
|
959
|
8 USE_GREP(NEWTOY(grep, "EFHahinosvclqe*f*m#", TOYFLAG_BIN))
|
948
|
9
|
|
10 config GREP
|
|
11 bool "grep"
|
|
12 default n
|
|
13 help
|
959
|
14 usage: grep [-clq] [-EFHhinosv] (-e RE | -f REfile | RE) [file...]
|
948
|
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
|
959
|
25 -H: print file name
|
948
|
26 -h: not print file name
|
|
27 -i: case insensitive
|
|
28 -n: print line numbers
|
|
29 -o: print only matching part
|
959
|
30 -s: keep silent on error
|
948
|
31 -v: invert match
|
|
32 */
|
|
33
|
|
34 #define FOR_grep
|
|
35 #include "toys.h"
|
|
36 #include <regex.h>
|
|
37
|
|
38 static regex_t re; /* fails in GLOBALS */
|
|
39
|
|
40 GLOBALS(
|
|
41 long mArgu;
|
|
42 struct arg_list *fArgu, *eArgu;
|
959
|
43 char mode, *re_xs;
|
948
|
44 )
|
|
45
|
|
46 static void do_grep (int fd, char *name) {
|
|
47 int n = 0, nMatch = 0;
|
|
48
|
|
49 for (;;) {
|
|
50 char *x, *y;
|
|
51 regmatch_t match;
|
|
52 int atBOL = 1;
|
|
53
|
|
54 x = get_rawline (fd, 0, '\n');
|
|
55 if (!x) break;
|
|
56 y = x;
|
|
57 n++; /* start at 1 */
|
|
58
|
|
59 while (regexec (&re, y, 1, &match, atBOL ? 0 : REG_NOTBOL) == 0) {
|
|
60 if (atBOL) nMatch++;
|
959
|
61 toys.exitval = 0;
|
|
62 atBOL = 0;
|
948
|
63 switch (TT.mode) {
|
|
64 case 'q':
|
959
|
65 xexit ();
|
948
|
66 case 'l':
|
|
67 if (!(toys.optflags & FLAG_h)) printf ("%s\n", name);
|
|
68 free (x);
|
|
69 return;
|
|
70 case 'c':
|
|
71 break;
|
|
72 default:
|
|
73 if (!(toys.optflags & FLAG_h)) printf ("%s:", name);
|
|
74 if ( (toys.optflags & FLAG_n)) printf ("%d:", n);
|
|
75 if (!(toys.optflags & FLAG_o)) fputs (x, stdout);
|
|
76 else {
|
|
77 y += match.rm_so;
|
|
78 printf ("%.*s\n", match.rm_eo - match.rm_so, y++);
|
|
79 }
|
|
80 }
|
|
81 if (!(toys.optflags & FLAG_o)) break;
|
|
82 }
|
|
83
|
|
84 free (x);
|
|
85
|
|
86 if ((toys.optflags & FLAG_m) && nMatch >= TT.mArgu) break;
|
|
87 }
|
|
88
|
|
89 if (TT.mode == 'c') printf ("%s:%d\n", name, nMatch);
|
|
90 }
|
|
91
|
|
92 char *regfix (char *re_xs) {
|
|
93 char *re_ys;
|
|
94 int ii, jj = 0;
|
|
95 re_ys = xmalloc (2*strlen (re_xs) + 1);
|
|
96 for (ii = 0; re_xs[ii]; ii++) {
|
|
97 if (strchr ("^.[]$()|*+?{}\\", re_xs[ii])) re_ys[jj++] = '\\';
|
|
98 re_ys[jj++] = re_xs[ii];
|
|
99 }
|
|
100 re_ys[jj] = 0;
|
|
101 return re_ys;
|
|
102 }
|
|
103
|
959
|
104 void addRE (char *x) {
|
|
105 if (toys.optflags & FLAG_F) x = regfix (x);
|
|
106 if (TT.re_xs) TT.re_xs = astrcat (TT.re_xs, "|");
|
|
107 TT.re_xs = astrcat (TT.re_xs, x);
|
|
108 if (toys.optflags & FLAG_F) free (x);
|
|
109 }
|
948
|
110
|
959
|
111 void buildRE (void) {
|
|
112 for (; TT.eArgu; TT.eArgu = TT.eArgu -> next) addRE (TT.eArgu -> arg);
|
948
|
113 for (; TT.fArgu; TT.fArgu = TT.fArgu -> next) {
|
|
114 FILE *f;
|
|
115 char *x, *y;
|
|
116 size_t l;
|
|
117
|
|
118 f = xfopen (TT.fArgu -> arg, "r");
|
|
119 x = 0;
|
|
120 for (;;) {
|
|
121 if (getline (&x, &l, f) < 0) {
|
|
122 if (feof (f)) break;
|
959
|
123 toys.exitval = 2;
|
|
124 perror_exit ("failed to read");
|
948
|
125 }
|
|
126 y = x + strlen (x) - 1;
|
|
127 if (y[0] == '\n') y[0] = 0;
|
|
128
|
959
|
129 addRE (x);
|
948
|
130 }
|
|
131 free (x);
|
|
132 fclose (f);
|
|
133 }
|
|
134
|
959
|
135 if (!TT.re_xs) {
|
|
136 if (toys.optc < 1) {
|
|
137 toys.exitval = 2;
|
|
138 error_exit ("no RE");
|
|
139 }
|
|
140 TT.re_xs = toys.optflags & FLAG_F ? regfix (toys.optargs[0]) : toys.optargs[0];
|
948
|
141 toys.optc--; toys.optargs++;
|
|
142 }
|
|
143
|
959
|
144 if (regcomp (&re, TT.re_xs,
|
948
|
145 (toys.optflags & (FLAG_E | FLAG_F) ? REG_EXTENDED : 0) |
|
|
146 (toys.optflags & FLAG_i ? REG_ICASE : 0)) != 0) {
|
959
|
147 toys.exitval = 2;
|
|
148 error_exit ("bad RE");
|
948
|
149 }
|
|
150 }
|
|
151
|
|
152 void grep_main (void) {
|
|
153 buildRE ();
|
|
154
|
|
155 if (toys.optflags & FLAG_c) TT.mode = 'c';
|
|
156 if (toys.optflags & FLAG_l) TT.mode = 'l';
|
|
157 if (toys.optflags & FLAG_q) TT.mode = 'q';
|
|
158
|
959
|
159 if (!(toys.optflags & FLAG_H) && (toys.optc < 2)) toys.optflags |= FLAG_h;
|
948
|
160
|
959
|
161 toys.exitval = 1;
|
|
162 loopfiles_rw (toys.optargs, O_RDONLY, 0, toys.optflags & FLAG_s, do_grep);
|
|
163 xexit ();
|
948
|
164 }
|