1f3f50de6SPedro F. Giffuni /* $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $ */
24dc88ebeSGabor Kovesdan /* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
34dc88ebeSGabor Kovesdan
44dc88ebeSGabor Kovesdan /*-
54d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
61de7b4b8SPedro F. Giffuni *
7e738085bSDag-Erling Smørgrav * Copyright (c) 1999 James Howard and Dag-Erling Smørgrav
84dc88ebeSGabor Kovesdan * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
94dc88ebeSGabor Kovesdan * All rights reserved.
104dc88ebeSGabor Kovesdan *
114dc88ebeSGabor Kovesdan * Redistribution and use in source and binary forms, with or without
124dc88ebeSGabor Kovesdan * modification, are permitted provided that the following conditions
134dc88ebeSGabor Kovesdan * are met:
144dc88ebeSGabor Kovesdan * 1. Redistributions of source code must retain the above copyright
154dc88ebeSGabor Kovesdan * notice, this list of conditions and the following disclaimer.
164dc88ebeSGabor Kovesdan * 2. Redistributions in binary form must reproduce the above copyright
174dc88ebeSGabor Kovesdan * notice, this list of conditions and the following disclaimer in the
184dc88ebeSGabor Kovesdan * documentation and/or other materials provided with the distribution.
194dc88ebeSGabor Kovesdan *
204dc88ebeSGabor Kovesdan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214dc88ebeSGabor Kovesdan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224dc88ebeSGabor Kovesdan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234dc88ebeSGabor Kovesdan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244dc88ebeSGabor Kovesdan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254dc88ebeSGabor Kovesdan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264dc88ebeSGabor Kovesdan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274dc88ebeSGabor Kovesdan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284dc88ebeSGabor Kovesdan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294dc88ebeSGabor Kovesdan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304dc88ebeSGabor Kovesdan * SUCH DAMAGE.
314dc88ebeSGabor Kovesdan */
324dc88ebeSGabor Kovesdan
334dc88ebeSGabor Kovesdan #include <sys/cdefs.h>
344dc88ebeSGabor Kovesdan #include <sys/stat.h>
354dc88ebeSGabor Kovesdan #include <sys/types.h>
364dc88ebeSGabor Kovesdan
374dc88ebeSGabor Kovesdan #include <ctype.h>
384dc88ebeSGabor Kovesdan #include <err.h>
394dc88ebeSGabor Kovesdan #include <errno.h>
40f20f6f3fSGabor Kovesdan #include <fcntl.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 const char *errstr[] = {
544dc88ebeSGabor Kovesdan "",
554dc88ebeSGabor Kovesdan /* 1*/ "(standard input)",
56a1852807SKyle Evans /* 2*/ "unknown %s option",
574c14980bSKyle Evans /* 3*/ "usage: %s [-abcDEFGHhIiLlmnOopqRSsUVvwxz] [-A num] [-B num] [-C num]\n",
58a1852807SKyle Evans /* 4*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
59be6b8b7aSMateusz Piotrowski /* 5*/ "\t[--context=num] [--directories=action] [--label] [--line-buffered]\n",
60a1852807SKyle Evans /* 6*/ "\t[--null] [pattern] [file ...]\n",
61a1852807SKyle Evans /* 7*/ "Binary file %s matches\n",
627c2f310fSKyle Evans /* 8*/ "%s (BSD grep, GNU compatible) %s\n",
634dc88ebeSGabor Kovesdan };
644dc88ebeSGabor Kovesdan
654dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */
668bf46064SEd Maste int cflags = REG_NOSUB | REG_NEWLINE;
674dc88ebeSGabor Kovesdan int eflags = REG_STARTEND;
684dc88ebeSGabor Kovesdan
694dc88ebeSGabor Kovesdan bool matchall;
704dc88ebeSGabor Kovesdan
714dc88ebeSGabor Kovesdan /* Searching patterns */
72bf70beceSEd Schouten unsigned int patterns;
73bf70beceSEd Schouten static unsigned int pattern_sz;
74f20f6f3fSGabor Kovesdan struct pat *pattern;
754dc88ebeSGabor Kovesdan regex_t *r_pattern;
764dc88ebeSGabor Kovesdan
774dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */
78bf70beceSEd Schouten unsigned int fpatterns, dpatterns;
79bf70beceSEd Schouten static unsigned int fpattern_sz, dpattern_sz;
8055e44f51SGabor Kovesdan struct epat *dpattern, *fpattern;
814dc88ebeSGabor Kovesdan
824dc88ebeSGabor Kovesdan /* For regex errors */
834dc88ebeSGabor Kovesdan char re_error[RE_ERROR_BUF + 1];
844dc88ebeSGabor Kovesdan
854dc88ebeSGabor Kovesdan /* Command-line flags */
86b5fc583cSEd Maste long long Aflag; /* -A x: print x lines trailing each match */
87b5fc583cSEd Maste long long Bflag; /* -B x: print x lines leading each match */
884dc88ebeSGabor Kovesdan bool Hflag; /* -H: always print file name */
894dc88ebeSGabor Kovesdan bool Lflag; /* -L: only show names of files with no matches */
904dc88ebeSGabor Kovesdan bool bflag; /* -b: show block numbers for each match */
914dc88ebeSGabor Kovesdan bool cflag; /* -c: only show a count of matching lines */
924dc88ebeSGabor Kovesdan bool hflag; /* -h: don't print filename headers */
934dc88ebeSGabor Kovesdan bool iflag; /* -i: ignore case */
944dc88ebeSGabor Kovesdan bool lflag; /* -l: only show names of files with matches */
954dc88ebeSGabor Kovesdan bool mflag; /* -m x: stop reading the files after x matches */
96f20f6f3fSGabor Kovesdan long long mcount; /* count for -m */
97924500b7SEitan Adler long long mlimit; /* requested value for -m */
985ee1ea02SEd Maste char fileeol; /* indicator for eol */
994dc88ebeSGabor Kovesdan bool nflag; /* -n: show line numbers in front of matching lines */
1004dc88ebeSGabor Kovesdan bool oflag; /* -o: print only matching part */
1014dc88ebeSGabor Kovesdan bool qflag; /* -q: quiet mode (don't output anything) */
1024dc88ebeSGabor Kovesdan bool sflag; /* -s: silent mode (ignore errors) */
1034dc88ebeSGabor Kovesdan bool vflag; /* -v: only show non-matching lines */
1044dc88ebeSGabor Kovesdan bool wflag; /* -w: pattern must start and end on word boundaries */
1054dc88ebeSGabor Kovesdan bool xflag; /* -x: pattern must match entire line */
1064dc88ebeSGabor Kovesdan bool lbflag; /* --line-buffered */
1074dc88ebeSGabor Kovesdan bool nullflag; /* --null */
1084dc88ebeSGabor Kovesdan char *label; /* --label */
10927116286SGabor Kovesdan const char *color; /* --color */
1104c14980bSKyle Evans int grepbehave = GREP_BASIC; /* -EFG: type of the regex */
1114dc88ebeSGabor Kovesdan int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
1124a5b4207SBaptiste Daroussin int filebehave = FILE_STDIO;
11327116286SGabor Kovesdan int devbehave = DEV_READ; /* -D: handling of devices */
11427116286SGabor Kovesdan int dirbehave = DIR_READ; /* -dRr: handling of directories */
115*fc12c191SJohn Baldwin int linkbehave = LINK_SKIP; /* -OpS: handling of symlinks */
1164dc88ebeSGabor Kovesdan
11759218eb7SGabor Kovesdan bool dexclude, dinclude; /* --exclude-dir and --include-dir */
11859218eb7SGabor Kovesdan bool fexclude, finclude; /* --exclude and --include */
11955e44f51SGabor Kovesdan
1204dc88ebeSGabor Kovesdan enum {
1214dc88ebeSGabor Kovesdan BIN_OPT = CHAR_MAX + 1,
1224dc88ebeSGabor Kovesdan COLOR_OPT,
1234dc88ebeSGabor Kovesdan HELP_OPT,
1244dc88ebeSGabor Kovesdan MMAP_OPT,
1254dc88ebeSGabor Kovesdan LINEBUF_OPT,
1264dc88ebeSGabor Kovesdan LABEL_OPT,
1274dc88ebeSGabor Kovesdan NULL_OPT,
1284dc88ebeSGabor Kovesdan R_EXCLUDE_OPT,
1294dc88ebeSGabor Kovesdan R_INCLUDE_OPT,
1304dc88ebeSGabor Kovesdan R_DEXCLUDE_OPT,
1314dc88ebeSGabor Kovesdan R_DINCLUDE_OPT
1324dc88ebeSGabor Kovesdan };
1334dc88ebeSGabor Kovesdan
13427116286SGabor Kovesdan static inline const char *init_color(const char *);
13527116286SGabor Kovesdan
1364dc88ebeSGabor Kovesdan /* Housekeeping */
1376f4cbf7cSGabor Kovesdan bool file_err; /* file reading error */
1384dc88ebeSGabor Kovesdan
1394dc88ebeSGabor Kovesdan /*
1404dc88ebeSGabor Kovesdan * Prints usage information and returns 2.
1414dc88ebeSGabor Kovesdan */
1424dc88ebeSGabor Kovesdan static void
usage(void)1434dc88ebeSGabor Kovesdan usage(void)
1444dc88ebeSGabor Kovesdan {
14530dc9502SBaptiste Daroussin fprintf(stderr, errstr[3], getprogname());
14630dc9502SBaptiste Daroussin fprintf(stderr, "%s", errstr[4]);
14730dc9502SBaptiste Daroussin fprintf(stderr, "%s", errstr[5]);
14830dc9502SBaptiste Daroussin fprintf(stderr, "%s", errstr[6]);
1494dc88ebeSGabor Kovesdan exit(2);
1504dc88ebeSGabor Kovesdan }
1514dc88ebeSGabor Kovesdan
1524c14980bSKyle Evans static const char *optstr = "0123456789A:B:C:D:EFGHILOSRUVabcd:e:f:hilm:nopqrsuvwxyz";
1534dc88ebeSGabor Kovesdan
1548375d512SEd Schouten static const struct option long_options[] =
1554dc88ebeSGabor Kovesdan {
1564dc88ebeSGabor Kovesdan {"binary-files", required_argument, NULL, BIN_OPT},
1574dc88ebeSGabor Kovesdan {"help", no_argument, NULL, HELP_OPT},
1584dc88ebeSGabor Kovesdan {"mmap", no_argument, NULL, MMAP_OPT},
1594dc88ebeSGabor Kovesdan {"line-buffered", no_argument, NULL, LINEBUF_OPT},
1604dc88ebeSGabor Kovesdan {"label", required_argument, NULL, LABEL_OPT},
1614dc88ebeSGabor Kovesdan {"null", no_argument, NULL, NULL_OPT},
1624dc88ebeSGabor Kovesdan {"color", optional_argument, NULL, COLOR_OPT},
1634dc88ebeSGabor Kovesdan {"colour", optional_argument, NULL, COLOR_OPT},
1644dc88ebeSGabor Kovesdan {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
1654dc88ebeSGabor Kovesdan {"include", required_argument, NULL, R_INCLUDE_OPT},
1664dc88ebeSGabor Kovesdan {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
1674dc88ebeSGabor Kovesdan {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
1684dc88ebeSGabor Kovesdan {"after-context", required_argument, NULL, 'A'},
1694dc88ebeSGabor Kovesdan {"text", no_argument, NULL, 'a'},
1704dc88ebeSGabor Kovesdan {"before-context", required_argument, NULL, 'B'},
1714dc88ebeSGabor Kovesdan {"byte-offset", no_argument, NULL, 'b'},
1724dc88ebeSGabor Kovesdan {"context", optional_argument, NULL, 'C'},
1734dc88ebeSGabor Kovesdan {"count", no_argument, NULL, 'c'},
1744dc88ebeSGabor Kovesdan {"devices", required_argument, NULL, 'D'},
1754dc88ebeSGabor Kovesdan {"directories", required_argument, NULL, 'd'},
1764dc88ebeSGabor Kovesdan {"extended-regexp", no_argument, NULL, 'E'},
1774dc88ebeSGabor Kovesdan {"regexp", required_argument, NULL, 'e'},
1784dc88ebeSGabor Kovesdan {"fixed-strings", no_argument, NULL, 'F'},
1794dc88ebeSGabor Kovesdan {"file", required_argument, NULL, 'f'},
1804dc88ebeSGabor Kovesdan {"basic-regexp", no_argument, NULL, 'G'},
1814dc88ebeSGabor Kovesdan {"no-filename", no_argument, NULL, 'h'},
1824dc88ebeSGabor Kovesdan {"with-filename", no_argument, NULL, 'H'},
1834dc88ebeSGabor Kovesdan {"ignore-case", no_argument, NULL, 'i'},
1844dc88ebeSGabor Kovesdan {"files-with-matches", no_argument, NULL, 'l'},
1854dc88ebeSGabor Kovesdan {"files-without-match", no_argument, NULL, 'L'},
1864dc88ebeSGabor Kovesdan {"max-count", required_argument, NULL, 'm'},
1874dc88ebeSGabor Kovesdan {"line-number", no_argument, NULL, 'n'},
1884dc88ebeSGabor Kovesdan {"only-matching", no_argument, NULL, 'o'},
1894dc88ebeSGabor Kovesdan {"quiet", no_argument, NULL, 'q'},
1904dc88ebeSGabor Kovesdan {"silent", no_argument, NULL, 'q'},
1914dc88ebeSGabor Kovesdan {"recursive", no_argument, NULL, 'r'},
1924dc88ebeSGabor Kovesdan {"no-messages", no_argument, NULL, 's'},
1934dc88ebeSGabor Kovesdan {"binary", no_argument, NULL, 'U'},
1944dc88ebeSGabor Kovesdan {"unix-byte-offsets", no_argument, NULL, 'u'},
1954dc88ebeSGabor Kovesdan {"invert-match", no_argument, NULL, 'v'},
1964dc88ebeSGabor Kovesdan {"version", no_argument, NULL, 'V'},
1974dc88ebeSGabor Kovesdan {"word-regexp", no_argument, NULL, 'w'},
1984dc88ebeSGabor Kovesdan {"line-regexp", no_argument, NULL, 'x'},
1995ee1ea02SEd Maste {"null-data", no_argument, NULL, 'z'},
2004dc88ebeSGabor Kovesdan {NULL, no_argument, NULL, 0}
2014dc88ebeSGabor Kovesdan };
2024dc88ebeSGabor Kovesdan
2034dc88ebeSGabor Kovesdan /*
2044dc88ebeSGabor Kovesdan * Adds a searching pattern to the internal array.
2054dc88ebeSGabor Kovesdan */
2064dc88ebeSGabor Kovesdan static void
add_pattern(char * pat,size_t len)2074dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len)
2084dc88ebeSGabor Kovesdan {
2094dc88ebeSGabor Kovesdan
2104dc88ebeSGabor Kovesdan /* Check if we can do a shortcut */
211f20f6f3fSGabor Kovesdan if (len == 0) {
2124dc88ebeSGabor Kovesdan matchall = true;
2134dc88ebeSGabor Kovesdan return;
2144dc88ebeSGabor Kovesdan }
2154dc88ebeSGabor Kovesdan /* Increase size if necessary */
2164dc88ebeSGabor Kovesdan if (patterns == pattern_sz) {
2174dc88ebeSGabor Kovesdan pattern_sz *= 2;
2184dc88ebeSGabor Kovesdan pattern = grep_realloc(pattern, ++pattern_sz *
219f20f6f3fSGabor Kovesdan sizeof(struct pat));
2204dc88ebeSGabor Kovesdan }
2214dc88ebeSGabor Kovesdan if (len > 0 && pat[len - 1] == '\n')
2224dc88ebeSGabor Kovesdan --len;
2234dc88ebeSGabor Kovesdan /* pat may not be NUL-terminated */
224f20f6f3fSGabor Kovesdan pattern[patterns].pat = grep_malloc(len + 1);
225f20f6f3fSGabor Kovesdan memcpy(pattern[patterns].pat, pat, len);
226f20f6f3fSGabor Kovesdan pattern[patterns].len = len;
227f20f6f3fSGabor Kovesdan pattern[patterns].pat[len] = '\0';
2284dc88ebeSGabor Kovesdan ++patterns;
2294dc88ebeSGabor Kovesdan }
2304dc88ebeSGabor Kovesdan
2314dc88ebeSGabor Kovesdan /*
23255e44f51SGabor Kovesdan * Adds a file include/exclude pattern to the internal array.
2334dc88ebeSGabor Kovesdan */
2344dc88ebeSGabor Kovesdan static void
add_fpattern(const char * pat,int mode)23555e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode)
2364dc88ebeSGabor Kovesdan {
2374dc88ebeSGabor Kovesdan
2384dc88ebeSGabor Kovesdan /* Increase size if necessary */
23955e44f51SGabor Kovesdan if (fpatterns == fpattern_sz) {
24055e44f51SGabor Kovesdan fpattern_sz *= 2;
24155e44f51SGabor Kovesdan fpattern = grep_realloc(fpattern, ++fpattern_sz *
2424dc88ebeSGabor Kovesdan sizeof(struct epat));
2434dc88ebeSGabor Kovesdan }
24455e44f51SGabor Kovesdan fpattern[fpatterns].pat = grep_strdup(pat);
24555e44f51SGabor Kovesdan fpattern[fpatterns].mode = mode;
24655e44f51SGabor Kovesdan ++fpatterns;
24755e44f51SGabor Kovesdan }
24855e44f51SGabor Kovesdan
24955e44f51SGabor Kovesdan /*
25055e44f51SGabor Kovesdan * Adds a directory include/exclude pattern to the internal array.
25155e44f51SGabor Kovesdan */
25255e44f51SGabor Kovesdan static void
add_dpattern(const char * pat,int mode)25355e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode)
25455e44f51SGabor Kovesdan {
25555e44f51SGabor Kovesdan
25655e44f51SGabor Kovesdan /* Increase size if necessary */
25755e44f51SGabor Kovesdan if (dpatterns == dpattern_sz) {
25855e44f51SGabor Kovesdan dpattern_sz *= 2;
25955e44f51SGabor Kovesdan dpattern = grep_realloc(dpattern, ++dpattern_sz *
26055e44f51SGabor Kovesdan sizeof(struct epat));
26155e44f51SGabor Kovesdan }
26255e44f51SGabor Kovesdan dpattern[dpatterns].pat = grep_strdup(pat);
26355e44f51SGabor Kovesdan dpattern[dpatterns].mode = mode;
26455e44f51SGabor Kovesdan ++dpatterns;
2654dc88ebeSGabor Kovesdan }
2664dc88ebeSGabor Kovesdan
2674dc88ebeSGabor Kovesdan /*
2684dc88ebeSGabor Kovesdan * Reads searching patterns from a file and adds them with add_pattern().
2694dc88ebeSGabor Kovesdan */
2704dc88ebeSGabor Kovesdan static void
read_patterns(const char * fn)2714dc88ebeSGabor Kovesdan read_patterns(const char *fn)
2724dc88ebeSGabor Kovesdan {
273f20f6f3fSGabor Kovesdan struct stat st;
2744dc88ebeSGabor Kovesdan FILE *f;
2754dc88ebeSGabor Kovesdan char *line;
2764dc88ebeSGabor Kovesdan size_t len;
277f3f50de6SPedro F. Giffuni ssize_t rlen;
2784dc88ebeSGabor Kovesdan
27924a656c2SKyle Evans if (strcmp(fn, "-") == 0)
28024a656c2SKyle Evans f = stdin;
28124a656c2SKyle Evans else if ((f = fopen(fn, "r")) == NULL)
2824dc88ebeSGabor Kovesdan err(2, "%s", fn);
283f20f6f3fSGabor Kovesdan if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
284f20f6f3fSGabor Kovesdan fclose(f);
285f20f6f3fSGabor Kovesdan return;
286f20f6f3fSGabor Kovesdan }
287f3f50de6SPedro F. Giffuni len = 0;
288f3f50de6SPedro F. Giffuni line = NULL;
289d204af1eSEd Maste while ((rlen = getline(&line, &len, f)) != -1) {
290d204af1eSEd Maste if (line[0] == '\0')
291d204af1eSEd Maste continue;
2922fa7a2afSPedro F. Giffuni add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
293d204af1eSEd Maste }
294d204af1eSEd Maste
295f3f50de6SPedro F. Giffuni free(line);
2964dc88ebeSGabor Kovesdan if (ferror(f))
2974dc88ebeSGabor Kovesdan err(2, "%s", fn);
29824a656c2SKyle Evans if (strcmp(fn, "-") != 0)
2994dc88ebeSGabor Kovesdan fclose(f);
3004dc88ebeSGabor Kovesdan }
3014dc88ebeSGabor Kovesdan
30227116286SGabor Kovesdan static inline const char *
init_color(const char * d)30327116286SGabor Kovesdan init_color(const char *d)
30427116286SGabor Kovesdan {
30527116286SGabor Kovesdan char *c;
30627116286SGabor Kovesdan
30727116286SGabor Kovesdan c = getenv("GREP_COLOR");
308dab19f30SGabor Kovesdan return (c != NULL && c[0] != '\0' ? c : d);
30927116286SGabor Kovesdan }
31027116286SGabor Kovesdan
3114dc88ebeSGabor Kovesdan int
main(int argc,char * argv[])3124dc88ebeSGabor Kovesdan main(int argc, char *argv[])
3134dc88ebeSGabor Kovesdan {
3144dc88ebeSGabor Kovesdan char **aargv, **eargv, *eopts;
315afbbd357SGabor Kovesdan char *ep;
316afbbd357SGabor Kovesdan const char *pn;
317b5fc583cSEd Maste long long l;
3184dc88ebeSGabor Kovesdan unsigned int aargc, eargc, i;
3194dc88ebeSGabor Kovesdan int c, lastc, needpattern, newarg, prevoptind;
320cbfff13fSKyle Evans bool matched;
3214dc88ebeSGabor Kovesdan
3224dc88ebeSGabor Kovesdan setlocale(LC_ALL, "");
3234dc88ebeSGabor Kovesdan
32425385eb3SKyle Evans /*
32525385eb3SKyle Evans * Check how we've bene invoked to determine the behavior we should
32625385eb3SKyle Evans * exhibit. In this way we can have all the functionalities in one
32725385eb3SKyle Evans * binary without the need of scripting and using ugly hacks.
32825385eb3SKyle Evans */
329afbbd357SGabor Kovesdan pn = getprogname();
330f20f6f3fSGabor Kovesdan switch (pn[0]) {
3314dc88ebeSGabor Kovesdan case 'e':
3324dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED;
3334dc88ebeSGabor Kovesdan break;
3344dc88ebeSGabor Kovesdan case 'f':
3354dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED;
3364dc88ebeSGabor Kovesdan break;
33725385eb3SKyle Evans case 'r':
33825385eb3SKyle Evans dirbehave = DIR_RECURSE;
33925385eb3SKyle Evans Hflag = true;
34025385eb3SKyle Evans break;
3414dc88ebeSGabor Kovesdan }
3424dc88ebeSGabor Kovesdan
3434dc88ebeSGabor Kovesdan lastc = '\0';
3444dc88ebeSGabor Kovesdan newarg = 1;
3454dc88ebeSGabor Kovesdan prevoptind = 1;
3464dc88ebeSGabor Kovesdan needpattern = 1;
3475ee1ea02SEd Maste fileeol = '\n';
3484dc88ebeSGabor Kovesdan
3494dc88ebeSGabor Kovesdan eopts = getenv("GREP_OPTIONS");
3504dc88ebeSGabor Kovesdan
35159218eb7SGabor Kovesdan /* support for extra arguments in GREP_OPTIONS */
35259218eb7SGabor Kovesdan eargc = 0;
353dab19f30SGabor Kovesdan if (eopts != NULL && eopts[0] != '\0') {
3544dc88ebeSGabor Kovesdan char *str;
3554dc88ebeSGabor Kovesdan
35659218eb7SGabor Kovesdan /* make an estimation of how many extra arguments we have */
35759218eb7SGabor Kovesdan for (unsigned int j = 0; j < strlen(eopts); j++)
35859218eb7SGabor Kovesdan if (eopts[j] == ' ')
3594dc88ebeSGabor Kovesdan eargc++;
3604dc88ebeSGabor Kovesdan
3614dc88ebeSGabor Kovesdan eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
3624dc88ebeSGabor Kovesdan
3634dc88ebeSGabor Kovesdan eargc = 0;
36459218eb7SGabor Kovesdan /* parse extra arguments */
36559218eb7SGabor Kovesdan while ((str = strsep(&eopts, " ")) != NULL)
366dab19f30SGabor Kovesdan if (str[0] != '\0')
36759218eb7SGabor Kovesdan eargv[eargc++] = grep_strdup(str);
3684dc88ebeSGabor Kovesdan
3690c41ffb3SXin LI aargv = (char **)grep_calloc(eargc + argc + 1,
3700c41ffb3SXin LI sizeof(char *));
37159218eb7SGabor Kovesdan
3724dc88ebeSGabor Kovesdan aargv[0] = argv[0];
37359218eb7SGabor Kovesdan for (i = 0; i < eargc; i++)
37459218eb7SGabor Kovesdan aargv[i + 1] = eargv[i];
37559218eb7SGabor Kovesdan for (int j = 1; j < argc; j++, i++)
37659218eb7SGabor Kovesdan aargv[i + 1] = argv[j];
3774dc88ebeSGabor Kovesdan
37859218eb7SGabor Kovesdan aargc = eargc + argc;
3794dc88ebeSGabor Kovesdan } else {
3804dc88ebeSGabor Kovesdan aargv = argv;
3814dc88ebeSGabor Kovesdan aargc = argc;
3824dc88ebeSGabor Kovesdan }
3834dc88ebeSGabor Kovesdan
3844dc88ebeSGabor Kovesdan while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
3854dc88ebeSGabor Kovesdan -1)) {
3864dc88ebeSGabor Kovesdan switch (c) {
3874dc88ebeSGabor Kovesdan case '0': case '1': case '2': case '3': case '4':
3884dc88ebeSGabor Kovesdan case '5': case '6': case '7': case '8': case '9':
3894dc88ebeSGabor Kovesdan if (newarg || !isdigit(lastc))
3904dc88ebeSGabor Kovesdan Aflag = 0;
391b5fc583cSEd Maste else if (Aflag > LLONG_MAX / 10 - 1) {
3924dc88ebeSGabor Kovesdan errno = ERANGE;
3934dc88ebeSGabor Kovesdan err(2, NULL);
3944dc88ebeSGabor Kovesdan }
395b5fc583cSEd Maste
3964dc88ebeSGabor Kovesdan Aflag = Bflag = (Aflag * 10) + (c - '0');
3974dc88ebeSGabor Kovesdan break;
3984dc88ebeSGabor Kovesdan case 'C':
3994dc88ebeSGabor Kovesdan if (optarg == NULL) {
4004dc88ebeSGabor Kovesdan Aflag = Bflag = 2;
4014dc88ebeSGabor Kovesdan break;
4024dc88ebeSGabor Kovesdan }
4034dc88ebeSGabor Kovesdan /* FALLTHROUGH */
4044dc88ebeSGabor Kovesdan case 'A':
4054dc88ebeSGabor Kovesdan /* FALLTHROUGH */
4064dc88ebeSGabor Kovesdan case 'B':
4074dc88ebeSGabor Kovesdan errno = 0;
408b5fc583cSEd Maste l = strtoll(optarg, &ep, 10);
409b5fc583cSEd Maste if (errno == ERANGE || errno == EINVAL)
4104dc88ebeSGabor Kovesdan err(2, NULL);
4114dc88ebeSGabor Kovesdan else if (ep[0] != '\0') {
4124dc88ebeSGabor Kovesdan errno = EINVAL;
4134dc88ebeSGabor Kovesdan err(2, NULL);
414b5fc583cSEd Maste } else if (l < 0) {
415b5fc583cSEd Maste errno = EINVAL;
416b5fc583cSEd Maste err(2, "context argument must be non-negative");
4174dc88ebeSGabor Kovesdan }
418b5fc583cSEd Maste
4194dc88ebeSGabor Kovesdan if (c == 'A')
4204dc88ebeSGabor Kovesdan Aflag = l;
4214dc88ebeSGabor Kovesdan else if (c == 'B')
4224dc88ebeSGabor Kovesdan Bflag = l;
4234dc88ebeSGabor Kovesdan else
4244dc88ebeSGabor Kovesdan Aflag = Bflag = l;
4254dc88ebeSGabor Kovesdan break;
4264dc88ebeSGabor Kovesdan case 'a':
4274dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT;
4284dc88ebeSGabor Kovesdan break;
4294dc88ebeSGabor Kovesdan case 'b':
4304dc88ebeSGabor Kovesdan bflag = true;
4314dc88ebeSGabor Kovesdan break;
4324dc88ebeSGabor Kovesdan case 'c':
4334dc88ebeSGabor Kovesdan cflag = true;
4344dc88ebeSGabor Kovesdan break;
4354dc88ebeSGabor Kovesdan case 'D':
43627116286SGabor Kovesdan if (strcasecmp(optarg, "skip") == 0)
4374dc88ebeSGabor Kovesdan devbehave = DEV_SKIP;
43827116286SGabor Kovesdan else if (strcasecmp(optarg, "read") == 0)
43927116286SGabor Kovesdan devbehave = DEV_READ;
44097a012f2SGabor Kovesdan else
44130dc9502SBaptiste Daroussin errx(2, errstr[2], "--devices");
4424dc88ebeSGabor Kovesdan break;
4434dc88ebeSGabor Kovesdan case 'd':
44427116286SGabor Kovesdan if (strcasecmp("recurse", optarg) == 0) {
4454dc88ebeSGabor Kovesdan Hflag = true;
4464dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE;
44727116286SGabor Kovesdan } else if (strcasecmp("skip", optarg) == 0)
4484dc88ebeSGabor Kovesdan dirbehave = DIR_SKIP;
44927116286SGabor Kovesdan else if (strcasecmp("read", optarg) == 0)
45027116286SGabor Kovesdan dirbehave = DIR_READ;
45197a012f2SGabor Kovesdan else
45230dc9502SBaptiste Daroussin errx(2, errstr[2], "--directories");
4534dc88ebeSGabor Kovesdan break;
4544dc88ebeSGabor Kovesdan case 'E':
4554dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED;
4564dc88ebeSGabor Kovesdan break;
4574dc88ebeSGabor Kovesdan case 'e':
458e411593dSGabor Kovesdan {
459e411593dSGabor Kovesdan char *token;
460cd64c588SGabor Kovesdan char *string = optarg;
461e411593dSGabor Kovesdan
462e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL)
463e411593dSGabor Kovesdan add_pattern(token, strlen(token));
464e411593dSGabor Kovesdan }
4654dc88ebeSGabor Kovesdan needpattern = 0;
4664dc88ebeSGabor Kovesdan break;
4674dc88ebeSGabor Kovesdan case 'F':
4684dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED;
4694dc88ebeSGabor Kovesdan break;
4704dc88ebeSGabor Kovesdan case 'f':
4714dc88ebeSGabor Kovesdan read_patterns(optarg);
4724dc88ebeSGabor Kovesdan needpattern = 0;
4734dc88ebeSGabor Kovesdan break;
4744dc88ebeSGabor Kovesdan case 'G':
4754dc88ebeSGabor Kovesdan grepbehave = GREP_BASIC;
4764dc88ebeSGabor Kovesdan break;
4774dc88ebeSGabor Kovesdan case 'H':
4784dc88ebeSGabor Kovesdan Hflag = true;
4794dc88ebeSGabor Kovesdan break;
4804dc88ebeSGabor Kovesdan case 'h':
4814dc88ebeSGabor Kovesdan Hflag = false;
4824dc88ebeSGabor Kovesdan hflag = true;
4834dc88ebeSGabor Kovesdan break;
4844dc88ebeSGabor Kovesdan case 'I':
4854dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP;
4864dc88ebeSGabor Kovesdan break;
4874dc88ebeSGabor Kovesdan case 'i':
4884dc88ebeSGabor Kovesdan case 'y':
4894dc88ebeSGabor Kovesdan iflag = true;
4904dc88ebeSGabor Kovesdan cflags |= REG_ICASE;
4914dc88ebeSGabor Kovesdan break;
4924dc88ebeSGabor Kovesdan case 'L':
4934dc88ebeSGabor Kovesdan lflag = false;
49427116286SGabor Kovesdan Lflag = true;
4954dc88ebeSGabor Kovesdan break;
4964dc88ebeSGabor Kovesdan case 'l':
4974dc88ebeSGabor Kovesdan Lflag = false;
49827116286SGabor Kovesdan lflag = true;
4994dc88ebeSGabor Kovesdan break;
5004dc88ebeSGabor Kovesdan case 'm':
5014dc88ebeSGabor Kovesdan mflag = true;
5024dc88ebeSGabor Kovesdan errno = 0;
503924500b7SEitan Adler mlimit = mcount = strtoll(optarg, &ep, 10);
504f20f6f3fSGabor Kovesdan if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
5054dc88ebeSGabor Kovesdan ((errno == EINVAL) && (mcount == 0)))
5064dc88ebeSGabor Kovesdan err(2, NULL);
5074dc88ebeSGabor Kovesdan else if (ep[0] != '\0') {
5084dc88ebeSGabor Kovesdan errno = EINVAL;
5094dc88ebeSGabor Kovesdan err(2, NULL);
5104dc88ebeSGabor Kovesdan }
5114dc88ebeSGabor Kovesdan break;
5124dc88ebeSGabor Kovesdan case 'n':
5134dc88ebeSGabor Kovesdan nflag = true;
5144dc88ebeSGabor Kovesdan break;
5154dc88ebeSGabor Kovesdan case 'O':
5164dc88ebeSGabor Kovesdan linkbehave = LINK_EXPLICIT;
5174dc88ebeSGabor Kovesdan break;
5184dc88ebeSGabor Kovesdan case 'o':
5194dc88ebeSGabor Kovesdan oflag = true;
52069a6d198SGabor Kovesdan cflags &= ~REG_NOSUB;
5214dc88ebeSGabor Kovesdan break;
5224dc88ebeSGabor Kovesdan case 'p':
5234dc88ebeSGabor Kovesdan linkbehave = LINK_SKIP;
5244dc88ebeSGabor Kovesdan break;
5254dc88ebeSGabor Kovesdan case 'q':
5264dc88ebeSGabor Kovesdan qflag = true;
5274dc88ebeSGabor Kovesdan break;
5284dc88ebeSGabor Kovesdan case 'S':
52927116286SGabor Kovesdan linkbehave = LINK_READ;
5304dc88ebeSGabor Kovesdan break;
5314dc88ebeSGabor Kovesdan case 'R':
5324dc88ebeSGabor Kovesdan case 'r':
5334dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE;
5344dc88ebeSGabor Kovesdan Hflag = true;
5354dc88ebeSGabor Kovesdan break;
5364dc88ebeSGabor Kovesdan case 's':
5374dc88ebeSGabor Kovesdan sflag = true;
5384dc88ebeSGabor Kovesdan break;
5394dc88ebeSGabor Kovesdan case 'U':
5404dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN;
5414dc88ebeSGabor Kovesdan break;
5424dc88ebeSGabor Kovesdan case 'u':
5434dc88ebeSGabor Kovesdan case MMAP_OPT:
544f20f6f3fSGabor Kovesdan filebehave = FILE_MMAP;
5454dc88ebeSGabor Kovesdan break;
5464dc88ebeSGabor Kovesdan case 'V':
54730dc9502SBaptiste Daroussin printf(errstr[8], getprogname(), VERSION);
5484dc88ebeSGabor Kovesdan exit(0);
5494dc88ebeSGabor Kovesdan case 'v':
5504dc88ebeSGabor Kovesdan vflag = true;
5514dc88ebeSGabor Kovesdan break;
5524dc88ebeSGabor Kovesdan case 'w':
5534dc88ebeSGabor Kovesdan wflag = true;
55469a6d198SGabor Kovesdan cflags &= ~REG_NOSUB;
5554dc88ebeSGabor Kovesdan break;
5564dc88ebeSGabor Kovesdan case 'x':
5574dc88ebeSGabor Kovesdan xflag = true;
55869a6d198SGabor Kovesdan cflags &= ~REG_NOSUB;
5594dc88ebeSGabor Kovesdan break;
5605ee1ea02SEd Maste case 'z':
5615ee1ea02SEd Maste fileeol = '\0';
562e898a3afSKyle Evans cflags &= ~REG_NEWLINE;
5635ee1ea02SEd Maste break;
5644dc88ebeSGabor Kovesdan case BIN_OPT:
56527116286SGabor Kovesdan if (strcasecmp("binary", optarg) == 0)
5664dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN;
56727116286SGabor Kovesdan else if (strcasecmp("without-match", optarg) == 0)
5684dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP;
56927116286SGabor Kovesdan else if (strcasecmp("text", optarg) == 0)
5704dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT;
5714dc88ebeSGabor Kovesdan else
57230dc9502SBaptiste Daroussin errx(2, errstr[2], "--binary-files");
5734dc88ebeSGabor Kovesdan break;
5744dc88ebeSGabor Kovesdan case COLOR_OPT:
5754dc88ebeSGabor Kovesdan color = NULL;
57627116286SGabor Kovesdan if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
57727116286SGabor Kovesdan strcasecmp("tty", optarg) == 0 ||
57827116286SGabor Kovesdan strcasecmp("if-tty", optarg) == 0) {
57927116286SGabor Kovesdan char *term;
58027116286SGabor Kovesdan
58127116286SGabor Kovesdan term = getenv("TERM");
58227116286SGabor Kovesdan if (isatty(STDOUT_FILENO) && term != NULL &&
58327116286SGabor Kovesdan strcasecmp(term, "dumb") != 0)
58427116286SGabor Kovesdan color = init_color("01;31");
58527116286SGabor Kovesdan } else if (strcasecmp("always", optarg) == 0 ||
58627116286SGabor Kovesdan strcasecmp("yes", optarg) == 0 ||
58727116286SGabor Kovesdan strcasecmp("force", optarg) == 0) {
58827116286SGabor Kovesdan color = init_color("01;31");
58927116286SGabor Kovesdan } else if (strcasecmp("never", optarg) != 0 &&
59027116286SGabor Kovesdan strcasecmp("none", optarg) != 0 &&
59127116286SGabor Kovesdan strcasecmp("no", optarg) != 0)
59230dc9502SBaptiste Daroussin errx(2, errstr[2], "--color");
59369a6d198SGabor Kovesdan cflags &= ~REG_NOSUB;
5944dc88ebeSGabor Kovesdan break;
5954dc88ebeSGabor Kovesdan case LABEL_OPT:
5964dc88ebeSGabor Kovesdan label = optarg;
5974dc88ebeSGabor Kovesdan break;
5984dc88ebeSGabor Kovesdan case LINEBUF_OPT:
5994dc88ebeSGabor Kovesdan lbflag = true;
6004dc88ebeSGabor Kovesdan break;
6014dc88ebeSGabor Kovesdan case NULL_OPT:
6024dc88ebeSGabor Kovesdan nullflag = true;
6034dc88ebeSGabor Kovesdan break;
6044dc88ebeSGabor Kovesdan case R_INCLUDE_OPT:
60555e44f51SGabor Kovesdan finclude = true;
60655e44f51SGabor Kovesdan add_fpattern(optarg, INCL_PAT);
6074dc88ebeSGabor Kovesdan break;
6084dc88ebeSGabor Kovesdan case R_EXCLUDE_OPT:
60955e44f51SGabor Kovesdan fexclude = true;
61055e44f51SGabor Kovesdan add_fpattern(optarg, EXCL_PAT);
6114dc88ebeSGabor Kovesdan break;
6124dc88ebeSGabor Kovesdan case R_DINCLUDE_OPT:
61359218eb7SGabor Kovesdan dinclude = true;
61455e44f51SGabor Kovesdan add_dpattern(optarg, INCL_PAT);
6154dc88ebeSGabor Kovesdan break;
6164dc88ebeSGabor Kovesdan case R_DEXCLUDE_OPT:
61759218eb7SGabor Kovesdan dexclude = true;
61855e44f51SGabor Kovesdan add_dpattern(optarg, EXCL_PAT);
6194dc88ebeSGabor Kovesdan break;
6204dc88ebeSGabor Kovesdan case HELP_OPT:
6214dc88ebeSGabor Kovesdan default:
6224dc88ebeSGabor Kovesdan usage();
6234dc88ebeSGabor Kovesdan }
6244dc88ebeSGabor Kovesdan lastc = c;
6254dc88ebeSGabor Kovesdan newarg = optind != prevoptind;
6264dc88ebeSGabor Kovesdan prevoptind = optind;
6274dc88ebeSGabor Kovesdan }
6284dc88ebeSGabor Kovesdan aargc -= optind;
6294dc88ebeSGabor Kovesdan aargv += optind;
6304dc88ebeSGabor Kovesdan
6312373acbbSKyle Evans /* xflag takes precedence, don't confuse the matching bits. */
6322373acbbSKyle Evans if (wflag && xflag)
6332373acbbSKyle Evans wflag = false;
6342373acbbSKyle Evans
6354dc88ebeSGabor Kovesdan /* Fail if we don't have any pattern */
6364dc88ebeSGabor Kovesdan if (aargc == 0 && needpattern)
6374dc88ebeSGabor Kovesdan usage();
6384dc88ebeSGabor Kovesdan
6394dc88ebeSGabor Kovesdan /* Process patterns from command line */
6404dc88ebeSGabor Kovesdan if (aargc != 0 && needpattern) {
641e411593dSGabor Kovesdan char *token;
642cd64c588SGabor Kovesdan char *string = *aargv;
643e411593dSGabor Kovesdan
644e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL)
645e411593dSGabor Kovesdan add_pattern(token, strlen(token));
6464dc88ebeSGabor Kovesdan --aargc;
6474dc88ebeSGabor Kovesdan ++aargv;
6484dc88ebeSGabor Kovesdan }
6494dc88ebeSGabor Kovesdan
6504dc88ebeSGabor Kovesdan switch (grepbehave) {
6514dc88ebeSGabor Kovesdan case GREP_BASIC:
6524dc88ebeSGabor Kovesdan break;
653f20f6f3fSGabor Kovesdan case GREP_FIXED:
65405ad8215SKyle Evans /*
65505ad8215SKyle Evans * regex(3) implementations that support fixed-string searches generally
65605ad8215SKyle Evans * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
65705ad8215SKyle Evans * here. If neither are defined, GREP_FIXED later implies that the
65805ad8215SKyle Evans * internal literal matcher should be used. Other cflags that have
65905ad8215SKyle Evans * the same interpretation as REG_NOSPEC and REG_LITERAL should be
66005ad8215SKyle Evans * similarly added here, and grep.h should be amended to take this into
66105ad8215SKyle Evans * consideration when defining WITH_INTERNAL_NOSPEC.
66205ad8215SKyle Evans */
663476d2098SEd Maste #if defined(REG_NOSPEC)
664476d2098SEd Maste cflags |= REG_NOSPEC;
665476d2098SEd Maste #elif defined(REG_LITERAL)
666476d2098SEd Maste cflags |= REG_LITERAL;
667476d2098SEd Maste #endif
668f20f6f3fSGabor Kovesdan break;
6694dc88ebeSGabor Kovesdan case GREP_EXTENDED:
6704dc88ebeSGabor Kovesdan cflags |= REG_EXTENDED;
6714dc88ebeSGabor Kovesdan break;
6724dc88ebeSGabor Kovesdan default:
6734dc88ebeSGabor Kovesdan /* NOTREACHED */
6744dc88ebeSGabor Kovesdan usage();
6754dc88ebeSGabor Kovesdan }
6764dc88ebeSGabor Kovesdan
6774dc88ebeSGabor Kovesdan r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
678f20f6f3fSGabor Kovesdan
67905ad8215SKyle Evans #ifdef WITH_INTERNAL_NOSPEC
68038325e2aSKyle Evans if (grepbehave != GREP_FIXED) {
68105ad8215SKyle Evans #else
68238325e2aSKyle Evans {
68305ad8215SKyle Evans #endif
6844dc88ebeSGabor Kovesdan /* Check if cheating is allowed (always is for fgrep). */
6854dc88ebeSGabor Kovesdan for (i = 0; i < patterns; ++i) {
686f20f6f3fSGabor Kovesdan c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
6874dc88ebeSGabor Kovesdan if (c != 0) {
6884dc88ebeSGabor Kovesdan regerror(c, &r_pattern[i], re_error,
6894dc88ebeSGabor Kovesdan RE_ERROR_BUF);
6904dc88ebeSGabor Kovesdan errx(2, "%s", re_error);
6914dc88ebeSGabor Kovesdan }
6924dc88ebeSGabor Kovesdan }
693a4f3f02bSEd Maste }
6944dc88ebeSGabor Kovesdan
6954dc88ebeSGabor Kovesdan if (lbflag)
6964dc88ebeSGabor Kovesdan setlinebuf(stdout);
6974dc88ebeSGabor Kovesdan
6984dc88ebeSGabor Kovesdan if ((aargc == 0 || aargc == 1) && !Hflag)
6994dc88ebeSGabor Kovesdan hflag = true;
7004dc88ebeSGabor Kovesdan
701df546c3bSKyle Evans initqueue();
702df546c3bSKyle Evans
703a461896aSEd Maste if (aargc == 0 && dirbehave != DIR_RECURSE)
7044dc88ebeSGabor Kovesdan exit(!procfile("-"));
7054dc88ebeSGabor Kovesdan
7064dc88ebeSGabor Kovesdan if (dirbehave == DIR_RECURSE)
707cbfff13fSKyle Evans matched = grep_tree(aargv);
708c38208adSXin LI else
709cbfff13fSKyle Evans for (matched = false; aargc--; ++aargv) {
71055e44f51SGabor Kovesdan if ((finclude || fexclude) && !file_matching(*aargv))
71155e44f51SGabor Kovesdan continue;
712cbfff13fSKyle Evans if (procfile(*aargv))
713cbfff13fSKyle Evans matched = true;
71455e44f51SGabor Kovesdan }
7154dc88ebeSGabor Kovesdan
71638325e2aSKyle Evans if (Lflag)
71738325e2aSKyle Evans matched = !matched;
71838325e2aSKyle Evans
71938325e2aSKyle Evans /*
72038325e2aSKyle Evans * Calculate the correct return value according to the
72138325e2aSKyle Evans * results and the command line option.
72238325e2aSKyle Evans */
723cbfff13fSKyle Evans exit(matched ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
7244dc88ebeSGabor Kovesdan }
725