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