grep.c revision 231135
1/*	$NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 joerg Exp $	*/
2/* 	$FreeBSD: stable/9/usr.bin/grep/grep.c 231135 2012-02-07 17:42: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 231135 2012-02-07 17:42: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(6));
162	fprintf(stderr, "%s", getstr(7));
163	exit(2);
164}
165
166static const char	*optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy";
167
168struct option long_options[] =
169{
170	{"binary-files",	required_argument,	NULL, BIN_OPT},
171	{"help",		no_argument,		NULL, HELP_OPT},
172	{"mmap",		no_argument,		NULL, MMAP_OPT},
173	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
174	{"label",		required_argument,	NULL, LABEL_OPT},
175	{"null",		no_argument,		NULL, NULL_OPT},
176	{"color",		optional_argument,	NULL, COLOR_OPT},
177	{"colour",		optional_argument,	NULL, COLOR_OPT},
178	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
179	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
180	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
181	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
182	{"after-context",	required_argument,	NULL, 'A'},
183	{"text",		no_argument,		NULL, 'a'},
184	{"before-context",	required_argument,	NULL, 'B'},
185	{"byte-offset",		no_argument,		NULL, 'b'},
186	{"context",		optional_argument,	NULL, 'C'},
187	{"count",		no_argument,		NULL, 'c'},
188	{"devices",		required_argument,	NULL, 'D'},
189        {"directories",		required_argument,	NULL, 'd'},
190	{"extended-regexp",	no_argument,		NULL, 'E'},
191	{"regexp",		required_argument,	NULL, 'e'},
192	{"fixed-strings",	no_argument,		NULL, 'F'},
193	{"file",		required_argument,	NULL, 'f'},
194	{"basic-regexp",	no_argument,		NULL, 'G'},
195	{"no-filename",		no_argument,		NULL, 'h'},
196	{"with-filename",	no_argument,		NULL, 'H'},
197	{"ignore-case",		no_argument,		NULL, 'i'},
198	{"bz2decompress",	no_argument,		NULL, 'J'},
199	{"files-with-matches",	no_argument,		NULL, 'l'},
200	{"files-without-match", no_argument,            NULL, 'L'},
201	{"max-count",		required_argument,	NULL, 'm'},
202	{"lzma",		no_argument,		NULL, 'M'},
203	{"line-number",		no_argument,		NULL, 'n'},
204	{"only-matching",	no_argument,		NULL, 'o'},
205	{"quiet",		no_argument,		NULL, 'q'},
206	{"silent",		no_argument,		NULL, 'q'},
207	{"recursive",		no_argument,		NULL, 'r'},
208	{"no-messages",		no_argument,		NULL, 's'},
209	{"binary",		no_argument,		NULL, 'U'},
210	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
211	{"invert-match",	no_argument,		NULL, 'v'},
212	{"version",		no_argument,		NULL, 'V'},
213	{"word-regexp",		no_argument,		NULL, 'w'},
214	{"line-regexp",		no_argument,		NULL, 'x'},
215	{"xz",			no_argument,		NULL, 'X'},
216	{"decompress",          no_argument,            NULL, 'Z'},
217	{NULL,			no_argument,		NULL, 0}
218};
219
220/*
221 * Adds a searching pattern to the internal array.
222 */
223static void
224add_pattern(char *pat, size_t len)
225{
226
227	/* Do not add further pattern is we already match everything */
228	if (matchall)
229	  return;
230
231	/* Check if we can do a shortcut */
232	if (len == 0) {
233		matchall = true;
234		for (unsigned int i = 0; i < patterns; i++) {
235			free(pattern[i].pat);
236		}
237		pattern = grep_realloc(pattern, sizeof(struct pat));
238		pattern[0].pat = NULL;
239		pattern[0].len = 0;
240		patterns = 1;
241		return;
242	}
243	/* Increase size if necessary */
244	if (patterns == pattern_sz) {
245		pattern_sz *= 2;
246		pattern = grep_realloc(pattern, ++pattern_sz *
247		    sizeof(struct pat));
248	}
249	if (len > 0 && pat[len - 1] == '\n')
250		--len;
251	/* pat may not be NUL-terminated */
252	pattern[patterns].pat = grep_malloc(len + 1);
253	memcpy(pattern[patterns].pat, pat, len);
254	pattern[patterns].len = len;
255	pattern[patterns].pat[len] = '\0';
256	++patterns;
257}
258
259/*
260 * Adds a file include/exclude pattern to the internal array.
261 */
262static void
263add_fpattern(const char *pat, int mode)
264{
265
266	/* Increase size if necessary */
267	if (fpatterns == fpattern_sz) {
268		fpattern_sz *= 2;
269		fpattern = grep_realloc(fpattern, ++fpattern_sz *
270		    sizeof(struct epat));
271	}
272	fpattern[fpatterns].pat = grep_strdup(pat);
273	fpattern[fpatterns].mode = mode;
274	++fpatterns;
275}
276
277/*
278 * Adds a directory include/exclude pattern to the internal array.
279 */
280static void
281add_dpattern(const char *pat, int mode)
282{
283
284	/* Increase size if necessary */
285	if (dpatterns == dpattern_sz) {
286		dpattern_sz *= 2;
287		dpattern = grep_realloc(dpattern, ++dpattern_sz *
288		    sizeof(struct epat));
289	}
290	dpattern[dpatterns].pat = grep_strdup(pat);
291	dpattern[dpatterns].mode = mode;
292	++dpatterns;
293}
294
295/*
296 * Reads searching patterns from a file and adds them with add_pattern().
297 */
298static void
299read_patterns(const char *fn)
300{
301	struct stat st;
302	FILE *f;
303	char *line;
304	size_t len;
305
306	if ((f = fopen(fn, "r")) == NULL)
307		err(2, "%s", fn);
308	if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
309		fclose(f);
310		return;
311	}
312        while ((line = fgetln(f, &len)) != NULL)
313		add_pattern(line, line[0] == '\n' ? 0 : len);
314	if (ferror(f))
315		err(2, "%s", fn);
316	fclose(f);
317}
318
319static inline const char *
320init_color(const char *d)
321{
322	char *c;
323
324	c = getenv("GREP_COLOR");
325	return (c != NULL && c[0] != '\0' ? c : d);
326}
327
328int
329main(int argc, char *argv[])
330{
331	char **aargv, **eargv, *eopts;
332	char *ep;
333	const char *pn;
334	unsigned long long l;
335	unsigned int aargc, eargc, i;
336	int c, lastc, needpattern, newarg, prevoptind;
337
338	setlocale(LC_ALL, "");
339
340#ifndef WITHOUT_NLS
341	catalog = catopen("grep", NL_CAT_LOCALE);
342#endif
343
344	/* Check what is the program name of the binary.  In this
345	   way we can have all the funcionalities in one binary
346	   without the need of scripting and using ugly hacks. */
347	pn = getprogname();
348	if (pn[0] == 'b' && pn[1] == 'z') {
349		filebehave = FILE_BZIP;
350		pn += 2;
351	} else if (pn[0] == 'x' && pn[1] == 'z') {
352		filebehave = FILE_XZ;
353		pn += 2;
354	} else if (pn[0] == 'l' && pn[1] == 'z') {
355		filebehave = FILE_LZMA;
356		pn += 2;
357	} else if (pn[0] == 'z') {
358		filebehave = FILE_GZIP;
359		pn += 1;
360	}
361	switch (pn[0]) {
362	case 'e':
363		grepbehave = GREP_EXTENDED;
364		break;
365	case 'f':
366		grepbehave = GREP_FIXED;
367		break;
368	}
369
370	lastc = '\0';
371	newarg = 1;
372	prevoptind = 1;
373	needpattern = 1;
374
375	eopts = getenv("GREP_OPTIONS");
376
377	/* support for extra arguments in GREP_OPTIONS */
378	eargc = 0;
379	if (eopts != NULL && eopts[0] != '\0') {
380		char *str;
381
382		/* make an estimation of how many extra arguments we have */
383		for (unsigned int j = 0; j < strlen(eopts); j++)
384			if (eopts[j] == ' ')
385				eargc++;
386
387		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
388
389		eargc = 0;
390		/* parse extra arguments */
391		while ((str = strsep(&eopts, " ")) != NULL)
392			if (str[0] != '\0')
393				eargv[eargc++] = grep_strdup(str);
394
395		aargv = (char **)grep_calloc(eargc + argc + 1,
396		    sizeof(char *));
397
398		aargv[0] = argv[0];
399		for (i = 0; i < eargc; i++)
400			aargv[i + 1] = eargv[i];
401		for (int j = 1; j < argc; j++, i++)
402			aargv[i + 1] = argv[j];
403
404		aargc = eargc + argc;
405	} else {
406		aargv = argv;
407		aargc = argc;
408	}
409
410	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
411	    -1)) {
412		switch (c) {
413		case '0': case '1': case '2': case '3': case '4':
414		case '5': case '6': case '7': case '8': case '9':
415			if (newarg || !isdigit(lastc))
416				Aflag = 0;
417			else if (Aflag > LLONG_MAX / 10) {
418				errno = ERANGE;
419				err(2, NULL);
420			}
421			Aflag = Bflag = (Aflag * 10) + (c - '0');
422			break;
423		case 'C':
424			if (optarg == NULL) {
425				Aflag = Bflag = 2;
426				break;
427			}
428			/* FALLTHROUGH */
429		case 'A':
430			/* FALLTHROUGH */
431		case 'B':
432			errno = 0;
433			l = strtoull(optarg, &ep, 10);
434			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
435			    ((errno == EINVAL) && (l == 0)))
436				err(2, NULL);
437			else if (ep[0] != '\0') {
438				errno = EINVAL;
439				err(2, NULL);
440			}
441			if (c == 'A')
442				Aflag = l;
443			else if (c == 'B')
444				Bflag = l;
445			else
446				Aflag = Bflag = l;
447			break;
448		case 'a':
449			binbehave = BINFILE_TEXT;
450			break;
451		case 'b':
452			bflag = true;
453			break;
454		case 'c':
455			cflag = true;
456			break;
457		case 'D':
458			if (strcasecmp(optarg, "skip") == 0)
459				devbehave = DEV_SKIP;
460			else if (strcasecmp(optarg, "read") == 0)
461				devbehave = DEV_READ;
462			else
463				errx(2, getstr(3), "--devices");
464			break;
465		case 'd':
466			if (strcasecmp("recurse", optarg) == 0) {
467				Hflag = true;
468				dirbehave = DIR_RECURSE;
469			} else if (strcasecmp("skip", optarg) == 0)
470				dirbehave = DIR_SKIP;
471			else if (strcasecmp("read", optarg) == 0)
472				dirbehave = DIR_READ;
473			else
474				errx(2, getstr(3), "--directories");
475			break;
476		case 'E':
477			grepbehave = GREP_EXTENDED;
478			break;
479		case 'e':
480			add_pattern(optarg, strlen(optarg));
481			needpattern = 0;
482			break;
483		case 'F':
484			grepbehave = GREP_FIXED;
485			break;
486		case 'f':
487			read_patterns(optarg);
488			needpattern = 0;
489			break;
490		case 'G':
491			grepbehave = GREP_BASIC;
492			break;
493		case 'H':
494			Hflag = true;
495			break;
496		case 'h':
497			Hflag = false;
498			hflag = true;
499			break;
500		case 'I':
501			binbehave = BINFILE_SKIP;
502			break;
503		case 'i':
504		case 'y':
505			iflag =  true;
506			cflags |= REG_ICASE;
507			break;
508		case 'J':
509#ifdef WITHOUT_BZIP2
510			errno = EOPNOTSUPP;
511			err(2, "bzip2 support was disabled at compile-time");
512#endif
513			filebehave = FILE_BZIP;
514			break;
515		case 'L':
516			lflag = false;
517			Lflag = true;
518			break;
519		case 'l':
520			Lflag = false;
521			lflag = true;
522			break;
523		case 'm':
524			mflag = true;
525			errno = 0;
526			mcount = strtoll(optarg, &ep, 10);
527			if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
528			    ((errno == EINVAL) && (mcount == 0)))
529				err(2, NULL);
530			else if (ep[0] != '\0') {
531				errno = EINVAL;
532				err(2, NULL);
533			}
534			break;
535		case 'M':
536			filebehave = FILE_LZMA;
537			break;
538		case 'n':
539			nflag = true;
540			break;
541		case 'O':
542			linkbehave = LINK_EXPLICIT;
543			break;
544		case 'o':
545			oflag = true;
546			cflags &= ~REG_NOSUB;
547			break;
548		case 'p':
549			linkbehave = LINK_SKIP;
550			break;
551		case 'q':
552			qflag = true;
553			break;
554		case 'S':
555			linkbehave = LINK_READ;
556			break;
557		case 'R':
558		case 'r':
559			dirbehave = DIR_RECURSE;
560			Hflag = true;
561			break;
562		case 's':
563			sflag = true;
564			break;
565		case 'U':
566			binbehave = BINFILE_BIN;
567			break;
568		case 'u':
569		case MMAP_OPT:
570			filebehave = FILE_MMAP;
571			break;
572		case 'V':
573			printf(getstr(9), getprogname(), VERSION);
574			exit(0);
575		case 'v':
576			vflag = true;
577			break;
578		case 'w':
579			wflag = true;
580			cflags &= ~REG_NOSUB;
581			break;
582		case 'x':
583			xflag = true;
584			cflags &= ~REG_NOSUB;
585			break;
586		case 'X':
587			filebehave = FILE_XZ;
588			break;
589		case 'Z':
590			filebehave = FILE_GZIP;
591			break;
592		case BIN_OPT:
593			if (strcasecmp("binary", optarg) == 0)
594				binbehave = BINFILE_BIN;
595			else if (strcasecmp("without-match", optarg) == 0)
596				binbehave = BINFILE_SKIP;
597			else if (strcasecmp("text", optarg) == 0)
598				binbehave = BINFILE_TEXT;
599			else
600				errx(2, getstr(3), "--binary-files");
601			break;
602		case COLOR_OPT:
603			color = NULL;
604			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
605			    strcasecmp("tty", optarg) == 0 ||
606			    strcasecmp("if-tty", optarg) == 0) {
607				char *term;
608
609				term = getenv("TERM");
610				if (isatty(STDOUT_FILENO) && term != NULL &&
611				    strcasecmp(term, "dumb") != 0)
612					color = init_color("01;31");
613			} else if (strcasecmp("always", optarg) == 0 ||
614			    strcasecmp("yes", optarg) == 0 ||
615			    strcasecmp("force", optarg) == 0) {
616				color = init_color("01;31");
617			} else if (strcasecmp("never", optarg) != 0 &&
618			    strcasecmp("none", optarg) != 0 &&
619			    strcasecmp("no", optarg) != 0)
620				errx(2, getstr(3), "--color");
621			cflags &= ~REG_NOSUB;
622			break;
623		case LABEL_OPT:
624			label = optarg;
625			break;
626		case LINEBUF_OPT:
627			lbflag = true;
628			break;
629		case NULL_OPT:
630			nullflag = true;
631			break;
632		case R_INCLUDE_OPT:
633			finclude = true;
634			add_fpattern(optarg, INCL_PAT);
635			break;
636		case R_EXCLUDE_OPT:
637			fexclude = true;
638			add_fpattern(optarg, EXCL_PAT);
639			break;
640		case R_DINCLUDE_OPT:
641			dinclude = true;
642			add_dpattern(optarg, INCL_PAT);
643			break;
644		case R_DEXCLUDE_OPT:
645			dexclude = true;
646			add_dpattern(optarg, EXCL_PAT);
647			break;
648		case HELP_OPT:
649		default:
650			usage();
651		}
652		lastc = c;
653		newarg = optind != prevoptind;
654		prevoptind = optind;
655	}
656	aargc -= optind;
657	aargv += optind;
658
659	/* Empty pattern file matches nothing */
660	if (!needpattern && (patterns == 0))
661		exit(1);
662
663	/* Fail if we don't have any pattern */
664	if (aargc == 0 && needpattern)
665		usage();
666
667	/* Process patterns from command line */
668	if (aargc != 0 && needpattern) {
669		add_pattern(*aargv, strlen(*aargv));
670		--aargc;
671		++aargv;
672	}
673
674	switch (grepbehave) {
675	case GREP_BASIC:
676		break;
677	case GREP_FIXED:
678		/* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */
679		cflags |= 0020;
680		break;
681	case GREP_EXTENDED:
682		cflags |= REG_EXTENDED;
683		break;
684	default:
685		/* NOTREACHED */
686		usage();
687	}
688
689	fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
690	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
691
692	/* Check if cheating is allowed (always is for fgrep). */
693	for (i = 0; i < patterns; ++i) {
694		if (fastncomp(&fg_pattern[i], pattern[i].pat,
695		    pattern[i].len, cflags) != 0) {
696			/* Fall back to full regex library */
697			c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
698			if (c != 0) {
699				regerror(c, &r_pattern[i], re_error,
700				    RE_ERROR_BUF);
701				errx(2, "%s", re_error);
702			}
703		}
704	}
705
706	if (lbflag)
707		setlinebuf(stdout);
708
709	if ((aargc == 0 || aargc == 1) && !Hflag)
710		hflag = true;
711
712	if (aargc == 0)
713		exit(!procfile("-"));
714
715	if (dirbehave == DIR_RECURSE)
716		c = grep_tree(aargv);
717	else
718		for (c = 0; aargc--; ++aargv) {
719			if ((finclude || fexclude) && !file_matching(*aargv))
720				continue;
721			c+= procfile(*aargv);
722		}
723
724#ifndef WITHOUT_NLS
725	catclose(catalog);
726#endif
727
728	/* Find out the correct return value according to the
729	   results and the command line option. */
730	exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
731}
732