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