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