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