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