grep.c revision 1.6 1 1.6 joerg /* $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg 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.6 joerg __RCSID("$NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg 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.4 joerg /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-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.4 joerg /* 7*/ "\t[--null] [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 /* Shortcut for matching all cases like empty regex */
84 1.4 joerg bool matchall;
85 1.1 cjep
86 1.4 joerg /* Searching patterns */
87 1.4 joerg unsigned int patterns, pattern_sz;
88 1.4 joerg char **pattern;
89 1.4 joerg regex_t *r_pattern;
90 1.4 joerg fastgrep_t *fg_pattern;
91 1.4 joerg
92 1.4 joerg /* Filename exclusion/inclusion patterns */
93 1.4 joerg unsigned int fpatterns, fpattern_sz;
94 1.4 joerg unsigned int dpatterns, dpattern_sz;
95 1.4 joerg struct epat *dpattern, *fpattern;
96 1.1 cjep
97 1.1 cjep /* For regex errors */
98 1.4 joerg char re_error[RE_ERROR_BUF + 1];
99 1.1 cjep
100 1.1 cjep /* Command-line flags */
101 1.4 joerg unsigned long long Aflag; /* -A x: print x lines trailing each match */
102 1.4 joerg unsigned long long Bflag; /* -B x: print x lines leading each match */
103 1.4 joerg bool Hflag; /* -H: always print file name */
104 1.4 joerg bool Lflag; /* -L: only show names of files with no matches */
105 1.4 joerg bool bflag; /* -b: show block numbers for each match */
106 1.4 joerg bool cflag; /* -c: only show a count of matching lines */
107 1.4 joerg bool hflag; /* -h: don't print filename headers */
108 1.4 joerg bool iflag; /* -i: ignore case */
109 1.4 joerg bool lflag; /* -l: only show names of files with matches */
110 1.4 joerg bool mflag; /* -m x: stop reading the files after x matches */
111 1.4 joerg unsigned long long mcount; /* count for -m */
112 1.4 joerg bool nflag; /* -n: show line numbers in front of matching lines */
113 1.4 joerg bool oflag; /* -o: print only matching part */
114 1.4 joerg bool qflag; /* -q: quiet mode (don't output anything) */
115 1.4 joerg bool sflag; /* -s: silent mode (ignore errors) */
116 1.4 joerg bool vflag; /* -v: only show non-matching lines */
117 1.4 joerg bool wflag; /* -w: pattern must start and end on word boundaries */
118 1.4 joerg bool xflag; /* -x: pattern must match entire line */
119 1.4 joerg bool lbflag; /* --line-buffered */
120 1.4 joerg bool nullflag; /* --null */
121 1.4 joerg char *label; /* --label */
122 1.4 joerg const char *color; /* --color */
123 1.4 joerg int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
124 1.4 joerg int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
125 1.4 joerg int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
126 1.4 joerg int devbehave = DEV_READ; /* -D: handling of devices */
127 1.4 joerg int dirbehave = DIR_READ; /* -dRr: handling of directories */
128 1.4 joerg int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
129 1.4 joerg
130 1.4 joerg bool dexclude, dinclude; /* --exclude-dir and --include-dir */
131 1.4 joerg bool fexclude, finclude; /* --exclude and --include */
132 1.2 cjep
133 1.2 cjep enum {
134 1.2 cjep BIN_OPT = CHAR_MAX + 1,
135 1.4 joerg COLOR_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 NULL_OPT,
141 1.4 joerg R_EXCLUDE_OPT,
142 1.4 joerg R_INCLUDE_OPT,
143 1.4 joerg R_DEXCLUDE_OPT,
144 1.4 joerg R_DINCLUDE_OPT
145 1.2 cjep };
146 1.1 cjep
147 1.4 joerg static inline const char *init_color(const char *);
148 1.4 joerg
149 1.1 cjep /* Housekeeping */
150 1.4 joerg bool first = true; /* flag whether we are processing the first match */
151 1.4 joerg bool prev; /* flag whether or not the previous line matched */
152 1.4 joerg int tail; /* lines left to print */
153 1.4 joerg bool notfound; /* file not found */
154 1.4 joerg
155 1.4 joerg extern char *__progname;
156 1.1 cjep
157 1.4 joerg /*
158 1.4 joerg * Prints usage information and returns 2.
159 1.4 joerg */
160 1.1 cjep static void
161 1.1 cjep usage(void)
162 1.1 cjep {
163 1.4 joerg fprintf(stderr, getstr(4), __progname);
164 1.4 joerg fprintf(stderr, "%s", getstr(5));
165 1.4 joerg fprintf(stderr, "%s", getstr(5));
166 1.4 joerg fprintf(stderr, "%s", getstr(6));
167 1.4 joerg fprintf(stderr, "%s", getstr(7));
168 1.1 cjep exit(2);
169 1.1 cjep }
170 1.1 cjep
171 1.4 joerg static const char *optstr = "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxy";
172 1.1 cjep
173 1.2 cjep struct option long_options[] =
174 1.1 cjep {
175 1.4 joerg {"binary-files", required_argument, NULL, BIN_OPT},
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 {"null", no_argument, NULL, NULL_OPT},
181 1.4 joerg {"color", optional_argument, NULL, COLOR_OPT},
182 1.4 joerg {"colour", optional_argument, NULL, COLOR_OPT},
183 1.4 joerg {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
184 1.4 joerg {"include", required_argument, NULL, R_INCLUDE_OPT},
185 1.4 joerg {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
186 1.4 joerg {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
187 1.4 joerg {"after-context", required_argument, NULL, 'A'},
188 1.4 joerg {"text", no_argument, NULL, 'a'},
189 1.4 joerg {"before-context", required_argument, NULL, 'B'},
190 1.4 joerg {"byte-offset", no_argument, NULL, 'b'},
191 1.4 joerg {"context", optional_argument, NULL, 'C'},
192 1.4 joerg {"count", no_argument, NULL, 'c'},
193 1.4 joerg {"devices", required_argument, NULL, 'D'},
194 1.4 joerg {"directories", required_argument, NULL, 'd'},
195 1.4 joerg {"extended-regexp", no_argument, NULL, 'E'},
196 1.4 joerg {"regexp", required_argument, NULL, 'e'},
197 1.4 joerg {"fixed-strings", no_argument, NULL, 'F'},
198 1.4 joerg {"file", required_argument, NULL, 'f'},
199 1.4 joerg {"basic-regexp", no_argument, NULL, 'G'},
200 1.4 joerg {"no-filename", no_argument, NULL, 'h'},
201 1.4 joerg {"with-filename", no_argument, NULL, 'H'},
202 1.4 joerg {"ignore-case", no_argument, NULL, 'i'},
203 1.4 joerg {"bz2decompress", no_argument, NULL, 'J'},
204 1.4 joerg {"files-with-matches", no_argument, NULL, 'l'},
205 1.4 joerg {"files-without-match", no_argument, NULL, 'L'},
206 1.4 joerg {"max-count", required_argument, NULL, 'm'},
207 1.4 joerg {"line-number", no_argument, NULL, 'n'},
208 1.4 joerg {"only-matching", no_argument, NULL, 'o'},
209 1.4 joerg {"quiet", no_argument, NULL, 'q'},
210 1.4 joerg {"silent", no_argument, NULL, 'q'},
211 1.4 joerg {"recursive", no_argument, NULL, 'r'},
212 1.4 joerg {"no-messages", no_argument, NULL, 's'},
213 1.4 joerg {"binary", no_argument, NULL, 'U'},
214 1.4 joerg {"unix-byte-offsets", no_argument, NULL, 'u'},
215 1.4 joerg {"invert-match", no_argument, NULL, 'v'},
216 1.4 joerg {"version", no_argument, NULL, 'V'},
217 1.4 joerg {"word-regexp", no_argument, NULL, 'w'},
218 1.4 joerg {"line-regexp", no_argument, NULL, 'x'},
219 1.4 joerg {"decompress", 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.4 joerg /* Check if we can do a shortcut */
231 1.1 cjep if (len == 0 || matchall) {
232 1.4 joerg matchall = true;
233 1.1 cjep return;
234 1.1 cjep }
235 1.4 joerg /* Increase size if necessary */
236 1.1 cjep if (patterns == pattern_sz) {
237 1.1 cjep pattern_sz *= 2;
238 1.4 joerg pattern = grep_realloc(pattern, ++pattern_sz *
239 1.4 joerg sizeof(*pattern));
240 1.1 cjep }
241 1.4 joerg if (len > 0 && pat[len - 1] == '\n')
242 1.1 cjep --len;
243 1.4 joerg /* pat may not be NUL-terminated */
244 1.2 cjep pattern[patterns] = grep_malloc(len + 1);
245 1.4 joerg memcpy(pattern[patterns], pat, len);
246 1.1 cjep pattern[patterns][len] = '\0';
247 1.1 cjep ++patterns;
248 1.1 cjep }
249 1.1 cjep
250 1.4 joerg /*
251 1.4 joerg * Adds a file include/exclude pattern to the internal array.
252 1.4 joerg */
253 1.1 cjep static void
254 1.4 joerg add_fpattern(const char *pat, int mode)
255 1.4 joerg {
256 1.4 joerg
257 1.4 joerg /* Increase size if necessary */
258 1.4 joerg if (fpatterns == fpattern_sz) {
259 1.4 joerg fpattern_sz *= 2;
260 1.4 joerg fpattern = grep_realloc(fpattern, ++fpattern_sz *
261 1.4 joerg sizeof(struct epat));
262 1.4 joerg }
263 1.4 joerg fpattern[fpatterns].pat = grep_strdup(pat);
264 1.4 joerg fpattern[fpatterns].mode = mode;
265 1.4 joerg ++fpatterns;
266 1.4 joerg }
267 1.4 joerg
268 1.4 joerg /*
269 1.4 joerg * Adds a directory include/exclude pattern to the internal array.
270 1.4 joerg */
271 1.4 joerg static void
272 1.4 joerg add_dpattern(const char *pat, int mode)
273 1.4 joerg {
274 1.4 joerg
275 1.4 joerg /* Increase size if necessary */
276 1.4 joerg if (dpatterns == dpattern_sz) {
277 1.4 joerg dpattern_sz *= 2;
278 1.4 joerg dpattern = grep_realloc(dpattern, ++dpattern_sz *
279 1.4 joerg sizeof(struct epat));
280 1.4 joerg }
281 1.4 joerg dpattern[dpatterns].pat = grep_strdup(pat);
282 1.4 joerg dpattern[dpatterns].mode = mode;
283 1.4 joerg ++dpatterns;
284 1.4 joerg }
285 1.4 joerg
286 1.4 joerg /*
287 1.4 joerg * Reads searching patterns from a file and adds them with add_pattern().
288 1.4 joerg */
289 1.4 joerg static void
290 1.4 joerg read_patterns(const char *fn)
291 1.1 cjep {
292 1.1 cjep FILE *f;
293 1.1 cjep char *line;
294 1.1 cjep size_t len;
295 1.6 joerg ssize_t rlen;
296 1.1 cjep
297 1.1 cjep if ((f = fopen(fn, "r")) == NULL)
298 1.2 cjep err(2, "%s", fn);
299 1.6 joerg line = NULL;
300 1.6 joerg len = 0;
301 1.6 joerg while ((rlen = getline(&line, &len, f)) != -1)
302 1.6 joerg add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
303 1.6 joerg free(line);
304 1.1 cjep if (ferror(f))
305 1.2 cjep err(2, "%s", fn);
306 1.1 cjep fclose(f);
307 1.1 cjep }
308 1.1 cjep
309 1.4 joerg static inline const char *
310 1.4 joerg init_color(const char *d)
311 1.2 cjep {
312 1.4 joerg char *c;
313 1.2 cjep
314 1.4 joerg c = getenv("GREP_COLOR");
315 1.4 joerg return (c != NULL ? c : d);
316 1.2 cjep }
317 1.2 cjep
318 1.1 cjep int
319 1.1 cjep main(int argc, char *argv[])
320 1.1 cjep {
321 1.4 joerg char **aargv, **eargv, *eopts;
322 1.4 joerg char *ep;
323 1.4 joerg unsigned long long l;
324 1.4 joerg unsigned int aargc, eargc, i;
325 1.4 joerg int c, lastc, needpattern, newarg, prevoptind;
326 1.4 joerg
327 1.4 joerg setlocale(LC_ALL, "");
328 1.4 joerg
329 1.4 joerg #ifndef WITHOUT_NLS
330 1.4 joerg catalog = catopen("grep", NL_CAT_LOCALE);
331 1.4 joerg #endif
332 1.4 joerg
333 1.4 joerg /* Check what is the program name of the binary. In this
334 1.4 joerg way we can have all the funcionalities in one binary
335 1.4 joerg without the need of scripting and using ugly hacks. */
336 1.4 joerg switch (__progname[0]) {
337 1.2 cjep case 'e':
338 1.4 joerg grepbehave = GREP_EXTENDED;
339 1.2 cjep break;
340 1.2 cjep case 'f':
341 1.4 joerg grepbehave = GREP_FIXED;
342 1.2 cjep break;
343 1.2 cjep case 'g':
344 1.4 joerg grepbehave = GREP_BASIC;
345 1.2 cjep break;
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.2 cjep }
361 1.1 cjep
362 1.4 joerg lastc = '\0';
363 1.4 joerg newarg = 1;
364 1.4 joerg prevoptind = 1;
365 1.4 joerg needpattern = 1;
366 1.4 joerg
367 1.4 joerg eopts = getenv("GREP_OPTIONS");
368 1.4 joerg
369 1.4 joerg /* support for extra arguments in GREP_OPTIONS */
370 1.4 joerg eargc = 0;
371 1.4 joerg if (eopts != NULL) {
372 1.4 joerg char *str;
373 1.4 joerg
374 1.4 joerg /* make an estimation of how many extra arguments we have */
375 1.4 joerg for (unsigned int j = 0; j < strlen(eopts); j++)
376 1.4 joerg if (eopts[j] == ' ')
377 1.4 joerg eargc++;
378 1.4 joerg
379 1.4 joerg eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
380 1.4 joerg
381 1.4 joerg eargc = 0;
382 1.4 joerg /* parse extra arguments */
383 1.4 joerg while ((str = strsep(&eopts, " ")) != NULL)
384 1.4 joerg eargv[eargc++] = grep_strdup(str);
385 1.4 joerg
386 1.4 joerg aargv = (char **)grep_calloc(eargc + argc + 1,
387 1.4 joerg sizeof(char *));
388 1.4 joerg
389 1.4 joerg aargv[0] = argv[0];
390 1.4 joerg for (i = 0; i < eargc; i++)
391 1.4 joerg aargv[i + 1] = eargv[i];
392 1.4 joerg for (int j = 1; j < argc; j++, i++)
393 1.4 joerg aargv[i + 1] = argv[j];
394 1.4 joerg
395 1.4 joerg aargc = eargc + argc;
396 1.4 joerg } else {
397 1.4 joerg aargv = argv;
398 1.4 joerg aargc = argc;
399 1.4 joerg }
400 1.4 joerg
401 1.4 joerg while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
402 1.4 joerg -1)) {
403 1.1 cjep switch (c) {
404 1.4 joerg case '0': case '1': case '2': case '3': case '4':
405 1.4 joerg case '5': case '6': case '7': case '8': case '9':
406 1.4 joerg if (newarg || !isdigit(lastc))
407 1.4 joerg Aflag = 0;
408 1.4 joerg else if (Aflag > LLONG_MAX / 10) {
409 1.4 joerg errno = ERANGE;
410 1.4 joerg err(2, NULL);
411 1.4 joerg }
412 1.4 joerg Aflag = Bflag = (Aflag * 10) + (c - '0');
413 1.1 cjep break;
414 1.1 cjep case 'C':
415 1.4 joerg if (optarg == NULL) {
416 1.1 cjep Aflag = Bflag = 2;
417 1.4 joerg break;
418 1.4 joerg }
419 1.4 joerg /* FALLTHROUGH */
420 1.4 joerg case 'A':
421 1.4 joerg /* FALLTHROUGH */
422 1.4 joerg case 'B':
423 1.4 joerg errno = 0;
424 1.4 joerg l = strtoull(optarg, &ep, 10);
425 1.4 joerg if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
426 1.4 joerg ((errno == EINVAL) && (l == 0)))
427 1.4 joerg err(2, NULL);
428 1.4 joerg else if (ep[0] != '\0') {
429 1.4 joerg errno = EINVAL;
430 1.4 joerg err(2, NULL);
431 1.4 joerg }
432 1.4 joerg if (c == 'A')
433 1.4 joerg Aflag = l;
434 1.4 joerg else if (c == 'B')
435 1.4 joerg Bflag = l;
436 1.1 cjep else
437 1.4 joerg Aflag = Bflag = l;
438 1.1 cjep break;
439 1.1 cjep case 'a':
440 1.4 joerg binbehave = BINFILE_TEXT;
441 1.1 cjep break;
442 1.1 cjep case 'b':
443 1.4 joerg bflag = true;
444 1.1 cjep break;
445 1.1 cjep case 'c':
446 1.4 joerg cflag = true;
447 1.4 joerg break;
448 1.4 joerg case 'D':
449 1.4 joerg if (strcasecmp(optarg, "skip") == 0)
450 1.4 joerg devbehave = DEV_SKIP;
451 1.4 joerg else if (strcasecmp(optarg, "read") == 0)
452 1.4 joerg devbehave = DEV_READ;
453 1.4 joerg else
454 1.4 joerg errx(2, getstr(3), "--devices");
455 1.1 cjep break;
456 1.2 cjep case 'd':
457 1.4 joerg if (strcasecmp("recurse", optarg) == 0) {
458 1.4 joerg Hflag = true;
459 1.4 joerg dirbehave = DIR_RECURSE;
460 1.4 joerg } else if (strcasecmp("skip", optarg) == 0)
461 1.4 joerg dirbehave = DIR_SKIP;
462 1.4 joerg else if (strcasecmp("read", optarg) == 0)
463 1.4 joerg dirbehave = DIR_READ;
464 1.4 joerg else
465 1.4 joerg errx(2, getstr(3), "--directories");
466 1.4 joerg break;
467 1.4 joerg case 'E':
468 1.4 joerg grepbehave = GREP_EXTENDED;
469 1.2 cjep break;
470 1.1 cjep case 'e':
471 1.1 cjep add_pattern(optarg, strlen(optarg));
472 1.4 joerg needpattern = 0;
473 1.4 joerg break;
474 1.4 joerg case 'F':
475 1.4 joerg grepbehave = GREP_FIXED;
476 1.1 cjep break;
477 1.1 cjep case 'f':
478 1.1 cjep read_patterns(optarg);
479 1.4 joerg needpattern = 0;
480 1.4 joerg break;
481 1.4 joerg case 'G':
482 1.4 joerg grepbehave = GREP_BASIC;
483 1.4 joerg break;
484 1.4 joerg case 'H':
485 1.4 joerg Hflag = true;
486 1.1 cjep break;
487 1.1 cjep case 'h':
488 1.4 joerg Hflag = false;
489 1.4 joerg hflag = true;
490 1.4 joerg break;
491 1.4 joerg case 'I':
492 1.4 joerg binbehave = BINFILE_SKIP;
493 1.1 cjep break;
494 1.1 cjep case 'i':
495 1.1 cjep case 'y':
496 1.4 joerg iflag = true;
497 1.1 cjep cflags |= REG_ICASE;
498 1.1 cjep break;
499 1.4 joerg case 'J':
500 1.4 joerg filebehave = FILE_BZIP;
501 1.4 joerg break;
502 1.4 joerg case 'L':
503 1.4 joerg lflag = false;
504 1.4 joerg Lflag = true;
505 1.4 joerg break;
506 1.1 cjep case 'l':
507 1.4 joerg Lflag = false;
508 1.4 joerg lflag = true;
509 1.1 cjep break;
510 1.2 cjep case 'm':
511 1.4 joerg mflag = true;
512 1.4 joerg errno = 0;
513 1.4 joerg mcount = strtoull(optarg, &ep, 10);
514 1.4 joerg if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
515 1.4 joerg ((errno == EINVAL) && (mcount == 0)))
516 1.4 joerg err(2, NULL);
517 1.4 joerg else if (ep[0] != '\0') {
518 1.4 joerg errno = EINVAL;
519 1.4 joerg err(2, NULL);
520 1.4 joerg }
521 1.2 cjep break;
522 1.1 cjep case 'n':
523 1.4 joerg nflag = true;
524 1.4 joerg break;
525 1.4 joerg case 'O':
526 1.4 joerg linkbehave = LINK_EXPLICIT;
527 1.1 cjep break;
528 1.1 cjep case 'o':
529 1.4 joerg oflag = true;
530 1.4 joerg break;
531 1.4 joerg case 'p':
532 1.4 joerg linkbehave = LINK_SKIP;
533 1.1 cjep break;
534 1.1 cjep case 'q':
535 1.4 joerg qflag = true;
536 1.4 joerg break;
537 1.4 joerg case 'S':
538 1.4 joerg linkbehave = LINK_READ;
539 1.4 joerg break;
540 1.4 joerg case 'R':
541 1.4 joerg case 'r':
542 1.4 joerg dirbehave = DIR_RECURSE;
543 1.4 joerg Hflag = true;
544 1.1 cjep break;
545 1.1 cjep case 's':
546 1.4 joerg sflag = true;
547 1.4 joerg break;
548 1.4 joerg case 'U':
549 1.4 joerg binbehave = BINFILE_BIN;
550 1.1 cjep break;
551 1.4 joerg case 'u':
552 1.4 joerg case MMAP_OPT:
553 1.4 joerg /* noop, compatibility */
554 1.4 joerg break;
555 1.4 joerg case 'V':
556 1.4 joerg printf(getstr(9), __progname, VERSION);
557 1.4 joerg exit(0);
558 1.1 cjep case 'v':
559 1.4 joerg vflag = true;
560 1.1 cjep break;
561 1.1 cjep case 'w':
562 1.4 joerg wflag = true;
563 1.1 cjep break;
564 1.1 cjep case 'x':
565 1.4 joerg xflag = true;
566 1.1 cjep break;
567 1.4 joerg case 'Z':
568 1.4 joerg filebehave = FILE_GZIP;
569 1.2 cjep break;
570 1.2 cjep case BIN_OPT:
571 1.4 joerg if (strcasecmp("binary", optarg) == 0)
572 1.4 joerg binbehave = BINFILE_BIN;
573 1.4 joerg else if (strcasecmp("without-match", optarg) == 0)
574 1.4 joerg binbehave = BINFILE_SKIP;
575 1.4 joerg else if (strcasecmp("text", optarg) == 0)
576 1.4 joerg binbehave = BINFILE_TEXT;
577 1.4 joerg else
578 1.4 joerg errx(2, getstr(3), "--binary-files");
579 1.4 joerg break;
580 1.4 joerg case COLOR_OPT:
581 1.4 joerg color = NULL;
582 1.4 joerg if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
583 1.4 joerg strcasecmp("tty", optarg) == 0 ||
584 1.4 joerg strcasecmp("if-tty", optarg) == 0) {
585 1.4 joerg char *term;
586 1.4 joerg
587 1.4 joerg term = getenv("TERM");
588 1.4 joerg if (isatty(STDOUT_FILENO) && term != NULL &&
589 1.4 joerg strcasecmp(term, "dumb") != 0)
590 1.4 joerg color = init_color("01;31");
591 1.4 joerg } else if (strcasecmp("always", optarg) == 0 ||
592 1.4 joerg strcasecmp("yes", optarg) == 0 ||
593 1.4 joerg strcasecmp("force", optarg) == 0) {
594 1.4 joerg color = init_color("01;31");
595 1.4 joerg } else if (strcasecmp("never", optarg) != 0 &&
596 1.4 joerg strcasecmp("none", optarg) != 0 &&
597 1.4 joerg strcasecmp("no", optarg) != 0)
598 1.4 joerg errx(2, getstr(3), "--color");
599 1.2 cjep break;
600 1.2 cjep case LABEL_OPT:
601 1.4 joerg label = optarg;
602 1.4 joerg break;
603 1.4 joerg case LINEBUF_OPT:
604 1.4 joerg lbflag = true;
605 1.2 cjep break;
606 1.4 joerg case NULL_OPT:
607 1.4 joerg nullflag = true;
608 1.2 cjep break;
609 1.4 joerg case R_INCLUDE_OPT:
610 1.4 joerg finclude = true;
611 1.4 joerg add_fpattern(optarg, INCL_PAT);
612 1.4 joerg break;
613 1.4 joerg case R_EXCLUDE_OPT:
614 1.4 joerg fexclude = true;
615 1.4 joerg add_fpattern(optarg, EXCL_PAT);
616 1.4 joerg break;
617 1.4 joerg case R_DINCLUDE_OPT:
618 1.4 joerg dinclude = true;
619 1.4 joerg add_dpattern(optarg, INCL_PAT);
620 1.4 joerg break;
621 1.4 joerg case R_DEXCLUDE_OPT:
622 1.4 joerg dexclude = true;
623 1.4 joerg add_dpattern(optarg, EXCL_PAT);
624 1.2 cjep break;
625 1.2 cjep case HELP_OPT:
626 1.1 cjep default:
627 1.1 cjep usage();
628 1.1 cjep }
629 1.4 joerg lastc = c;
630 1.4 joerg newarg = optind != prevoptind;
631 1.4 joerg prevoptind = optind;
632 1.1 cjep }
633 1.4 joerg aargc -= optind;
634 1.4 joerg aargv += optind;
635 1.1 cjep
636 1.4 joerg /* Fail if we don't have any pattern */
637 1.4 joerg if (aargc == 0 && needpattern)
638 1.1 cjep usage();
639 1.4 joerg
640 1.4 joerg /* Process patterns from command line */
641 1.4 joerg if (aargc != 0 && needpattern) {
642 1.4 joerg add_pattern(*aargv, strlen(*aargv));
643 1.4 joerg --aargc;
644 1.4 joerg ++aargv;
645 1.1 cjep }
646 1.1 cjep
647 1.4 joerg switch (grepbehave) {
648 1.4 joerg case GREP_FIXED:
649 1.4 joerg case GREP_BASIC:
650 1.4 joerg break;
651 1.4 joerg case GREP_EXTENDED:
652 1.2 cjep cflags |= REG_EXTENDED;
653 1.4 joerg break;
654 1.4 joerg default:
655 1.4 joerg /* NOTREACHED */
656 1.4 joerg usage();
657 1.4 joerg }
658 1.4 joerg
659 1.4 joerg fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
660 1.4 joerg r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
661 1.4 joerg /*
662 1.4 joerg * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
663 1.4 joerg * Optimizations should be done there.
664 1.4 joerg */
665 1.4 joerg /* Check if cheating is allowed (always is for fgrep). */
666 1.4 joerg if (grepbehave == GREP_FIXED) {
667 1.4 joerg for (i = 0; i < patterns; ++i)
668 1.4 joerg fgrepcomp(&fg_pattern[i], pattern[i]);
669 1.4 joerg } else {
670 1.4 joerg for (i = 0; i < patterns; ++i) {
671 1.4 joerg if (fastcomp(&fg_pattern[i], pattern[i])) {
672 1.4 joerg /* Fall back to full regex library */
673 1.4 joerg c = regcomp(&r_pattern[i], pattern[i], cflags);
674 1.4 joerg if (c != 0) {
675 1.4 joerg regerror(c, &r_pattern[i], re_error,
676 1.4 joerg RE_ERROR_BUF);
677 1.4 joerg errx(2, "%s", re_error);
678 1.4 joerg }
679 1.4 joerg }
680 1.1 cjep }
681 1.1 cjep }
682 1.1 cjep
683 1.4 joerg if (lbflag)
684 1.4 joerg setlinebuf(stdout);
685 1.1 cjep
686 1.4 joerg if ((aargc == 0 || aargc == 1) && !Hflag)
687 1.4 joerg hflag = true;
688 1.2 cjep
689 1.4 joerg if (aargc == 0)
690 1.4 joerg exit(!procfile("-"));
691 1.2 cjep
692 1.4 joerg if (dirbehave == DIR_RECURSE)
693 1.4 joerg c = grep_tree(aargv);
694 1.1 cjep else
695 1.4 joerg for (c = 0; aargc--; ++aargv) {
696 1.4 joerg if ((finclude || fexclude) && !file_matching(*aargv))
697 1.4 joerg continue;
698 1.4 joerg c+= procfile(*aargv);
699 1.4 joerg }
700 1.1 cjep
701 1.4 joerg #ifndef WITHOUT_NLS
702 1.4 joerg catclose(catalog);
703 1.4 joerg #endif
704 1.4 joerg
705 1.4 joerg /* Find out the correct return value according to the
706 1.4 joerg results and the command line option. */
707 1.4 joerg exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
708 1.1 cjep }
709