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