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