xref: /freebsd/usr.bin/grep/grep.c (revision b66a823be88d3f3dab30b6beb083a3ef994cbe15)
1*b66a823bSGabor Kovesdan /*	$NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 joerg Exp $	*/
2*b66a823bSGabor Kovesdan /* 	$FreeBSD$	*/
34dc88ebeSGabor Kovesdan /*	$OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $	*/
44dc88ebeSGabor Kovesdan 
54dc88ebeSGabor Kovesdan /*-
6a0ef9ad6SDag-Erling Smørgrav  * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
74dc88ebeSGabor Kovesdan  * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
84dc88ebeSGabor Kovesdan  * All rights reserved.
94dc88ebeSGabor Kovesdan  *
104dc88ebeSGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
114dc88ebeSGabor Kovesdan  * modification, are permitted provided that the following conditions
124dc88ebeSGabor Kovesdan  * are met:
134dc88ebeSGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
144dc88ebeSGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
154dc88ebeSGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
164dc88ebeSGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
174dc88ebeSGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
184dc88ebeSGabor Kovesdan  *
194dc88ebeSGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
204dc88ebeSGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214dc88ebeSGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224dc88ebeSGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
234dc88ebeSGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244dc88ebeSGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254dc88ebeSGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264dc88ebeSGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274dc88ebeSGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284dc88ebeSGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294dc88ebeSGabor Kovesdan  * SUCH DAMAGE.
304dc88ebeSGabor Kovesdan  */
314dc88ebeSGabor Kovesdan 
324dc88ebeSGabor Kovesdan #include <sys/cdefs.h>
334dc88ebeSGabor Kovesdan __FBSDID("$FreeBSD$");
344dc88ebeSGabor Kovesdan 
354dc88ebeSGabor Kovesdan #include <sys/stat.h>
364dc88ebeSGabor Kovesdan #include <sys/types.h>
374dc88ebeSGabor Kovesdan 
384dc88ebeSGabor Kovesdan #include <ctype.h>
394dc88ebeSGabor Kovesdan #include <err.h>
404dc88ebeSGabor Kovesdan #include <errno.h>
414dc88ebeSGabor Kovesdan #include <getopt.h>
424dc88ebeSGabor Kovesdan #include <limits.h>
434dc88ebeSGabor Kovesdan #include <libgen.h>
444dc88ebeSGabor Kovesdan #include <locale.h>
454dc88ebeSGabor Kovesdan #include <stdbool.h>
464dc88ebeSGabor Kovesdan #include <stdio.h>
474dc88ebeSGabor Kovesdan #include <stdlib.h>
484dc88ebeSGabor Kovesdan #include <string.h>
494dc88ebeSGabor Kovesdan #include <unistd.h>
504dc88ebeSGabor Kovesdan 
514dc88ebeSGabor Kovesdan #include "grep.h"
524dc88ebeSGabor Kovesdan 
534dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS
544dc88ebeSGabor Kovesdan #include <nl_types.h>
554dc88ebeSGabor Kovesdan nl_catd	 catalog;
564dc88ebeSGabor Kovesdan #endif
574dc88ebeSGabor Kovesdan 
584dc88ebeSGabor Kovesdan /*
594dc88ebeSGabor Kovesdan  * Default messags to use when NLS is disabled or no catalogue
604dc88ebeSGabor Kovesdan  * is found.
614dc88ebeSGabor Kovesdan  */
624dc88ebeSGabor Kovesdan const char	*errstr[] = {
634dc88ebeSGabor Kovesdan 	"",
644dc88ebeSGabor Kovesdan /* 1*/	"(standard input)",
654dc88ebeSGabor Kovesdan /* 2*/	"cannot read bzip2 compressed file",
6697a012f2SGabor Kovesdan /* 3*/	"unknown %s option",
674dc88ebeSGabor Kovesdan /* 4*/	"usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n",
684dc88ebeSGabor Kovesdan /* 5*/	"\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
694dc88ebeSGabor Kovesdan /* 6*/	"\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
704dc88ebeSGabor Kovesdan /* 7*/	"\t[--null] [pattern] [file ...]\n",
7197a012f2SGabor Kovesdan /* 8*/	"Binary file %s matches\n",
7297a012f2SGabor Kovesdan /* 9*/	"%s (BSD grep) %s\n",
734dc88ebeSGabor Kovesdan };
744dc88ebeSGabor Kovesdan 
754dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */
764dc88ebeSGabor Kovesdan int		 cflags = 0;
774dc88ebeSGabor Kovesdan int		 eflags = REG_STARTEND;
784dc88ebeSGabor Kovesdan 
794dc88ebeSGabor Kovesdan /* Shortcut for matching all cases like empty regex */
804dc88ebeSGabor Kovesdan bool		 matchall;
814dc88ebeSGabor Kovesdan 
824dc88ebeSGabor Kovesdan /* Searching patterns */
834dc88ebeSGabor Kovesdan unsigned int	 patterns, pattern_sz;
844dc88ebeSGabor Kovesdan char		**pattern;
854dc88ebeSGabor Kovesdan regex_t		*r_pattern;
864dc88ebeSGabor Kovesdan fastgrep_t	*fg_pattern;
874dc88ebeSGabor Kovesdan 
884dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */
8955e44f51SGabor Kovesdan unsigned int	 fpatterns, fpattern_sz;
9055e44f51SGabor Kovesdan unsigned int	 dpatterns, dpattern_sz;
9155e44f51SGabor Kovesdan struct epat	*dpattern, *fpattern;
924dc88ebeSGabor Kovesdan 
934dc88ebeSGabor Kovesdan /* For regex errors  */
944dc88ebeSGabor Kovesdan char	 re_error[RE_ERROR_BUF + 1];
954dc88ebeSGabor Kovesdan 
964dc88ebeSGabor Kovesdan /* Command-line flags */
974dc88ebeSGabor Kovesdan unsigned long long Aflag;	/* -A x: print x lines trailing each match */
984dc88ebeSGabor Kovesdan unsigned long long Bflag;	/* -B x: print x lines leading each match */
994dc88ebeSGabor Kovesdan bool	 Hflag;		/* -H: always print file name */
1004dc88ebeSGabor Kovesdan bool	 Lflag;		/* -L: only show names of files with no matches */
1014dc88ebeSGabor Kovesdan bool	 bflag;		/* -b: show block numbers for each match */
1024dc88ebeSGabor Kovesdan bool	 cflag;		/* -c: only show a count of matching lines */
1034dc88ebeSGabor Kovesdan bool	 hflag;		/* -h: don't print filename headers */
1044dc88ebeSGabor Kovesdan bool	 iflag;		/* -i: ignore case */
1054dc88ebeSGabor Kovesdan bool	 lflag;		/* -l: only show names of files with matches */
1064dc88ebeSGabor Kovesdan bool	 mflag;		/* -m x: stop reading the files after x matches */
1074dc88ebeSGabor Kovesdan unsigned long long mcount;	/* count for -m */
1084dc88ebeSGabor Kovesdan bool	 nflag;		/* -n: show line numbers in front of matching lines */
1094dc88ebeSGabor Kovesdan bool	 oflag;		/* -o: print only matching part */
1104dc88ebeSGabor Kovesdan bool	 qflag;		/* -q: quiet mode (don't output anything) */
1114dc88ebeSGabor Kovesdan bool	 sflag;		/* -s: silent mode (ignore errors) */
1124dc88ebeSGabor Kovesdan bool	 vflag;		/* -v: only show non-matching lines */
1134dc88ebeSGabor Kovesdan bool	 wflag;		/* -w: pattern must start and end on word boundaries */
1144dc88ebeSGabor Kovesdan bool	 xflag;		/* -x: pattern must match entire line */
1154dc88ebeSGabor Kovesdan bool	 lbflag;	/* --line-buffered */
1164dc88ebeSGabor Kovesdan bool	 nullflag;	/* --null */
1174dc88ebeSGabor Kovesdan char	*label;		/* --label */
11827116286SGabor Kovesdan const char *color;	/* --color */
1194dc88ebeSGabor Kovesdan int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
1204dc88ebeSGabor Kovesdan int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
1214dc88ebeSGabor Kovesdan int	 filebehave = FILE_STDIO;	/* -JZ: normal, gzip or bzip2 file */
12227116286SGabor Kovesdan int	 devbehave = DEV_READ;		/* -D: handling of devices */
12327116286SGabor Kovesdan int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
12427116286SGabor Kovesdan int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
1254dc88ebeSGabor Kovesdan 
12659218eb7SGabor Kovesdan bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
12759218eb7SGabor Kovesdan bool	 fexclude, finclude;	/* --exclude and --include */
12855e44f51SGabor Kovesdan 
1294dc88ebeSGabor Kovesdan enum {
1304dc88ebeSGabor Kovesdan 	BIN_OPT = CHAR_MAX + 1,
1314dc88ebeSGabor Kovesdan 	COLOR_OPT,
1324dc88ebeSGabor Kovesdan 	HELP_OPT,
1334dc88ebeSGabor Kovesdan 	MMAP_OPT,
1344dc88ebeSGabor Kovesdan 	LINEBUF_OPT,
1354dc88ebeSGabor Kovesdan 	LABEL_OPT,
1364dc88ebeSGabor Kovesdan 	NULL_OPT,
1374dc88ebeSGabor Kovesdan 	R_EXCLUDE_OPT,
1384dc88ebeSGabor Kovesdan 	R_INCLUDE_OPT,
1394dc88ebeSGabor Kovesdan 	R_DEXCLUDE_OPT,
1404dc88ebeSGabor Kovesdan 	R_DINCLUDE_OPT
1414dc88ebeSGabor Kovesdan };
1424dc88ebeSGabor Kovesdan 
14327116286SGabor Kovesdan static inline const char	*init_color(const char *);
14427116286SGabor Kovesdan 
1454dc88ebeSGabor Kovesdan /* Housekeeping */
1464dc88ebeSGabor Kovesdan bool	 first = true;	/* flag whether we are processing the first match */
1474dc88ebeSGabor Kovesdan bool	 prev;		/* flag whether or not the previous line matched */
1484dc88ebeSGabor Kovesdan int	 tail;		/* lines left to print */
1494dc88ebeSGabor Kovesdan bool	 notfound;	/* file not found */
1504dc88ebeSGabor Kovesdan 
1514dc88ebeSGabor Kovesdan extern char	*__progname;
1524dc88ebeSGabor Kovesdan 
1534dc88ebeSGabor Kovesdan /*
1544dc88ebeSGabor Kovesdan  * Prints usage information and returns 2.
1554dc88ebeSGabor Kovesdan  */
1564dc88ebeSGabor Kovesdan static void
1574dc88ebeSGabor Kovesdan usage(void)
1584dc88ebeSGabor Kovesdan {
1594dc88ebeSGabor Kovesdan 	fprintf(stderr, getstr(4), __progname);
1604dc88ebeSGabor Kovesdan 	fprintf(stderr, "%s", getstr(5));
1614dc88ebeSGabor Kovesdan 	fprintf(stderr, "%s", getstr(5));
1624dc88ebeSGabor Kovesdan 	fprintf(stderr, "%s", getstr(6));
1634dc88ebeSGabor Kovesdan 	fprintf(stderr, "%s", getstr(7));
1644dc88ebeSGabor Kovesdan 	exit(2);
1654dc88ebeSGabor Kovesdan }
1664dc88ebeSGabor Kovesdan 
1674dc88ebeSGabor Kovesdan static const char	*optstr = "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxy";
1684dc88ebeSGabor Kovesdan 
1694dc88ebeSGabor Kovesdan struct option long_options[] =
1704dc88ebeSGabor Kovesdan {
1714dc88ebeSGabor Kovesdan 	{"binary-files",	required_argument,	NULL, BIN_OPT},
1724dc88ebeSGabor Kovesdan 	{"help",		no_argument,		NULL, HELP_OPT},
1734dc88ebeSGabor Kovesdan 	{"mmap",		no_argument,		NULL, MMAP_OPT},
1744dc88ebeSGabor Kovesdan 	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
1754dc88ebeSGabor Kovesdan 	{"label",		required_argument,	NULL, LABEL_OPT},
1764dc88ebeSGabor Kovesdan 	{"null",		no_argument,		NULL, NULL_OPT},
1774dc88ebeSGabor Kovesdan 	{"color",		optional_argument,	NULL, COLOR_OPT},
1784dc88ebeSGabor Kovesdan 	{"colour",		optional_argument,	NULL, COLOR_OPT},
1794dc88ebeSGabor Kovesdan 	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
1804dc88ebeSGabor Kovesdan 	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
1814dc88ebeSGabor Kovesdan 	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
1824dc88ebeSGabor Kovesdan 	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
1834dc88ebeSGabor Kovesdan 	{"after-context",	required_argument,	NULL, 'A'},
1844dc88ebeSGabor Kovesdan 	{"text",		no_argument,		NULL, 'a'},
1854dc88ebeSGabor Kovesdan 	{"before-context",	required_argument,	NULL, 'B'},
1864dc88ebeSGabor Kovesdan 	{"byte-offset",		no_argument,		NULL, 'b'},
1874dc88ebeSGabor Kovesdan 	{"context",		optional_argument,	NULL, 'C'},
1884dc88ebeSGabor Kovesdan 	{"count",		no_argument,		NULL, 'c'},
1894dc88ebeSGabor Kovesdan 	{"devices",		required_argument,	NULL, 'D'},
1904dc88ebeSGabor Kovesdan         {"directories",		required_argument,	NULL, 'd'},
1914dc88ebeSGabor Kovesdan 	{"extended-regexp",	no_argument,		NULL, 'E'},
1924dc88ebeSGabor Kovesdan 	{"regexp",		required_argument,	NULL, 'e'},
1934dc88ebeSGabor Kovesdan 	{"fixed-strings",	no_argument,		NULL, 'F'},
1944dc88ebeSGabor Kovesdan 	{"file",		required_argument,	NULL, 'f'},
1954dc88ebeSGabor Kovesdan 	{"basic-regexp",	no_argument,		NULL, 'G'},
1964dc88ebeSGabor Kovesdan 	{"no-filename",		no_argument,		NULL, 'h'},
1974dc88ebeSGabor Kovesdan 	{"with-filename",	no_argument,		NULL, 'H'},
1984dc88ebeSGabor Kovesdan 	{"ignore-case",		no_argument,		NULL, 'i'},
1994dc88ebeSGabor Kovesdan 	{"bz2decompress",	no_argument,		NULL, 'J'},
2004dc88ebeSGabor Kovesdan 	{"files-with-matches",	no_argument,		NULL, 'l'},
2014dc88ebeSGabor Kovesdan 	{"files-without-match", no_argument,            NULL, 'L'},
2024dc88ebeSGabor Kovesdan 	{"max-count",		required_argument,	NULL, 'm'},
2034dc88ebeSGabor Kovesdan 	{"line-number",		no_argument,		NULL, 'n'},
2044dc88ebeSGabor Kovesdan 	{"only-matching",	no_argument,		NULL, 'o'},
2054dc88ebeSGabor Kovesdan 	{"quiet",		no_argument,		NULL, 'q'},
2064dc88ebeSGabor Kovesdan 	{"silent",		no_argument,		NULL, 'q'},
2074dc88ebeSGabor Kovesdan 	{"recursive",		no_argument,		NULL, 'r'},
2084dc88ebeSGabor Kovesdan 	{"no-messages",		no_argument,		NULL, 's'},
2094dc88ebeSGabor Kovesdan 	{"binary",		no_argument,		NULL, 'U'},
2104dc88ebeSGabor Kovesdan 	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
2114dc88ebeSGabor Kovesdan 	{"invert-match",	no_argument,		NULL, 'v'},
2124dc88ebeSGabor Kovesdan 	{"version",		no_argument,		NULL, 'V'},
2134dc88ebeSGabor Kovesdan 	{"word-regexp",		no_argument,		NULL, 'w'},
2144dc88ebeSGabor Kovesdan 	{"line-regexp",		no_argument,		NULL, 'x'},
2154dc88ebeSGabor Kovesdan 	{"decompress",          no_argument,            NULL, 'Z'},
2164dc88ebeSGabor Kovesdan 	{NULL,			no_argument,		NULL, 0}
2174dc88ebeSGabor Kovesdan };
2184dc88ebeSGabor Kovesdan 
2194dc88ebeSGabor Kovesdan /*
2204dc88ebeSGabor Kovesdan  * Adds a searching pattern to the internal array.
2214dc88ebeSGabor Kovesdan  */
2224dc88ebeSGabor Kovesdan static void
2234dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len)
2244dc88ebeSGabor Kovesdan {
2254dc88ebeSGabor Kovesdan 
2264dc88ebeSGabor Kovesdan 	/* Check if we can do a shortcut */
2274dc88ebeSGabor Kovesdan 	if (len == 0 || matchall) {
2284dc88ebeSGabor Kovesdan 		matchall = true;
2294dc88ebeSGabor Kovesdan 		return;
2304dc88ebeSGabor Kovesdan 	}
2314dc88ebeSGabor Kovesdan 	/* Increase size if necessary */
2324dc88ebeSGabor Kovesdan 	if (patterns == pattern_sz) {
2334dc88ebeSGabor Kovesdan 		pattern_sz *= 2;
2344dc88ebeSGabor Kovesdan 		pattern = grep_realloc(pattern, ++pattern_sz *
2354dc88ebeSGabor Kovesdan 		    sizeof(*pattern));
2364dc88ebeSGabor Kovesdan 	}
2374dc88ebeSGabor Kovesdan 	if (len > 0 && pat[len - 1] == '\n')
2384dc88ebeSGabor Kovesdan 		--len;
2394dc88ebeSGabor Kovesdan 	/* pat may not be NUL-terminated */
2404dc88ebeSGabor Kovesdan 	pattern[patterns] = grep_malloc(len + 1);
24159218eb7SGabor Kovesdan 	memcpy(pattern[patterns], pat, len);
24259218eb7SGabor Kovesdan 	pattern[patterns][len] = '\0';
2434dc88ebeSGabor Kovesdan 	++patterns;
2444dc88ebeSGabor Kovesdan }
2454dc88ebeSGabor Kovesdan 
2464dc88ebeSGabor Kovesdan /*
24755e44f51SGabor Kovesdan  * Adds a file include/exclude pattern to the internal array.
2484dc88ebeSGabor Kovesdan  */
2494dc88ebeSGabor Kovesdan static void
25055e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode)
2514dc88ebeSGabor Kovesdan {
2524dc88ebeSGabor Kovesdan 
2534dc88ebeSGabor Kovesdan 	/* Increase size if necessary */
25455e44f51SGabor Kovesdan 	if (fpatterns == fpattern_sz) {
25555e44f51SGabor Kovesdan 		fpattern_sz *= 2;
25655e44f51SGabor Kovesdan 		fpattern = grep_realloc(fpattern, ++fpattern_sz *
2574dc88ebeSGabor Kovesdan 		    sizeof(struct epat));
2584dc88ebeSGabor Kovesdan 	}
25955e44f51SGabor Kovesdan 	fpattern[fpatterns].pat = grep_strdup(pat);
26055e44f51SGabor Kovesdan 	fpattern[fpatterns].mode = mode;
26155e44f51SGabor Kovesdan 	++fpatterns;
26255e44f51SGabor Kovesdan }
26355e44f51SGabor Kovesdan 
26455e44f51SGabor Kovesdan /*
26555e44f51SGabor Kovesdan  * Adds a directory include/exclude pattern to the internal array.
26655e44f51SGabor Kovesdan  */
26755e44f51SGabor Kovesdan static void
26855e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode)
26955e44f51SGabor Kovesdan {
27055e44f51SGabor Kovesdan 
27155e44f51SGabor Kovesdan 	/* Increase size if necessary */
27255e44f51SGabor Kovesdan 	if (dpatterns == dpattern_sz) {
27355e44f51SGabor Kovesdan 		dpattern_sz *= 2;
27455e44f51SGabor Kovesdan 		dpattern = grep_realloc(dpattern, ++dpattern_sz *
27555e44f51SGabor Kovesdan 		    sizeof(struct epat));
27655e44f51SGabor Kovesdan 	}
27755e44f51SGabor Kovesdan 	dpattern[dpatterns].pat = grep_strdup(pat);
27855e44f51SGabor Kovesdan 	dpattern[dpatterns].mode = mode;
27955e44f51SGabor Kovesdan 	++dpatterns;
2804dc88ebeSGabor Kovesdan }
2814dc88ebeSGabor Kovesdan 
2824dc88ebeSGabor Kovesdan /*
2834dc88ebeSGabor Kovesdan  * Reads searching patterns from a file and adds them with add_pattern().
2844dc88ebeSGabor Kovesdan  */
2854dc88ebeSGabor Kovesdan static void
2864dc88ebeSGabor Kovesdan read_patterns(const char *fn)
2874dc88ebeSGabor Kovesdan {
2884dc88ebeSGabor Kovesdan 	FILE *f;
2894dc88ebeSGabor Kovesdan 	char *line;
2904dc88ebeSGabor Kovesdan 	size_t len;
2914dc88ebeSGabor Kovesdan 
2924dc88ebeSGabor Kovesdan 	if ((f = fopen(fn, "r")) == NULL)
2934dc88ebeSGabor Kovesdan 		err(2, "%s", fn);
2944dc88ebeSGabor Kovesdan 	while ((line = fgetln(f, &len)) != NULL)
2954dc88ebeSGabor Kovesdan 		add_pattern(line, *line == '\n' ? 0 : len);
2964dc88ebeSGabor Kovesdan 	if (ferror(f))
2974dc88ebeSGabor Kovesdan 		err(2, "%s", fn);
2984dc88ebeSGabor Kovesdan 	fclose(f);
2994dc88ebeSGabor Kovesdan }
3004dc88ebeSGabor Kovesdan 
30127116286SGabor Kovesdan static inline const char *
30227116286SGabor Kovesdan init_color(const char *d)
30327116286SGabor Kovesdan {
30427116286SGabor Kovesdan 	char *c;
30527116286SGabor Kovesdan 
30627116286SGabor Kovesdan 	c = getenv("GREP_COLOR");
30727116286SGabor Kovesdan 	return (c != NULL ? c : d);
30827116286SGabor Kovesdan }
30927116286SGabor Kovesdan 
3104dc88ebeSGabor Kovesdan int
3114dc88ebeSGabor Kovesdan main(int argc, char *argv[])
3124dc88ebeSGabor Kovesdan {
3134dc88ebeSGabor Kovesdan 	char **aargv, **eargv, *eopts;
3144dc88ebeSGabor Kovesdan 	char *ep;
3154dc88ebeSGabor Kovesdan 	unsigned long long l;
3164dc88ebeSGabor Kovesdan 	unsigned int aargc, eargc, i;
3174dc88ebeSGabor Kovesdan 	int c, lastc, needpattern, newarg, prevoptind;
3184dc88ebeSGabor Kovesdan 
3194dc88ebeSGabor Kovesdan 	setlocale(LC_ALL, "");
3204dc88ebeSGabor Kovesdan 
3214dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS
3224dc88ebeSGabor Kovesdan 	catalog = catopen("grep", NL_CAT_LOCALE);
3234dc88ebeSGabor Kovesdan #endif
3244dc88ebeSGabor Kovesdan 
3254dc88ebeSGabor Kovesdan 	/* Check what is the program name of the binary.  In this
3264dc88ebeSGabor Kovesdan 	   way we can have all the funcionalities in one binary
3274dc88ebeSGabor Kovesdan 	   without the need of scripting and using ugly hacks. */
3284dc88ebeSGabor Kovesdan 	switch (__progname[0]) {
3294dc88ebeSGabor Kovesdan 	case 'e':
3304dc88ebeSGabor Kovesdan 		grepbehave = GREP_EXTENDED;
3314dc88ebeSGabor Kovesdan 		break;
3324dc88ebeSGabor Kovesdan 	case 'f':
3334dc88ebeSGabor Kovesdan 		grepbehave = GREP_FIXED;
3344dc88ebeSGabor Kovesdan 		break;
3354dc88ebeSGabor Kovesdan 	case 'g':
3364dc88ebeSGabor Kovesdan 		grepbehave = GREP_BASIC;
3374dc88ebeSGabor Kovesdan 		break;
3384dc88ebeSGabor Kovesdan 	case 'z':
3394dc88ebeSGabor Kovesdan 		filebehave = FILE_GZIP;
3404dc88ebeSGabor Kovesdan 		switch(__progname[1]) {
3414dc88ebeSGabor Kovesdan 		case 'e':
3424dc88ebeSGabor Kovesdan 			grepbehave = GREP_EXTENDED;
3434dc88ebeSGabor Kovesdan 			break;
3444dc88ebeSGabor Kovesdan 		case 'f':
3454dc88ebeSGabor Kovesdan 			grepbehave = GREP_FIXED;
3464dc88ebeSGabor Kovesdan 			break;
3474dc88ebeSGabor Kovesdan 		case 'g':
3484dc88ebeSGabor Kovesdan 			grepbehave = GREP_BASIC;
3494dc88ebeSGabor Kovesdan 			break;
3504dc88ebeSGabor Kovesdan 		}
3514dc88ebeSGabor Kovesdan 		break;
3524dc88ebeSGabor Kovesdan 	}
3534dc88ebeSGabor Kovesdan 
3544dc88ebeSGabor Kovesdan 	lastc = '\0';
3554dc88ebeSGabor Kovesdan 	newarg = 1;
3564dc88ebeSGabor Kovesdan 	prevoptind = 1;
3574dc88ebeSGabor Kovesdan 	needpattern = 1;
3584dc88ebeSGabor Kovesdan 
3594dc88ebeSGabor Kovesdan 	eopts = getenv("GREP_OPTIONS");
3604dc88ebeSGabor Kovesdan 
36159218eb7SGabor Kovesdan 	/* support for extra arguments in GREP_OPTIONS */
36259218eb7SGabor Kovesdan 	eargc = 0;
3634dc88ebeSGabor Kovesdan 	if (eopts != NULL) {
3644dc88ebeSGabor Kovesdan 		char *str;
3654dc88ebeSGabor Kovesdan 
36659218eb7SGabor Kovesdan 		/* make an estimation of how many extra arguments we have */
36759218eb7SGabor Kovesdan 		for (unsigned int j = 0; j < strlen(eopts); j++)
36859218eb7SGabor Kovesdan 			if (eopts[j] == ' ')
3694dc88ebeSGabor Kovesdan 				eargc++;
3704dc88ebeSGabor Kovesdan 
3714dc88ebeSGabor Kovesdan 		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
3724dc88ebeSGabor Kovesdan 
3734dc88ebeSGabor Kovesdan 		eargc = 0;
37459218eb7SGabor Kovesdan 		/* parse extra arguments */
37559218eb7SGabor Kovesdan 		while ((str = strsep(&eopts, " ")) != NULL)
37659218eb7SGabor Kovesdan 			eargv[eargc++] = grep_strdup(str);
3774dc88ebeSGabor Kovesdan 
3780c41ffb3SXin LI 		aargv = (char **)grep_calloc(eargc + argc + 1,
3790c41ffb3SXin LI 		    sizeof(char *));
38059218eb7SGabor Kovesdan 
3814dc88ebeSGabor Kovesdan 		aargv[0] = argv[0];
38259218eb7SGabor Kovesdan 		for (i = 0; i < eargc; i++)
38359218eb7SGabor Kovesdan 			aargv[i + 1] = eargv[i];
38459218eb7SGabor Kovesdan 		for (int j = 1; j < argc; j++, i++)
38559218eb7SGabor Kovesdan 			aargv[i + 1] = argv[j];
3864dc88ebeSGabor Kovesdan 
38759218eb7SGabor Kovesdan 		aargc = eargc + argc;
3884dc88ebeSGabor Kovesdan 	} else {
3894dc88ebeSGabor Kovesdan 		aargv = argv;
3904dc88ebeSGabor Kovesdan 		aargc = argc;
3914dc88ebeSGabor Kovesdan 	}
3924dc88ebeSGabor Kovesdan 
3934dc88ebeSGabor Kovesdan 	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
3944dc88ebeSGabor Kovesdan 	    -1)) {
3954dc88ebeSGabor Kovesdan 		switch (c) {
3964dc88ebeSGabor Kovesdan 		case '0': case '1': case '2': case '3': case '4':
3974dc88ebeSGabor Kovesdan 		case '5': case '6': case '7': case '8': case '9':
3984dc88ebeSGabor Kovesdan 			if (newarg || !isdigit(lastc))
3994dc88ebeSGabor Kovesdan 				Aflag = 0;
4004dc88ebeSGabor Kovesdan 			else if (Aflag > LLONG_MAX / 10) {
4014dc88ebeSGabor Kovesdan 				errno = ERANGE;
4024dc88ebeSGabor Kovesdan 				err(2, NULL);
4034dc88ebeSGabor Kovesdan 			}
4044dc88ebeSGabor Kovesdan 			Aflag = Bflag = (Aflag * 10) + (c - '0');
4054dc88ebeSGabor Kovesdan 			break;
4064dc88ebeSGabor Kovesdan 		case 'C':
4074dc88ebeSGabor Kovesdan 			if (optarg == NULL) {
4084dc88ebeSGabor Kovesdan 				Aflag = Bflag = 2;
4094dc88ebeSGabor Kovesdan 				break;
4104dc88ebeSGabor Kovesdan 			}
4114dc88ebeSGabor Kovesdan 			/* FALLTHROUGH */
4124dc88ebeSGabor Kovesdan 		case 'A':
4134dc88ebeSGabor Kovesdan 			/* FALLTHROUGH */
4144dc88ebeSGabor Kovesdan 		case 'B':
4154dc88ebeSGabor Kovesdan 			errno = 0;
4164dc88ebeSGabor Kovesdan 			l = strtoull(optarg, &ep, 10);
4174dc88ebeSGabor Kovesdan 			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
4184dc88ebeSGabor Kovesdan 			    ((errno == EINVAL) && (l == 0)))
4194dc88ebeSGabor Kovesdan 				err(2, NULL);
4204dc88ebeSGabor Kovesdan 			else if (ep[0] != '\0') {
4214dc88ebeSGabor Kovesdan 				errno = EINVAL;
4224dc88ebeSGabor Kovesdan 				err(2, NULL);
4234dc88ebeSGabor Kovesdan 			}
4244dc88ebeSGabor Kovesdan 			if (c == 'A')
4254dc88ebeSGabor Kovesdan 				Aflag = l;
4264dc88ebeSGabor Kovesdan 			else if (c == 'B')
4274dc88ebeSGabor Kovesdan 				Bflag = l;
4284dc88ebeSGabor Kovesdan 			else
4294dc88ebeSGabor Kovesdan 				Aflag = Bflag = l;
4304dc88ebeSGabor Kovesdan 			break;
4314dc88ebeSGabor Kovesdan 		case 'a':
4324dc88ebeSGabor Kovesdan 			binbehave = BINFILE_TEXT;
4334dc88ebeSGabor Kovesdan 			break;
4344dc88ebeSGabor Kovesdan 		case 'b':
4354dc88ebeSGabor Kovesdan 			bflag = true;
4364dc88ebeSGabor Kovesdan 			break;
4374dc88ebeSGabor Kovesdan 		case 'c':
4384dc88ebeSGabor Kovesdan 			cflag = true;
4394dc88ebeSGabor Kovesdan 			break;
4404dc88ebeSGabor Kovesdan 		case 'D':
44127116286SGabor Kovesdan 			if (strcasecmp(optarg, "skip") == 0)
4424dc88ebeSGabor Kovesdan 				devbehave = DEV_SKIP;
44327116286SGabor Kovesdan 			else if (strcasecmp(optarg, "read") == 0)
44427116286SGabor Kovesdan 				devbehave = DEV_READ;
44597a012f2SGabor Kovesdan 			else
44697a012f2SGabor Kovesdan 				errx(2, getstr(3), "--devices");
4474dc88ebeSGabor Kovesdan 			break;
4484dc88ebeSGabor Kovesdan 		case 'd':
44927116286SGabor Kovesdan 			if (strcasecmp("recurse", optarg) == 0) {
4504dc88ebeSGabor Kovesdan 				Hflag = true;
4514dc88ebeSGabor Kovesdan 				dirbehave = DIR_RECURSE;
45227116286SGabor Kovesdan 			} else if (strcasecmp("skip", optarg) == 0)
4534dc88ebeSGabor Kovesdan 				dirbehave = DIR_SKIP;
45427116286SGabor Kovesdan 			else if (strcasecmp("read", optarg) == 0)
45527116286SGabor Kovesdan 				dirbehave = DIR_READ;
45697a012f2SGabor Kovesdan 			else
45797a012f2SGabor Kovesdan 				errx(2, getstr(3), "--directories");
4584dc88ebeSGabor Kovesdan 			break;
4594dc88ebeSGabor Kovesdan 		case 'E':
4604dc88ebeSGabor Kovesdan 			grepbehave = GREP_EXTENDED;
4614dc88ebeSGabor Kovesdan 			break;
4624dc88ebeSGabor Kovesdan 		case 'e':
4634dc88ebeSGabor Kovesdan 			add_pattern(optarg, strlen(optarg));
4644dc88ebeSGabor Kovesdan 			needpattern = 0;
4654dc88ebeSGabor Kovesdan 			break;
4664dc88ebeSGabor Kovesdan 		case 'F':
4674dc88ebeSGabor Kovesdan 			grepbehave = GREP_FIXED;
4684dc88ebeSGabor Kovesdan 			break;
4694dc88ebeSGabor Kovesdan 		case 'f':
4704dc88ebeSGabor Kovesdan 			read_patterns(optarg);
4714dc88ebeSGabor Kovesdan 			needpattern = 0;
4724dc88ebeSGabor Kovesdan 			break;
4734dc88ebeSGabor Kovesdan 		case 'G':
4744dc88ebeSGabor Kovesdan 			grepbehave = GREP_BASIC;
4754dc88ebeSGabor Kovesdan 			break;
4764dc88ebeSGabor Kovesdan 		case 'H':
4774dc88ebeSGabor Kovesdan 			Hflag = true;
4784dc88ebeSGabor Kovesdan 			break;
4794dc88ebeSGabor Kovesdan 		case 'h':
4804dc88ebeSGabor Kovesdan 			Hflag = false;
4814dc88ebeSGabor Kovesdan 			hflag = true;
4824dc88ebeSGabor Kovesdan 			break;
4834dc88ebeSGabor Kovesdan 		case 'I':
4844dc88ebeSGabor Kovesdan 			binbehave = BINFILE_SKIP;
4854dc88ebeSGabor Kovesdan 			break;
4864dc88ebeSGabor Kovesdan 		case 'i':
4874dc88ebeSGabor Kovesdan 		case 'y':
4884dc88ebeSGabor Kovesdan 			iflag =  true;
4894dc88ebeSGabor Kovesdan 			cflags |= REG_ICASE;
4904dc88ebeSGabor Kovesdan 			break;
4914dc88ebeSGabor Kovesdan 		case 'J':
4924dc88ebeSGabor Kovesdan 			filebehave = FILE_BZIP;
4934dc88ebeSGabor Kovesdan 			break;
4944dc88ebeSGabor Kovesdan 		case 'L':
4954dc88ebeSGabor Kovesdan 			lflag = false;
49627116286SGabor Kovesdan 			Lflag = true;
4974dc88ebeSGabor Kovesdan 			break;
4984dc88ebeSGabor Kovesdan 		case 'l':
4994dc88ebeSGabor Kovesdan 			Lflag = false;
50027116286SGabor Kovesdan 			lflag = true;
5014dc88ebeSGabor Kovesdan 			break;
5024dc88ebeSGabor Kovesdan 		case 'm':
5034dc88ebeSGabor Kovesdan 			mflag = true;
5044dc88ebeSGabor Kovesdan 			errno = 0;
5054dc88ebeSGabor Kovesdan 			mcount = strtoull(optarg, &ep, 10);
5064dc88ebeSGabor Kovesdan 			if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
5074dc88ebeSGabor Kovesdan 			    ((errno == EINVAL) && (mcount == 0)))
5084dc88ebeSGabor Kovesdan 				err(2, NULL);
5094dc88ebeSGabor Kovesdan 			else if (ep[0] != '\0') {
5104dc88ebeSGabor Kovesdan 				errno = EINVAL;
5114dc88ebeSGabor Kovesdan 				err(2, NULL);
5124dc88ebeSGabor Kovesdan 			}
5134dc88ebeSGabor Kovesdan 			break;
5144dc88ebeSGabor Kovesdan 		case 'n':
5154dc88ebeSGabor Kovesdan 			nflag = true;
5164dc88ebeSGabor Kovesdan 			break;
5174dc88ebeSGabor Kovesdan 		case 'O':
5184dc88ebeSGabor Kovesdan 			linkbehave = LINK_EXPLICIT;
5194dc88ebeSGabor Kovesdan 			break;
5204dc88ebeSGabor Kovesdan 		case 'o':
5214dc88ebeSGabor Kovesdan 			oflag = true;
5224dc88ebeSGabor Kovesdan 			break;
5234dc88ebeSGabor Kovesdan 		case 'p':
5244dc88ebeSGabor Kovesdan 			linkbehave = LINK_SKIP;
5254dc88ebeSGabor Kovesdan 			break;
5264dc88ebeSGabor Kovesdan 		case 'q':
5274dc88ebeSGabor Kovesdan 			qflag = true;
5284dc88ebeSGabor Kovesdan 			break;
5294dc88ebeSGabor Kovesdan 		case 'S':
53027116286SGabor Kovesdan 			linkbehave = LINK_READ;
5314dc88ebeSGabor Kovesdan 			break;
5324dc88ebeSGabor Kovesdan 		case 'R':
5334dc88ebeSGabor Kovesdan 		case 'r':
5344dc88ebeSGabor Kovesdan 			dirbehave = DIR_RECURSE;
5354dc88ebeSGabor Kovesdan 			Hflag = true;
5364dc88ebeSGabor Kovesdan 			break;
5374dc88ebeSGabor Kovesdan 		case 's':
5384dc88ebeSGabor Kovesdan 			sflag = true;
5394dc88ebeSGabor Kovesdan 			break;
5404dc88ebeSGabor Kovesdan 		case 'U':
5414dc88ebeSGabor Kovesdan 			binbehave = BINFILE_BIN;
5424dc88ebeSGabor Kovesdan 			break;
5434dc88ebeSGabor Kovesdan 		case 'u':
5444dc88ebeSGabor Kovesdan 		case MMAP_OPT:
5454dc88ebeSGabor Kovesdan 			/* noop, compatibility */
5464dc88ebeSGabor Kovesdan 			break;
5474dc88ebeSGabor Kovesdan 		case 'V':
54897a012f2SGabor Kovesdan 			printf(getstr(9), __progname, VERSION);
5494dc88ebeSGabor Kovesdan 			exit(0);
5504dc88ebeSGabor Kovesdan 		case 'v':
5514dc88ebeSGabor Kovesdan 			vflag = true;
5524dc88ebeSGabor Kovesdan 			break;
5534dc88ebeSGabor Kovesdan 		case 'w':
5544dc88ebeSGabor Kovesdan 			wflag = true;
5554dc88ebeSGabor Kovesdan 			break;
5564dc88ebeSGabor Kovesdan 		case 'x':
5574dc88ebeSGabor Kovesdan 			xflag = true;
5584dc88ebeSGabor Kovesdan 			break;
5594dc88ebeSGabor Kovesdan 		case 'Z':
5604dc88ebeSGabor Kovesdan 			filebehave = FILE_GZIP;
5614dc88ebeSGabor Kovesdan 			break;
5624dc88ebeSGabor Kovesdan 		case BIN_OPT:
56327116286SGabor Kovesdan 			if (strcasecmp("binary", optarg) == 0)
5644dc88ebeSGabor Kovesdan 				binbehave = BINFILE_BIN;
56527116286SGabor Kovesdan 			else if (strcasecmp("without-match", optarg) == 0)
5664dc88ebeSGabor Kovesdan 				binbehave = BINFILE_SKIP;
56727116286SGabor Kovesdan 			else if (strcasecmp("text", optarg) == 0)
5684dc88ebeSGabor Kovesdan 				binbehave = BINFILE_TEXT;
5694dc88ebeSGabor Kovesdan 			else
57097a012f2SGabor Kovesdan 				errx(2, getstr(3), "--binary-files");
5714dc88ebeSGabor Kovesdan 			break;
5724dc88ebeSGabor Kovesdan 		case COLOR_OPT:
5734dc88ebeSGabor Kovesdan 			color = NULL;
57427116286SGabor Kovesdan 			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
57527116286SGabor Kovesdan 			    strcasecmp("tty", optarg) == 0 ||
57627116286SGabor Kovesdan 			    strcasecmp("if-tty", optarg) == 0) {
57727116286SGabor Kovesdan 				char *term;
57827116286SGabor Kovesdan 
57927116286SGabor Kovesdan 				term = getenv("TERM");
58027116286SGabor Kovesdan 				if (isatty(STDOUT_FILENO) && term != NULL &&
58127116286SGabor Kovesdan 				    strcasecmp(term, "dumb") != 0)
58227116286SGabor Kovesdan 					color = init_color("01;31");
58327116286SGabor Kovesdan 			} else if (strcasecmp("always", optarg) == 0 ||
58427116286SGabor Kovesdan 			    strcasecmp("yes", optarg) == 0 ||
58527116286SGabor Kovesdan 			    strcasecmp("force", optarg) == 0) {
58627116286SGabor Kovesdan 				color = init_color("01;31");
58727116286SGabor Kovesdan 			} else if (strcasecmp("never", optarg) != 0 &&
58827116286SGabor Kovesdan 			    strcasecmp("none", optarg) != 0 &&
58927116286SGabor Kovesdan 			    strcasecmp("no", optarg) != 0)
59097a012f2SGabor Kovesdan 				errx(2, getstr(3), "--color");
5914dc88ebeSGabor Kovesdan 			break;
5924dc88ebeSGabor Kovesdan 		case LABEL_OPT:
5934dc88ebeSGabor Kovesdan 			label = optarg;
5944dc88ebeSGabor Kovesdan 			break;
5954dc88ebeSGabor Kovesdan 		case LINEBUF_OPT:
5964dc88ebeSGabor Kovesdan 			lbflag = true;
5974dc88ebeSGabor Kovesdan 			break;
5984dc88ebeSGabor Kovesdan 		case NULL_OPT:
5994dc88ebeSGabor Kovesdan 			nullflag = true;
6004dc88ebeSGabor Kovesdan 			break;
6014dc88ebeSGabor Kovesdan 		case R_INCLUDE_OPT:
60255e44f51SGabor Kovesdan 			finclude = true;
60355e44f51SGabor Kovesdan 			add_fpattern(optarg, INCL_PAT);
6044dc88ebeSGabor Kovesdan 			break;
6054dc88ebeSGabor Kovesdan 		case R_EXCLUDE_OPT:
60655e44f51SGabor Kovesdan 			fexclude = true;
60755e44f51SGabor Kovesdan 			add_fpattern(optarg, EXCL_PAT);
6084dc88ebeSGabor Kovesdan 			break;
6094dc88ebeSGabor Kovesdan 		case R_DINCLUDE_OPT:
61059218eb7SGabor Kovesdan 			dinclude = true;
61155e44f51SGabor Kovesdan 			add_dpattern(optarg, INCL_PAT);
6124dc88ebeSGabor Kovesdan 			break;
6134dc88ebeSGabor Kovesdan 		case R_DEXCLUDE_OPT:
61459218eb7SGabor Kovesdan 			dexclude = true;
61555e44f51SGabor Kovesdan 			add_dpattern(optarg, EXCL_PAT);
6164dc88ebeSGabor Kovesdan 			break;
6174dc88ebeSGabor Kovesdan 		case HELP_OPT:
6184dc88ebeSGabor Kovesdan 		default:
6194dc88ebeSGabor Kovesdan 			usage();
6204dc88ebeSGabor Kovesdan 		}
6214dc88ebeSGabor Kovesdan 		lastc = c;
6224dc88ebeSGabor Kovesdan 		newarg = optind != prevoptind;
6234dc88ebeSGabor Kovesdan 		prevoptind = optind;
6244dc88ebeSGabor Kovesdan 	}
6254dc88ebeSGabor Kovesdan 	aargc -= optind;
6264dc88ebeSGabor Kovesdan 	aargv += optind;
6274dc88ebeSGabor Kovesdan 
6284dc88ebeSGabor Kovesdan 	/* Fail if we don't have any pattern */
6294dc88ebeSGabor Kovesdan 	if (aargc == 0 && needpattern)
6304dc88ebeSGabor Kovesdan 		usage();
6314dc88ebeSGabor Kovesdan 
6324dc88ebeSGabor Kovesdan 	/* Process patterns from command line */
6334dc88ebeSGabor Kovesdan 	if (aargc != 0 && needpattern) {
6344dc88ebeSGabor Kovesdan 		add_pattern(*aargv, strlen(*aargv));
6354dc88ebeSGabor Kovesdan 		--aargc;
6364dc88ebeSGabor Kovesdan 		++aargv;
6374dc88ebeSGabor Kovesdan 	}
6384dc88ebeSGabor Kovesdan 
6394dc88ebeSGabor Kovesdan 	switch (grepbehave) {
6404dc88ebeSGabor Kovesdan 	case GREP_FIXED:
6414dc88ebeSGabor Kovesdan 	case GREP_BASIC:
6424dc88ebeSGabor Kovesdan 		break;
6434dc88ebeSGabor Kovesdan 	case GREP_EXTENDED:
6444dc88ebeSGabor Kovesdan 		cflags |= REG_EXTENDED;
6454dc88ebeSGabor Kovesdan 		break;
6464dc88ebeSGabor Kovesdan 	default:
6474dc88ebeSGabor Kovesdan 		/* NOTREACHED */
6484dc88ebeSGabor Kovesdan 		usage();
6494dc88ebeSGabor Kovesdan 	}
6504dc88ebeSGabor Kovesdan 
6514dc88ebeSGabor Kovesdan 	fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
6524dc88ebeSGabor Kovesdan 	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
6534dc88ebeSGabor Kovesdan /*
6544dc88ebeSGabor Kovesdan  * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance.
6554dc88ebeSGabor Kovesdan  * Optimizations should be done there.
6564dc88ebeSGabor Kovesdan  */
6574dc88ebeSGabor Kovesdan 		/* Check if cheating is allowed (always is for fgrep). */
6584dc88ebeSGabor Kovesdan 	if (grepbehave == GREP_FIXED) {
6594dc88ebeSGabor Kovesdan 		for (i = 0; i < patterns; ++i)
6604dc88ebeSGabor Kovesdan 			fgrepcomp(&fg_pattern[i], pattern[i]);
6614dc88ebeSGabor Kovesdan 	} else {
6624dc88ebeSGabor Kovesdan 		for (i = 0; i < patterns; ++i) {
6634dc88ebeSGabor Kovesdan 			if (fastcomp(&fg_pattern[i], pattern[i])) {
6644dc88ebeSGabor Kovesdan 				/* Fall back to full regex library */
6654dc88ebeSGabor Kovesdan 				c = regcomp(&r_pattern[i], pattern[i], cflags);
6664dc88ebeSGabor Kovesdan 				if (c != 0) {
6674dc88ebeSGabor Kovesdan 					regerror(c, &r_pattern[i], re_error,
6684dc88ebeSGabor Kovesdan 					    RE_ERROR_BUF);
6694dc88ebeSGabor Kovesdan 					errx(2, "%s", re_error);
6704dc88ebeSGabor Kovesdan 				}
6714dc88ebeSGabor Kovesdan 			}
6724dc88ebeSGabor Kovesdan 		}
6734dc88ebeSGabor Kovesdan 	}
6744dc88ebeSGabor Kovesdan 
6754dc88ebeSGabor Kovesdan 	if (lbflag)
6764dc88ebeSGabor Kovesdan 		setlinebuf(stdout);
6774dc88ebeSGabor Kovesdan 
6784dc88ebeSGabor Kovesdan 	if ((aargc == 0 || aargc == 1) && !Hflag)
6794dc88ebeSGabor Kovesdan 		hflag = true;
6804dc88ebeSGabor Kovesdan 
6814dc88ebeSGabor Kovesdan 	if (aargc == 0)
6824dc88ebeSGabor Kovesdan 		exit(!procfile("-"));
6834dc88ebeSGabor Kovesdan 
6844dc88ebeSGabor Kovesdan 	if (dirbehave == DIR_RECURSE)
6854dc88ebeSGabor Kovesdan 		c = grep_tree(aargv);
686c38208adSXin LI 	else
68755e44f51SGabor Kovesdan 		for (c = 0; aargc--; ++aargv) {
68855e44f51SGabor Kovesdan 			if ((finclude || fexclude) && !file_matching(*aargv))
68955e44f51SGabor Kovesdan 				continue;
6904dc88ebeSGabor Kovesdan 			c+= procfile(*aargv);
69155e44f51SGabor Kovesdan 		}
6924dc88ebeSGabor Kovesdan 
6934dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS
6944dc88ebeSGabor Kovesdan 	catclose(catalog);
6954dc88ebeSGabor Kovesdan #endif
6964dc88ebeSGabor Kovesdan 
6974dc88ebeSGabor Kovesdan 	/* Find out the correct return value according to the
6984dc88ebeSGabor Kovesdan 	   results and the command line option. */
6994dc88ebeSGabor Kovesdan 	exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1));
7004dc88ebeSGabor Kovesdan }
701