xref: /freebsd/usr.bin/grep/grep.c (revision a18528077c75f94c77d2bd8cb05af0e2370f86e3)
1f3f50de6SPedro F. Giffuni /*	$NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $	*/
2b66a823bSGabor Kovesdan /* 	$FreeBSD$	*/
34dc88ebeSGabor Kovesdan /*	$OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $	*/
44dc88ebeSGabor Kovesdan 
54dc88ebeSGabor Kovesdan /*-
61de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
71de7b4b8SPedro F. Giffuni  *
8a0ef9ad6SDag-Erling Smørgrav  * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
94dc88ebeSGabor Kovesdan  * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
104dc88ebeSGabor Kovesdan  * All rights reserved.
114dc88ebeSGabor Kovesdan  *
124dc88ebeSGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
134dc88ebeSGabor Kovesdan  * modification, are permitted provided that the following conditions
144dc88ebeSGabor Kovesdan  * are met:
154dc88ebeSGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
164dc88ebeSGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
174dc88ebeSGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
184dc88ebeSGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
194dc88ebeSGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
204dc88ebeSGabor Kovesdan  *
214dc88ebeSGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
224dc88ebeSGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
234dc88ebeSGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244dc88ebeSGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
254dc88ebeSGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
264dc88ebeSGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
274dc88ebeSGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
284dc88ebeSGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
294dc88ebeSGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
304dc88ebeSGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
314dc88ebeSGabor Kovesdan  * SUCH DAMAGE.
324dc88ebeSGabor Kovesdan  */
334dc88ebeSGabor Kovesdan 
344dc88ebeSGabor Kovesdan #include <sys/cdefs.h>
354dc88ebeSGabor Kovesdan __FBSDID("$FreeBSD$");
364dc88ebeSGabor Kovesdan 
374dc88ebeSGabor Kovesdan #include <sys/stat.h>
384dc88ebeSGabor Kovesdan #include <sys/types.h>
394dc88ebeSGabor Kovesdan 
404dc88ebeSGabor Kovesdan #include <ctype.h>
414dc88ebeSGabor Kovesdan #include <err.h>
424dc88ebeSGabor Kovesdan #include <errno.h>
43f20f6f3fSGabor Kovesdan #include <fcntl.h>
444dc88ebeSGabor Kovesdan #include <getopt.h>
454dc88ebeSGabor Kovesdan #include <limits.h>
464dc88ebeSGabor Kovesdan #include <libgen.h>
474dc88ebeSGabor Kovesdan #include <locale.h>
484dc88ebeSGabor Kovesdan #include <stdbool.h>
494dc88ebeSGabor Kovesdan #include <stdio.h>
504dc88ebeSGabor Kovesdan #include <stdlib.h>
514dc88ebeSGabor Kovesdan #include <string.h>
524dc88ebeSGabor Kovesdan #include <unistd.h>
534dc88ebeSGabor Kovesdan 
543f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH
55f20f6f3fSGabor Kovesdan #include "fastmatch.h"
563f39ffc8SEd Maste #endif
574dc88ebeSGabor Kovesdan #include "grep.h"
584dc88ebeSGabor Kovesdan 
594dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS
604dc88ebeSGabor Kovesdan #include <nl_types.h>
614dc88ebeSGabor Kovesdan nl_catd	 catalog;
624dc88ebeSGabor Kovesdan #endif
634dc88ebeSGabor Kovesdan 
644dc88ebeSGabor Kovesdan /*
654dc88ebeSGabor Kovesdan  * Default messags to use when NLS is disabled or no catalogue
664dc88ebeSGabor Kovesdan  * is found.
674dc88ebeSGabor Kovesdan  */
684dc88ebeSGabor Kovesdan const char	*errstr[] = {
694dc88ebeSGabor Kovesdan 	"",
704dc88ebeSGabor Kovesdan /* 1*/	"(standard input)",
71*a1852807SKyle Evans /* 2*/	"unknown %s option",
72*a1852807SKyle Evans /* 3*/	"usage: %s [-abcDEFGHhIiLlmnOoPqRSsUVvwxz] [-A num] [-B num] [-C[num]]\n",
73*a1852807SKyle Evans /* 4*/	"\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
74*a1852807SKyle Evans /* 5*/	"\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
75*a1852807SKyle Evans /* 6*/	"\t[--null] [pattern] [file ...]\n",
76*a1852807SKyle Evans /* 7*/	"Binary file %s matches\n",
77*a1852807SKyle Evans /* 8*/	"%s (BSD grep) %s\n",
78*a1852807SKyle Evans /* 9*/	"%s (BSD grep, GNU compatible) %s\n",
794dc88ebeSGabor Kovesdan };
804dc88ebeSGabor Kovesdan 
814dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */
828bf46064SEd Maste int		 cflags = REG_NOSUB | REG_NEWLINE;
834dc88ebeSGabor Kovesdan int		 eflags = REG_STARTEND;
844dc88ebeSGabor Kovesdan 
85a4f3f02bSEd Maste /* XXX TODO: Get rid of this flag.
86a4f3f02bSEd Maste  * matchall is a gross hack that means that an empty pattern was passed to us.
87a4f3f02bSEd Maste  * It is a necessary evil at the moment because our regex(3) implementation
88a4f3f02bSEd Maste  * does not allow for empty patterns, as supported by POSIX's definition of
89a4f3f02bSEd Maste  * grammar for BREs/EREs. When libregex becomes available, it would be wise
90a4f3f02bSEd Maste  * to remove this and let regex(3) handle the dirty details of empty patterns.
91a4f3f02bSEd Maste  */
924dc88ebeSGabor Kovesdan bool		 matchall;
934dc88ebeSGabor Kovesdan 
944dc88ebeSGabor Kovesdan /* Searching patterns */
95bf70beceSEd Schouten unsigned int	 patterns;
96bf70beceSEd Schouten static unsigned int pattern_sz;
97f20f6f3fSGabor Kovesdan struct pat	*pattern;
984dc88ebeSGabor Kovesdan regex_t		*r_pattern;
993f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH
100f20f6f3fSGabor Kovesdan fastmatch_t	*fg_pattern;
1013f39ffc8SEd Maste #endif
1024dc88ebeSGabor Kovesdan 
1034dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */
104bf70beceSEd Schouten unsigned int	fpatterns, dpatterns;
105bf70beceSEd Schouten static unsigned int fpattern_sz, dpattern_sz;
10655e44f51SGabor Kovesdan struct epat	*dpattern, *fpattern;
1074dc88ebeSGabor Kovesdan 
1084dc88ebeSGabor Kovesdan /* For regex errors  */
1094dc88ebeSGabor Kovesdan char	 re_error[RE_ERROR_BUF + 1];
1104dc88ebeSGabor Kovesdan 
1114dc88ebeSGabor Kovesdan /* Command-line flags */
112b5fc583cSEd Maste long long Aflag;	/* -A x: print x lines trailing each match */
113b5fc583cSEd Maste long long Bflag;	/* -B x: print x lines leading each match */
1144dc88ebeSGabor Kovesdan bool	 Hflag;		/* -H: always print file name */
1154dc88ebeSGabor Kovesdan bool	 Lflag;		/* -L: only show names of files with no matches */
1164dc88ebeSGabor Kovesdan bool	 bflag;		/* -b: show block numbers for each match */
1174dc88ebeSGabor Kovesdan bool	 cflag;		/* -c: only show a count of matching lines */
1184dc88ebeSGabor Kovesdan bool	 hflag;		/* -h: don't print filename headers */
1194dc88ebeSGabor Kovesdan bool	 iflag;		/* -i: ignore case */
1204dc88ebeSGabor Kovesdan bool	 lflag;		/* -l: only show names of files with matches */
1214dc88ebeSGabor Kovesdan bool	 mflag;		/* -m x: stop reading the files after x matches */
122f20f6f3fSGabor Kovesdan long long mcount;	/* count for -m */
123924500b7SEitan Adler long long mlimit;	/* requested value for -m */
1245ee1ea02SEd Maste char	 fileeol;	/* indicator for eol */
1254dc88ebeSGabor Kovesdan bool	 nflag;		/* -n: show line numbers in front of matching lines */
1264dc88ebeSGabor Kovesdan bool	 oflag;		/* -o: print only matching part */
1274dc88ebeSGabor Kovesdan bool	 qflag;		/* -q: quiet mode (don't output anything) */
1284dc88ebeSGabor Kovesdan bool	 sflag;		/* -s: silent mode (ignore errors) */
1294dc88ebeSGabor Kovesdan bool	 vflag;		/* -v: only show non-matching lines */
1304dc88ebeSGabor Kovesdan bool	 wflag;		/* -w: pattern must start and end on word boundaries */
1314dc88ebeSGabor Kovesdan bool	 xflag;		/* -x: pattern must match entire line */
1324dc88ebeSGabor Kovesdan bool	 lbflag;	/* --line-buffered */
1334dc88ebeSGabor Kovesdan bool	 nullflag;	/* --null */
1344dc88ebeSGabor Kovesdan char	*label;		/* --label */
13527116286SGabor Kovesdan const char *color;	/* --color */
1364dc88ebeSGabor Kovesdan int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
1374dc88ebeSGabor Kovesdan int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
1384a5b4207SBaptiste Daroussin int	 filebehave = FILE_STDIO;
13927116286SGabor Kovesdan int	 devbehave = DEV_READ;		/* -D: handling of devices */
14027116286SGabor Kovesdan int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
14127116286SGabor Kovesdan int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
1424dc88ebeSGabor Kovesdan 
14359218eb7SGabor Kovesdan bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
14459218eb7SGabor Kovesdan bool	 fexclude, finclude;	/* --exclude and --include */
14555e44f51SGabor Kovesdan 
1464dc88ebeSGabor Kovesdan enum {
1474dc88ebeSGabor Kovesdan 	BIN_OPT = CHAR_MAX + 1,
1484dc88ebeSGabor Kovesdan 	COLOR_OPT,
1494dc88ebeSGabor Kovesdan 	HELP_OPT,
1504dc88ebeSGabor Kovesdan 	MMAP_OPT,
1514dc88ebeSGabor Kovesdan 	LINEBUF_OPT,
1524dc88ebeSGabor Kovesdan 	LABEL_OPT,
1534dc88ebeSGabor Kovesdan 	NULL_OPT,
1544dc88ebeSGabor Kovesdan 	R_EXCLUDE_OPT,
1554dc88ebeSGabor Kovesdan 	R_INCLUDE_OPT,
1564dc88ebeSGabor Kovesdan 	R_DEXCLUDE_OPT,
1574dc88ebeSGabor Kovesdan 	R_DINCLUDE_OPT
1584dc88ebeSGabor Kovesdan };
1594dc88ebeSGabor Kovesdan 
16027116286SGabor Kovesdan static inline const char	*init_color(const char *);
16127116286SGabor Kovesdan 
1624dc88ebeSGabor Kovesdan /* Housekeeping */
1636f4cbf7cSGabor Kovesdan bool	 file_err;	/* file reading error */
1644dc88ebeSGabor Kovesdan 
1654dc88ebeSGabor Kovesdan /*
1664dc88ebeSGabor Kovesdan  * Prints usage information and returns 2.
1674dc88ebeSGabor Kovesdan  */
1684dc88ebeSGabor Kovesdan static void
1694dc88ebeSGabor Kovesdan usage(void)
1704dc88ebeSGabor Kovesdan {
1714a5b4207SBaptiste Daroussin 	fprintf(stderr, getstr(3), getprogname());
1724a5b4207SBaptiste Daroussin 	fprintf(stderr, "%s", getstr(4));
1734dc88ebeSGabor Kovesdan 	fprintf(stderr, "%s", getstr(5));
1744dc88ebeSGabor Kovesdan 	fprintf(stderr, "%s", getstr(6));
1754dc88ebeSGabor Kovesdan 	exit(2);
1764dc88ebeSGabor Kovesdan }
1774dc88ebeSGabor Kovesdan 
1784a5b4207SBaptiste Daroussin static const char	*optstr = "0123456789A:B:C:D:EFGHILOPSRUVabcd:e:f:hilm:nopqrsuvwxyz";
1794dc88ebeSGabor Kovesdan 
1808375d512SEd Schouten static const struct option long_options[] =
1814dc88ebeSGabor Kovesdan {
1824dc88ebeSGabor Kovesdan 	{"binary-files",	required_argument,	NULL, BIN_OPT},
1834dc88ebeSGabor Kovesdan 	{"help",		no_argument,		NULL, HELP_OPT},
1844dc88ebeSGabor Kovesdan 	{"mmap",		no_argument,		NULL, MMAP_OPT},
1854dc88ebeSGabor Kovesdan 	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
1864dc88ebeSGabor Kovesdan 	{"label",		required_argument,	NULL, LABEL_OPT},
1874dc88ebeSGabor Kovesdan 	{"null",		no_argument,		NULL, NULL_OPT},
1884dc88ebeSGabor Kovesdan 	{"color",		optional_argument,	NULL, COLOR_OPT},
1894dc88ebeSGabor Kovesdan 	{"colour",		optional_argument,	NULL, COLOR_OPT},
1904dc88ebeSGabor Kovesdan 	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
1914dc88ebeSGabor Kovesdan 	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
1924dc88ebeSGabor Kovesdan 	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
1934dc88ebeSGabor Kovesdan 	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
1944dc88ebeSGabor Kovesdan 	{"after-context",	required_argument,	NULL, 'A'},
1954dc88ebeSGabor Kovesdan 	{"text",		no_argument,		NULL, 'a'},
1964dc88ebeSGabor Kovesdan 	{"before-context",	required_argument,	NULL, 'B'},
1974dc88ebeSGabor Kovesdan 	{"byte-offset",		no_argument,		NULL, 'b'},
1984dc88ebeSGabor Kovesdan 	{"context",		optional_argument,	NULL, 'C'},
1994dc88ebeSGabor Kovesdan 	{"count",		no_argument,		NULL, 'c'},
2004dc88ebeSGabor Kovesdan 	{"devices",		required_argument,	NULL, 'D'},
2014dc88ebeSGabor Kovesdan         {"directories",		required_argument,	NULL, 'd'},
2024dc88ebeSGabor Kovesdan 	{"extended-regexp",	no_argument,		NULL, 'E'},
2034dc88ebeSGabor Kovesdan 	{"regexp",		required_argument,	NULL, 'e'},
2044dc88ebeSGabor Kovesdan 	{"fixed-strings",	no_argument,		NULL, 'F'},
2054dc88ebeSGabor Kovesdan 	{"file",		required_argument,	NULL, 'f'},
2064dc88ebeSGabor Kovesdan 	{"basic-regexp",	no_argument,		NULL, 'G'},
2074dc88ebeSGabor Kovesdan 	{"no-filename",		no_argument,		NULL, 'h'},
2084dc88ebeSGabor Kovesdan 	{"with-filename",	no_argument,		NULL, 'H'},
2094dc88ebeSGabor Kovesdan 	{"ignore-case",		no_argument,		NULL, 'i'},
2104dc88ebeSGabor Kovesdan 	{"files-with-matches",	no_argument,		NULL, 'l'},
2114dc88ebeSGabor Kovesdan 	{"files-without-match", no_argument,            NULL, 'L'},
2124dc88ebeSGabor Kovesdan 	{"max-count",		required_argument,	NULL, 'm'},
2134dc88ebeSGabor Kovesdan 	{"line-number",		no_argument,		NULL, 'n'},
2144dc88ebeSGabor Kovesdan 	{"only-matching",	no_argument,		NULL, 'o'},
2154dc88ebeSGabor Kovesdan 	{"quiet",		no_argument,		NULL, 'q'},
2164dc88ebeSGabor Kovesdan 	{"silent",		no_argument,		NULL, 'q'},
2174dc88ebeSGabor Kovesdan 	{"recursive",		no_argument,		NULL, 'r'},
2184dc88ebeSGabor Kovesdan 	{"no-messages",		no_argument,		NULL, 's'},
2194dc88ebeSGabor Kovesdan 	{"binary",		no_argument,		NULL, 'U'},
2204dc88ebeSGabor Kovesdan 	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
2214dc88ebeSGabor Kovesdan 	{"invert-match",	no_argument,		NULL, 'v'},
2224dc88ebeSGabor Kovesdan 	{"version",		no_argument,		NULL, 'V'},
2234dc88ebeSGabor Kovesdan 	{"word-regexp",		no_argument,		NULL, 'w'},
2244dc88ebeSGabor Kovesdan 	{"line-regexp",		no_argument,		NULL, 'x'},
2255ee1ea02SEd Maste 	{"null-data",		no_argument,		NULL, 'z'},
2264dc88ebeSGabor Kovesdan 	{NULL,			no_argument,		NULL, 0}
2274dc88ebeSGabor Kovesdan };
2284dc88ebeSGabor Kovesdan 
2294dc88ebeSGabor Kovesdan /*
2304dc88ebeSGabor Kovesdan  * Adds a searching pattern to the internal array.
2314dc88ebeSGabor Kovesdan  */
2324dc88ebeSGabor Kovesdan static void
2334dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len)
2344dc88ebeSGabor Kovesdan {
2354dc88ebeSGabor Kovesdan 
236f20f6f3fSGabor Kovesdan 	/* Do not add further pattern is we already match everything */
237f20f6f3fSGabor Kovesdan 	if (matchall)
238f20f6f3fSGabor Kovesdan 	  return;
239f20f6f3fSGabor Kovesdan 
2404dc88ebeSGabor Kovesdan 	/* Check if we can do a shortcut */
241f20f6f3fSGabor Kovesdan 	if (len == 0) {
2424dc88ebeSGabor Kovesdan 		matchall = true;
243f20f6f3fSGabor Kovesdan 		for (unsigned int i = 0; i < patterns; i++) {
244f20f6f3fSGabor Kovesdan 			free(pattern[i].pat);
245f20f6f3fSGabor Kovesdan 		}
246f20f6f3fSGabor Kovesdan 		pattern = grep_realloc(pattern, sizeof(struct pat));
247f20f6f3fSGabor Kovesdan 		pattern[0].pat = NULL;
248f20f6f3fSGabor Kovesdan 		pattern[0].len = 0;
249f20f6f3fSGabor Kovesdan 		patterns = 1;
2504dc88ebeSGabor Kovesdan 		return;
2514dc88ebeSGabor Kovesdan 	}
2524dc88ebeSGabor Kovesdan 	/* Increase size if necessary */
2534dc88ebeSGabor Kovesdan 	if (patterns == pattern_sz) {
2544dc88ebeSGabor Kovesdan 		pattern_sz *= 2;
2554dc88ebeSGabor Kovesdan 		pattern = grep_realloc(pattern, ++pattern_sz *
256f20f6f3fSGabor Kovesdan 		    sizeof(struct pat));
2574dc88ebeSGabor Kovesdan 	}
2584dc88ebeSGabor Kovesdan 	if (len > 0 && pat[len - 1] == '\n')
2594dc88ebeSGabor Kovesdan 		--len;
2604dc88ebeSGabor Kovesdan 	/* pat may not be NUL-terminated */
261f20f6f3fSGabor Kovesdan 	pattern[patterns].pat = grep_malloc(len + 1);
262f20f6f3fSGabor Kovesdan 	memcpy(pattern[patterns].pat, pat, len);
263f20f6f3fSGabor Kovesdan 	pattern[patterns].len = len;
264f20f6f3fSGabor Kovesdan 	pattern[patterns].pat[len] = '\0';
2654dc88ebeSGabor Kovesdan 	++patterns;
2664dc88ebeSGabor Kovesdan }
2674dc88ebeSGabor Kovesdan 
2684dc88ebeSGabor Kovesdan /*
26955e44f51SGabor Kovesdan  * Adds a file include/exclude pattern to the internal array.
2704dc88ebeSGabor Kovesdan  */
2714dc88ebeSGabor Kovesdan static void
27255e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode)
2734dc88ebeSGabor Kovesdan {
2744dc88ebeSGabor Kovesdan 
2754dc88ebeSGabor Kovesdan 	/* Increase size if necessary */
27655e44f51SGabor Kovesdan 	if (fpatterns == fpattern_sz) {
27755e44f51SGabor Kovesdan 		fpattern_sz *= 2;
27855e44f51SGabor Kovesdan 		fpattern = grep_realloc(fpattern, ++fpattern_sz *
2794dc88ebeSGabor Kovesdan 		    sizeof(struct epat));
2804dc88ebeSGabor Kovesdan 	}
28155e44f51SGabor Kovesdan 	fpattern[fpatterns].pat = grep_strdup(pat);
28255e44f51SGabor Kovesdan 	fpattern[fpatterns].mode = mode;
28355e44f51SGabor Kovesdan 	++fpatterns;
28455e44f51SGabor Kovesdan }
28555e44f51SGabor Kovesdan 
28655e44f51SGabor Kovesdan /*
28755e44f51SGabor Kovesdan  * Adds a directory include/exclude pattern to the internal array.
28855e44f51SGabor Kovesdan  */
28955e44f51SGabor Kovesdan static void
29055e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode)
29155e44f51SGabor Kovesdan {
29255e44f51SGabor Kovesdan 
29355e44f51SGabor Kovesdan 	/* Increase size if necessary */
29455e44f51SGabor Kovesdan 	if (dpatterns == dpattern_sz) {
29555e44f51SGabor Kovesdan 		dpattern_sz *= 2;
29655e44f51SGabor Kovesdan 		dpattern = grep_realloc(dpattern, ++dpattern_sz *
29755e44f51SGabor Kovesdan 		    sizeof(struct epat));
29855e44f51SGabor Kovesdan 	}
29955e44f51SGabor Kovesdan 	dpattern[dpatterns].pat = grep_strdup(pat);
30055e44f51SGabor Kovesdan 	dpattern[dpatterns].mode = mode;
30155e44f51SGabor Kovesdan 	++dpatterns;
3024dc88ebeSGabor Kovesdan }
3034dc88ebeSGabor Kovesdan 
3044dc88ebeSGabor Kovesdan /*
3054dc88ebeSGabor Kovesdan  * Reads searching patterns from a file and adds them with add_pattern().
3064dc88ebeSGabor Kovesdan  */
3074dc88ebeSGabor Kovesdan static void
3084dc88ebeSGabor Kovesdan read_patterns(const char *fn)
3094dc88ebeSGabor Kovesdan {
310f20f6f3fSGabor Kovesdan 	struct stat st;
3114dc88ebeSGabor Kovesdan 	FILE *f;
3124dc88ebeSGabor Kovesdan 	char *line;
3134dc88ebeSGabor Kovesdan 	size_t len;
314f3f50de6SPedro F. Giffuni 	ssize_t rlen;
3154dc88ebeSGabor Kovesdan 
3164dc88ebeSGabor Kovesdan 	if ((f = fopen(fn, "r")) == NULL)
3174dc88ebeSGabor Kovesdan 		err(2, "%s", fn);
318f20f6f3fSGabor Kovesdan 	if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
319f20f6f3fSGabor Kovesdan 		fclose(f);
320f20f6f3fSGabor Kovesdan 		return;
321f20f6f3fSGabor Kovesdan 	}
322f3f50de6SPedro F. Giffuni 	len = 0;
323f3f50de6SPedro F. Giffuni 	line = NULL;
324d204af1eSEd Maste 	while ((rlen = getline(&line, &len, f)) != -1) {
325d204af1eSEd Maste 		if (line[0] == '\0')
326d204af1eSEd Maste 			continue;
3272fa7a2afSPedro F. Giffuni 		add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
328d204af1eSEd Maste 	}
329d204af1eSEd Maste 
330f3f50de6SPedro F. Giffuni 	free(line);
3314dc88ebeSGabor Kovesdan 	if (ferror(f))
3324dc88ebeSGabor Kovesdan 		err(2, "%s", fn);
3334dc88ebeSGabor Kovesdan 	fclose(f);
3344dc88ebeSGabor Kovesdan }
3354dc88ebeSGabor Kovesdan 
33627116286SGabor Kovesdan static inline const char *
33727116286SGabor Kovesdan init_color(const char *d)
33827116286SGabor Kovesdan {
33927116286SGabor Kovesdan 	char *c;
34027116286SGabor Kovesdan 
34127116286SGabor Kovesdan 	c = getenv("GREP_COLOR");
342dab19f30SGabor Kovesdan 	return (c != NULL && c[0] != '\0' ? c : d);
34327116286SGabor Kovesdan }
34427116286SGabor Kovesdan 
3454dc88ebeSGabor Kovesdan int
3464dc88ebeSGabor Kovesdan main(int argc, char *argv[])
3474dc88ebeSGabor Kovesdan {
3484dc88ebeSGabor Kovesdan 	char **aargv, **eargv, *eopts;
349afbbd357SGabor Kovesdan 	char *ep;
350afbbd357SGabor Kovesdan 	const char *pn;
351b5fc583cSEd Maste 	long long l;
3524dc88ebeSGabor Kovesdan 	unsigned int aargc, eargc, i;
3534dc88ebeSGabor Kovesdan 	int c, lastc, needpattern, newarg, prevoptind;
3544dc88ebeSGabor Kovesdan 
3554dc88ebeSGabor Kovesdan 	setlocale(LC_ALL, "");
3564dc88ebeSGabor Kovesdan 
3574dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS
3584dc88ebeSGabor Kovesdan 	catalog = catopen("grep", NL_CAT_LOCALE);
3594dc88ebeSGabor Kovesdan #endif
3604dc88ebeSGabor Kovesdan 
3614dc88ebeSGabor Kovesdan 	/* Check what is the program name of the binary.  In this
3624dc88ebeSGabor Kovesdan 	   way we can have all the funcionalities in one binary
3634dc88ebeSGabor Kovesdan 	   without the need of scripting and using ugly hacks. */
364afbbd357SGabor Kovesdan 	pn = getprogname();
3654a5b4207SBaptiste Daroussin 	if (pn[0] == 'r') {
366491b8b16SEd Maste 		dirbehave = DIR_RECURSE;
367491b8b16SEd Maste 		Hflag = true;
368f20f6f3fSGabor Kovesdan 	}
369f20f6f3fSGabor Kovesdan 	switch (pn[0]) {
3704dc88ebeSGabor Kovesdan 	case 'e':
3714dc88ebeSGabor Kovesdan 		grepbehave = GREP_EXTENDED;
3724dc88ebeSGabor Kovesdan 		break;
3734dc88ebeSGabor Kovesdan 	case 'f':
3744dc88ebeSGabor Kovesdan 		grepbehave = GREP_FIXED;
3754dc88ebeSGabor Kovesdan 		break;
3764dc88ebeSGabor Kovesdan 	}
3774dc88ebeSGabor Kovesdan 
3784dc88ebeSGabor Kovesdan 	lastc = '\0';
3794dc88ebeSGabor Kovesdan 	newarg = 1;
3804dc88ebeSGabor Kovesdan 	prevoptind = 1;
3814dc88ebeSGabor Kovesdan 	needpattern = 1;
3825ee1ea02SEd Maste 	fileeol = '\n';
3834dc88ebeSGabor Kovesdan 
3844dc88ebeSGabor Kovesdan 	eopts = getenv("GREP_OPTIONS");
3854dc88ebeSGabor Kovesdan 
38659218eb7SGabor Kovesdan 	/* support for extra arguments in GREP_OPTIONS */
38759218eb7SGabor Kovesdan 	eargc = 0;
388dab19f30SGabor Kovesdan 	if (eopts != NULL && eopts[0] != '\0') {
3894dc88ebeSGabor Kovesdan 		char *str;
3904dc88ebeSGabor Kovesdan 
39159218eb7SGabor Kovesdan 		/* make an estimation of how many extra arguments we have */
39259218eb7SGabor Kovesdan 		for (unsigned int j = 0; j < strlen(eopts); j++)
39359218eb7SGabor Kovesdan 			if (eopts[j] == ' ')
3944dc88ebeSGabor Kovesdan 				eargc++;
3954dc88ebeSGabor Kovesdan 
3964dc88ebeSGabor Kovesdan 		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
3974dc88ebeSGabor Kovesdan 
3984dc88ebeSGabor Kovesdan 		eargc = 0;
39959218eb7SGabor Kovesdan 		/* parse extra arguments */
40059218eb7SGabor Kovesdan 		while ((str = strsep(&eopts, " ")) != NULL)
401dab19f30SGabor Kovesdan 			if (str[0] != '\0')
40259218eb7SGabor Kovesdan 				eargv[eargc++] = grep_strdup(str);
4034dc88ebeSGabor Kovesdan 
4040c41ffb3SXin LI 		aargv = (char **)grep_calloc(eargc + argc + 1,
4050c41ffb3SXin LI 		    sizeof(char *));
40659218eb7SGabor Kovesdan 
4074dc88ebeSGabor Kovesdan 		aargv[0] = argv[0];
40859218eb7SGabor Kovesdan 		for (i = 0; i < eargc; i++)
40959218eb7SGabor Kovesdan 			aargv[i + 1] = eargv[i];
41059218eb7SGabor Kovesdan 		for (int j = 1; j < argc; j++, i++)
41159218eb7SGabor Kovesdan 			aargv[i + 1] = argv[j];
4124dc88ebeSGabor Kovesdan 
41359218eb7SGabor Kovesdan 		aargc = eargc + argc;
4144dc88ebeSGabor Kovesdan 	} else {
4154dc88ebeSGabor Kovesdan 		aargv = argv;
4164dc88ebeSGabor Kovesdan 		aargc = argc;
4174dc88ebeSGabor Kovesdan 	}
4184dc88ebeSGabor Kovesdan 
4194dc88ebeSGabor Kovesdan 	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
4204dc88ebeSGabor Kovesdan 	    -1)) {
4214dc88ebeSGabor Kovesdan 		switch (c) {
4224dc88ebeSGabor Kovesdan 		case '0': case '1': case '2': case '3': case '4':
4234dc88ebeSGabor Kovesdan 		case '5': case '6': case '7': case '8': case '9':
4244dc88ebeSGabor Kovesdan 			if (newarg || !isdigit(lastc))
4254dc88ebeSGabor Kovesdan 				Aflag = 0;
426b5fc583cSEd Maste 			else if (Aflag > LLONG_MAX / 10 - 1) {
4274dc88ebeSGabor Kovesdan 				errno = ERANGE;
4284dc88ebeSGabor Kovesdan 				err(2, NULL);
4294dc88ebeSGabor Kovesdan 			}
430b5fc583cSEd Maste 
4314dc88ebeSGabor Kovesdan 			Aflag = Bflag = (Aflag * 10) + (c - '0');
4324dc88ebeSGabor Kovesdan 			break;
4334dc88ebeSGabor Kovesdan 		case 'C':
4344dc88ebeSGabor Kovesdan 			if (optarg == NULL) {
4354dc88ebeSGabor Kovesdan 				Aflag = Bflag = 2;
4364dc88ebeSGabor Kovesdan 				break;
4374dc88ebeSGabor Kovesdan 			}
4384dc88ebeSGabor Kovesdan 			/* FALLTHROUGH */
4394dc88ebeSGabor Kovesdan 		case 'A':
4404dc88ebeSGabor Kovesdan 			/* FALLTHROUGH */
4414dc88ebeSGabor Kovesdan 		case 'B':
4424dc88ebeSGabor Kovesdan 			errno = 0;
443b5fc583cSEd Maste 			l = strtoll(optarg, &ep, 10);
444b5fc583cSEd Maste 			if (errno == ERANGE || errno == EINVAL)
4454dc88ebeSGabor Kovesdan 				err(2, NULL);
4464dc88ebeSGabor Kovesdan 			else if (ep[0] != '\0') {
4474dc88ebeSGabor Kovesdan 				errno = EINVAL;
4484dc88ebeSGabor Kovesdan 				err(2, NULL);
449b5fc583cSEd Maste 			} else if (l < 0) {
450b5fc583cSEd Maste 				errno = EINVAL;
451b5fc583cSEd Maste 				err(2, "context argument must be non-negative");
4524dc88ebeSGabor Kovesdan 			}
453b5fc583cSEd Maste 
4544dc88ebeSGabor Kovesdan 			if (c == 'A')
4554dc88ebeSGabor Kovesdan 				Aflag = l;
4564dc88ebeSGabor Kovesdan 			else if (c == 'B')
4574dc88ebeSGabor Kovesdan 				Bflag = l;
4584dc88ebeSGabor Kovesdan 			else
4594dc88ebeSGabor Kovesdan 				Aflag = Bflag = l;
4604dc88ebeSGabor Kovesdan 			break;
4614dc88ebeSGabor Kovesdan 		case 'a':
4624dc88ebeSGabor Kovesdan 			binbehave = BINFILE_TEXT;
4634dc88ebeSGabor Kovesdan 			break;
4644dc88ebeSGabor Kovesdan 		case 'b':
4654dc88ebeSGabor Kovesdan 			bflag = true;
4664dc88ebeSGabor Kovesdan 			break;
4674dc88ebeSGabor Kovesdan 		case 'c':
4684dc88ebeSGabor Kovesdan 			cflag = true;
4694dc88ebeSGabor Kovesdan 			break;
4704dc88ebeSGabor Kovesdan 		case 'D':
47127116286SGabor Kovesdan 			if (strcasecmp(optarg, "skip") == 0)
4724dc88ebeSGabor Kovesdan 				devbehave = DEV_SKIP;
47327116286SGabor Kovesdan 			else if (strcasecmp(optarg, "read") == 0)
47427116286SGabor Kovesdan 				devbehave = DEV_READ;
47597a012f2SGabor Kovesdan 			else
4764a5b4207SBaptiste Daroussin 				errx(2, getstr(2), "--devices");
4774dc88ebeSGabor Kovesdan 			break;
4784dc88ebeSGabor Kovesdan 		case 'd':
47927116286SGabor Kovesdan 			if (strcasecmp("recurse", optarg) == 0) {
4804dc88ebeSGabor Kovesdan 				Hflag = true;
4814dc88ebeSGabor Kovesdan 				dirbehave = DIR_RECURSE;
48227116286SGabor Kovesdan 			} else if (strcasecmp("skip", optarg) == 0)
4834dc88ebeSGabor Kovesdan 				dirbehave = DIR_SKIP;
48427116286SGabor Kovesdan 			else if (strcasecmp("read", optarg) == 0)
48527116286SGabor Kovesdan 				dirbehave = DIR_READ;
48697a012f2SGabor Kovesdan 			else
4874a5b4207SBaptiste Daroussin 				errx(2, getstr(2), "--directories");
4884dc88ebeSGabor Kovesdan 			break;
4894dc88ebeSGabor Kovesdan 		case 'E':
4904dc88ebeSGabor Kovesdan 			grepbehave = GREP_EXTENDED;
4914dc88ebeSGabor Kovesdan 			break;
4924dc88ebeSGabor Kovesdan 		case 'e':
493e411593dSGabor Kovesdan 			{
494e411593dSGabor Kovesdan 				char *token;
495cd64c588SGabor Kovesdan 				char *string = optarg;
496e411593dSGabor Kovesdan 
497e411593dSGabor Kovesdan 				while ((token = strsep(&string, "\n")) != NULL)
498e411593dSGabor Kovesdan 					add_pattern(token, strlen(token));
499e411593dSGabor Kovesdan 			}
5004dc88ebeSGabor Kovesdan 			needpattern = 0;
5014dc88ebeSGabor Kovesdan 			break;
5024dc88ebeSGabor Kovesdan 		case 'F':
5034dc88ebeSGabor Kovesdan 			grepbehave = GREP_FIXED;
5044dc88ebeSGabor Kovesdan 			break;
5054dc88ebeSGabor Kovesdan 		case 'f':
5064dc88ebeSGabor Kovesdan 			read_patterns(optarg);
5074dc88ebeSGabor Kovesdan 			needpattern = 0;
5084dc88ebeSGabor Kovesdan 			break;
5094dc88ebeSGabor Kovesdan 		case 'G':
5104dc88ebeSGabor Kovesdan 			grepbehave = GREP_BASIC;
5114dc88ebeSGabor Kovesdan 			break;
5124dc88ebeSGabor Kovesdan 		case 'H':
5134dc88ebeSGabor Kovesdan 			Hflag = true;
5144dc88ebeSGabor Kovesdan 			break;
5154dc88ebeSGabor Kovesdan 		case 'h':
5164dc88ebeSGabor Kovesdan 			Hflag = false;
5174dc88ebeSGabor Kovesdan 			hflag = true;
5184dc88ebeSGabor Kovesdan 			break;
5194dc88ebeSGabor Kovesdan 		case 'I':
5204dc88ebeSGabor Kovesdan 			binbehave = BINFILE_SKIP;
5214dc88ebeSGabor Kovesdan 			break;
5224dc88ebeSGabor Kovesdan 		case 'i':
5234dc88ebeSGabor Kovesdan 		case 'y':
5244dc88ebeSGabor Kovesdan 			iflag =  true;
5254dc88ebeSGabor Kovesdan 			cflags |= REG_ICASE;
5264dc88ebeSGabor Kovesdan 			break;
5274dc88ebeSGabor Kovesdan 		case 'L':
5284dc88ebeSGabor Kovesdan 			lflag = false;
52927116286SGabor Kovesdan 			Lflag = true;
5304dc88ebeSGabor Kovesdan 			break;
5314dc88ebeSGabor Kovesdan 		case 'l':
5324dc88ebeSGabor Kovesdan 			Lflag = false;
53327116286SGabor Kovesdan 			lflag = true;
5344dc88ebeSGabor Kovesdan 			break;
5354dc88ebeSGabor Kovesdan 		case 'm':
5364dc88ebeSGabor Kovesdan 			mflag = true;
5374dc88ebeSGabor Kovesdan 			errno = 0;
538924500b7SEitan Adler 			mlimit = mcount = strtoll(optarg, &ep, 10);
539f20f6f3fSGabor Kovesdan 			if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
5404dc88ebeSGabor Kovesdan 			    ((errno == EINVAL) && (mcount == 0)))
5414dc88ebeSGabor Kovesdan 				err(2, NULL);
5424dc88ebeSGabor Kovesdan 			else if (ep[0] != '\0') {
5434dc88ebeSGabor Kovesdan 				errno = EINVAL;
5444dc88ebeSGabor Kovesdan 				err(2, NULL);
5454dc88ebeSGabor Kovesdan 			}
5464dc88ebeSGabor Kovesdan 			break;
5474dc88ebeSGabor Kovesdan 		case 'n':
5484dc88ebeSGabor Kovesdan 			nflag = true;
5494dc88ebeSGabor Kovesdan 			break;
5504dc88ebeSGabor Kovesdan 		case 'O':
5514dc88ebeSGabor Kovesdan 			linkbehave = LINK_EXPLICIT;
5524dc88ebeSGabor Kovesdan 			break;
5534dc88ebeSGabor Kovesdan 		case 'o':
5544dc88ebeSGabor Kovesdan 			oflag = true;
55569a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
5564dc88ebeSGabor Kovesdan 			break;
5574dc88ebeSGabor Kovesdan 		case 'p':
5584dc88ebeSGabor Kovesdan 			linkbehave = LINK_SKIP;
5594dc88ebeSGabor Kovesdan 			break;
5604dc88ebeSGabor Kovesdan 		case 'q':
5614dc88ebeSGabor Kovesdan 			qflag = true;
5624dc88ebeSGabor Kovesdan 			break;
5634dc88ebeSGabor Kovesdan 		case 'S':
56427116286SGabor Kovesdan 			linkbehave = LINK_READ;
5654dc88ebeSGabor Kovesdan 			break;
5664dc88ebeSGabor Kovesdan 		case 'R':
5674dc88ebeSGabor Kovesdan 		case 'r':
5684dc88ebeSGabor Kovesdan 			dirbehave = DIR_RECURSE;
5694dc88ebeSGabor Kovesdan 			Hflag = true;
5704dc88ebeSGabor Kovesdan 			break;
5714dc88ebeSGabor Kovesdan 		case 's':
5724dc88ebeSGabor Kovesdan 			sflag = true;
5734dc88ebeSGabor Kovesdan 			break;
5744dc88ebeSGabor Kovesdan 		case 'U':
5754dc88ebeSGabor Kovesdan 			binbehave = BINFILE_BIN;
5764dc88ebeSGabor Kovesdan 			break;
5774dc88ebeSGabor Kovesdan 		case 'u':
5784dc88ebeSGabor Kovesdan 		case MMAP_OPT:
579f20f6f3fSGabor Kovesdan 			filebehave = FILE_MMAP;
5804dc88ebeSGabor Kovesdan 			break;
5814dc88ebeSGabor Kovesdan 		case 'V':
582cc41ba26SEd Maste #ifdef WITH_GNU
583afbbd357SGabor Kovesdan 			printf(getstr(9), getprogname(), VERSION);
5844a5b4207SBaptiste Daroussin #else
5854a5b4207SBaptiste Daroussin 			printf(getstr(8), getprogname(), VERSION);
586cc41ba26SEd Maste #endif
5874dc88ebeSGabor Kovesdan 			exit(0);
5884dc88ebeSGabor Kovesdan 		case 'v':
5894dc88ebeSGabor Kovesdan 			vflag = true;
5904dc88ebeSGabor Kovesdan 			break;
5914dc88ebeSGabor Kovesdan 		case 'w':
5924dc88ebeSGabor Kovesdan 			wflag = true;
59369a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
5944dc88ebeSGabor Kovesdan 			break;
5954dc88ebeSGabor Kovesdan 		case 'x':
5964dc88ebeSGabor Kovesdan 			xflag = true;
59769a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
5984dc88ebeSGabor Kovesdan 			break;
5995ee1ea02SEd Maste 		case 'z':
6005ee1ea02SEd Maste 			fileeol = '\0';
6015ee1ea02SEd Maste 			break;
6024dc88ebeSGabor Kovesdan 		case BIN_OPT:
60327116286SGabor Kovesdan 			if (strcasecmp("binary", optarg) == 0)
6044dc88ebeSGabor Kovesdan 				binbehave = BINFILE_BIN;
60527116286SGabor Kovesdan 			else if (strcasecmp("without-match", optarg) == 0)
6064dc88ebeSGabor Kovesdan 				binbehave = BINFILE_SKIP;
60727116286SGabor Kovesdan 			else if (strcasecmp("text", optarg) == 0)
6084dc88ebeSGabor Kovesdan 				binbehave = BINFILE_TEXT;
6094dc88ebeSGabor Kovesdan 			else
6104a5b4207SBaptiste Daroussin 				errx(2, getstr(2), "--binary-files");
6114dc88ebeSGabor Kovesdan 			break;
6124dc88ebeSGabor Kovesdan 		case COLOR_OPT:
6134dc88ebeSGabor Kovesdan 			color = NULL;
61427116286SGabor Kovesdan 			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
61527116286SGabor Kovesdan 			    strcasecmp("tty", optarg) == 0 ||
61627116286SGabor Kovesdan 			    strcasecmp("if-tty", optarg) == 0) {
61727116286SGabor Kovesdan 				char *term;
61827116286SGabor Kovesdan 
61927116286SGabor Kovesdan 				term = getenv("TERM");
62027116286SGabor Kovesdan 				if (isatty(STDOUT_FILENO) && term != NULL &&
62127116286SGabor Kovesdan 				    strcasecmp(term, "dumb") != 0)
62227116286SGabor Kovesdan 					color = init_color("01;31");
62327116286SGabor Kovesdan 			} else if (strcasecmp("always", optarg) == 0 ||
62427116286SGabor Kovesdan 			    strcasecmp("yes", optarg) == 0 ||
62527116286SGabor Kovesdan 			    strcasecmp("force", optarg) == 0) {
62627116286SGabor Kovesdan 				color = init_color("01;31");
62727116286SGabor Kovesdan 			} else if (strcasecmp("never", optarg) != 0 &&
62827116286SGabor Kovesdan 			    strcasecmp("none", optarg) != 0 &&
62927116286SGabor Kovesdan 			    strcasecmp("no", optarg) != 0)
6304a5b4207SBaptiste Daroussin 				errx(2, getstr(2), "--color");
63169a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
6324dc88ebeSGabor Kovesdan 			break;
6334dc88ebeSGabor Kovesdan 		case LABEL_OPT:
6344dc88ebeSGabor Kovesdan 			label = optarg;
6354dc88ebeSGabor Kovesdan 			break;
6364dc88ebeSGabor Kovesdan 		case LINEBUF_OPT:
6374dc88ebeSGabor Kovesdan 			lbflag = true;
6384dc88ebeSGabor Kovesdan 			break;
6394dc88ebeSGabor Kovesdan 		case NULL_OPT:
6404dc88ebeSGabor Kovesdan 			nullflag = true;
6414dc88ebeSGabor Kovesdan 			break;
6424dc88ebeSGabor Kovesdan 		case R_INCLUDE_OPT:
64355e44f51SGabor Kovesdan 			finclude = true;
64455e44f51SGabor Kovesdan 			add_fpattern(optarg, INCL_PAT);
6454dc88ebeSGabor Kovesdan 			break;
6464dc88ebeSGabor Kovesdan 		case R_EXCLUDE_OPT:
64755e44f51SGabor Kovesdan 			fexclude = true;
64855e44f51SGabor Kovesdan 			add_fpattern(optarg, EXCL_PAT);
6494dc88ebeSGabor Kovesdan 			break;
6504dc88ebeSGabor Kovesdan 		case R_DINCLUDE_OPT:
65159218eb7SGabor Kovesdan 			dinclude = true;
65255e44f51SGabor Kovesdan 			add_dpattern(optarg, INCL_PAT);
6534dc88ebeSGabor Kovesdan 			break;
6544dc88ebeSGabor Kovesdan 		case R_DEXCLUDE_OPT:
65559218eb7SGabor Kovesdan 			dexclude = true;
65655e44f51SGabor Kovesdan 			add_dpattern(optarg, EXCL_PAT);
6574dc88ebeSGabor Kovesdan 			break;
6584dc88ebeSGabor Kovesdan 		case HELP_OPT:
6594dc88ebeSGabor Kovesdan 		default:
6604dc88ebeSGabor Kovesdan 			usage();
6614dc88ebeSGabor Kovesdan 		}
6624dc88ebeSGabor Kovesdan 		lastc = c;
6634dc88ebeSGabor Kovesdan 		newarg = optind != prevoptind;
6644dc88ebeSGabor Kovesdan 		prevoptind = optind;
6654dc88ebeSGabor Kovesdan 	}
6664dc88ebeSGabor Kovesdan 	aargc -= optind;
6674dc88ebeSGabor Kovesdan 	aargv += optind;
6684dc88ebeSGabor Kovesdan 
669f20f6f3fSGabor Kovesdan 	/* Empty pattern file matches nothing */
670f20f6f3fSGabor Kovesdan 	if (!needpattern && (patterns == 0))
671f20f6f3fSGabor Kovesdan 		exit(1);
672f20f6f3fSGabor Kovesdan 
6734dc88ebeSGabor Kovesdan 	/* Fail if we don't have any pattern */
6744dc88ebeSGabor Kovesdan 	if (aargc == 0 && needpattern)
6754dc88ebeSGabor Kovesdan 		usage();
6764dc88ebeSGabor Kovesdan 
6774dc88ebeSGabor Kovesdan 	/* Process patterns from command line */
6784dc88ebeSGabor Kovesdan 	if (aargc != 0 && needpattern) {
679e411593dSGabor Kovesdan 		char *token;
680cd64c588SGabor Kovesdan 		char *string = *aargv;
681e411593dSGabor Kovesdan 
682e411593dSGabor Kovesdan 		while ((token = strsep(&string, "\n")) != NULL)
683e411593dSGabor Kovesdan 			add_pattern(token, strlen(token));
6844dc88ebeSGabor Kovesdan 		--aargc;
6854dc88ebeSGabor Kovesdan 		++aargv;
6864dc88ebeSGabor Kovesdan 	}
6874dc88ebeSGabor Kovesdan 
6884dc88ebeSGabor Kovesdan 	switch (grepbehave) {
6894dc88ebeSGabor Kovesdan 	case GREP_BASIC:
6904dc88ebeSGabor Kovesdan 		break;
691f20f6f3fSGabor Kovesdan 	case GREP_FIXED:
69205ad8215SKyle Evans 		/*
69305ad8215SKyle Evans 		 * regex(3) implementations that support fixed-string searches generally
69405ad8215SKyle Evans 		 * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
69505ad8215SKyle Evans 		 * here. If neither are defined, GREP_FIXED later implies that the
69605ad8215SKyle Evans 		 * internal literal matcher should be used. Other cflags that have
69705ad8215SKyle Evans 		 * the same interpretation as REG_NOSPEC and REG_LITERAL should be
69805ad8215SKyle Evans 		 * similarly added here, and grep.h should be amended to take this into
69905ad8215SKyle Evans 		 * consideration when defining WITH_INTERNAL_NOSPEC.
70005ad8215SKyle Evans 		 */
701476d2098SEd Maste #if defined(REG_NOSPEC)
702476d2098SEd Maste 		cflags |= REG_NOSPEC;
703476d2098SEd Maste #elif defined(REG_LITERAL)
704476d2098SEd Maste 		cflags |= REG_LITERAL;
705476d2098SEd Maste #endif
706f20f6f3fSGabor Kovesdan 		break;
7074dc88ebeSGabor Kovesdan 	case GREP_EXTENDED:
7084dc88ebeSGabor Kovesdan 		cflags |= REG_EXTENDED;
7094dc88ebeSGabor Kovesdan 		break;
7104dc88ebeSGabor Kovesdan 	default:
7114dc88ebeSGabor Kovesdan 		/* NOTREACHED */
7124dc88ebeSGabor Kovesdan 		usage();
7134dc88ebeSGabor Kovesdan 	}
7144dc88ebeSGabor Kovesdan 
7153f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH
7164dc88ebeSGabor Kovesdan 	fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
7173f39ffc8SEd Maste #endif
7184dc88ebeSGabor Kovesdan 	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
719f20f6f3fSGabor Kovesdan 
720a4f3f02bSEd Maste 	/* Don't process any patterns if we have a blank one */
72105ad8215SKyle Evans #ifdef WITH_INTERNAL_NOSPEC
72205ad8215SKyle Evans 	if (!matchall && grepbehave != GREP_FIXED) {
72305ad8215SKyle Evans #else
724a4f3f02bSEd Maste 	if (!matchall) {
72505ad8215SKyle Evans #endif
7264dc88ebeSGabor Kovesdan 		/* Check if cheating is allowed (always is for fgrep). */
7274dc88ebeSGabor Kovesdan 		for (i = 0; i < patterns; ++i) {
7283f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH
729a4f3f02bSEd Maste 			/*
730a4f3f02bSEd Maste 			 * Attempt compilation with fastmatch regex and
731a4f3f02bSEd Maste 			 * fallback to regex(3) if it fails.
732a4f3f02bSEd Maste 			 */
733f20f6f3fSGabor Kovesdan 			if (fastncomp(&fg_pattern[i], pattern[i].pat,
7343f39ffc8SEd Maste 			    pattern[i].len, cflags) == 0)
7353f39ffc8SEd Maste 				continue;
7363f39ffc8SEd Maste #endif
737f20f6f3fSGabor Kovesdan 			c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
7384dc88ebeSGabor Kovesdan 			if (c != 0) {
7394dc88ebeSGabor Kovesdan 				regerror(c, &r_pattern[i], re_error,
7404dc88ebeSGabor Kovesdan 				    RE_ERROR_BUF);
7414dc88ebeSGabor Kovesdan 				errx(2, "%s", re_error);
7424dc88ebeSGabor Kovesdan 			}
7434dc88ebeSGabor Kovesdan 		}
744a4f3f02bSEd Maste 	}
7454dc88ebeSGabor Kovesdan 
7464dc88ebeSGabor Kovesdan 	if (lbflag)
7474dc88ebeSGabor Kovesdan 		setlinebuf(stdout);
7484dc88ebeSGabor Kovesdan 
7494dc88ebeSGabor Kovesdan 	if ((aargc == 0 || aargc == 1) && !Hflag)
7504dc88ebeSGabor Kovesdan 		hflag = true;
7514dc88ebeSGabor Kovesdan 
752a461896aSEd Maste 	if (aargc == 0 && dirbehave != DIR_RECURSE)
7534dc88ebeSGabor Kovesdan 		exit(!procfile("-"));
7544dc88ebeSGabor Kovesdan 
7554dc88ebeSGabor Kovesdan 	if (dirbehave == DIR_RECURSE)
7564dc88ebeSGabor Kovesdan 		c = grep_tree(aargv);
757c38208adSXin LI 	else
75855e44f51SGabor Kovesdan 		for (c = 0; aargc--; ++aargv) {
75955e44f51SGabor Kovesdan 			if ((finclude || fexclude) && !file_matching(*aargv))
76055e44f51SGabor Kovesdan 				continue;
7614dc88ebeSGabor Kovesdan 			c+= procfile(*aargv);
76255e44f51SGabor Kovesdan 		}
7634dc88ebeSGabor Kovesdan 
7644dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS
7654dc88ebeSGabor Kovesdan 	catclose(catalog);
7664dc88ebeSGabor Kovesdan #endif
7674dc88ebeSGabor Kovesdan 
7684dc88ebeSGabor Kovesdan 	/* Find out the correct return value according to the
7694dc88ebeSGabor Kovesdan 	   results and the command line option. */
7706f4cbf7cSGabor Kovesdan 	exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
7714dc88ebeSGabor Kovesdan }
772