xref: /freebsd/usr.bin/grep/grep.c (revision a2584d1b)
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 ((f = fopen(fn, "r")) == NULL)
311 		err(2, "%s", fn);
312 	if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
313 		fclose(f);
314 		return;
315 	}
316 	len = 0;
317 	line = NULL;
318 	while ((rlen = getline(&line, &len, f)) != -1) {
319 		if (line[0] == '\0')
320 			continue;
321 		add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
322 	}
323 
324 	free(line);
325 	if (ferror(f))
326 		err(2, "%s", fn);
327 	fclose(f);
328 }
329 
330 static inline const char *
331 init_color(const char *d)
332 {
333 	char *c;
334 
335 	c = getenv("GREP_COLOR");
336 	return (c != NULL && c[0] != '\0' ? c : d);
337 }
338 
339 int
340 main(int argc, char *argv[])
341 {
342 	char **aargv, **eargv, *eopts;
343 	char *ep;
344 	const char *pn;
345 	long long l;
346 	unsigned int aargc, eargc, i;
347 	int c, lastc, needpattern, newarg, prevoptind;
348 
349 	setlocale(LC_ALL, "");
350 
351 #ifndef WITHOUT_NLS
352 	catalog = catopen("grep", NL_CAT_LOCALE);
353 #endif
354 
355 	/* Check what is the program name of the binary.  In this
356 	   way we can have all the funcionalities in one binary
357 	   without the need of scripting and using ugly hacks. */
358 	pn = getprogname();
359 	if (pn[0] == 'r') {
360 		dirbehave = DIR_RECURSE;
361 		Hflag = true;
362 	}
363 	switch (pn[0]) {
364 	case 'e':
365 		grepbehave = GREP_EXTENDED;
366 		break;
367 	case 'f':
368 		grepbehave = GREP_FIXED;
369 		break;
370 	}
371 
372 	lastc = '\0';
373 	newarg = 1;
374 	prevoptind = 1;
375 	needpattern = 1;
376 	fileeol = '\n';
377 
378 	eopts = getenv("GREP_OPTIONS");
379 
380 	/* support for extra arguments in GREP_OPTIONS */
381 	eargc = 0;
382 	if (eopts != NULL && eopts[0] != '\0') {
383 		char *str;
384 
385 		/* make an estimation of how many extra arguments we have */
386 		for (unsigned int j = 0; j < strlen(eopts); j++)
387 			if (eopts[j] == ' ')
388 				eargc++;
389 
390 		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
391 
392 		eargc = 0;
393 		/* parse extra arguments */
394 		while ((str = strsep(&eopts, " ")) != NULL)
395 			if (str[0] != '\0')
396 				eargv[eargc++] = grep_strdup(str);
397 
398 		aargv = (char **)grep_calloc(eargc + argc + 1,
399 		    sizeof(char *));
400 
401 		aargv[0] = argv[0];
402 		for (i = 0; i < eargc; i++)
403 			aargv[i + 1] = eargv[i];
404 		for (int j = 1; j < argc; j++, i++)
405 			aargv[i + 1] = argv[j];
406 
407 		aargc = eargc + argc;
408 	} else {
409 		aargv = argv;
410 		aargc = argc;
411 	}
412 
413 	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
414 	    -1)) {
415 		switch (c) {
416 		case '0': case '1': case '2': case '3': case '4':
417 		case '5': case '6': case '7': case '8': case '9':
418 			if (newarg || !isdigit(lastc))
419 				Aflag = 0;
420 			else if (Aflag > LLONG_MAX / 10 - 1) {
421 				errno = ERANGE;
422 				err(2, NULL);
423 			}
424 
425 			Aflag = Bflag = (Aflag * 10) + (c - '0');
426 			break;
427 		case 'C':
428 			if (optarg == NULL) {
429 				Aflag = Bflag = 2;
430 				break;
431 			}
432 			/* FALLTHROUGH */
433 		case 'A':
434 			/* FALLTHROUGH */
435 		case 'B':
436 			errno = 0;
437 			l = strtoll(optarg, &ep, 10);
438 			if (errno == ERANGE || errno == EINVAL)
439 				err(2, NULL);
440 			else if (ep[0] != '\0') {
441 				errno = EINVAL;
442 				err(2, NULL);
443 			} else if (l < 0) {
444 				errno = EINVAL;
445 				err(2, "context argument must be non-negative");
446 			}
447 
448 			if (c == 'A')
449 				Aflag = l;
450 			else if (c == 'B')
451 				Bflag = l;
452 			else
453 				Aflag = Bflag = l;
454 			break;
455 		case 'a':
456 			binbehave = BINFILE_TEXT;
457 			break;
458 		case 'b':
459 			bflag = true;
460 			break;
461 		case 'c':
462 			cflag = true;
463 			break;
464 		case 'D':
465 			if (strcasecmp(optarg, "skip") == 0)
466 				devbehave = DEV_SKIP;
467 			else if (strcasecmp(optarg, "read") == 0)
468 				devbehave = DEV_READ;
469 			else
470 				errx(2, getstr(2), "--devices");
471 			break;
472 		case 'd':
473 			if (strcasecmp("recurse", optarg) == 0) {
474 				Hflag = true;
475 				dirbehave = DIR_RECURSE;
476 			} else if (strcasecmp("skip", optarg) == 0)
477 				dirbehave = DIR_SKIP;
478 			else if (strcasecmp("read", optarg) == 0)
479 				dirbehave = DIR_READ;
480 			else
481 				errx(2, getstr(2), "--directories");
482 			break;
483 		case 'E':
484 			grepbehave = GREP_EXTENDED;
485 			break;
486 		case 'e':
487 			{
488 				char *token;
489 				char *string = optarg;
490 
491 				while ((token = strsep(&string, "\n")) != NULL)
492 					add_pattern(token, strlen(token));
493 			}
494 			needpattern = 0;
495 			break;
496 		case 'F':
497 			grepbehave = GREP_FIXED;
498 			break;
499 		case 'f':
500 			read_patterns(optarg);
501 			needpattern = 0;
502 			break;
503 		case 'G':
504 			grepbehave = GREP_BASIC;
505 			break;
506 		case 'H':
507 			Hflag = true;
508 			break;
509 		case 'h':
510 			Hflag = false;
511 			hflag = true;
512 			break;
513 		case 'I':
514 			binbehave = BINFILE_SKIP;
515 			break;
516 		case 'i':
517 		case 'y':
518 			iflag =  true;
519 			cflags |= REG_ICASE;
520 			break;
521 		case 'L':
522 			lflag = false;
523 			Lflag = true;
524 			break;
525 		case 'l':
526 			Lflag = false;
527 			lflag = true;
528 			break;
529 		case 'm':
530 			mflag = true;
531 			errno = 0;
532 			mlimit = mcount = strtoll(optarg, &ep, 10);
533 			if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
534 			    ((errno == EINVAL) && (mcount == 0)))
535 				err(2, NULL);
536 			else if (ep[0] != '\0') {
537 				errno = EINVAL;
538 				err(2, NULL);
539 			}
540 			break;
541 		case 'n':
542 			nflag = true;
543 			break;
544 		case 'O':
545 			linkbehave = LINK_EXPLICIT;
546 			break;
547 		case 'o':
548 			oflag = true;
549 			cflags &= ~REG_NOSUB;
550 			break;
551 		case 'p':
552 			linkbehave = LINK_SKIP;
553 			break;
554 		case 'q':
555 			qflag = true;
556 			break;
557 		case 'S':
558 			linkbehave = LINK_READ;
559 			break;
560 		case 'R':
561 		case 'r':
562 			dirbehave = DIR_RECURSE;
563 			Hflag = true;
564 			break;
565 		case 's':
566 			sflag = true;
567 			break;
568 		case 'U':
569 			binbehave = BINFILE_BIN;
570 			break;
571 		case 'u':
572 		case MMAP_OPT:
573 			filebehave = FILE_MMAP;
574 			break;
575 		case 'V':
576 #ifdef WITH_GNU
577 			printf(getstr(9), getprogname(), VERSION);
578 #else
579 			printf(getstr(8), getprogname(), VERSION);
580 #endif
581 			exit(0);
582 		case 'v':
583 			vflag = true;
584 			break;
585 		case 'w':
586 			wflag = true;
587 			cflags &= ~REG_NOSUB;
588 			break;
589 		case 'x':
590 			xflag = true;
591 			cflags &= ~REG_NOSUB;
592 			break;
593 		case 'z':
594 			fileeol = '\0';
595 			break;
596 		case BIN_OPT:
597 			if (strcasecmp("binary", optarg) == 0)
598 				binbehave = BINFILE_BIN;
599 			else if (strcasecmp("without-match", optarg) == 0)
600 				binbehave = BINFILE_SKIP;
601 			else if (strcasecmp("text", optarg) == 0)
602 				binbehave = BINFILE_TEXT;
603 			else
604 				errx(2, getstr(2), "--binary-files");
605 			break;
606 		case COLOR_OPT:
607 			color = NULL;
608 			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
609 			    strcasecmp("tty", optarg) == 0 ||
610 			    strcasecmp("if-tty", optarg) == 0) {
611 				char *term;
612 
613 				term = getenv("TERM");
614 				if (isatty(STDOUT_FILENO) && term != NULL &&
615 				    strcasecmp(term, "dumb") != 0)
616 					color = init_color("01;31");
617 			} else if (strcasecmp("always", optarg) == 0 ||
618 			    strcasecmp("yes", optarg) == 0 ||
619 			    strcasecmp("force", optarg) == 0) {
620 				color = init_color("01;31");
621 			} else if (strcasecmp("never", optarg) != 0 &&
622 			    strcasecmp("none", optarg) != 0 &&
623 			    strcasecmp("no", optarg) != 0)
624 				errx(2, getstr(2), "--color");
625 			cflags &= ~REG_NOSUB;
626 			break;
627 		case LABEL_OPT:
628 			label = optarg;
629 			break;
630 		case LINEBUF_OPT:
631 			lbflag = true;
632 			break;
633 		case NULL_OPT:
634 			nullflag = true;
635 			break;
636 		case R_INCLUDE_OPT:
637 			finclude = true;
638 			add_fpattern(optarg, INCL_PAT);
639 			break;
640 		case R_EXCLUDE_OPT:
641 			fexclude = true;
642 			add_fpattern(optarg, EXCL_PAT);
643 			break;
644 		case R_DINCLUDE_OPT:
645 			dinclude = true;
646 			add_dpattern(optarg, INCL_PAT);
647 			break;
648 		case R_DEXCLUDE_OPT:
649 			dexclude = true;
650 			add_dpattern(optarg, EXCL_PAT);
651 			break;
652 		case HELP_OPT:
653 		default:
654 			usage();
655 		}
656 		lastc = c;
657 		newarg = optind != prevoptind;
658 		prevoptind = optind;
659 	}
660 	aargc -= optind;
661 	aargv += optind;
662 
663 	/* Empty pattern file matches nothing */
664 	if (!needpattern && (patterns == 0))
665 		exit(1);
666 
667 	/* Fail if we don't have any pattern */
668 	if (aargc == 0 && needpattern)
669 		usage();
670 
671 	/* Process patterns from command line */
672 	if (aargc != 0 && needpattern) {
673 		char *token;
674 		char *string = *aargv;
675 
676 		while ((token = strsep(&string, "\n")) != NULL)
677 			add_pattern(token, strlen(token));
678 		--aargc;
679 		++aargv;
680 	}
681 
682 	switch (grepbehave) {
683 	case GREP_BASIC:
684 		break;
685 	case GREP_FIXED:
686 		/*
687 		 * regex(3) implementations that support fixed-string searches generally
688 		 * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
689 		 * here. If neither are defined, GREP_FIXED later implies that the
690 		 * internal literal matcher should be used. Other cflags that have
691 		 * the same interpretation as REG_NOSPEC and REG_LITERAL should be
692 		 * similarly added here, and grep.h should be amended to take this into
693 		 * consideration when defining WITH_INTERNAL_NOSPEC.
694 		 */
695 #if defined(REG_NOSPEC)
696 		cflags |= REG_NOSPEC;
697 #elif defined(REG_LITERAL)
698 		cflags |= REG_LITERAL;
699 #endif
700 		break;
701 	case GREP_EXTENDED:
702 		cflags |= REG_EXTENDED;
703 		break;
704 	default:
705 		/* NOTREACHED */
706 		usage();
707 	}
708 
709 	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
710 
711 	/* Don't process any patterns if we have a blank one */
712 #ifdef WITH_INTERNAL_NOSPEC
713 	if (!matchall && grepbehave != GREP_FIXED) {
714 #else
715 	if (!matchall) {
716 #endif
717 		/* Check if cheating is allowed (always is for fgrep). */
718 		for (i = 0; i < patterns; ++i) {
719 			c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
720 			if (c != 0) {
721 				regerror(c, &r_pattern[i], re_error,
722 				    RE_ERROR_BUF);
723 				errx(2, "%s", re_error);
724 			}
725 		}
726 	}
727 
728 	if (lbflag)
729 		setlinebuf(stdout);
730 
731 	if ((aargc == 0 || aargc == 1) && !Hflag)
732 		hflag = true;
733 
734 	if (aargc == 0 && dirbehave != DIR_RECURSE)
735 		exit(!procfile("-"));
736 
737 	if (dirbehave == DIR_RECURSE)
738 		c = grep_tree(aargv);
739 	else
740 		for (c = 0; aargc--; ++aargv) {
741 			if ((finclude || fexclude) && !file_matching(*aargv))
742 				continue;
743 			c+= procfile(*aargv);
744 		}
745 
746 #ifndef WITHOUT_NLS
747 	catclose(catalog);
748 #endif
749 
750 	/* Find out the correct return value according to the
751 	   results and the command line option. */
752 	exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
753 }
754