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