xref: /freebsd/usr.bin/grep/grep.c (revision 7c2f310f6dd8cf0ed249933eea7c643f2c311745)
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 
544dc88ebeSGabor Kovesdan #include "grep.h"
554dc88ebeSGabor Kovesdan 
564dc88ebeSGabor Kovesdan const char	*errstr[] = {
574dc88ebeSGabor Kovesdan 	"",
584dc88ebeSGabor Kovesdan /* 1*/	"(standard input)",
59a1852807SKyle Evans /* 2*/	"unknown %s option",
60a1852807SKyle Evans /* 3*/	"usage: %s [-abcDEFGHhIiLlmnOoPqRSsUVvwxz] [-A num] [-B num] [-C[num]]\n",
61a1852807SKyle Evans /* 4*/	"\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
62a1852807SKyle Evans /* 5*/	"\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
63a1852807SKyle Evans /* 6*/	"\t[--null] [pattern] [file ...]\n",
64a1852807SKyle Evans /* 7*/	"Binary file %s matches\n",
65*7c2f310fSKyle Evans /* 8*/	"%s (BSD grep, GNU compatible) %s\n",
664dc88ebeSGabor Kovesdan };
674dc88ebeSGabor Kovesdan 
684dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */
698bf46064SEd Maste int		 cflags = REG_NOSUB | REG_NEWLINE;
704dc88ebeSGabor Kovesdan int		 eflags = REG_STARTEND;
714dc88ebeSGabor Kovesdan 
72a4f3f02bSEd Maste /* XXX TODO: Get rid of this flag.
73a4f3f02bSEd Maste  * matchall is a gross hack that means that an empty pattern was passed to us.
74a4f3f02bSEd Maste  * It is a necessary evil at the moment because our regex(3) implementation
75a4f3f02bSEd Maste  * does not allow for empty patterns, as supported by POSIX's definition of
76a4f3f02bSEd Maste  * grammar for BREs/EREs. When libregex becomes available, it would be wise
77a4f3f02bSEd Maste  * to remove this and let regex(3) handle the dirty details of empty patterns.
78a4f3f02bSEd Maste  */
794dc88ebeSGabor Kovesdan bool		 matchall;
804dc88ebeSGabor Kovesdan 
814dc88ebeSGabor Kovesdan /* Searching patterns */
82bf70beceSEd Schouten unsigned int	 patterns;
83bf70beceSEd Schouten static unsigned int pattern_sz;
84f20f6f3fSGabor Kovesdan struct pat	*pattern;
854dc88ebeSGabor Kovesdan regex_t		*r_pattern;
864dc88ebeSGabor Kovesdan 
874dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */
88bf70beceSEd Schouten unsigned int	fpatterns, dpatterns;
89bf70beceSEd Schouten static unsigned int fpattern_sz, dpattern_sz;
9055e44f51SGabor Kovesdan struct epat	*dpattern, *fpattern;
914dc88ebeSGabor Kovesdan 
924dc88ebeSGabor Kovesdan /* For regex errors  */
934dc88ebeSGabor Kovesdan char	 re_error[RE_ERROR_BUF + 1];
944dc88ebeSGabor Kovesdan 
954dc88ebeSGabor Kovesdan /* Command-line flags */
96b5fc583cSEd Maste long long Aflag;	/* -A x: print x lines trailing each match */
97b5fc583cSEd Maste long long Bflag;	/* -B x: print x lines leading each match */
984dc88ebeSGabor Kovesdan bool	 Hflag;		/* -H: always print file name */
994dc88ebeSGabor Kovesdan bool	 Lflag;		/* -L: only show names of files with no matches */
1004dc88ebeSGabor Kovesdan bool	 bflag;		/* -b: show block numbers for each match */
1014dc88ebeSGabor Kovesdan bool	 cflag;		/* -c: only show a count of matching lines */
1024dc88ebeSGabor Kovesdan bool	 hflag;		/* -h: don't print filename headers */
1034dc88ebeSGabor Kovesdan bool	 iflag;		/* -i: ignore case */
1044dc88ebeSGabor Kovesdan bool	 lflag;		/* -l: only show names of files with matches */
1054dc88ebeSGabor Kovesdan bool	 mflag;		/* -m x: stop reading the files after x matches */
106f20f6f3fSGabor Kovesdan long long mcount;	/* count for -m */
107924500b7SEitan Adler long long mlimit;	/* requested value for -m */
1085ee1ea02SEd Maste char	 fileeol;	/* indicator for eol */
1094dc88ebeSGabor Kovesdan bool	 nflag;		/* -n: show line numbers in front of matching lines */
1104dc88ebeSGabor Kovesdan bool	 oflag;		/* -o: print only matching part */
1114dc88ebeSGabor Kovesdan bool	 qflag;		/* -q: quiet mode (don't output anything) */
1124dc88ebeSGabor Kovesdan bool	 sflag;		/* -s: silent mode (ignore errors) */
1134dc88ebeSGabor Kovesdan bool	 vflag;		/* -v: only show non-matching lines */
1144dc88ebeSGabor Kovesdan bool	 wflag;		/* -w: pattern must start and end on word boundaries */
1154dc88ebeSGabor Kovesdan bool	 xflag;		/* -x: pattern must match entire line */
1164dc88ebeSGabor Kovesdan bool	 lbflag;	/* --line-buffered */
1174dc88ebeSGabor Kovesdan bool	 nullflag;	/* --null */
1184dc88ebeSGabor Kovesdan char	*label;		/* --label */
11927116286SGabor Kovesdan const char *color;	/* --color */
1204dc88ebeSGabor Kovesdan int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
1214dc88ebeSGabor Kovesdan int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
1224a5b4207SBaptiste Daroussin int	 filebehave = FILE_STDIO;
12327116286SGabor Kovesdan int	 devbehave = DEV_READ;		/* -D: handling of devices */
12427116286SGabor Kovesdan int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
12527116286SGabor Kovesdan int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
1264dc88ebeSGabor Kovesdan 
12759218eb7SGabor Kovesdan bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
12859218eb7SGabor Kovesdan bool	 fexclude, finclude;	/* --exclude and --include */
12955e44f51SGabor Kovesdan 
1304dc88ebeSGabor Kovesdan enum {
1314dc88ebeSGabor Kovesdan 	BIN_OPT = CHAR_MAX + 1,
1324dc88ebeSGabor Kovesdan 	COLOR_OPT,
1334dc88ebeSGabor Kovesdan 	HELP_OPT,
1344dc88ebeSGabor Kovesdan 	MMAP_OPT,
1354dc88ebeSGabor Kovesdan 	LINEBUF_OPT,
1364dc88ebeSGabor Kovesdan 	LABEL_OPT,
1374dc88ebeSGabor Kovesdan 	NULL_OPT,
1384dc88ebeSGabor Kovesdan 	R_EXCLUDE_OPT,
1394dc88ebeSGabor Kovesdan 	R_INCLUDE_OPT,
1404dc88ebeSGabor Kovesdan 	R_DEXCLUDE_OPT,
1414dc88ebeSGabor Kovesdan 	R_DINCLUDE_OPT
1424dc88ebeSGabor Kovesdan };
1434dc88ebeSGabor Kovesdan 
14427116286SGabor Kovesdan static inline const char	*init_color(const char *);
14527116286SGabor Kovesdan 
1464dc88ebeSGabor Kovesdan /* Housekeeping */
1476f4cbf7cSGabor Kovesdan bool	 file_err;	/* file reading error */
1484dc88ebeSGabor Kovesdan 
1494dc88ebeSGabor Kovesdan /*
1504dc88ebeSGabor Kovesdan  * Prints usage information and returns 2.
1514dc88ebeSGabor Kovesdan  */
1524dc88ebeSGabor Kovesdan static void
1534dc88ebeSGabor Kovesdan usage(void)
1544dc88ebeSGabor Kovesdan {
15530dc9502SBaptiste Daroussin 	fprintf(stderr, errstr[3], getprogname());
15630dc9502SBaptiste Daroussin 	fprintf(stderr, "%s", errstr[4]);
15730dc9502SBaptiste Daroussin 	fprintf(stderr, "%s", errstr[5]);
15830dc9502SBaptiste Daroussin 	fprintf(stderr, "%s", errstr[6]);
1594dc88ebeSGabor Kovesdan 	exit(2);
1604dc88ebeSGabor Kovesdan }
1614dc88ebeSGabor Kovesdan 
1624a5b4207SBaptiste Daroussin static const char	*optstr = "0123456789A:B:C:D:EFGHILOPSRUVabcd:e:f:hilm:nopqrsuvwxyz";
1634dc88ebeSGabor Kovesdan 
1648375d512SEd Schouten static const struct option long_options[] =
1654dc88ebeSGabor Kovesdan {
1664dc88ebeSGabor Kovesdan 	{"binary-files",	required_argument,	NULL, BIN_OPT},
1674dc88ebeSGabor Kovesdan 	{"help",		no_argument,		NULL, HELP_OPT},
1684dc88ebeSGabor Kovesdan 	{"mmap",		no_argument,		NULL, MMAP_OPT},
1694dc88ebeSGabor Kovesdan 	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
1704dc88ebeSGabor Kovesdan 	{"label",		required_argument,	NULL, LABEL_OPT},
1714dc88ebeSGabor Kovesdan 	{"null",		no_argument,		NULL, NULL_OPT},
1724dc88ebeSGabor Kovesdan 	{"color",		optional_argument,	NULL, COLOR_OPT},
1734dc88ebeSGabor Kovesdan 	{"colour",		optional_argument,	NULL, COLOR_OPT},
1744dc88ebeSGabor Kovesdan 	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
1754dc88ebeSGabor Kovesdan 	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
1764dc88ebeSGabor Kovesdan 	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
1774dc88ebeSGabor Kovesdan 	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
1784dc88ebeSGabor Kovesdan 	{"after-context",	required_argument,	NULL, 'A'},
1794dc88ebeSGabor Kovesdan 	{"text",		no_argument,		NULL, 'a'},
1804dc88ebeSGabor Kovesdan 	{"before-context",	required_argument,	NULL, 'B'},
1814dc88ebeSGabor Kovesdan 	{"byte-offset",		no_argument,		NULL, 'b'},
1824dc88ebeSGabor Kovesdan 	{"context",		optional_argument,	NULL, 'C'},
1834dc88ebeSGabor Kovesdan 	{"count",		no_argument,		NULL, 'c'},
1844dc88ebeSGabor Kovesdan 	{"devices",		required_argument,	NULL, 'D'},
1854dc88ebeSGabor Kovesdan         {"directories",		required_argument,	NULL, 'd'},
1864dc88ebeSGabor Kovesdan 	{"extended-regexp",	no_argument,		NULL, 'E'},
1874dc88ebeSGabor Kovesdan 	{"regexp",		required_argument,	NULL, 'e'},
1884dc88ebeSGabor Kovesdan 	{"fixed-strings",	no_argument,		NULL, 'F'},
1894dc88ebeSGabor Kovesdan 	{"file",		required_argument,	NULL, 'f'},
1904dc88ebeSGabor Kovesdan 	{"basic-regexp",	no_argument,		NULL, 'G'},
1914dc88ebeSGabor Kovesdan 	{"no-filename",		no_argument,		NULL, 'h'},
1924dc88ebeSGabor Kovesdan 	{"with-filename",	no_argument,		NULL, 'H'},
1934dc88ebeSGabor Kovesdan 	{"ignore-case",		no_argument,		NULL, 'i'},
1944dc88ebeSGabor Kovesdan 	{"files-with-matches",	no_argument,		NULL, 'l'},
1954dc88ebeSGabor Kovesdan 	{"files-without-match", no_argument,            NULL, 'L'},
1964dc88ebeSGabor Kovesdan 	{"max-count",		required_argument,	NULL, 'm'},
1974dc88ebeSGabor Kovesdan 	{"line-number",		no_argument,		NULL, 'n'},
1984dc88ebeSGabor Kovesdan 	{"only-matching",	no_argument,		NULL, 'o'},
1994dc88ebeSGabor Kovesdan 	{"quiet",		no_argument,		NULL, 'q'},
2004dc88ebeSGabor Kovesdan 	{"silent",		no_argument,		NULL, 'q'},
2014dc88ebeSGabor Kovesdan 	{"recursive",		no_argument,		NULL, 'r'},
2024dc88ebeSGabor Kovesdan 	{"no-messages",		no_argument,		NULL, 's'},
2034dc88ebeSGabor Kovesdan 	{"binary",		no_argument,		NULL, 'U'},
2044dc88ebeSGabor Kovesdan 	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
2054dc88ebeSGabor Kovesdan 	{"invert-match",	no_argument,		NULL, 'v'},
2064dc88ebeSGabor Kovesdan 	{"version",		no_argument,		NULL, 'V'},
2074dc88ebeSGabor Kovesdan 	{"word-regexp",		no_argument,		NULL, 'w'},
2084dc88ebeSGabor Kovesdan 	{"line-regexp",		no_argument,		NULL, 'x'},
2095ee1ea02SEd Maste 	{"null-data",		no_argument,		NULL, 'z'},
2104dc88ebeSGabor Kovesdan 	{NULL,			no_argument,		NULL, 0}
2114dc88ebeSGabor Kovesdan };
2124dc88ebeSGabor Kovesdan 
2134dc88ebeSGabor Kovesdan /*
2144dc88ebeSGabor Kovesdan  * Adds a searching pattern to the internal array.
2154dc88ebeSGabor Kovesdan  */
2164dc88ebeSGabor Kovesdan static void
2174dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len)
2184dc88ebeSGabor Kovesdan {
2194dc88ebeSGabor Kovesdan 
2204dc88ebeSGabor Kovesdan 	/* Check if we can do a shortcut */
221f20f6f3fSGabor Kovesdan 	if (len == 0) {
2224dc88ebeSGabor Kovesdan 		matchall = true;
2234dc88ebeSGabor Kovesdan 		return;
2244dc88ebeSGabor Kovesdan 	}
2254dc88ebeSGabor Kovesdan 	/* Increase size if necessary */
2264dc88ebeSGabor Kovesdan 	if (patterns == pattern_sz) {
2274dc88ebeSGabor Kovesdan 		pattern_sz *= 2;
2284dc88ebeSGabor Kovesdan 		pattern = grep_realloc(pattern, ++pattern_sz *
229f20f6f3fSGabor Kovesdan 		    sizeof(struct pat));
2304dc88ebeSGabor Kovesdan 	}
2314dc88ebeSGabor Kovesdan 	if (len > 0 && pat[len - 1] == '\n')
2324dc88ebeSGabor Kovesdan 		--len;
2334dc88ebeSGabor Kovesdan 	/* pat may not be NUL-terminated */
234f20f6f3fSGabor Kovesdan 	pattern[patterns].pat = grep_malloc(len + 1);
235f20f6f3fSGabor Kovesdan 	memcpy(pattern[patterns].pat, pat, len);
236f20f6f3fSGabor Kovesdan 	pattern[patterns].len = len;
237f20f6f3fSGabor Kovesdan 	pattern[patterns].pat[len] = '\0';
2384dc88ebeSGabor Kovesdan 	++patterns;
2394dc88ebeSGabor Kovesdan }
2404dc88ebeSGabor Kovesdan 
2414dc88ebeSGabor Kovesdan /*
24255e44f51SGabor Kovesdan  * Adds a file include/exclude pattern to the internal array.
2434dc88ebeSGabor Kovesdan  */
2444dc88ebeSGabor Kovesdan static void
24555e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode)
2464dc88ebeSGabor Kovesdan {
2474dc88ebeSGabor Kovesdan 
2484dc88ebeSGabor Kovesdan 	/* Increase size if necessary */
24955e44f51SGabor Kovesdan 	if (fpatterns == fpattern_sz) {
25055e44f51SGabor Kovesdan 		fpattern_sz *= 2;
25155e44f51SGabor Kovesdan 		fpattern = grep_realloc(fpattern, ++fpattern_sz *
2524dc88ebeSGabor Kovesdan 		    sizeof(struct epat));
2534dc88ebeSGabor Kovesdan 	}
25455e44f51SGabor Kovesdan 	fpattern[fpatterns].pat = grep_strdup(pat);
25555e44f51SGabor Kovesdan 	fpattern[fpatterns].mode = mode;
25655e44f51SGabor Kovesdan 	++fpatterns;
25755e44f51SGabor Kovesdan }
25855e44f51SGabor Kovesdan 
25955e44f51SGabor Kovesdan /*
26055e44f51SGabor Kovesdan  * Adds a directory include/exclude pattern to the internal array.
26155e44f51SGabor Kovesdan  */
26255e44f51SGabor Kovesdan static void
26355e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode)
26455e44f51SGabor Kovesdan {
26555e44f51SGabor Kovesdan 
26655e44f51SGabor Kovesdan 	/* Increase size if necessary */
26755e44f51SGabor Kovesdan 	if (dpatterns == dpattern_sz) {
26855e44f51SGabor Kovesdan 		dpattern_sz *= 2;
26955e44f51SGabor Kovesdan 		dpattern = grep_realloc(dpattern, ++dpattern_sz *
27055e44f51SGabor Kovesdan 		    sizeof(struct epat));
27155e44f51SGabor Kovesdan 	}
27255e44f51SGabor Kovesdan 	dpattern[dpatterns].pat = grep_strdup(pat);
27355e44f51SGabor Kovesdan 	dpattern[dpatterns].mode = mode;
27455e44f51SGabor Kovesdan 	++dpatterns;
2754dc88ebeSGabor Kovesdan }
2764dc88ebeSGabor Kovesdan 
2774dc88ebeSGabor Kovesdan /*
2784dc88ebeSGabor Kovesdan  * Reads searching patterns from a file and adds them with add_pattern().
2794dc88ebeSGabor Kovesdan  */
2804dc88ebeSGabor Kovesdan static void
2814dc88ebeSGabor Kovesdan read_patterns(const char *fn)
2824dc88ebeSGabor Kovesdan {
283f20f6f3fSGabor Kovesdan 	struct stat st;
2844dc88ebeSGabor Kovesdan 	FILE *f;
2854dc88ebeSGabor Kovesdan 	char *line;
2864dc88ebeSGabor Kovesdan 	size_t len;
287f3f50de6SPedro F. Giffuni 	ssize_t rlen;
2884dc88ebeSGabor Kovesdan 
28924a656c2SKyle Evans 	if (strcmp(fn, "-") == 0)
29024a656c2SKyle Evans 		f = stdin;
29124a656c2SKyle Evans 	else if ((f = fopen(fn, "r")) == NULL)
2924dc88ebeSGabor Kovesdan 		err(2, "%s", fn);
293f20f6f3fSGabor Kovesdan 	if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
294f20f6f3fSGabor Kovesdan 		fclose(f);
295f20f6f3fSGabor Kovesdan 		return;
296f20f6f3fSGabor Kovesdan 	}
297f3f50de6SPedro F. Giffuni 	len = 0;
298f3f50de6SPedro F. Giffuni 	line = NULL;
299d204af1eSEd Maste 	while ((rlen = getline(&line, &len, f)) != -1) {
300d204af1eSEd Maste 		if (line[0] == '\0')
301d204af1eSEd Maste 			continue;
3022fa7a2afSPedro F. Giffuni 		add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
303d204af1eSEd Maste 	}
304d204af1eSEd Maste 
305f3f50de6SPedro F. Giffuni 	free(line);
3064dc88ebeSGabor Kovesdan 	if (ferror(f))
3074dc88ebeSGabor Kovesdan 		err(2, "%s", fn);
30824a656c2SKyle Evans 	if (strcmp(fn, "-") != 0)
3094dc88ebeSGabor Kovesdan 		fclose(f);
3104dc88ebeSGabor Kovesdan }
3114dc88ebeSGabor Kovesdan 
31227116286SGabor Kovesdan static inline const char *
31327116286SGabor Kovesdan init_color(const char *d)
31427116286SGabor Kovesdan {
31527116286SGabor Kovesdan 	char *c;
31627116286SGabor Kovesdan 
31727116286SGabor Kovesdan 	c = getenv("GREP_COLOR");
318dab19f30SGabor Kovesdan 	return (c != NULL && c[0] != '\0' ? c : d);
31927116286SGabor Kovesdan }
32027116286SGabor Kovesdan 
3214dc88ebeSGabor Kovesdan int
3224dc88ebeSGabor Kovesdan main(int argc, char *argv[])
3234dc88ebeSGabor Kovesdan {
3244dc88ebeSGabor Kovesdan 	char **aargv, **eargv, *eopts;
325afbbd357SGabor Kovesdan 	char *ep;
326afbbd357SGabor Kovesdan 	const char *pn;
327b5fc583cSEd Maste 	long long l;
3284dc88ebeSGabor Kovesdan 	unsigned int aargc, eargc, i;
3294dc88ebeSGabor Kovesdan 	int c, lastc, needpattern, newarg, prevoptind;
330cbfff13fSKyle Evans 	bool matched;
3314dc88ebeSGabor Kovesdan 
3324dc88ebeSGabor Kovesdan 	setlocale(LC_ALL, "");
3334dc88ebeSGabor Kovesdan 
33425385eb3SKyle Evans 	/*
33525385eb3SKyle Evans 	 * Check how we've bene invoked to determine the behavior we should
33625385eb3SKyle Evans 	 * exhibit. In this way we can have all the functionalities in one
33725385eb3SKyle Evans 	 * binary without the need of scripting and using ugly hacks.
33825385eb3SKyle Evans 	 */
339afbbd357SGabor Kovesdan 	pn = getprogname();
340f20f6f3fSGabor Kovesdan 	switch (pn[0]) {
3414dc88ebeSGabor Kovesdan 	case 'e':
3424dc88ebeSGabor Kovesdan 		grepbehave = GREP_EXTENDED;
3434dc88ebeSGabor Kovesdan 		break;
3444dc88ebeSGabor Kovesdan 	case 'f':
3454dc88ebeSGabor Kovesdan 		grepbehave = GREP_FIXED;
3464dc88ebeSGabor Kovesdan 		break;
34725385eb3SKyle Evans 	case 'r':
34825385eb3SKyle Evans 		dirbehave = DIR_RECURSE;
34925385eb3SKyle Evans 		Hflag = true;
35025385eb3SKyle Evans 		break;
3514dc88ebeSGabor Kovesdan 	}
3524dc88ebeSGabor Kovesdan 
3534dc88ebeSGabor Kovesdan 	lastc = '\0';
3544dc88ebeSGabor Kovesdan 	newarg = 1;
3554dc88ebeSGabor Kovesdan 	prevoptind = 1;
3564dc88ebeSGabor Kovesdan 	needpattern = 1;
3575ee1ea02SEd Maste 	fileeol = '\n';
3584dc88ebeSGabor Kovesdan 
3594dc88ebeSGabor Kovesdan 	eopts = getenv("GREP_OPTIONS");
3604dc88ebeSGabor Kovesdan 
36159218eb7SGabor Kovesdan 	/* support for extra arguments in GREP_OPTIONS */
36259218eb7SGabor Kovesdan 	eargc = 0;
363dab19f30SGabor Kovesdan 	if (eopts != NULL && eopts[0] != '\0') {
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)
376dab19f30SGabor Kovesdan 			if (str[0] != '\0')
37759218eb7SGabor Kovesdan 				eargv[eargc++] = grep_strdup(str);
3784dc88ebeSGabor Kovesdan 
3790c41ffb3SXin LI 		aargv = (char **)grep_calloc(eargc + argc + 1,
3800c41ffb3SXin LI 		    sizeof(char *));
38159218eb7SGabor Kovesdan 
3824dc88ebeSGabor Kovesdan 		aargv[0] = argv[0];
38359218eb7SGabor Kovesdan 		for (i = 0; i < eargc; i++)
38459218eb7SGabor Kovesdan 			aargv[i + 1] = eargv[i];
38559218eb7SGabor Kovesdan 		for (int j = 1; j < argc; j++, i++)
38659218eb7SGabor Kovesdan 			aargv[i + 1] = argv[j];
3874dc88ebeSGabor Kovesdan 
38859218eb7SGabor Kovesdan 		aargc = eargc + argc;
3894dc88ebeSGabor Kovesdan 	} else {
3904dc88ebeSGabor Kovesdan 		aargv = argv;
3914dc88ebeSGabor Kovesdan 		aargc = argc;
3924dc88ebeSGabor Kovesdan 	}
3934dc88ebeSGabor Kovesdan 
3944dc88ebeSGabor Kovesdan 	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
3954dc88ebeSGabor Kovesdan 	    -1)) {
3964dc88ebeSGabor Kovesdan 		switch (c) {
3974dc88ebeSGabor Kovesdan 		case '0': case '1': case '2': case '3': case '4':
3984dc88ebeSGabor Kovesdan 		case '5': case '6': case '7': case '8': case '9':
3994dc88ebeSGabor Kovesdan 			if (newarg || !isdigit(lastc))
4004dc88ebeSGabor Kovesdan 				Aflag = 0;
401b5fc583cSEd Maste 			else if (Aflag > LLONG_MAX / 10 - 1) {
4024dc88ebeSGabor Kovesdan 				errno = ERANGE;
4034dc88ebeSGabor Kovesdan 				err(2, NULL);
4044dc88ebeSGabor Kovesdan 			}
405b5fc583cSEd Maste 
4064dc88ebeSGabor Kovesdan 			Aflag = Bflag = (Aflag * 10) + (c - '0');
4074dc88ebeSGabor Kovesdan 			break;
4084dc88ebeSGabor Kovesdan 		case 'C':
4094dc88ebeSGabor Kovesdan 			if (optarg == NULL) {
4104dc88ebeSGabor Kovesdan 				Aflag = Bflag = 2;
4114dc88ebeSGabor Kovesdan 				break;
4124dc88ebeSGabor Kovesdan 			}
4134dc88ebeSGabor Kovesdan 			/* FALLTHROUGH */
4144dc88ebeSGabor Kovesdan 		case 'A':
4154dc88ebeSGabor Kovesdan 			/* FALLTHROUGH */
4164dc88ebeSGabor Kovesdan 		case 'B':
4174dc88ebeSGabor Kovesdan 			errno = 0;
418b5fc583cSEd Maste 			l = strtoll(optarg, &ep, 10);
419b5fc583cSEd Maste 			if (errno == ERANGE || errno == EINVAL)
4204dc88ebeSGabor Kovesdan 				err(2, NULL);
4214dc88ebeSGabor Kovesdan 			else if (ep[0] != '\0') {
4224dc88ebeSGabor Kovesdan 				errno = EINVAL;
4234dc88ebeSGabor Kovesdan 				err(2, NULL);
424b5fc583cSEd Maste 			} else if (l < 0) {
425b5fc583cSEd Maste 				errno = EINVAL;
426b5fc583cSEd Maste 				err(2, "context argument must be non-negative");
4274dc88ebeSGabor Kovesdan 			}
428b5fc583cSEd Maste 
4294dc88ebeSGabor Kovesdan 			if (c == 'A')
4304dc88ebeSGabor Kovesdan 				Aflag = l;
4314dc88ebeSGabor Kovesdan 			else if (c == 'B')
4324dc88ebeSGabor Kovesdan 				Bflag = l;
4334dc88ebeSGabor Kovesdan 			else
4344dc88ebeSGabor Kovesdan 				Aflag = Bflag = l;
4354dc88ebeSGabor Kovesdan 			break;
4364dc88ebeSGabor Kovesdan 		case 'a':
4374dc88ebeSGabor Kovesdan 			binbehave = BINFILE_TEXT;
4384dc88ebeSGabor Kovesdan 			break;
4394dc88ebeSGabor Kovesdan 		case 'b':
4404dc88ebeSGabor Kovesdan 			bflag = true;
4414dc88ebeSGabor Kovesdan 			break;
4424dc88ebeSGabor Kovesdan 		case 'c':
4434dc88ebeSGabor Kovesdan 			cflag = true;
4444dc88ebeSGabor Kovesdan 			break;
4454dc88ebeSGabor Kovesdan 		case 'D':
44627116286SGabor Kovesdan 			if (strcasecmp(optarg, "skip") == 0)
4474dc88ebeSGabor Kovesdan 				devbehave = DEV_SKIP;
44827116286SGabor Kovesdan 			else if (strcasecmp(optarg, "read") == 0)
44927116286SGabor Kovesdan 				devbehave = DEV_READ;
45097a012f2SGabor Kovesdan 			else
45130dc9502SBaptiste Daroussin 				errx(2, errstr[2], "--devices");
4524dc88ebeSGabor Kovesdan 			break;
4534dc88ebeSGabor Kovesdan 		case 'd':
45427116286SGabor Kovesdan 			if (strcasecmp("recurse", optarg) == 0) {
4554dc88ebeSGabor Kovesdan 				Hflag = true;
4564dc88ebeSGabor Kovesdan 				dirbehave = DIR_RECURSE;
45727116286SGabor Kovesdan 			} else if (strcasecmp("skip", optarg) == 0)
4584dc88ebeSGabor Kovesdan 				dirbehave = DIR_SKIP;
45927116286SGabor Kovesdan 			else if (strcasecmp("read", optarg) == 0)
46027116286SGabor Kovesdan 				dirbehave = DIR_READ;
46197a012f2SGabor Kovesdan 			else
46230dc9502SBaptiste Daroussin 				errx(2, errstr[2], "--directories");
4634dc88ebeSGabor Kovesdan 			break;
4644dc88ebeSGabor Kovesdan 		case 'E':
4654dc88ebeSGabor Kovesdan 			grepbehave = GREP_EXTENDED;
4664dc88ebeSGabor Kovesdan 			break;
4674dc88ebeSGabor Kovesdan 		case 'e':
468e411593dSGabor Kovesdan 			{
469e411593dSGabor Kovesdan 				char *token;
470cd64c588SGabor Kovesdan 				char *string = optarg;
471e411593dSGabor Kovesdan 
472e411593dSGabor Kovesdan 				while ((token = strsep(&string, "\n")) != NULL)
473e411593dSGabor Kovesdan 					add_pattern(token, strlen(token));
474e411593dSGabor Kovesdan 			}
4754dc88ebeSGabor Kovesdan 			needpattern = 0;
4764dc88ebeSGabor Kovesdan 			break;
4774dc88ebeSGabor Kovesdan 		case 'F':
4784dc88ebeSGabor Kovesdan 			grepbehave = GREP_FIXED;
4794dc88ebeSGabor Kovesdan 			break;
4804dc88ebeSGabor Kovesdan 		case 'f':
4814dc88ebeSGabor Kovesdan 			read_patterns(optarg);
4824dc88ebeSGabor Kovesdan 			needpattern = 0;
4834dc88ebeSGabor Kovesdan 			break;
4844dc88ebeSGabor Kovesdan 		case 'G':
4854dc88ebeSGabor Kovesdan 			grepbehave = GREP_BASIC;
4864dc88ebeSGabor Kovesdan 			break;
4874dc88ebeSGabor Kovesdan 		case 'H':
4884dc88ebeSGabor Kovesdan 			Hflag = true;
4894dc88ebeSGabor Kovesdan 			break;
4904dc88ebeSGabor Kovesdan 		case 'h':
4914dc88ebeSGabor Kovesdan 			Hflag = false;
4924dc88ebeSGabor Kovesdan 			hflag = true;
4934dc88ebeSGabor Kovesdan 			break;
4944dc88ebeSGabor Kovesdan 		case 'I':
4954dc88ebeSGabor Kovesdan 			binbehave = BINFILE_SKIP;
4964dc88ebeSGabor Kovesdan 			break;
4974dc88ebeSGabor Kovesdan 		case 'i':
4984dc88ebeSGabor Kovesdan 		case 'y':
4994dc88ebeSGabor Kovesdan 			iflag =  true;
5004dc88ebeSGabor Kovesdan 			cflags |= REG_ICASE;
5014dc88ebeSGabor Kovesdan 			break;
5024dc88ebeSGabor Kovesdan 		case 'L':
5034dc88ebeSGabor Kovesdan 			lflag = false;
50427116286SGabor Kovesdan 			Lflag = true;
5054dc88ebeSGabor Kovesdan 			break;
5064dc88ebeSGabor Kovesdan 		case 'l':
5074dc88ebeSGabor Kovesdan 			Lflag = false;
50827116286SGabor Kovesdan 			lflag = true;
5094dc88ebeSGabor Kovesdan 			break;
5104dc88ebeSGabor Kovesdan 		case 'm':
5114dc88ebeSGabor Kovesdan 			mflag = true;
5124dc88ebeSGabor Kovesdan 			errno = 0;
513924500b7SEitan Adler 			mlimit = mcount = strtoll(optarg, &ep, 10);
514f20f6f3fSGabor Kovesdan 			if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
5154dc88ebeSGabor Kovesdan 			    ((errno == EINVAL) && (mcount == 0)))
5164dc88ebeSGabor Kovesdan 				err(2, NULL);
5174dc88ebeSGabor Kovesdan 			else if (ep[0] != '\0') {
5184dc88ebeSGabor Kovesdan 				errno = EINVAL;
5194dc88ebeSGabor Kovesdan 				err(2, NULL);
5204dc88ebeSGabor Kovesdan 			}
5214dc88ebeSGabor Kovesdan 			break;
5224dc88ebeSGabor Kovesdan 		case 'n':
5234dc88ebeSGabor Kovesdan 			nflag = true;
5244dc88ebeSGabor Kovesdan 			break;
5254dc88ebeSGabor Kovesdan 		case 'O':
5264dc88ebeSGabor Kovesdan 			linkbehave = LINK_EXPLICIT;
5274dc88ebeSGabor Kovesdan 			break;
5284dc88ebeSGabor Kovesdan 		case 'o':
5294dc88ebeSGabor Kovesdan 			oflag = true;
53069a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
5314dc88ebeSGabor Kovesdan 			break;
5324dc88ebeSGabor Kovesdan 		case 'p':
5334dc88ebeSGabor Kovesdan 			linkbehave = LINK_SKIP;
5344dc88ebeSGabor Kovesdan 			break;
5354dc88ebeSGabor Kovesdan 		case 'q':
5364dc88ebeSGabor Kovesdan 			qflag = true;
5374dc88ebeSGabor Kovesdan 			break;
5384dc88ebeSGabor Kovesdan 		case 'S':
53927116286SGabor Kovesdan 			linkbehave = LINK_READ;
5404dc88ebeSGabor Kovesdan 			break;
5414dc88ebeSGabor Kovesdan 		case 'R':
5424dc88ebeSGabor Kovesdan 		case 'r':
5434dc88ebeSGabor Kovesdan 			dirbehave = DIR_RECURSE;
5444dc88ebeSGabor Kovesdan 			Hflag = true;
5454dc88ebeSGabor Kovesdan 			break;
5464dc88ebeSGabor Kovesdan 		case 's':
5474dc88ebeSGabor Kovesdan 			sflag = true;
5484dc88ebeSGabor Kovesdan 			break;
5494dc88ebeSGabor Kovesdan 		case 'U':
5504dc88ebeSGabor Kovesdan 			binbehave = BINFILE_BIN;
5514dc88ebeSGabor Kovesdan 			break;
5524dc88ebeSGabor Kovesdan 		case 'u':
5534dc88ebeSGabor Kovesdan 		case MMAP_OPT:
554f20f6f3fSGabor Kovesdan 			filebehave = FILE_MMAP;
5554dc88ebeSGabor Kovesdan 			break;
5564dc88ebeSGabor Kovesdan 		case 'V':
55730dc9502SBaptiste Daroussin 			printf(errstr[8], getprogname(), VERSION);
5584dc88ebeSGabor Kovesdan 			exit(0);
5594dc88ebeSGabor Kovesdan 		case 'v':
5604dc88ebeSGabor Kovesdan 			vflag = true;
5614dc88ebeSGabor Kovesdan 			break;
5624dc88ebeSGabor Kovesdan 		case 'w':
5634dc88ebeSGabor Kovesdan 			wflag = true;
56469a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
5654dc88ebeSGabor Kovesdan 			break;
5664dc88ebeSGabor Kovesdan 		case 'x':
5674dc88ebeSGabor Kovesdan 			xflag = true;
56869a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
5694dc88ebeSGabor Kovesdan 			break;
5705ee1ea02SEd Maste 		case 'z':
5715ee1ea02SEd Maste 			fileeol = '\0';
5725ee1ea02SEd Maste 			break;
5734dc88ebeSGabor Kovesdan 		case BIN_OPT:
57427116286SGabor Kovesdan 			if (strcasecmp("binary", optarg) == 0)
5754dc88ebeSGabor Kovesdan 				binbehave = BINFILE_BIN;
57627116286SGabor Kovesdan 			else if (strcasecmp("without-match", optarg) == 0)
5774dc88ebeSGabor Kovesdan 				binbehave = BINFILE_SKIP;
57827116286SGabor Kovesdan 			else if (strcasecmp("text", optarg) == 0)
5794dc88ebeSGabor Kovesdan 				binbehave = BINFILE_TEXT;
5804dc88ebeSGabor Kovesdan 			else
58130dc9502SBaptiste Daroussin 				errx(2, errstr[2], "--binary-files");
5824dc88ebeSGabor Kovesdan 			break;
5834dc88ebeSGabor Kovesdan 		case COLOR_OPT:
5844dc88ebeSGabor Kovesdan 			color = NULL;
58527116286SGabor Kovesdan 			if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
58627116286SGabor Kovesdan 			    strcasecmp("tty", optarg) == 0 ||
58727116286SGabor Kovesdan 			    strcasecmp("if-tty", optarg) == 0) {
58827116286SGabor Kovesdan 				char *term;
58927116286SGabor Kovesdan 
59027116286SGabor Kovesdan 				term = getenv("TERM");
59127116286SGabor Kovesdan 				if (isatty(STDOUT_FILENO) && term != NULL &&
59227116286SGabor Kovesdan 				    strcasecmp(term, "dumb") != 0)
59327116286SGabor Kovesdan 					color = init_color("01;31");
59427116286SGabor Kovesdan 			} else if (strcasecmp("always", optarg) == 0 ||
59527116286SGabor Kovesdan 			    strcasecmp("yes", optarg) == 0 ||
59627116286SGabor Kovesdan 			    strcasecmp("force", optarg) == 0) {
59727116286SGabor Kovesdan 				color = init_color("01;31");
59827116286SGabor Kovesdan 			} else if (strcasecmp("never", optarg) != 0 &&
59927116286SGabor Kovesdan 			    strcasecmp("none", optarg) != 0 &&
60027116286SGabor Kovesdan 			    strcasecmp("no", optarg) != 0)
60130dc9502SBaptiste Daroussin 				errx(2, errstr[2], "--color");
60269a6d198SGabor Kovesdan 			cflags &= ~REG_NOSUB;
6034dc88ebeSGabor Kovesdan 			break;
6044dc88ebeSGabor Kovesdan 		case LABEL_OPT:
6054dc88ebeSGabor Kovesdan 			label = optarg;
6064dc88ebeSGabor Kovesdan 			break;
6074dc88ebeSGabor Kovesdan 		case LINEBUF_OPT:
6084dc88ebeSGabor Kovesdan 			lbflag = true;
6094dc88ebeSGabor Kovesdan 			break;
6104dc88ebeSGabor Kovesdan 		case NULL_OPT:
6114dc88ebeSGabor Kovesdan 			nullflag = true;
6124dc88ebeSGabor Kovesdan 			break;
6134dc88ebeSGabor Kovesdan 		case R_INCLUDE_OPT:
61455e44f51SGabor Kovesdan 			finclude = true;
61555e44f51SGabor Kovesdan 			add_fpattern(optarg, INCL_PAT);
6164dc88ebeSGabor Kovesdan 			break;
6174dc88ebeSGabor Kovesdan 		case R_EXCLUDE_OPT:
61855e44f51SGabor Kovesdan 			fexclude = true;
61955e44f51SGabor Kovesdan 			add_fpattern(optarg, EXCL_PAT);
6204dc88ebeSGabor Kovesdan 			break;
6214dc88ebeSGabor Kovesdan 		case R_DINCLUDE_OPT:
62259218eb7SGabor Kovesdan 			dinclude = true;
62355e44f51SGabor Kovesdan 			add_dpattern(optarg, INCL_PAT);
6244dc88ebeSGabor Kovesdan 			break;
6254dc88ebeSGabor Kovesdan 		case R_DEXCLUDE_OPT:
62659218eb7SGabor Kovesdan 			dexclude = true;
62755e44f51SGabor Kovesdan 			add_dpattern(optarg, EXCL_PAT);
6284dc88ebeSGabor Kovesdan 			break;
6294dc88ebeSGabor Kovesdan 		case HELP_OPT:
6304dc88ebeSGabor Kovesdan 		default:
6314dc88ebeSGabor Kovesdan 			usage();
6324dc88ebeSGabor Kovesdan 		}
6334dc88ebeSGabor Kovesdan 		lastc = c;
6344dc88ebeSGabor Kovesdan 		newarg = optind != prevoptind;
6354dc88ebeSGabor Kovesdan 		prevoptind = optind;
6364dc88ebeSGabor Kovesdan 	}
6374dc88ebeSGabor Kovesdan 	aargc -= optind;
6384dc88ebeSGabor Kovesdan 	aargv += optind;
6394dc88ebeSGabor Kovesdan 
640f20f6f3fSGabor Kovesdan 	/* Empty pattern file matches nothing */
64138325e2aSKyle Evans 	if (!needpattern && (patterns == 0) && !matchall)
642f20f6f3fSGabor Kovesdan 		exit(1);
643f20f6f3fSGabor Kovesdan 
6444dc88ebeSGabor Kovesdan 	/* Fail if we don't have any pattern */
6454dc88ebeSGabor Kovesdan 	if (aargc == 0 && needpattern)
6464dc88ebeSGabor Kovesdan 		usage();
6474dc88ebeSGabor Kovesdan 
6484dc88ebeSGabor Kovesdan 	/* Process patterns from command line */
6494dc88ebeSGabor Kovesdan 	if (aargc != 0 && needpattern) {
650e411593dSGabor Kovesdan 		char *token;
651cd64c588SGabor Kovesdan 		char *string = *aargv;
652e411593dSGabor Kovesdan 
653e411593dSGabor Kovesdan 		while ((token = strsep(&string, "\n")) != NULL)
654e411593dSGabor Kovesdan 			add_pattern(token, strlen(token));
6554dc88ebeSGabor Kovesdan 		--aargc;
6564dc88ebeSGabor Kovesdan 		++aargv;
6574dc88ebeSGabor Kovesdan 	}
6584dc88ebeSGabor Kovesdan 
6594dc88ebeSGabor Kovesdan 	switch (grepbehave) {
6604dc88ebeSGabor Kovesdan 	case GREP_BASIC:
6614dc88ebeSGabor Kovesdan 		break;
662f20f6f3fSGabor Kovesdan 	case GREP_FIXED:
66305ad8215SKyle Evans 		/*
66405ad8215SKyle Evans 		 * regex(3) implementations that support fixed-string searches generally
66505ad8215SKyle Evans 		 * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
66605ad8215SKyle Evans 		 * here. If neither are defined, GREP_FIXED later implies that the
66705ad8215SKyle Evans 		 * internal literal matcher should be used. Other cflags that have
66805ad8215SKyle Evans 		 * the same interpretation as REG_NOSPEC and REG_LITERAL should be
66905ad8215SKyle Evans 		 * similarly added here, and grep.h should be amended to take this into
67005ad8215SKyle Evans 		 * consideration when defining WITH_INTERNAL_NOSPEC.
67105ad8215SKyle Evans 		 */
672476d2098SEd Maste #if defined(REG_NOSPEC)
673476d2098SEd Maste 		cflags |= REG_NOSPEC;
674476d2098SEd Maste #elif defined(REG_LITERAL)
675476d2098SEd Maste 		cflags |= REG_LITERAL;
676476d2098SEd Maste #endif
677f20f6f3fSGabor Kovesdan 		break;
6784dc88ebeSGabor Kovesdan 	case GREP_EXTENDED:
6794dc88ebeSGabor Kovesdan 		cflags |= REG_EXTENDED;
6804dc88ebeSGabor Kovesdan 		break;
6814dc88ebeSGabor Kovesdan 	default:
6824dc88ebeSGabor Kovesdan 		/* NOTREACHED */
6834dc88ebeSGabor Kovesdan 		usage();
6844dc88ebeSGabor Kovesdan 	}
6854dc88ebeSGabor Kovesdan 
6864dc88ebeSGabor Kovesdan 	r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
687f20f6f3fSGabor Kovesdan 
68805ad8215SKyle Evans #ifdef WITH_INTERNAL_NOSPEC
68938325e2aSKyle Evans 	if (grepbehave != GREP_FIXED) {
69005ad8215SKyle Evans #else
69138325e2aSKyle Evans 	{
69205ad8215SKyle Evans #endif
6934dc88ebeSGabor Kovesdan 		/* Check if cheating is allowed (always is for fgrep). */
6944dc88ebeSGabor Kovesdan 		for (i = 0; i < patterns; ++i) {
695f20f6f3fSGabor Kovesdan 			c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
6964dc88ebeSGabor Kovesdan 			if (c != 0) {
6974dc88ebeSGabor Kovesdan 				regerror(c, &r_pattern[i], re_error,
6984dc88ebeSGabor Kovesdan 				    RE_ERROR_BUF);
6994dc88ebeSGabor Kovesdan 				errx(2, "%s", re_error);
7004dc88ebeSGabor Kovesdan 			}
7014dc88ebeSGabor Kovesdan 		}
702a4f3f02bSEd Maste 	}
7034dc88ebeSGabor Kovesdan 
7044dc88ebeSGabor Kovesdan 	if (lbflag)
7054dc88ebeSGabor Kovesdan 		setlinebuf(stdout);
7064dc88ebeSGabor Kovesdan 
7074dc88ebeSGabor Kovesdan 	if ((aargc == 0 || aargc == 1) && !Hflag)
7084dc88ebeSGabor Kovesdan 		hflag = true;
7094dc88ebeSGabor Kovesdan 
710a461896aSEd Maste 	if (aargc == 0 && dirbehave != DIR_RECURSE)
7114dc88ebeSGabor Kovesdan 		exit(!procfile("-"));
7124dc88ebeSGabor Kovesdan 
7134dc88ebeSGabor Kovesdan 	if (dirbehave == DIR_RECURSE)
714cbfff13fSKyle Evans 		matched = grep_tree(aargv);
715c38208adSXin LI 	else
716cbfff13fSKyle Evans 		for (matched = false; aargc--; ++aargv) {
71755e44f51SGabor Kovesdan 			if ((finclude || fexclude) && !file_matching(*aargv))
71855e44f51SGabor Kovesdan 				continue;
719cbfff13fSKyle Evans 			if (procfile(*aargv))
720cbfff13fSKyle Evans 				matched = true;
72155e44f51SGabor Kovesdan 		}
7224dc88ebeSGabor Kovesdan 
72338325e2aSKyle Evans 	if (Lflag)
72438325e2aSKyle Evans 		matched = !matched;
72538325e2aSKyle Evans 
72638325e2aSKyle Evans 	/*
72738325e2aSKyle Evans 	 * Calculate the correct return value according to the
72838325e2aSKyle Evans 	 * results and the command line option.
72938325e2aSKyle Evans 	 */
730cbfff13fSKyle Evans 	exit(matched ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
7314dc88ebeSGabor Kovesdan }
732