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