xref: /freebsd/usr.bin/grep/grep.c (revision b7c60aadbbd5c846a250c05791fe7406d6d78bf4)
1 /*	$NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 joerg Exp $	*/
2 /* 	$FreeBSD$	*/
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$");
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>
57 nl_catd	 catalog;
58 #endif
59 
60 /*
61  * Default messags to use when NLS is disabled or no catalogue
62  * is found.
63  */
64 const 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() */
78 int		 cflags = REG_NOSUB;
79 int		 eflags = REG_STARTEND;
80 
81 /* Shortcut for matching all cases like empty regex */
82 bool		 matchall;
83 
84 /* Searching patterns */
85 unsigned int	 patterns, pattern_sz;
86 struct pat	*pattern;
87 regex_t		*r_pattern;
88 fastmatch_t	*fg_pattern;
89 
90 /* Filename exclusion/inclusion patterns */
91 unsigned int	 fpatterns, fpattern_sz;
92 unsigned int	 dpatterns, dpattern_sz;
93 struct epat	*dpattern, *fpattern;
94 
95 /* For regex errors  */
96 char	 re_error[RE_ERROR_BUF + 1];
97 
98 /* Command-line flags */
99 unsigned long long Aflag;	/* -A x: print x lines trailing each match */
100 unsigned long long Bflag;	/* -B x: print x lines leading each match */
101 bool	 Hflag;		/* -H: always print file name */
102 bool	 Lflag;		/* -L: only show names of files with no matches */
103 bool	 bflag;		/* -b: show block numbers for each match */
104 bool	 cflag;		/* -c: only show a count of matching lines */
105 bool	 hflag;		/* -h: don't print filename headers */
106 bool	 iflag;		/* -i: ignore case */
107 bool	 lflag;		/* -l: only show names of files with matches */
108 bool	 mflag;		/* -m x: stop reading the files after x matches */
109 long long mcount;	/* count for -m */
110 bool	 nflag;		/* -n: show line numbers in front of matching lines */
111 bool	 oflag;		/* -o: print only matching part */
112 bool	 qflag;		/* -q: quiet mode (don't output anything) */
113 bool	 sflag;		/* -s: silent mode (ignore errors) */
114 bool	 vflag;		/* -v: only show non-matching lines */
115 bool	 wflag;		/* -w: pattern must start and end on word boundaries */
116 bool	 xflag;		/* -x: pattern must match entire line */
117 bool	 lbflag;	/* --line-buffered */
118 bool	 nullflag;	/* --null */
119 char	*label;		/* --label */
120 const char *color;	/* --color */
121 int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
122 int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
123 int	 filebehave = FILE_STDIO;	/* -JZ: normal, gzip or bzip2 file */
124 int	 devbehave = DEV_READ;		/* -D: handling of devices */
125 int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
126 int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
127 
128 bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
129 bool	 fexclude, finclude;	/* --exclude and --include */
130 
131 enum {
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 
145 static inline const char	*init_color(const char *);
146 
147 /* Housekeeping */
148 bool	 first = true;	/* flag whether we are processing the first match */
149 bool	 prev;		/* flag whether or not the previous line matched */
150 int	 tail;		/* lines left to print */
151 bool	 file_err;	/* file reading error */
152 
153 /*
154  * Prints usage information and returns 2.
155  */
156 static void
157 usage(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 
166 static const char	*optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy";
167 
168 static const struct 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  */
223 static void
224 add_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  */
262 static void
263 add_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  */
280 static void
281 add_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  */
298 static void
299 read_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 
319 static inline const char *
320 init_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 
328 int
329 main(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