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