grep.c revision 1.15 1 1.15 christos /* $NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $ */
2 1.4 joerg /* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */
3 1.4 joerg /* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
4 1.2 cjep
5 1.1 cjep /*-
6 1.4 joerg * Copyright (c) 1999 James Howard and Dag-Erling Codan Smrgrav
7 1.4 joerg * Copyright (C) 2008-2009 Gabor Kovesdan <gabor (at) FreeBSD.org>
8 1.1 cjep * All rights reserved.
9 1.1 cjep *
10 1.1 cjep * Redistribution and use in source and binary forms, with or without
11 1.1 cjep * modification, are permitted provided that the following conditions
12 1.1 cjep * are met:
13 1.1 cjep * 1. Redistributions of source code must retain the above copyright
14 1.1 cjep * notice, this list of conditions and the following disclaimer.
15 1.1 cjep * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cjep * notice, this list of conditions and the following disclaimer in the
17 1.1 cjep * documentation and/or other materials provided with the distribution.
18 1.1 cjep *
19 1.1 cjep * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 1.1 cjep * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 cjep * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 cjep * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 1.1 cjep * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 cjep * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 cjep * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 cjep * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 cjep * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 cjep * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 cjep * SUCH DAMAGE.
30 1.1 cjep */
31 1.2 cjep
32 1.5 joerg #if HAVE_NBTOOL_CONFIG_H
33 1.5 joerg #include "nbtool_config.h"
34 1.5 joerg #endif
35 1.5 joerg
36 1.2 cjep #include <sys/cdefs.h>
37 1.15 christos __RCSID("$NetBSD: grep.c,v 1.15 2018/08/12 09:03:21 christos Exp $");
38 1.1 cjep
39 1.4 joerg #include <sys/stat.h>
40 1.1 cjep #include <sys/types.h>
41 1.1 cjep
42 1.4 joerg #include <ctype.h>
43 1.1 cjep #include <err.h>
44 1.1 cjep #include <errno.h>
45 1.1 cjep #include <getopt.h>
46 1.2 cjep #include <limits.h>
47 1.4 joerg #include <libgen.h>
48 1.4 joerg #include <locale.h>
49 1.4 joerg #include <stdbool.h>
50 1.1 cjep #include <stdio.h>
51 1.1 cjep #include <stdlib.h>
52 1.1 cjep #include <string.h>
53 1.1 cjep #include <unistd.h>
54 1.1 cjep
55 1.1 cjep #include "grep.h"
56 1.1 cjep
57 1.4 joerg #ifndef WITHOUT_NLS
58 1.4 joerg #include <nl_types.h>
59 1.4 joerg nl_catd catalog;
60 1.4 joerg #endif
61 1.4 joerg
62 1.4 joerg /*
63 1.4 joerg * Default messags to use when NLS is disabled or no catalogue
64 1.4 joerg * is found.
65 1.2 cjep */
66 1.4 joerg const char *errstr[] = {
67 1.4 joerg "",
68 1.4 joerg /* 1*/ "(standard input)",
69 1.4 joerg /* 2*/ "cannot read bzip2 compressed file",
70 1.4 joerg /* 3*/ "unknown %s option",
71 1.8 joerg /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
72 1.4 joerg /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
73 1.4 joerg /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
74 1.8 joerg /* 7*/ "\t[pattern] [file ...]\n",
75 1.4 joerg /* 8*/ "Binary file %s matches\n",
76 1.4 joerg /* 9*/ "%s (BSD grep) %s\n",
77 1.4 joerg };
78 1.2 cjep
79 1.1 cjep /* Flags passed to regcomp() and regexec() */
80 1.4 joerg int cflags = 0;
81 1.4 joerg int eflags = REG_STARTEND;
82 1.4 joerg
83 1.4 joerg /* Searching patterns */
84 1.4 joerg unsigned int patterns, pattern_sz;
85 1.4 joerg char **pattern;
86 1.4 joerg regex_t *r_pattern;
87 1.4 joerg fastgrep_t *fg_pattern;
88 1.4 joerg
89 1.4 joerg /* Filename exclusion/inclusion patterns */
90 1.4 joerg unsigned int fpatterns, fpattern_sz;
91 1.4 joerg unsigned int dpatterns, dpattern_sz;
92 1.4 joerg struct epat *dpattern, *fpattern;
93 1.1 cjep
94 1.1 cjep /* For regex errors */
95 1.4 joerg char re_error[RE_ERROR_BUF + 1];
96 1.1 cjep
97 1.1 cjep /* Command-line flags */
98 1.4 joerg unsigned long long Aflag; /* -A x: print x lines trailing each match */
99 1.4 joerg unsigned long long Bflag; /* -B x: print x lines leading each match */
100 1.4 joerg bool Hflag; /* -H: always print file name */
101 1.4 joerg bool Lflag; /* -L: only show names of files with no matches */
102 1.4 joerg bool bflag; /* -b: show block numbers for each match */
103 1.4 joerg bool cflag; /* -c: only show a count of matching lines */
104 1.4 joerg bool hflag; /* -h: don't print filename headers */
105 1.4 joerg bool iflag; /* -i: ignore case */
106 1.4 joerg bool lflag; /* -l: only show names of files with matches */
107 1.4 joerg bool mflag; /* -m x: stop reading the files after x matches */
108 1.4 joerg unsigned long long mcount; /* count for -m */
109 1.4 joerg bool nflag; /* -n: show line numbers in front of matching lines */
110 1.4 joerg bool oflag; /* -o: print only matching part */
111 1.4 joerg bool qflag; /* -q: quiet mode (don't output anything) */
112 1.4 joerg bool sflag; /* -s: silent mode (ignore errors) */
113 1.4 joerg bool vflag; /* -v: only show non-matching lines */
114 1.4 joerg bool wflag; /* -w: pattern must start and end on word boundaries */
115 1.4 joerg bool xflag; /* -x: pattern must match entire line */
116 1.4 joerg bool lbflag; /* --line-buffered */
117 1.4 joerg bool nullflag; /* --null */
118 1.8 joerg bool nulldataflag; /* --null-data */
119 1.8 joerg unsigned char line_sep = '\n'; /* 0 for --null-data */
120 1.4 joerg char *label; /* --label */
121 1.4 joerg const char *color; /* --color */
122 1.4 joerg int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
123 1.4 joerg int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
124 1.4 joerg int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
125 1.4 joerg int devbehave = DEV_READ; /* -D: handling of devices */
126 1.4 joerg int dirbehave = DIR_READ; /* -dRr: handling of directories */
127 1.4 joerg int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
128 1.4 joerg
129 1.4 joerg bool dexclude, dinclude; /* --exclude-dir and --include-dir */
130 1.4 joerg bool fexclude, finclude; /* --exclude and --include */
131 1.2 cjep
132 1.2 cjep enum {
133 1.2 cjep BIN_OPT = CHAR_MAX + 1,
134 1.4 joerg COLOR_OPT,
135 1.8 joerg DECOMPRESS_OPT,
136 1.2 cjep HELP_OPT,
137 1.4 joerg MMAP_OPT,
138 1.4 joerg LINEBUF_OPT,
139 1.2 cjep LABEL_OPT,
140 1.4 joerg R_EXCLUDE_OPT,
141 1.4 joerg R_INCLUDE_OPT,
142 1.4 joerg R_DEXCLUDE_OPT,
143 1.4 joerg R_DINCLUDE_OPT
144 1.2 cjep };
145 1.1 cjep
146 1.4 joerg static inline const char *init_color(const char *);
147 1.4 joerg
148 1.1 cjep /* Housekeeping */
149 1.4 joerg int tail; /* lines left to print */
150 1.4 joerg bool notfound; /* file not found */
151 1.4 joerg
152 1.4 joerg extern char *__progname;
153 1.1 cjep
154 1.4 joerg /*
155 1.4 joerg * Prints usage information and returns 2.
156 1.4 joerg */
157 1.10 joerg __dead static void
158 1.1 cjep usage(void)
159 1.1 cjep {
160 1.4 joerg fprintf(stderr, getstr(4), __progname);
161 1.4 joerg fprintf(stderr, "%s", getstr(5));
162 1.4 joerg fprintf(stderr, "%s", getstr(6));
163 1.4 joerg fprintf(stderr, "%s", getstr(7));
164 1.1 cjep exit(2);
165 1.1 cjep }
166 1.1 cjep
167 1.8 joerg static const char optstr[] =
168 1.8 joerg "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz";
169 1.1 cjep
170 1.2 cjep struct option long_options[] =
171 1.1 cjep {
172 1.4 joerg {"binary-files", required_argument, NULL, BIN_OPT},
173 1.15 christos #ifndef WITHOUT_GZIP
174 1.8 joerg {"decompress", no_argument, NULL, DECOMPRESS_OPT},
175 1.15 christos #endif
176 1.4 joerg {"help", no_argument, NULL, HELP_OPT},
177 1.4 joerg {"mmap", no_argument, NULL, MMAP_OPT},
178 1.4 joerg {"line-buffered", no_argument, NULL, LINEBUF_OPT},
179 1.4 joerg {"label", required_argument, NULL, LABEL_OPT},
180 1.4 joerg {"color", optional_argument, NULL, COLOR_OPT},
181 1.4 joerg {"colour", optional_argument, NULL, COLOR_OPT},
182 1.4 joerg {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
183 1.4 joerg {"include", required_argument, NULL, R_INCLUDE_OPT},
184 1.4 joerg {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
185 1.4 joerg {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
186 1.4 joerg {"after-context", required_argument, NULL, 'A'},
187 1.4 joerg {"text", no_argument, NULL, 'a'},
188 1.4 joerg {"before-context", required_argument, NULL, 'B'},
189 1.4 joerg {"byte-offset", no_argument, NULL, 'b'},
190 1.4 joerg {"context", optional_argument, NULL, 'C'},
191 1.4 joerg {"count", no_argument, NULL, 'c'},
192 1.4 joerg {"devices", required_argument, NULL, 'D'},
193 1.4 joerg {"directories", required_argument, NULL, 'd'},
194 1.4 joerg {"extended-regexp", no_argument, NULL, 'E'},
195 1.4 joerg {"regexp", required_argument, NULL, 'e'},
196 1.4 joerg {"fixed-strings", no_argument, NULL, 'F'},
197 1.4 joerg {"file", required_argument, NULL, 'f'},
198 1.4 joerg {"basic-regexp", no_argument, NULL, 'G'},
199 1.4 joerg {"no-filename", no_argument, NULL, 'h'},
200 1.4 joerg {"with-filename", no_argument, NULL, 'H'},
201 1.4 joerg {"ignore-case", no_argument, NULL, 'i'},
202 1.14 christos #ifndef WITHOUT_BZ2
203 1.4 joerg {"bz2decompress", no_argument, NULL, 'J'},
204 1.14 christos #endif
205 1.4 joerg {"files-with-matches", no_argument, NULL, 'l'},
206 1.4 joerg {"files-without-match", no_argument, NULL, 'L'},
207 1.4 joerg {"max-count", required_argument, NULL, 'm'},
208 1.4 joerg {"line-number", no_argument, NULL, 'n'},
209 1.4 joerg {"only-matching", no_argument, NULL, 'o'},
210 1.4 joerg {"quiet", no_argument, NULL, 'q'},
211 1.4 joerg {"silent", no_argument, NULL, 'q'},
212 1.4 joerg {"recursive", no_argument, NULL, 'r'},
213 1.4 joerg {"no-messages", no_argument, NULL, 's'},
214 1.4 joerg {"binary", no_argument, NULL, 'U'},
215 1.4 joerg {"unix-byte-offsets", no_argument, NULL, 'u'},
216 1.4 joerg {"invert-match", no_argument, NULL, 'v'},
217 1.4 joerg {"version", no_argument, NULL, 'V'},
218 1.4 joerg {"word-regexp", no_argument, NULL, 'w'},
219 1.4 joerg {"line-regexp", no_argument, NULL, 'x'},
220 1.8 joerg {"null", no_argument, NULL, 'Z'},
221 1.8 joerg {"null-data", no_argument, NULL, 'z'},
222 1.4 joerg {NULL, no_argument, NULL, 0}
223 1.1 cjep };
224 1.1 cjep
225 1.4 joerg /*
226 1.4 joerg * Adds a searching pattern to the internal array.
227 1.4 joerg */
228 1.1 cjep static void
229 1.1 cjep add_pattern(char *pat, size_t len)
230 1.1 cjep {
231 1.4 joerg
232 1.11 joerg /* TODO: Check for empty patterns and shortcut */
233 1.11 joerg
234 1.4 joerg /* Increase size if necessary */
235 1.1 cjep if (patterns == pattern_sz) {
236 1.1 cjep pattern_sz *= 2;
237 1.4 joerg pattern = grep_realloc(pattern, ++pattern_sz *
238 1.4 joerg sizeof(*pattern));
239 1.1 cjep }
240 1.4 joerg if (len > 0 && pat[len - 1] == '\n')
241 1.1 cjep --len;
242 1.4 joerg /* pat may not be NUL-terminated */
243 1.2 cjep pattern[patterns] = grep_malloc(len + 1);
244 1.4 joerg memcpy(pattern[patterns], pat, len);
245 1.1 cjep pattern[patterns][len] = '\0';
246 1.1 cjep ++patterns;
247 1.1 cjep }
248 1.1 cjep
249 1.4 joerg /*
250 1.4 joerg * Adds a file include/exclude pattern to the internal array.
251 1.4 joerg */
252 1.1 cjep static void
253 1.4 joerg add_fpattern(const char *pat, int mode)
254 1.4 joerg {
255 1.4 joerg
256 1.4 joerg /* Increase size if necessary */
257 1.4 joerg if (fpatterns == fpattern_sz) {
258 1.4 joerg fpattern_sz *= 2;
259 1.4 joerg fpattern = grep_realloc(fpattern, ++fpattern_sz *
260 1.4 joerg sizeof(struct epat));
261 1.4 joerg }
262 1.4 joerg fpattern[fpatterns].pat = grep_strdup(pat);
263 1.4 joerg fpattern[fpatterns].mode = mode;
264 1.4 joerg ++fpatterns;
265 1.4 joerg }
266 1.4 joerg
267 1.4 joerg /*
268 1.4 joerg * Adds a directory include/exclude pattern to the internal array.
269 1.4 joerg */
270 1.4 joerg static void
271 1.4 joerg add_dpattern(const char *pat, int mode)
272 1.4 joerg {
273 1.4 joerg
274 1.4 joerg /* Increase size if necessary */
275 1.4 joerg if (dpatterns == dpattern_sz) {
276 1.4 joerg dpattern_sz *= 2;
277 1.4 joerg dpattern = grep_realloc(dpattern, ++dpattern_sz *
278 1.4 joerg sizeof(struct epat));
279 1.4 joerg }
280 1.4 joerg dpattern[dpatterns].pat = grep_strdup(pat);
281 1.4 joerg dpattern[dpatterns].mode = mode;
282 1.4 joerg ++dpatterns;
283 1.4 joerg }
284 1.4 joerg
285 1.4 joerg /*
286 1.4 joerg * Reads searching patterns from a file and adds them with add_pattern().
287 1.4 joerg */
288 1.4 joerg static void
289 1.4 joerg read_patterns(const char *fn)
290 1.1 cjep {
291 1.1 cjep FILE *f;
292 1.1 cjep char *line;
293 1.1 cjep size_t len;
294 1.6 joerg ssize_t rlen;
295 1.1 cjep
296 1.1 cjep if ((f = fopen(fn, "r")) == NULL)
297 1.2 cjep err(2, "%s", fn);
298 1.6 joerg line = NULL;
299 1.6 joerg len = 0;
300 1.6 joerg while ((rlen = getline(&line, &len, f)) != -1)
301 1.6 joerg add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
302 1.6 joerg free(line);
303 1.1 cjep if (ferror(f))
304 1.2 cjep err(2, "%s", fn);
305 1.1 cjep fclose(f);
306 1.1 cjep }
307 1.1 cjep
308 1.4 joerg static inline const char *
309 1.4 joerg init_color(const char *d)
310 1.2 cjep {
311 1.4 joerg char *c;
312 1.2 cjep
313 1.4 joerg c = getenv("GREP_COLOR");
314 1.4 joerg return (c != NULL ? c : d);
315 1.2 cjep }
316 1.2 cjep
317 1.1 cjep int
318 1.1 cjep main(int argc, char *argv[])
319 1.1 cjep {
320 1.4 joerg char **aargv, **eargv, *eopts;
321 1.4 joerg char *ep;
322 1.4 joerg unsigned long long l;
323 1.9 joerg unsigned int aargc, eargc, i, j;
324 1.4 joerg int c, lastc, needpattern, newarg, prevoptind;
325 1.4 joerg
326 1.4 joerg setlocale(LC_ALL, "");
327 1.4 joerg
328 1.4 joerg #ifndef WITHOUT_NLS
329 1.4 joerg catalog = catopen("grep", NL_CAT_LOCALE);
330 1.4 joerg #endif
331 1.4 joerg
332 1.4 joerg /* Check what is the program name of the binary. In this
333 1.4 joerg way we can have all the funcionalities in one binary
334 1.4 joerg without the need of scripting and using ugly hacks. */
335 1.4 joerg switch (__progname[0]) {
336 1.2 cjep case 'e':
337 1.4 joerg grepbehave = GREP_EXTENDED;
338 1.2 cjep break;
339 1.2 cjep case 'f':
340 1.4 joerg grepbehave = GREP_FIXED;
341 1.2 cjep break;
342 1.2 cjep case 'g':
343 1.4 joerg grepbehave = GREP_BASIC;
344 1.2 cjep break;
345 1.15 christos #ifndef WITHOUT_GZIP
346 1.2 cjep case 'z':
347 1.4 joerg filebehave = FILE_GZIP;
348 1.4 joerg switch(__progname[1]) {
349 1.2 cjep case 'e':
350 1.4 joerg grepbehave = GREP_EXTENDED;
351 1.2 cjep break;
352 1.2 cjep case 'f':
353 1.4 joerg grepbehave = GREP_FIXED;
354 1.2 cjep break;
355 1.2 cjep case 'g':
356 1.4 joerg grepbehave = GREP_BASIC;
357 1.2 cjep break;
358 1.2 cjep }
359 1.2 cjep break;
360 1.15 christos #endif
361 1.2 cjep }
362 1.1 cjep
363 1.4 joerg lastc = '\0';
364 1.4 joerg newarg = 1;
365 1.4 joerg prevoptind = 1;
366 1.4 joerg needpattern = 1;
367 1.4 joerg
368 1.4 joerg eopts = getenv("GREP_OPTIONS");
369 1.4 joerg
370 1.4 joerg /* support for extra arguments in GREP_OPTIONS */
371 1.4 joerg eargc = 0;
372 1.4 joerg if (eopts != NULL) {
373 1.4 joerg char *str;
374 1.4 joerg
375 1.4 joerg /* make an estimation of how many extra arguments we have */
376 1.9 joerg for (j = 0; j < strlen(eopts); j++)
377 1.4 joerg if (eopts[j] == ' ')
378 1.4 joerg eargc++;
379 1.4 joerg
380 1.4 joerg eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
381 1.4 joerg
382 1.4 joerg eargc = 0;
383 1.4 joerg /* parse extra arguments */
384 1.4 joerg while ((str = strsep(&eopts, " ")) != NULL)
385 1.4 joerg eargv[eargc++] = grep_strdup(str);
386 1.4 joerg
387 1.4 joerg aargv = (char **)grep_calloc(eargc + argc + 1,
388 1.4 joerg sizeof(char *));
389 1.4 joerg
390 1.4 joerg aargv[0] = argv[0];
391 1.4 joerg for (i = 0; i < eargc; i++)
392 1.4 joerg aargv[i + 1] = eargv[i];
393 1.9 joerg for (j = 1; j < (unsigned int)argc; j++, i++)
394 1.4 joerg aargv[i + 1] = argv[j];
395 1.4 joerg
396 1.4 joerg aargc = eargc + argc;
397 1.4 joerg } else {
398 1.4 joerg aargv = argv;
399 1.4 joerg aargc = argc;
400 1.4 joerg }
401 1.4 joerg
402 1.4 joerg while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
403 1.4 joerg -1)) {
404 1.1 cjep switch (c) {
405 1.4 joerg case '0': case '1': case '2': case '3': case '4':
406 1.4 joerg case '5': case '6': case '7': case '8': case '9':
407 1.4 joerg if (newarg || !isdigit(lastc))
408 1.4 joerg Aflag = 0;
409 1.4 joerg else if (Aflag > LLONG_MAX / 10) {
410 1.4 joerg errno = ERANGE;
411 1.4 joerg err(2, NULL);
412 1.4 joerg }
413 1.4 joerg Aflag = Bflag = (Aflag * 10) + (c - '0');
414 1.1 cjep break;
415 1.1 cjep case 'C':
416 1.4 joerg if (optarg == NULL) {
417 1.1 cjep Aflag = Bflag = 2;
418 1.4 joerg break;
419 1.4 joerg }
420 1.4 joerg /* FALLTHROUGH */
421 1.4 joerg case 'A':
422 1.4 joerg /* FALLTHROUGH */
423 1.4 joerg case 'B':
424 1.4 joerg errno = 0;
425 1.4 joerg l = strtoull(optarg, &ep, 10);
426 1.4 joerg if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
427 1.4 joerg ((errno == EINVAL) && (l == 0)))
428 1.4 joerg err(2, NULL);
429 1.4 joerg else if (ep[0] != '\0') {
430 1.4 joerg errno = EINVAL;
431 1.4 joerg err(2, NULL);
432 1.4 joerg }
433 1.4 joerg if (c == 'A')
434 1.4 joerg Aflag = l;
435 1.4 joerg else if (c == 'B')
436 1.4 joerg Bflag = l;
437 1.1 cjep else
438 1.4 joerg Aflag = Bflag = l;
439 1.1 cjep break;
440 1.1 cjep case 'a':
441 1.4 joerg binbehave = BINFILE_TEXT;
442 1.1 cjep break;
443 1.1 cjep case 'b':
444 1.4 joerg bflag = true;
445 1.1 cjep break;
446 1.1 cjep case 'c':
447 1.4 joerg cflag = true;
448 1.4 joerg break;
449 1.4 joerg case 'D':
450 1.4 joerg if (strcasecmp(optarg, "skip") == 0)
451 1.4 joerg devbehave = DEV_SKIP;
452 1.4 joerg else if (strcasecmp(optarg, "read") == 0)
453 1.4 joerg devbehave = DEV_READ;
454 1.4 joerg else
455 1.4 joerg errx(2, getstr(3), "--devices");
456 1.1 cjep break;
457 1.2 cjep case 'd':
458 1.4 joerg if (strcasecmp("recurse", optarg) == 0) {
459 1.4 joerg Hflag = true;
460 1.4 joerg dirbehave = DIR_RECURSE;
461 1.4 joerg } else if (strcasecmp("skip", optarg) == 0)
462 1.4 joerg dirbehave = DIR_SKIP;
463 1.4 joerg else if (strcasecmp("read", optarg) == 0)
464 1.4 joerg dirbehave = DIR_READ;
465 1.4 joerg else
466 1.4 joerg errx(2, getstr(3), "--directories");
467 1.4 joerg break;
468 1.4 joerg case 'E':
469 1.4 joerg grepbehave = GREP_EXTENDED;
470 1.2 cjep break;
471 1.1 cjep case 'e':
472 1.1 cjep add_pattern(optarg, strlen(optarg));
473 1.4 joerg needpattern = 0;
474 1.4 joerg break;
475 1.4 joerg case 'F':
476 1.4 joerg grepbehave = GREP_FIXED;
477 1.1 cjep break;
478 1.1 cjep case 'f':
479 1.1 cjep read_patterns(optarg);
480 1.4 joerg needpattern = 0;
481 1.4 joerg break;
482 1.4 joerg case 'G':
483 1.4 joerg grepbehave = GREP_BASIC;
484 1.4 joerg break;
485 1.4 joerg case 'H':
486 1.4 joerg Hflag = true;
487 1.1 cjep break;
488 1.1 cjep case 'h':
489 1.4 joerg Hflag = false;
490 1.4 joerg hflag = true;
491 1.4 joerg break;
492 1.4 joerg case 'I':
493 1.4 joerg binbehave = BINFILE_SKIP;
494 1.1 cjep break;
495 1.1 cjep case 'i':
496 1.1 cjep case 'y':
497 1.4 joerg iflag = true;
498 1.1 cjep cflags |= REG_ICASE;
499 1.1 cjep break;
500 1.14 christos #ifndef WITHOUT_BZ2
501 1.4 joerg case 'J':
502 1.4 joerg filebehave = FILE_BZIP;
503 1.4 joerg break;
504 1.14 christos #endif
505 1.4 joerg case 'L':
506 1.4 joerg lflag = false;
507 1.4 joerg Lflag = true;
508 1.4 joerg break;
509 1.1 cjep case 'l':
510 1.4 joerg Lflag = false;
511 1.4 joerg lflag = true;
512 1.1 cjep break;
513 1.2 cjep case 'm':
514 1.4 joerg mflag = true;
515 1.4 joerg errno = 0;
516 1.4 joerg mcount = strtoull(optarg, &ep, 10);
517 1.4 joerg if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
518 1.4 joerg ((errno == EINVAL) && (mcount == 0)))
519 1.4 joerg err(2, NULL);
520 1.4 joerg else if (ep[0] != '\0') {
521 1.4 joerg errno = EINVAL;
522 1.4 joerg err(2, NULL);
523 1.4 joerg }
524 1.2 cjep break;
525 1.1 cjep case 'n':
526 1.4 joerg nflag = true;
527 1.4 joerg break;
528 1.4 joerg case 'O':
529 1.4 joerg linkbehave = LINK_EXPLICIT;
530 1.1 cjep break;
531 1.1 cjep case 'o':
532 1.4 joerg oflag = true;
533 1.4 joerg break;
534 1.4 joerg case 'p':
535 1.4 joerg linkbehave = LINK_SKIP;
536 1.1 cjep break;
537 1.1 cjep case 'q':
538 1.4 joerg qflag = true;
539 1.4 joerg break;
540 1.4 joerg case 'S':
541 1.4 joerg linkbehave = LINK_READ;
542 1.4 joerg break;
543 1.4 joerg case 'R':
544 1.4 joerg case 'r':
545 1.4 joerg dirbehave = DIR_RECURSE;
546 1.4 joerg Hflag = true;
547 1.1 cjep break;
548 1.1 cjep case 's':
549 1.4 joerg sflag = true;
550 1.4 joerg break;
551 1.4 joerg case 'U':
552 1.4 joerg binbehave = BINFILE_BIN;
553 1.1 cjep break;
554 1.4 joerg case 'u':
555 1.4 joerg case MMAP_OPT:
556 1.4 joerg /* noop, compatibility */
557 1.4 joerg break;
558 1.4 joerg case 'V':
559 1.4 joerg printf(getstr(9), __progname, VERSION);
560 1.4 joerg exit(0);
561 1.1 cjep case 'v':
562 1.4 joerg vflag = true;
563 1.1 cjep break;
564 1.1 cjep case 'w':
565 1.4 joerg wflag = true;
566 1.1 cjep break;
567 1.1 cjep case 'x':
568 1.4 joerg xflag = true;
569 1.1 cjep break;
570 1.4 joerg case 'Z':
571 1.8 joerg nullflag = true;
572 1.8 joerg break;
573 1.8 joerg case 'z':
574 1.8 joerg nulldataflag = true;
575 1.8 joerg line_sep = '\0';
576 1.2 cjep break;
577 1.2 cjep case BIN_OPT:
578 1.4 joerg if (strcasecmp("binary", optarg) == 0)
579 1.4 joerg binbehave = BINFILE_BIN;
580 1.4 joerg else if (strcasecmp("without-match", optarg) == 0)
581 1.4 joerg binbehave = BINFILE_SKIP;
582 1.4 joerg else if (strcasecmp("text", optarg) == 0)
583 1.4 joerg binbehave = BINFILE_TEXT;
584 1.4 joerg else
585 1.4 joerg errx(2, getstr(3), "--binary-files");
586 1.4 joerg break;
587 1.4 joerg case COLOR_OPT:
588 1.4 joerg color = NULL;
589 1.4 joerg if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
590 1.4 joerg strcasecmp("tty", optarg) == 0 ||
591 1.4 joerg strcasecmp("if-tty", optarg) == 0) {
592 1.4 joerg char *term;
593 1.4 joerg
594 1.4 joerg term = getenv("TERM");
595 1.4 joerg if (isatty(STDOUT_FILENO) && term != NULL &&
596 1.4 joerg strcasecmp(term, "dumb") != 0)
597 1.4 joerg color = init_color("01;31");
598 1.4 joerg } else if (strcasecmp("always", optarg) == 0 ||
599 1.4 joerg strcasecmp("yes", optarg) == 0 ||
600 1.4 joerg strcasecmp("force", optarg) == 0) {
601 1.4 joerg color = init_color("01;31");
602 1.4 joerg } else if (strcasecmp("never", optarg) != 0 &&
603 1.4 joerg strcasecmp("none", optarg) != 0 &&
604 1.4 joerg strcasecmp("no", optarg) != 0)
605 1.4 joerg errx(2, getstr(3), "--color");
606 1.2 cjep break;
607 1.15 christos #ifndef WITHOUT_GZIP
608 1.8 joerg case DECOMPRESS_OPT:
609 1.8 joerg filebehave = FILE_GZIP;
610 1.8 joerg break;
611 1.15 christos #endif
612 1.2 cjep case LABEL_OPT:
613 1.4 joerg label = optarg;
614 1.4 joerg break;
615 1.4 joerg case LINEBUF_OPT:
616 1.4 joerg lbflag = true;
617 1.2 cjep break;
618 1.4 joerg case R_INCLUDE_OPT:
619 1.4 joerg finclude = true;
620 1.4 joerg add_fpattern(optarg, INCL_PAT);
621 1.4 joerg break;
622 1.4 joerg case R_EXCLUDE_OPT:
623 1.4 joerg fexclude = true;
624 1.4 joerg add_fpattern(optarg, EXCL_PAT);
625 1.4 joerg break;
626 1.4 joerg case R_DINCLUDE_OPT:
627 1.4 joerg dinclude = true;
628 1.4 joerg add_dpattern(optarg, INCL_PAT);
629 1.4 joerg break;
630 1.4 joerg case R_DEXCLUDE_OPT:
631 1.4 joerg dexclude = true;
632 1.4 joerg add_dpattern(optarg, EXCL_PAT);
633 1.2 cjep break;
634 1.2 cjep case HELP_OPT:
635 1.1 cjep default:
636 1.1 cjep usage();
637 1.1 cjep }
638 1.4 joerg lastc = c;
639 1.4 joerg newarg = optind != prevoptind;
640 1.4 joerg prevoptind = optind;
641 1.1 cjep }
642 1.4 joerg aargc -= optind;
643 1.4 joerg aargv += optind;
644 1.1 cjep
645 1.4 joerg /* Fail if we don't have any pattern */
646 1.4 joerg if (aargc == 0 && needpattern)
647 1.1 cjep usage();
648 1.4 joerg
649 1.4 joerg /* Process patterns from command line */
650 1.4 joerg if (aargc != 0 && needpattern) {
651 1.4 joerg add_pattern(*aargv, strlen(*aargv));
652 1.4 joerg --aargc;
653 1.4 joerg ++aargv;
654 1.1 cjep }
655 1.1 cjep
656 1.4 joerg switch (grepbehave) {
657 1.4 joerg case GREP_FIXED:
658 1.4 joerg case GREP_BASIC:
659 1.4 joerg break;
660 1.4 joerg case GREP_EXTENDED:
661 1.2 cjep cflags |= REG_EXTENDED;
662 1.4 joerg break;
663 1.4 joerg default:
664 1.4 joerg /* NOTREACHED */
665 1.4 joerg usage();
666 1.4 joerg }
667 1.4 joerg
668 1.4 joerg fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
669 1.4 joerg r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
670 1.4 joerg /*
671 1.4 joerg * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
672 1.4 joerg * Optimizations should be done there.
673 1.4 joerg */
674 1.4 joerg /* Check if cheating is allowed (always is for fgrep). */
675 1.4 joerg if (grepbehave == GREP_FIXED) {
676 1.4 joerg for (i = 0; i < patterns; ++i)
677 1.4 joerg fgrepcomp(&fg_pattern[i], pattern[i]);
678 1.4 joerg } else {
679 1.4 joerg for (i = 0; i < patterns; ++i) {
680 1.4 joerg if (fastcomp(&fg_pattern[i], pattern[i])) {
681 1.4 joerg /* Fall back to full regex library */
682 1.4 joerg c = regcomp(&r_pattern[i], pattern[i], cflags);
683 1.4 joerg if (c != 0) {
684 1.4 joerg regerror(c, &r_pattern[i], re_error,
685 1.4 joerg RE_ERROR_BUF);
686 1.4 joerg errx(2, "%s", re_error);
687 1.4 joerg }
688 1.4 joerg }
689 1.1 cjep }
690 1.1 cjep }
691 1.1 cjep
692 1.13 christos if (lbflag) {
693 1.13 christos #ifdef _IOLBF
694 1.13 christos setvbuf(stdout, NULL, _IOLBF, 0);
695 1.13 christos #else
696 1.4 joerg setlinebuf(stdout);
697 1.13 christos #endif
698 1.13 christos }
699 1.1 cjep
700 1.4 joerg if ((aargc == 0 || aargc == 1) && !Hflag)
701 1.4 joerg hflag = true;
702 1.2 cjep
703 1.4 joerg if (aargc == 0)
704 1.4 joerg exit(!procfile("-"));
705 1.2 cjep
706 1.4 joerg if (dirbehave == DIR_RECURSE)
707 1.4 joerg c = grep_tree(aargv);
708 1.1 cjep else
709 1.4 joerg for (c = 0; aargc--; ++aargv) {
710 1.4 joerg if ((finclude || fexclude) && !file_matching(*aargv))
711 1.4 joerg continue;
712 1.4 joerg c+= procfile(*aargv);
713 1.4 joerg }
714 1.1 cjep
715 1.4 joerg #ifndef WITHOUT_NLS
716 1.4 joerg catclose(catalog);
717 1.4 joerg #endif
718 1.4 joerg
719 1.4 joerg /* Find out the correct return value according to the
720 1.4 joerg results and the command line option. */
721 1.4 joerg exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
722 1.1 cjep }
723