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