Introduction
Introduction Statistics Contact Development Disclaimer Help
grep.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
grep.c (5455B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <regex.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <strings.h>
7
8 #include "queue.h"
9 #include "util.h"
10
11 enum { Match = 0, NoMatch = 1, Error = 2 };
12
13 static void addpattern(const char *, size_t);
14 static void addpatternfile(FILE *);
15 static int grep(FILE *, const char *);
16
17 static int Eflag;
18 static int Fflag;
19 static int Hflag;
20 static int eflag;
21 static int fflag;
22 static int hflag;
23 static int iflag;
24 static int sflag;
25 static int vflag;
26 static int wflag;
27 static int xflag;
28 static int many;
29 static int mode;
30
31 struct pattern {
32 char *pattern;
33 regex_t preg;
34 SLIST_ENTRY(pattern) entry;
35 };
36
37 static SLIST_HEAD(phead, pattern) phead;
38
39 static void
40 addpattern(const char *pattern, size_t patlen)
41 {
42 struct pattern *pnode;
43 char *tmp;
44 int bol, eol;
45 size_t len;
46
47 if (!patlen)
48 return;
49
50 /* a null BRE/ERE matches every line */
51 if (!Fflag)
52 if (pattern[0] == '\0')
53 pattern = "^";
54
55 if (!Fflag && xflag) {
56 tmp = enmalloc(Error, patlen + 3);
57 snprintf(tmp, patlen + 3, "%s%s%s",
58 pattern[0] == '^' ? "" : "^",
59 pattern,
60 pattern[patlen - 1] == '$' ? "" : "$");
61 } else if (!Fflag && wflag) {
62 len = patlen + 5 + (Eflag ? 2 : 4);
63 tmp = enmalloc(Error, len);
64
65 bol = eol = 0;
66 if (pattern[0] == '^')
67 bol = 1;
68 if (pattern[patlen - 1] == '$')
69 eol = 1;
70
71 snprintf(tmp, len, "%s\\<%s%.*s%s\\>%s",
72 bol ? "^" : "",
73 Eflag ? "(" : "\\(",
74 (int)patlen - bol - eol, pattern + bol,
75 Eflag ? ")" : "\\)",
76 eol ? "$" : "");
77 } else {
78 tmp = enstrdup(Error, pattern);
79 }
80
81 pnode = enmalloc(Error, sizeof(*pnode));
82 pnode->pattern = tmp;
83 SLIST_INSERT_HEAD(&phead, pnode, entry);
84 }
85
86 static void
87 addpatternfile(FILE *fp)
88 {
89 static char *buf = NULL;
90 static size_t size = 0;
91 ssize_t len = 0;
92
93 while ((len = getline(&buf, &size, fp)) > 0) {
94 if (len > 0 && buf[len - 1] == '\n')
95 buf[len - 1] = '\0';
96 addpattern(buf, (size_t)len);
97 }
98 if (ferror(fp))
99 enprintf(Error, "read error:");
100 }
101
102 static int
103 grep(FILE *fp, const char *str)
104 {
105 static char *buf = NULL;
106 static size_t size = 0;
107 ssize_t len = 0;
108 long c = 0, n;
109 struct pattern *pnode;
110 int match, result = NoMatch;
111
112 for (n = 1; (len = getline(&buf, &size, fp)) > 0; n++) {
113 /* Remove the trailing newline if one is present. */
114 if (len && buf[len - 1] == '\n')
115 buf[len - 1] = '\0';
116 match = 0;
117 SLIST_FOREACH(pnode, &phead, entry) {
118 if (Fflag) {
119 if (xflag) {
120 if (!(iflag ? strcasecmp : strcm…
121 match = 1;
122 break;
123 }
124 } else {
125 if ((iflag ? strcasestr : strstr…
126 match = 1;
127 break;
128 }
129 }
130 } else {
131 if (regexec(&pnode->preg, buf, 0, NULL, …
132 match = 1;
133 break;
134 }
135 }
136 }
137 if (match != vflag) {
138 result = Match;
139 switch (mode) {
140 case 'c':
141 c++;
142 break;
143 case 'l':
144 puts(str);
145 goto end;
146 case 'q':
147 exit(Match);
148 default:
149 if (!hflag && (many || Hflag))
150 printf("%s:", str);
151 if (mode == 'n')
152 printf("%ld:", n);
153 puts(buf);
154 break;
155 }
156 }
157 }
158 if (mode == 'c')
159 printf("%ld\n", c);
160 end:
161 if (ferror(fp)) {
162 weprintf("%s: read error:", str);
163 result = Error;
164 }
165 return result;
166 }
167
168 static void
169 usage(void)
170 {
171 enprintf(Error, "usage: %s [-EFHchilnqsvwx] [-e pattern] [-f fil…
172 "[pattern] [file ...]\n", argv0);
173 }
174
175 int
176 main(int argc, char *argv[])
177 {
178 struct pattern *pnode;
179 int m, flags = REG_NOSUB, match = NoMatch;
180 FILE *fp;
181 char *arg;
182
183 SLIST_INIT(&phead);
184
185 ARGBEGIN {
186 case 'E':
187 Eflag = 1;
188 Fflag = 0;
189 flags |= REG_EXTENDED;
190 break;
191 case 'F':
192 Fflag = 1;
193 Eflag = 0;
194 flags &= ~REG_EXTENDED;
195 break;
196 case 'H':
197 Hflag = 1;
198 hflag = 0;
199 break;
200 case 'e':
201 arg = EARGF(usage());
202 if (!(fp = fmemopen(arg, strlen(arg) + 1, "r")))
203 eprintf("fmemopen:");
204 addpatternfile(fp);
205 efshut(fp, arg);
206 eflag = 1;
207 break;
208 case 'f':
209 arg = EARGF(usage());
210 fp = fopen(arg, "r");
211 if (!fp)
212 enprintf(Error, "fopen %s:", arg);
213 addpatternfile(fp);
214 efshut(fp, arg);
215 fflag = 1;
216 break;
217 case 'h':
218 hflag = 1;
219 Hflag = 0;
220 break;
221 case 'c':
222 case 'l':
223 case 'n':
224 case 'q':
225 mode = ARGC();
226 break;
227 case 'i':
228 flags |= REG_ICASE;
229 iflag = 1;
230 break;
231 case 's':
232 sflag = 1;
233 break;
234 case 'v':
235 vflag = 1;
236 break;
237 case 'w':
238 wflag = 1;
239 break;
240 case 'x':
241 xflag = 1;
242 break;
243 default:
244 usage();
245 } ARGEND
246
247 if (argc == 0 && !eflag && !fflag)
248 usage(); /* no pattern */
249
250 /* just add literal pattern to list */
251 if (!eflag && !fflag) {
252 if (!(fp = fmemopen(argv[0], strlen(argv[0]) + 1, "r")))
253 eprintf("fmemopen:");
254 addpatternfile(fp);
255 efshut(fp, argv[0]);
256 argc--;
257 argv++;
258 }
259
260 if (!Fflag)
261 /* Compile regex for all search patterns */
262 SLIST_FOREACH(pnode, &phead, entry)
263 enregcomp(Error, &pnode->preg, pnode->pattern, f…
264 many = (argc > 1);
265 if (argc == 0) {
266 match = grep(stdin, "<stdin>");
267 } else {
268 for (; *argv; argc--, argv++) {
269 if (!strcmp(*argv, "-")) {
270 *argv = "<stdin>";
271 fp = stdin;
272 } else if (!(fp = fopen(*argv, "r"))) {
273 if (!sflag)
274 weprintf("fopen %s:", *argv);
275 match = Error;
276 continue;
277 }
278 m = grep(fp, *argv);
279 if (m == Error || (match != Error && m == Match))
280 match = m;
281 if (fp != stdin && fshut(fp, *argv))
282 match = Error;
283 }
284 }
285
286 if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
287 match = Error;
288
289 return match;
290 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.