grep.c revision 1.14 1 1.14 christos /* $NetBSD: grep.c,v 1.14 2018/08/12 07:53:19 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.14 christos __RCSID("$NetBSD: grep.c,v 1.14 2018/08/12 07:53:19 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.8 joerg {"decompress", no_argument, NULL, DECOMPRESS_OPT},
174 1.4 joerg {"help", no_argument, NULL, HELP_OPT},
175 1.4 joerg {"mmap", no_argument, NULL, MMAP_OPT},
176 1.4 joerg {"line-buffered", no_argument, NULL, LINEBUF_OPT},
177 1.4 joerg {"label", required_argument, NULL, LABEL_OPT},
178 1.4 joerg {"color", optional_argument, NULL, COLOR_OPT},
179 1.4 joerg {"colour", optional_argument, NULL, COLOR_OPT},
180 1.4 joerg {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
181 1.4 joerg {"include", required_argument, NULL, R_INCLUDE_OPT},
182 1.4 joerg {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
183 1.4 joerg {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
184 1.4 joerg {"after-context", required_argument, NULL, 'A'},
185 1.4 joerg {"text", no_argument, NULL, 'a'},
186 1.4 joerg {"before-context", required_argument, NULL, 'B'},
187 1.4 joerg {"byte-offset", no_argument, NULL, 'b'},
188 1.4 joerg {"context", optional_argument, NULL, 'C'},
189 1.4 joerg {"count", no_argument, NULL, 'c'},
190 1.4 joerg {"devices", required_argument, NULL, 'D'},
191 1.4 joerg {"directories", required_argument, NULL, 'd'},
192 1.4 joerg {"extended-regexp", no_argument, NULL, 'E'},
193 1.4 joerg {"regexp", required_argument, NULL, 'e'},
194 1.4 joerg {"fixed-strings", no_argument, NULL, 'F'},
195 1.4 joerg {"file", required_argument, NULL, 'f'},
196 1.4 joerg {"basic-regexp", no_argument, NULL, 'G'},
197 1.4 joerg {"no-filename", no_argument, NULL, 'h'},
198 1.4 joerg {"with-filename", no_argument, NULL, 'H'},
199 1.4 joerg {"ignore-case", no_argument, NULL, 'i'},
200 1.14 christos #ifndef WITHOUT_BZ2
201 1.4 joerg {"bz2decompress", no_argument, NULL, 'J'},
202 1.14 christos #endif
203 1.4 joerg {"files-with-matches", no_argument, NULL, 'l'},
204 1.4 joerg {"files-without-match", no_argument, NULL, 'L'},
205 1.4 joerg {"max-count", required_argument, NULL, 'm'},
206 1.4 joerg {"line-number", no_argument, NULL, 'n'},
207 1.4 joerg {"only-matching", no_argument, NULL, 'o'},
208 1.4 joerg {"quiet", no_argument, NULL, 'q'},
209 1.4 joerg {"silent", no_argument, NULL, 'q'},
210 1.4 joerg {"recursive", no_argument, NULL, 'r'},
211 1.4 joerg {"no-messages", no_argument, NULL, 's'},
212 1.4 joerg {"binary", no_argument, NULL, 'U'},
213 1.4 joerg {"unix-byte-offsets", no_argument, NULL, 'u'},
214 1.4 joerg {"invert-match", no_argument, NULL, 'v'},
215 1.4 joerg {"version", no_argument, NULL, 'V'},
216 1.4 joerg {"word-regexp", no_argument, NULL, 'w'},
217 1.4 joerg {"line-regexp", no_argument, NULL, 'x'},
218 1.8 joerg {"null", no_argument, NULL, 'Z'},
219 1.8 joerg {"null-data", no_argument, NULL, 'z'},
220 1.4 joerg {NULL, no_argument, NULL, 0}
221 1.1 cjep };
222 1.1 cjep
223 1.4 joerg /*
224 1.4 joerg * Adds a searching pattern to the internal array.
225 1.4 joerg */
226 1.1 cjep static void
227 1.1 cjep add_pattern(char *pat, size_t len)
228 1.1 cjep {
229 1.4 joerg
230 1.11 joerg /* TODO: Check for empty patterns and shortcut */
231 1.11 joerg
232 1.4 joerg /* Increase size if necessary */
233 1.1 cjep if (patterns == pattern_sz) {
234 1.1 cjep pattern_sz *= 2;
235 1.4 joerg pattern = grep_realloc(pattern, ++pattern_sz *
236 1.4 joerg sizeof(*pattern));
237 1.1 cjep }
238 1.4 joerg if (len > 0 && pat[len - 1] == '\n')
239 1.1 cjep --len;
240 1.4 joerg /* pat may not be NUL-terminated */
241 1.2 cjep pattern[patterns] = grep_malloc(len + 1);
242 1.4 joerg memcpy(pattern[patterns], pat, len);
243 1.1 cjep pattern[patterns][len] = '\0';
244 1.1 cjep ++patterns;
245 1.1 cjep }
246 1.1 cjep
247 1.4 joerg /*
248 1.4 joerg * Adds a file include/exclude pattern to the internal array.
249 1.4 joerg */
250 1.1 cjep static void
251 1.4 joerg add_fpattern(const char *pat, int mode)
252 1.4 joerg {
253 1.4 joerg
254 1.4 joerg /* Increase size if necessary */
255 1.4 joerg if (fpatterns == fpattern_sz) {
256 1.4 joerg fpattern_sz *= 2;
257 1.4 joerg fpattern = grep_realloc(fpattern, ++fpattern_sz *
258 1.4 joerg sizeof(struct epat));
259 1.4 joerg }
260 1.4 joerg fpattern[fpatterns].pat = grep_strdup(pat);
261 1.4 joerg fpattern[fpatterns].mode = mode;
262 1.4 joerg ++fpatterns;
263 1.4 joerg }
264 1.4 joerg
265 1.4 joerg /*
266 1.4 joerg * Adds a directory include/exclude pattern to the internal array.
267 1.4 joerg */
268 1.4 joerg static void
269 1.4 joerg add_dpattern(const char *pat, int mode)
270 1.4 joerg {
271 1.4 joerg
272 1.4 joerg /* Increase size if necessary */
273 1.4 joerg if (dpatterns == dpattern_sz) {
274 1.4 joerg dpattern_sz *= 2;
275 1.4 joerg dpattern = grep_realloc(dpattern, ++dpattern_sz *
276 1.4 joerg sizeof(struct epat));
277 1.4 joerg }
278 1.4 joerg dpattern[dpatterns].pat = grep_strdup(pat);
279 1.4 joerg dpattern[dpatterns].mode = mode;
280 1.4 joerg ++dpatterns;
281 1.4 joerg }
282 1.4 joerg
283 1.4 joerg /*
284 1.4 joerg * Reads searching patterns from a file and adds them with add_pattern().
285 1.4 joerg */
286 1.4 joerg static void
287 1.4 joerg read_patterns(const char *fn)
288 1.1 cjep {
289 1.1 cjep FILE *f;
290 1.1 cjep char *line;
291 1.1 cjep size_t len;
292 1.6 joerg ssize_t rlen;
293 1.1 cjep
294 1.1 cjep if ((f = fopen(fn, "r")) == NULL)
295 1.2 cjep err(2, "%s", fn);
296 1.6 joerg line = NULL;
297 1.6 joerg len = 0;
298 1.6 joerg while ((rlen = getline(&line, &len, f)) != -1)
299 1.6 joerg add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
300 1.6 joerg free(line);
301 1.1 cjep if (ferror(f))
302 1.2 cjep err(2, "%s", fn);
303 1.1 cjep fclose(f);
304 1.1 cjep }
305 1.1 cjep
306 1.4 joerg static inline const char *
307 1.4 joerg init_color(const char *d)
308 1.2 cjep {
309 1.4 joerg char *c;
310 1.2 cjep
311 1.4 joerg c = getenv("GREP_COLOR");
312 1.4 joerg return (c != NULL ? c : d);
313 1.2 cjep }
314 1.2 cjep
315 1.1 cjep int
316 1.1 cjep main(int argc, char *argv[])
317 1.1 cjep {
318 1.4 joerg char **aargv, **eargv, *eopts;
319 1.4 joerg char *ep;
320 1.4 joerg unsigned long long l;
321 1.9 joerg unsigned int aargc, eargc, i, j;
322 1.4 joerg int c, lastc, needpattern, newarg, prevoptind;
323 1.4 joerg
324 1.4 joerg setlocale(LC_ALL, "");
325 1.4 joerg
326 1.4 joerg #ifndef WITHOUT_NLS
327 1.4 joerg catalog = catopen("grep", NL_CAT_LOCALE);
328 1.4 joerg #endif
329 1.4 joerg
330 1.4 joerg /* Check what is the program name of the binary. In this
331 1.4 joerg way we can have all the funcionalities in one binary
332 1.4 joerg without the need of scripting and using ugly hacks. */
333 1.4 joerg switch (__progname[0]) {
334 1.2 cjep case 'e':
335 1.4 joerg grepbehave = GREP_EXTENDED;
336 1.2 cjep break;
337 1.2 cjep case 'f':
338 1.4 joerg grepbehave = GREP_FIXED;
339 1.2 cjep break;
340 1.2 cjep case 'g':
341 1.4 joerg grepbehave = GREP_BASIC;
342 1.2 cjep break;
343 1.2 cjep case 'z':
344 1.4 joerg filebehave = FILE_GZIP;
345 1.4 joerg switch(__progname[1]) {
346 1.2 cjep case 'e':
347 1.4 joerg grepbehave = GREP_EXTENDED;
348 1.2 cjep break;
349 1.2 cjep case 'f':
350 1.4 joerg grepbehave = GREP_FIXED;
351 1.2 cjep break;
352 1.2 cjep case 'g':
353 1.4 joerg grepbehave = GREP_BASIC;
354 1.2 cjep break;
355 1.2 cjep }
356 1.2 cjep break;
357 1.2 cjep }
358 1.1 cjep
359 1.4 joerg lastc = '\0';
360 1.4 joerg newarg = 1;
361 1.4 joerg prevoptind = 1;
362 1.4 joerg needpattern = 1;
363 1.4 joerg
364 1.4 joerg eopts = getenv("GREP_OPTIONS");
365 1.4 joerg
366 1.4 joerg /* support for extra arguments in GREP_OPTIONS */
367 1.4 joerg eargc = 0;
368 1.4 joerg if (eopts != NULL) {
369 1.4 joerg char *str;
370 1.4 joerg
371 1.4 joerg /* make an estimation of how many extra arguments we have */
372 1.9 joerg for (j = 0; j < strlen(eopts); j++)
373 1.4 joerg if (eopts[j] == ' ')
374 1.4 joerg eargc++;
375 1.4 joerg
376 1.4 joerg eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
377 1.4 joerg
378 1.4 joerg eargc = 0;
379 1.4 joerg /* parse extra arguments */
380 1.4 joerg while ((str = strsep(&eopts, " ")) != NULL)
381 1.4 joerg eargv[eargc++] = grep_strdup(str);
382 1.4 joerg
383 1.4 joerg aargv = (char **)grep_calloc(eargc + argc + 1,
384 1.4 joerg sizeof(char *));
385 1.4 joerg
386 1.4 joerg aargv[0] = argv[0];
387 1.4 joerg for (i = 0; i < eargc; i++)
388 1.4 joerg aargv[i + 1] = eargv[i];
389 1.9 joerg for (j = 1; j < (unsigned int)argc; j++, i++)
390 1.4 joerg aargv[i + 1] = argv[j];
391 1.4 joerg
392 1.4 joerg aargc = eargc + argc;
393 1.4 joerg } else {
394 1.4 joerg aargv = argv;
395 1.4 joerg aargc = argc;
396 1.4 joerg }
397 1.4 joerg
398 1.4 joerg while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
399 1.4 joerg -1)) {
400 1.1 cjep switch (c) {
401 1.4 joerg case '0': case '1': case '2': case '3': case '4':
402 1.4 joerg case '5': case '6': case '7': case '8': case '9':
403 1.4 joerg if (newarg || !isdigit(lastc))
404 1.4 joerg Aflag = 0;
405 1.4 joerg else if (Aflag > LLONG_MAX / 10) {
406 1.4 joerg errno = ERANGE;
407 1.4 joerg err(2, NULL);
408 1.4 joerg }
409 1.4 joerg Aflag = Bflag = (Aflag * 10) + (c - '0');
410 1.1 cjep break;
411 1.1 cjep case 'C':
412 1.4 joerg if (optarg == NULL) {
413 1.1 cjep Aflag = Bflag = 2;
414 1.4 joerg break;
415 1.4 joerg }
416 1.4 joerg /* FALLTHROUGH */
417 1.4 joerg case 'A':
418 1.4 joerg /* FALLTHROUGH */
419 1.4 joerg case 'B':
420 1.4 joerg errno = 0;
421 1.4 joerg l = strtoull(optarg, &ep, 10);
422 1.4 joerg if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
423 1.4 joerg ((errno == EINVAL) && (l == 0)))
424 1.4 joerg err(2, NULL);
425 1.4 joerg else if (ep[0] != '\0') {
426 1.4 joerg errno = EINVAL;
427 1.4 joerg err(2, NULL);
428 1.4 joerg }
429 1.4 joerg if (c == 'A')
430 1.4 joerg Aflag = l;
431 1.4 joerg else if (c == 'B')
432 1.4 joerg Bflag = l;
433 1.1 cjep else
434 1.4 joerg Aflag = Bflag = l;
435 1.1 cjep break;
436 1.1 cjep case 'a':
437 1.4 joerg binbehave = BINFILE_TEXT;
438 1.1 cjep break;
439 1.1 cjep case 'b':
440 1.4 joerg bflag = true;
441 1.1 cjep break;
442 1.1 cjep case 'c':
443 1.4 joerg cflag = true;
444 1.4 joerg break;
445 1.4 joerg case 'D':
446 1.4 joerg if (strcasecmp(optarg, "skip") == 0)
447 1.4 joerg devbehave = DEV_SKIP;
448 1.4 joerg else if (strcasecmp(optarg, "read") == 0)
449 1.4 joerg devbehave = DEV_READ;
450 1.4 joerg else
451 1.4 joerg errx(2, getstr(3), "--devices");
452 1.1 cjep break;
453 1.2 cjep case 'd':
454 1.4 joerg if (strcasecmp("recurse", optarg) == 0) {
455 1.4 joerg Hflag = true;
456 1.4 joerg dirbehave = DIR_RECURSE;
457 1.4 joerg } else if (strcasecmp("skip", optarg) == 0)
458 1.4 joerg dirbehave = DIR_SKIP;
459 1.4 joerg else if (strcasecmp("read", optarg) == 0)
460 1.4 joerg dirbehave = DIR_READ;
461 1.4 joerg else
462 1.4 joerg errx(2, getstr(3), "--directories");
463 1.4 joerg break;
464 1.4 joerg case 'E':
465 1.4 joerg grepbehave = GREP_EXTENDED;
466 1.2 cjep break;
467 1.1 cjep case 'e':
468 1.1 cjep add_pattern(optarg, strlen(optarg));
469 1.4 joerg needpattern = 0;
470 1.4 joerg break;
471 1.4 joerg case 'F':
472 1.4 joerg grepbehave = GREP_FIXED;
473 1.1 cjep break;
474 1.1 cjep case 'f':
475 1.1 cjep read_patterns(optarg);
476 1.4 joerg needpattern = 0;
477 1.4 joerg break;
478 1.4 joerg case 'G':
479 1.4 joerg grepbehave = GREP_BASIC;
480 1.4 joerg break;
481 1.4 joerg case 'H':
482 1.4 joerg Hflag = true;
483 1.1 cjep break;
484 1.1 cjep case 'h':
485 1.4 joerg Hflag = false;
486 1.4 joerg hflag = true;
487 1.4 joerg break;
488 1.4 joerg case 'I':
489 1.4 joerg binbehave = BINFILE_SKIP;
490 1.1 cjep break;
491 1.1 cjep case 'i':
492 1.1 cjep case 'y':
493 1.4 joerg iflag = true;
494 1.1 cjep cflags |= REG_ICASE;
495 1.1 cjep break;
496 1.14 christos #ifndef WITHOUT_BZ2
497 1.4 joerg case 'J':
498 1.4 joerg filebehave = FILE_BZIP;
499 1.4 joerg break;
500 1.14 christos #endif
501 1.4 joerg case 'L':
502 1.4 joerg lflag = false;
503 1.4 joerg Lflag = true;
504 1.4 joerg break;
505 1.1 cjep case 'l':
506 1.4 joerg Lflag = false;
507 1.4 joerg lflag = true;
508 1.1 cjep break;
509 1.2 cjep case 'm':
510 1.4 joerg mflag = true;
511 1.4 joerg errno = 0;
512 1.4 joerg mcount = strtoull(optarg, &ep, 10);
513 1.4 joerg if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
514 1.4 joerg ((errno == EINVAL) && (mcount == 0)))
515 1.4 joerg err(2, NULL);
516 1.4 joerg else if (ep[0] != '\0') {
517 1.4 joerg errno = EINVAL;
518 1.4 joerg err(2, NULL);
519 1.4 joerg }
520 1.2 cjep break;
521 1.1 cjep case 'n':
522 1.4 joerg nflag = true;
523 1.4 joerg break;
524 1.4 joerg case 'O':
525 1.4 joerg linkbehave = LINK_EXPLICIT;
526 1.1 cjep break;
527 1.1 cjep case 'o':
528 1.4 joerg oflag = true;
529 1.4 joerg break;
530 1.4 joerg case 'p':
531 1.4 joerg linkbehave = LINK_SKIP;
532 1.1 cjep break;
533 1.1 cjep case 'q':
534 1.4 joerg qflag = true;
535 1.4 joerg break;
536 1.4 joerg case 'S':
537 1.4 joerg linkbehave = LINK_READ;
538 1.4 joerg break;
539 1.4 joerg case 'R':
540 1.4 joerg case 'r':
541 1.4 joerg dirbehave = DIR_RECURSE;
542 1.4 joerg Hflag = true;
543 1.1 cjep break;
544 1.1 cjep case 's':
545 1.4 joerg sflag = true;
546 1.4 joerg break;
547 1.4 joerg case 'U':
548 1.4 joerg binbehave = BINFILE_BIN;
549 1.1 cjep break;
550 1.4 joerg case 'u':
551 1.4 joerg case MMAP_OPT:
552 1.4 joerg /* noop, compatibility */
553 1.4 joerg break;
554 1.4 joerg case 'V':
555 1.4 joerg printf(getstr(9), __progname, VERSION);
556 1.4 joerg exit(0);
557 1.1 cjep case 'v':
558 1.4 joerg vflag = true;
559 1.1 cjep break;
560 1.1 cjep case 'w':
561 1.4 joerg wflag = true;
562 1.1 cjep break;
563 1.1 cjep case 'x':
564 1.4 joerg xflag = true;
565 1.1 cjep break;
566 1.4 joerg case 'Z':
567 1.8 joerg nullflag = true;
568 1.8 joerg break;
569 1.8 joerg case 'z':
570 1.8 joerg nulldataflag = true;
571 1.8 joerg line_sep = '\0';
572 1.2 cjep break;
573 1.2 cjep case BIN_OPT:
574 1.4 joerg if (strcasecmp("binary", optarg) == 0)
575 1.4 joerg binbehave = BINFILE_BIN;
576 1.4 joerg else if (strcasecmp("without-match", optarg) == 0)
577 1.4 joerg binbehave = BINFILE_SKIP;
578 1.4 joerg else if (strcasecmp("text", optarg) == 0)
579 1.4 joerg binbehave = BINFILE_TEXT;
580 1.4 joerg else
581 1.4 joerg errx(2, getstr(3), "--binary-files");
582 1.4 joerg break;
583 1.4 joerg case COLOR_OPT:
584 1.4 joerg color = NULL;
585 1.4 joerg if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
586 1.4 joerg strcasecmp("tty", optarg) == 0 ||
587 1.4 joerg strcasecmp("if-tty", optarg) == 0) {
588 1.4 joerg char *term;
589 1.4 joerg
590 1.4 joerg term = getenv("TERM");
591 1.4 joerg if (isatty(STDOUT_FILENO) && term != NULL &&
592 1.4 joerg strcasecmp(term, "dumb") != 0)
593 1.4 joerg color = init_color("01;31");
594 1.4 joerg } else if (strcasecmp("always", optarg) == 0 ||
595 1.4 joerg strcasecmp("yes", optarg) == 0 ||
596 1.4 joerg strcasecmp("force", optarg) == 0) {
597 1.4 joerg color = init_color("01;31");
598 1.4 joerg } else if (strcasecmp("never", optarg) != 0 &&
599 1.4 joerg strcasecmp("none", optarg) != 0 &&
600 1.4 joerg strcasecmp("no", optarg) != 0)
601 1.4 joerg errx(2, getstr(3), "--color");
602 1.2 cjep break;
603 1.8 joerg case DECOMPRESS_OPT:
604 1.8 joerg filebehave = FILE_GZIP;
605 1.8 joerg break;
606 1.2 cjep case LABEL_OPT:
607 1.4 joerg label = optarg;
608 1.4 joerg break;
609 1.4 joerg case LINEBUF_OPT:
610 1.4 joerg lbflag = true;
611 1.2 cjep break;
612 1.4 joerg case R_INCLUDE_OPT:
613 1.4 joerg finclude = true;
614 1.4 joerg add_fpattern(optarg, INCL_PAT);
615 1.4 joerg break;
616 1.4 joerg case R_EXCLUDE_OPT:
617 1.4 joerg fexclude = true;
618 1.4 joerg add_fpattern(optarg, EXCL_PAT);
619 1.4 joerg break;
620 1.4 joerg case R_DINCLUDE_OPT:
621 1.4 joerg dinclude = true;
622 1.4 joerg add_dpattern(optarg, INCL_PAT);
623 1.4 joerg break;
624 1.4 joerg case R_DEXCLUDE_OPT:
625 1.4 joerg dexclude = true;
626 1.4 joerg add_dpattern(optarg, EXCL_PAT);
627 1.2 cjep break;
628 1.2 cjep case HELP_OPT:
629 1.1 cjep default:
630 1.1 cjep usage();
631 1.1 cjep }
632 1.4 joerg lastc = c;
633 1.4 joerg newarg = optind != prevoptind;
634 1.4 joerg prevoptind = optind;
635 1.1 cjep }
636 1.4 joerg aargc -= optind;
637 1.4 joerg aargv += optind;
638 1.1 cjep
639 1.4 joerg /* Fail if we don't have any pattern */
640 1.4 joerg if (aargc == 0 && needpattern)
641 1.1 cjep usage();
642 1.4 joerg
643 1.4 joerg /* Process patterns from command line */
644 1.4 joerg if (aargc != 0 && needpattern) {
645 1.4 joerg add_pattern(*aargv, strlen(*aargv));
646 1.4 joerg --aargc;
647 1.4 joerg ++aargv;
648 1.1 cjep }
649 1.1 cjep
650 1.4 joerg switch (grepbehave) {
651 1.4 joerg case GREP_FIXED:
652 1.4 joerg case GREP_BASIC:
653 1.4 joerg break;
654 1.4 joerg case GREP_EXTENDED:
655 1.2 cjep cflags |= REG_EXTENDED;
656 1.4 joerg break;
657 1.4 joerg default:
658 1.4 joerg /* NOTREACHED */
659 1.4 joerg usage();
660 1.4 joerg }
661 1.4 joerg
662 1.4 joerg fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
663 1.4 joerg r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
664 1.4 joerg /*
665 1.4 joerg * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
666 1.4 joerg * Optimizations should be done there.
667 1.4 joerg */
668 1.4 joerg /* Check if cheating is allowed (always is for fgrep). */
669 1.4 joerg if (grepbehave == GREP_FIXED) {
670 1.4 joerg for (i = 0; i < patterns; ++i)
671 1.4 joerg fgrepcomp(&fg_pattern[i], pattern[i]);
672 1.4 joerg } else {
673 1.4 joerg for (i = 0; i < patterns; ++i) {
674 1.4 joerg if (fastcomp(&fg_pattern[i], pattern[i])) {
675 1.4 joerg /* Fall back to full regex library */
676 1.4 joerg c = regcomp(&r_pattern[i], pattern[i], cflags);
677 1.4 joerg if (c != 0) {
678 1.4 joerg regerror(c, &r_pattern[i], re_error,
679 1.4 joerg RE_ERROR_BUF);
680 1.4 joerg errx(2, "%s", re_error);
681 1.4 joerg }
682 1.4 joerg }
683 1.1 cjep }
684 1.1 cjep }
685 1.1 cjep
686 1.13 christos if (lbflag) {
687 1.13 christos #ifdef _IOLBF
688 1.13 christos setvbuf(stdout, NULL, _IOLBF, 0);
689 1.13 christos #else
690 1.4 joerg setlinebuf(stdout);
691 1.13 christos #endif
692 1.13 christos }
693 1.1 cjep
694 1.4 joerg if ((aargc == 0 || aargc == 1) && !Hflag)
695 1.4 joerg hflag = true;
696 1.2 cjep
697 1.4 joerg if (aargc == 0)
698 1.4 joerg exit(!procfile("-"));
699 1.2 cjep
700 1.4 joerg if (dirbehave == DIR_RECURSE)
701 1.4 joerg c = grep_tree(aargv);
702 1.1 cjep else
703 1.4 joerg for (c = 0; aargc--; ++aargv) {
704 1.4 joerg if ((finclude || fexclude) && !file_matching(*aargv))
705 1.4 joerg continue;
706 1.4 joerg c+= procfile(*aargv);
707 1.4 joerg }
708 1.1 cjep
709 1.4 joerg #ifndef WITHOUT_NLS
710 1.4 joerg catclose(catalog);
711 1.4 joerg #endif
712 1.4 joerg
713 1.4 joerg /* Find out the correct return value according to the
714 1.4 joerg results and the command line option. */
715 1.4 joerg exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
716 1.1 cjep }
717