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