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 /*- 6a0ef9ad6SDag-Erling Smørgrav * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav 74dc88ebeSGabor Kovesdan * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org> 84dc88ebeSGabor Kovesdan * All rights reserved. 94dc88ebeSGabor Kovesdan * 104dc88ebeSGabor Kovesdan * Redistribution and use in source and binary forms, with or without 114dc88ebeSGabor Kovesdan * modification, are permitted provided that the following conditions 124dc88ebeSGabor Kovesdan * are met: 134dc88ebeSGabor Kovesdan * 1. Redistributions of source code must retain the above copyright 144dc88ebeSGabor Kovesdan * notice, this list of conditions and the following disclaimer. 154dc88ebeSGabor Kovesdan * 2. Redistributions in binary form must reproduce the above copyright 164dc88ebeSGabor Kovesdan * notice, this list of conditions and the following disclaimer in the 174dc88ebeSGabor Kovesdan * documentation and/or other materials provided with the distribution. 184dc88ebeSGabor Kovesdan * 194dc88ebeSGabor Kovesdan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 204dc88ebeSGabor Kovesdan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 214dc88ebeSGabor Kovesdan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 224dc88ebeSGabor Kovesdan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 234dc88ebeSGabor Kovesdan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 244dc88ebeSGabor Kovesdan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 254dc88ebeSGabor Kovesdan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 264dc88ebeSGabor Kovesdan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 274dc88ebeSGabor Kovesdan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 284dc88ebeSGabor Kovesdan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 294dc88ebeSGabor Kovesdan * SUCH DAMAGE. 304dc88ebeSGabor Kovesdan */ 314dc88ebeSGabor Kovesdan 324dc88ebeSGabor Kovesdan #include <sys/cdefs.h> 334dc88ebeSGabor Kovesdan __FBSDID("$FreeBSD$"); 344dc88ebeSGabor Kovesdan 354dc88ebeSGabor Kovesdan #include <sys/stat.h> 364dc88ebeSGabor Kovesdan #include <sys/types.h> 374dc88ebeSGabor Kovesdan 384dc88ebeSGabor Kovesdan #include <ctype.h> 394dc88ebeSGabor Kovesdan #include <err.h> 404dc88ebeSGabor Kovesdan #include <errno.h> 41f20f6f3fSGabor Kovesdan #include <fcntl.h> 424dc88ebeSGabor Kovesdan #include <getopt.h> 434dc88ebeSGabor Kovesdan #include <limits.h> 444dc88ebeSGabor Kovesdan #include <libgen.h> 454dc88ebeSGabor Kovesdan #include <locale.h> 464dc88ebeSGabor Kovesdan #include <stdbool.h> 474dc88ebeSGabor Kovesdan #include <stdio.h> 484dc88ebeSGabor Kovesdan #include <stdlib.h> 494dc88ebeSGabor Kovesdan #include <string.h> 504dc88ebeSGabor Kovesdan #include <unistd.h> 514dc88ebeSGabor Kovesdan 52f20f6f3fSGabor Kovesdan #include "fastmatch.h" 534dc88ebeSGabor Kovesdan #include "grep.h" 544dc88ebeSGabor Kovesdan 554dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 564dc88ebeSGabor Kovesdan #include <nl_types.h> 574dc88ebeSGabor Kovesdan nl_catd catalog; 584dc88ebeSGabor Kovesdan #endif 594dc88ebeSGabor Kovesdan 604dc88ebeSGabor Kovesdan /* 614dc88ebeSGabor Kovesdan * Default messags to use when NLS is disabled or no catalogue 624dc88ebeSGabor Kovesdan * is found. 634dc88ebeSGabor Kovesdan */ 644dc88ebeSGabor Kovesdan const char *errstr[] = { 654dc88ebeSGabor Kovesdan "", 664dc88ebeSGabor Kovesdan /* 1*/ "(standard input)", 674dc88ebeSGabor Kovesdan /* 2*/ "cannot read bzip2 compressed file", 6897a012f2SGabor Kovesdan /* 3*/ "unknown %s option", 694dc88ebeSGabor Kovesdan /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n", 704dc88ebeSGabor Kovesdan /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 714dc88ebeSGabor Kovesdan /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 724dc88ebeSGabor Kovesdan /* 7*/ "\t[--null] [pattern] [file ...]\n", 7397a012f2SGabor Kovesdan /* 8*/ "Binary file %s matches\n", 7497a012f2SGabor Kovesdan /* 9*/ "%s (BSD grep) %s\n", 754dc88ebeSGabor Kovesdan }; 764dc88ebeSGabor Kovesdan 774dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */ 7869a6d198SGabor Kovesdan int cflags = REG_NOSUB; 794dc88ebeSGabor Kovesdan int eflags = REG_STARTEND; 804dc88ebeSGabor Kovesdan 814dc88ebeSGabor Kovesdan /* Shortcut for matching all cases like empty regex */ 824dc88ebeSGabor Kovesdan bool matchall; 834dc88ebeSGabor Kovesdan 844dc88ebeSGabor Kovesdan /* Searching patterns */ 85bf70beceSEd Schouten unsigned int patterns; 86bf70beceSEd Schouten static unsigned int pattern_sz; 87f20f6f3fSGabor Kovesdan struct pat *pattern; 884dc88ebeSGabor Kovesdan regex_t *r_pattern; 89f20f6f3fSGabor Kovesdan fastmatch_t *fg_pattern; 904dc88ebeSGabor Kovesdan 914dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */ 92bf70beceSEd Schouten unsigned int fpatterns, dpatterns; 93bf70beceSEd Schouten static unsigned int fpattern_sz, dpattern_sz; 9455e44f51SGabor Kovesdan struct epat *dpattern, *fpattern; 954dc88ebeSGabor Kovesdan 964dc88ebeSGabor Kovesdan /* For regex errors */ 974dc88ebeSGabor Kovesdan char re_error[RE_ERROR_BUF + 1]; 984dc88ebeSGabor Kovesdan 994dc88ebeSGabor Kovesdan /* Command-line flags */ 1004dc88ebeSGabor Kovesdan unsigned long long Aflag; /* -A x: print x lines trailing each match */ 1014dc88ebeSGabor Kovesdan unsigned long long Bflag; /* -B x: print x lines leading each match */ 1024dc88ebeSGabor Kovesdan bool Hflag; /* -H: always print file name */ 1034dc88ebeSGabor Kovesdan bool Lflag; /* -L: only show names of files with no matches */ 1044dc88ebeSGabor Kovesdan bool bflag; /* -b: show block numbers for each match */ 1054dc88ebeSGabor Kovesdan bool cflag; /* -c: only show a count of matching lines */ 1064dc88ebeSGabor Kovesdan bool hflag; /* -h: don't print filename headers */ 1074dc88ebeSGabor Kovesdan bool iflag; /* -i: ignore case */ 1084dc88ebeSGabor Kovesdan bool lflag; /* -l: only show names of files with matches */ 1094dc88ebeSGabor Kovesdan bool mflag; /* -m x: stop reading the files after x matches */ 110f20f6f3fSGabor Kovesdan long long mcount; /* count for -m */ 111924500b7SEitan Adler long long mlimit; /* requested value for -m */ 1124dc88ebeSGabor Kovesdan bool nflag; /* -n: show line numbers in front of matching lines */ 1134dc88ebeSGabor Kovesdan bool oflag; /* -o: print only matching part */ 1144dc88ebeSGabor Kovesdan bool qflag; /* -q: quiet mode (don't output anything) */ 1154dc88ebeSGabor Kovesdan bool sflag; /* -s: silent mode (ignore errors) */ 1164dc88ebeSGabor Kovesdan bool vflag; /* -v: only show non-matching lines */ 1174dc88ebeSGabor Kovesdan bool wflag; /* -w: pattern must start and end on word boundaries */ 1184dc88ebeSGabor Kovesdan bool xflag; /* -x: pattern must match entire line */ 1194dc88ebeSGabor Kovesdan bool lbflag; /* --line-buffered */ 1204dc88ebeSGabor Kovesdan bool nullflag; /* --null */ 1214dc88ebeSGabor Kovesdan char *label; /* --label */ 12227116286SGabor Kovesdan const char *color; /* --color */ 1234dc88ebeSGabor Kovesdan int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 1244dc88ebeSGabor Kovesdan int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 1254dc88ebeSGabor Kovesdan int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 12627116286SGabor Kovesdan int devbehave = DEV_READ; /* -D: handling of devices */ 12727116286SGabor Kovesdan int dirbehave = DIR_READ; /* -dRr: handling of directories */ 12827116286SGabor Kovesdan int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 1294dc88ebeSGabor Kovesdan 13059218eb7SGabor Kovesdan bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 13159218eb7SGabor Kovesdan bool fexclude, finclude; /* --exclude and --include */ 13255e44f51SGabor Kovesdan 1334dc88ebeSGabor Kovesdan enum { 1344dc88ebeSGabor Kovesdan BIN_OPT = CHAR_MAX + 1, 1354dc88ebeSGabor Kovesdan COLOR_OPT, 1364dc88ebeSGabor Kovesdan HELP_OPT, 1374dc88ebeSGabor Kovesdan MMAP_OPT, 1384dc88ebeSGabor Kovesdan LINEBUF_OPT, 1394dc88ebeSGabor Kovesdan LABEL_OPT, 1404dc88ebeSGabor Kovesdan NULL_OPT, 1414dc88ebeSGabor Kovesdan R_EXCLUDE_OPT, 1424dc88ebeSGabor Kovesdan R_INCLUDE_OPT, 1434dc88ebeSGabor Kovesdan R_DEXCLUDE_OPT, 1444dc88ebeSGabor Kovesdan R_DINCLUDE_OPT 1454dc88ebeSGabor Kovesdan }; 1464dc88ebeSGabor Kovesdan 14727116286SGabor Kovesdan static inline const char *init_color(const char *); 14827116286SGabor Kovesdan 1494dc88ebeSGabor Kovesdan /* Housekeeping */ 1504dc88ebeSGabor Kovesdan bool first = true; /* flag whether we are processing the first match */ 1514dc88ebeSGabor Kovesdan bool prev; /* flag whether or not the previous line matched */ 1524dc88ebeSGabor Kovesdan int tail; /* lines left to print */ 1536f4cbf7cSGabor Kovesdan bool file_err; /* file reading error */ 1544dc88ebeSGabor Kovesdan 1554dc88ebeSGabor Kovesdan /* 1564dc88ebeSGabor Kovesdan * Prints usage information and returns 2. 1574dc88ebeSGabor Kovesdan */ 1584dc88ebeSGabor Kovesdan static void 1594dc88ebeSGabor Kovesdan usage(void) 1604dc88ebeSGabor Kovesdan { 161afbbd357SGabor Kovesdan fprintf(stderr, getstr(4), getprogname()); 1624dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(5)); 1634dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(6)); 1644dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(7)); 1654dc88ebeSGabor Kovesdan exit(2); 1664dc88ebeSGabor Kovesdan } 1674dc88ebeSGabor Kovesdan 168f20f6f3fSGabor Kovesdan static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy"; 1694dc88ebeSGabor Kovesdan 1708375d512SEd Schouten static const struct option long_options[] = 1714dc88ebeSGabor Kovesdan { 1724dc88ebeSGabor Kovesdan {"binary-files", required_argument, NULL, BIN_OPT}, 1734dc88ebeSGabor Kovesdan {"help", no_argument, NULL, HELP_OPT}, 1744dc88ebeSGabor Kovesdan {"mmap", no_argument, NULL, MMAP_OPT}, 1754dc88ebeSGabor Kovesdan {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 1764dc88ebeSGabor Kovesdan {"label", required_argument, NULL, LABEL_OPT}, 1774dc88ebeSGabor Kovesdan {"null", no_argument, NULL, NULL_OPT}, 1784dc88ebeSGabor Kovesdan {"color", optional_argument, NULL, COLOR_OPT}, 1794dc88ebeSGabor Kovesdan {"colour", optional_argument, NULL, COLOR_OPT}, 1804dc88ebeSGabor Kovesdan {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 1814dc88ebeSGabor Kovesdan {"include", required_argument, NULL, R_INCLUDE_OPT}, 1824dc88ebeSGabor Kovesdan {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 1834dc88ebeSGabor Kovesdan {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 1844dc88ebeSGabor Kovesdan {"after-context", required_argument, NULL, 'A'}, 1854dc88ebeSGabor Kovesdan {"text", no_argument, NULL, 'a'}, 1864dc88ebeSGabor Kovesdan {"before-context", required_argument, NULL, 'B'}, 1874dc88ebeSGabor Kovesdan {"byte-offset", no_argument, NULL, 'b'}, 1884dc88ebeSGabor Kovesdan {"context", optional_argument, NULL, 'C'}, 1894dc88ebeSGabor Kovesdan {"count", no_argument, NULL, 'c'}, 1904dc88ebeSGabor Kovesdan {"devices", required_argument, NULL, 'D'}, 1914dc88ebeSGabor Kovesdan {"directories", required_argument, NULL, 'd'}, 1924dc88ebeSGabor Kovesdan {"extended-regexp", no_argument, NULL, 'E'}, 1934dc88ebeSGabor Kovesdan {"regexp", required_argument, NULL, 'e'}, 1944dc88ebeSGabor Kovesdan {"fixed-strings", no_argument, NULL, 'F'}, 1954dc88ebeSGabor Kovesdan {"file", required_argument, NULL, 'f'}, 1964dc88ebeSGabor Kovesdan {"basic-regexp", no_argument, NULL, 'G'}, 1974dc88ebeSGabor Kovesdan {"no-filename", no_argument, NULL, 'h'}, 1984dc88ebeSGabor Kovesdan {"with-filename", no_argument, NULL, 'H'}, 1994dc88ebeSGabor Kovesdan {"ignore-case", no_argument, NULL, 'i'}, 2004dc88ebeSGabor Kovesdan {"bz2decompress", no_argument, NULL, 'J'}, 2014dc88ebeSGabor Kovesdan {"files-with-matches", no_argument, NULL, 'l'}, 2024dc88ebeSGabor Kovesdan {"files-without-match", no_argument, NULL, 'L'}, 2034dc88ebeSGabor Kovesdan {"max-count", required_argument, NULL, 'm'}, 204f20f6f3fSGabor Kovesdan {"lzma", no_argument, NULL, 'M'}, 2054dc88ebeSGabor Kovesdan {"line-number", no_argument, NULL, 'n'}, 2064dc88ebeSGabor Kovesdan {"only-matching", no_argument, NULL, 'o'}, 2074dc88ebeSGabor Kovesdan {"quiet", no_argument, NULL, 'q'}, 2084dc88ebeSGabor Kovesdan {"silent", no_argument, NULL, 'q'}, 2094dc88ebeSGabor Kovesdan {"recursive", no_argument, NULL, 'r'}, 2104dc88ebeSGabor Kovesdan {"no-messages", no_argument, NULL, 's'}, 2114dc88ebeSGabor Kovesdan {"binary", no_argument, NULL, 'U'}, 2124dc88ebeSGabor Kovesdan {"unix-byte-offsets", no_argument, NULL, 'u'}, 2134dc88ebeSGabor Kovesdan {"invert-match", no_argument, NULL, 'v'}, 2144dc88ebeSGabor Kovesdan {"version", no_argument, NULL, 'V'}, 2154dc88ebeSGabor Kovesdan {"word-regexp", no_argument, NULL, 'w'}, 2164dc88ebeSGabor Kovesdan {"line-regexp", no_argument, NULL, 'x'}, 217f20f6f3fSGabor Kovesdan {"xz", no_argument, NULL, 'X'}, 2184dc88ebeSGabor Kovesdan {"decompress", no_argument, NULL, 'Z'}, 2194dc88ebeSGabor Kovesdan {NULL, no_argument, NULL, 0} 2204dc88ebeSGabor Kovesdan }; 2214dc88ebeSGabor Kovesdan 2224dc88ebeSGabor Kovesdan /* 2234dc88ebeSGabor Kovesdan * Adds a searching pattern to the internal array. 2244dc88ebeSGabor Kovesdan */ 2254dc88ebeSGabor Kovesdan static void 2264dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len) 2274dc88ebeSGabor Kovesdan { 2284dc88ebeSGabor Kovesdan 229f20f6f3fSGabor Kovesdan /* Do not add further pattern is we already match everything */ 230f20f6f3fSGabor Kovesdan if (matchall) 231f20f6f3fSGabor Kovesdan return; 232f20f6f3fSGabor Kovesdan 2334dc88ebeSGabor Kovesdan /* Check if we can do a shortcut */ 234f20f6f3fSGabor Kovesdan if (len == 0) { 2354dc88ebeSGabor Kovesdan matchall = true; 236f20f6f3fSGabor Kovesdan for (unsigned int i = 0; i < patterns; i++) { 237f20f6f3fSGabor Kovesdan free(pattern[i].pat); 238f20f6f3fSGabor Kovesdan } 239f20f6f3fSGabor Kovesdan pattern = grep_realloc(pattern, sizeof(struct pat)); 240f20f6f3fSGabor Kovesdan pattern[0].pat = NULL; 241f20f6f3fSGabor Kovesdan pattern[0].len = 0; 242f20f6f3fSGabor Kovesdan patterns = 1; 2434dc88ebeSGabor Kovesdan return; 2444dc88ebeSGabor Kovesdan } 2454dc88ebeSGabor Kovesdan /* Increase size if necessary */ 2464dc88ebeSGabor Kovesdan if (patterns == pattern_sz) { 2474dc88ebeSGabor Kovesdan pattern_sz *= 2; 2484dc88ebeSGabor Kovesdan pattern = grep_realloc(pattern, ++pattern_sz * 249f20f6f3fSGabor Kovesdan sizeof(struct pat)); 2504dc88ebeSGabor Kovesdan } 2514dc88ebeSGabor Kovesdan if (len > 0 && pat[len - 1] == '\n') 2524dc88ebeSGabor Kovesdan --len; 2534dc88ebeSGabor Kovesdan /* pat may not be NUL-terminated */ 254f20f6f3fSGabor Kovesdan pattern[patterns].pat = grep_malloc(len + 1); 255f20f6f3fSGabor Kovesdan memcpy(pattern[patterns].pat, pat, len); 256f20f6f3fSGabor Kovesdan pattern[patterns].len = len; 257f20f6f3fSGabor Kovesdan pattern[patterns].pat[len] = '\0'; 2584dc88ebeSGabor Kovesdan ++patterns; 2594dc88ebeSGabor Kovesdan } 2604dc88ebeSGabor Kovesdan 2614dc88ebeSGabor Kovesdan /* 26255e44f51SGabor Kovesdan * Adds a file include/exclude pattern to the internal array. 2634dc88ebeSGabor Kovesdan */ 2644dc88ebeSGabor Kovesdan static void 26555e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode) 2664dc88ebeSGabor Kovesdan { 2674dc88ebeSGabor Kovesdan 2684dc88ebeSGabor Kovesdan /* Increase size if necessary */ 26955e44f51SGabor Kovesdan if (fpatterns == fpattern_sz) { 27055e44f51SGabor Kovesdan fpattern_sz *= 2; 27155e44f51SGabor Kovesdan fpattern = grep_realloc(fpattern, ++fpattern_sz * 2724dc88ebeSGabor Kovesdan sizeof(struct epat)); 2734dc88ebeSGabor Kovesdan } 27455e44f51SGabor Kovesdan fpattern[fpatterns].pat = grep_strdup(pat); 27555e44f51SGabor Kovesdan fpattern[fpatterns].mode = mode; 27655e44f51SGabor Kovesdan ++fpatterns; 27755e44f51SGabor Kovesdan } 27855e44f51SGabor Kovesdan 27955e44f51SGabor Kovesdan /* 28055e44f51SGabor Kovesdan * Adds a directory include/exclude pattern to the internal array. 28155e44f51SGabor Kovesdan */ 28255e44f51SGabor Kovesdan static void 28355e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode) 28455e44f51SGabor Kovesdan { 28555e44f51SGabor Kovesdan 28655e44f51SGabor Kovesdan /* Increase size if necessary */ 28755e44f51SGabor Kovesdan if (dpatterns == dpattern_sz) { 28855e44f51SGabor Kovesdan dpattern_sz *= 2; 28955e44f51SGabor Kovesdan dpattern = grep_realloc(dpattern, ++dpattern_sz * 29055e44f51SGabor Kovesdan sizeof(struct epat)); 29155e44f51SGabor Kovesdan } 29255e44f51SGabor Kovesdan dpattern[dpatterns].pat = grep_strdup(pat); 29355e44f51SGabor Kovesdan dpattern[dpatterns].mode = mode; 29455e44f51SGabor Kovesdan ++dpatterns; 2954dc88ebeSGabor Kovesdan } 2964dc88ebeSGabor Kovesdan 2974dc88ebeSGabor Kovesdan /* 2984dc88ebeSGabor Kovesdan * Reads searching patterns from a file and adds them with add_pattern(). 2994dc88ebeSGabor Kovesdan */ 3004dc88ebeSGabor Kovesdan static void 3014dc88ebeSGabor Kovesdan read_patterns(const char *fn) 3024dc88ebeSGabor Kovesdan { 303f20f6f3fSGabor Kovesdan struct stat st; 3044dc88ebeSGabor Kovesdan FILE *f; 3054dc88ebeSGabor Kovesdan char *line; 3064dc88ebeSGabor Kovesdan size_t len; 307f3f50de6SPedro F. Giffuni ssize_t rlen; 3084dc88ebeSGabor Kovesdan 3094dc88ebeSGabor Kovesdan if ((f = fopen(fn, "r")) == NULL) 3104dc88ebeSGabor Kovesdan err(2, "%s", fn); 311f20f6f3fSGabor Kovesdan if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 312f20f6f3fSGabor Kovesdan fclose(f); 313f20f6f3fSGabor Kovesdan return; 314f20f6f3fSGabor Kovesdan } 315f3f50de6SPedro F. Giffuni len = 0; 316f3f50de6SPedro F. Giffuni line = NULL; 317*d204af1eSEd Maste while ((rlen = getline(&line, &len, f)) != -1) { 318*d204af1eSEd Maste if (line[0] == '\0') 319*d204af1eSEd Maste continue; 3202fa7a2afSPedro F. Giffuni add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); 321*d204af1eSEd Maste } 322*d204af1eSEd Maste 323f3f50de6SPedro F. Giffuni free(line); 3244dc88ebeSGabor Kovesdan if (ferror(f)) 3254dc88ebeSGabor Kovesdan err(2, "%s", fn); 3264dc88ebeSGabor Kovesdan fclose(f); 3274dc88ebeSGabor Kovesdan } 3284dc88ebeSGabor Kovesdan 32927116286SGabor Kovesdan static inline const char * 33027116286SGabor Kovesdan init_color(const char *d) 33127116286SGabor Kovesdan { 33227116286SGabor Kovesdan char *c; 33327116286SGabor Kovesdan 33427116286SGabor Kovesdan c = getenv("GREP_COLOR"); 335dab19f30SGabor Kovesdan return (c != NULL && c[0] != '\0' ? c : d); 33627116286SGabor Kovesdan } 33727116286SGabor Kovesdan 3384dc88ebeSGabor Kovesdan int 3394dc88ebeSGabor Kovesdan main(int argc, char *argv[]) 3404dc88ebeSGabor Kovesdan { 3414dc88ebeSGabor Kovesdan char **aargv, **eargv, *eopts; 342afbbd357SGabor Kovesdan char *ep; 343afbbd357SGabor Kovesdan const char *pn; 3444dc88ebeSGabor Kovesdan unsigned long long l; 3454dc88ebeSGabor Kovesdan unsigned int aargc, eargc, i; 3464dc88ebeSGabor Kovesdan int c, lastc, needpattern, newarg, prevoptind; 3474dc88ebeSGabor Kovesdan 3484dc88ebeSGabor Kovesdan setlocale(LC_ALL, ""); 3494dc88ebeSGabor Kovesdan 3504dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 3514dc88ebeSGabor Kovesdan catalog = catopen("grep", NL_CAT_LOCALE); 3524dc88ebeSGabor Kovesdan #endif 3534dc88ebeSGabor Kovesdan 3544dc88ebeSGabor Kovesdan /* Check what is the program name of the binary. In this 3554dc88ebeSGabor Kovesdan way we can have all the funcionalities in one binary 3564dc88ebeSGabor Kovesdan without the need of scripting and using ugly hacks. */ 357afbbd357SGabor Kovesdan pn = getprogname(); 358f20f6f3fSGabor Kovesdan if (pn[0] == 'b' && pn[1] == 'z') { 359f20f6f3fSGabor Kovesdan filebehave = FILE_BZIP; 360f20f6f3fSGabor Kovesdan pn += 2; 361f20f6f3fSGabor Kovesdan } else if (pn[0] == 'x' && pn[1] == 'z') { 362f20f6f3fSGabor Kovesdan filebehave = FILE_XZ; 363f20f6f3fSGabor Kovesdan pn += 2; 364f20f6f3fSGabor Kovesdan } else if (pn[0] == 'l' && pn[1] == 'z') { 365f20f6f3fSGabor Kovesdan filebehave = FILE_LZMA; 366f20f6f3fSGabor Kovesdan pn += 2; 367491b8b16SEd Maste } else if (pn[0] == 'r') { 368491b8b16SEd Maste dirbehave = DIR_RECURSE; 369491b8b16SEd Maste Hflag = true; 370f20f6f3fSGabor Kovesdan } else if (pn[0] == 'z') { 3714dc88ebeSGabor Kovesdan filebehave = FILE_GZIP; 372f20f6f3fSGabor Kovesdan pn += 1; 373f20f6f3fSGabor Kovesdan } 374f20f6f3fSGabor Kovesdan switch (pn[0]) { 3754dc88ebeSGabor Kovesdan case 'e': 3764dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 3774dc88ebeSGabor Kovesdan break; 3784dc88ebeSGabor Kovesdan case 'f': 3794dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 3804dc88ebeSGabor Kovesdan break; 3814dc88ebeSGabor Kovesdan } 3824dc88ebeSGabor Kovesdan 3834dc88ebeSGabor Kovesdan lastc = '\0'; 3844dc88ebeSGabor Kovesdan newarg = 1; 3854dc88ebeSGabor Kovesdan prevoptind = 1; 3864dc88ebeSGabor Kovesdan needpattern = 1; 3874dc88ebeSGabor Kovesdan 3884dc88ebeSGabor Kovesdan eopts = getenv("GREP_OPTIONS"); 3894dc88ebeSGabor Kovesdan 39059218eb7SGabor Kovesdan /* support for extra arguments in GREP_OPTIONS */ 39159218eb7SGabor Kovesdan eargc = 0; 392dab19f30SGabor Kovesdan if (eopts != NULL && eopts[0] != '\0') { 3934dc88ebeSGabor Kovesdan char *str; 3944dc88ebeSGabor Kovesdan 39559218eb7SGabor Kovesdan /* make an estimation of how many extra arguments we have */ 39659218eb7SGabor Kovesdan for (unsigned int j = 0; j < strlen(eopts); j++) 39759218eb7SGabor Kovesdan if (eopts[j] == ' ') 3984dc88ebeSGabor Kovesdan eargc++; 3994dc88ebeSGabor Kovesdan 4004dc88ebeSGabor Kovesdan eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 4014dc88ebeSGabor Kovesdan 4024dc88ebeSGabor Kovesdan eargc = 0; 40359218eb7SGabor Kovesdan /* parse extra arguments */ 40459218eb7SGabor Kovesdan while ((str = strsep(&eopts, " ")) != NULL) 405dab19f30SGabor Kovesdan if (str[0] != '\0') 40659218eb7SGabor Kovesdan eargv[eargc++] = grep_strdup(str); 4074dc88ebeSGabor Kovesdan 4080c41ffb3SXin LI aargv = (char **)grep_calloc(eargc + argc + 1, 4090c41ffb3SXin LI sizeof(char *)); 41059218eb7SGabor Kovesdan 4114dc88ebeSGabor Kovesdan aargv[0] = argv[0]; 41259218eb7SGabor Kovesdan for (i = 0; i < eargc; i++) 41359218eb7SGabor Kovesdan aargv[i + 1] = eargv[i]; 41459218eb7SGabor Kovesdan for (int j = 1; j < argc; j++, i++) 41559218eb7SGabor Kovesdan aargv[i + 1] = argv[j]; 4164dc88ebeSGabor Kovesdan 41759218eb7SGabor Kovesdan aargc = eargc + argc; 4184dc88ebeSGabor Kovesdan } else { 4194dc88ebeSGabor Kovesdan aargv = argv; 4204dc88ebeSGabor Kovesdan aargc = argc; 4214dc88ebeSGabor Kovesdan } 4224dc88ebeSGabor Kovesdan 4234dc88ebeSGabor Kovesdan while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 4244dc88ebeSGabor Kovesdan -1)) { 4254dc88ebeSGabor Kovesdan switch (c) { 4264dc88ebeSGabor Kovesdan case '0': case '1': case '2': case '3': case '4': 4274dc88ebeSGabor Kovesdan case '5': case '6': case '7': case '8': case '9': 4284dc88ebeSGabor Kovesdan if (newarg || !isdigit(lastc)) 4294dc88ebeSGabor Kovesdan Aflag = 0; 4304dc88ebeSGabor Kovesdan else if (Aflag > LLONG_MAX / 10) { 4314dc88ebeSGabor Kovesdan errno = ERANGE; 4324dc88ebeSGabor Kovesdan err(2, NULL); 4334dc88ebeSGabor Kovesdan } 4344dc88ebeSGabor Kovesdan Aflag = Bflag = (Aflag * 10) + (c - '0'); 4354dc88ebeSGabor Kovesdan break; 4364dc88ebeSGabor Kovesdan case 'C': 4374dc88ebeSGabor Kovesdan if (optarg == NULL) { 4384dc88ebeSGabor Kovesdan Aflag = Bflag = 2; 4394dc88ebeSGabor Kovesdan break; 4404dc88ebeSGabor Kovesdan } 4414dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4424dc88ebeSGabor Kovesdan case 'A': 4434dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4444dc88ebeSGabor Kovesdan case 'B': 4454dc88ebeSGabor Kovesdan errno = 0; 4464dc88ebeSGabor Kovesdan l = strtoull(optarg, &ep, 10); 4474dc88ebeSGabor Kovesdan if (((errno == ERANGE) && (l == ULLONG_MAX)) || 4484dc88ebeSGabor Kovesdan ((errno == EINVAL) && (l == 0))) 4494dc88ebeSGabor Kovesdan err(2, NULL); 4504dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 4514dc88ebeSGabor Kovesdan errno = EINVAL; 4524dc88ebeSGabor Kovesdan err(2, NULL); 4534dc88ebeSGabor Kovesdan } 4544dc88ebeSGabor Kovesdan if (c == 'A') 4554dc88ebeSGabor Kovesdan Aflag = l; 4564dc88ebeSGabor Kovesdan else if (c == 'B') 4574dc88ebeSGabor Kovesdan Bflag = l; 4584dc88ebeSGabor Kovesdan else 4594dc88ebeSGabor Kovesdan Aflag = Bflag = l; 4604dc88ebeSGabor Kovesdan break; 4614dc88ebeSGabor Kovesdan case 'a': 4624dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 4634dc88ebeSGabor Kovesdan break; 4644dc88ebeSGabor Kovesdan case 'b': 4654dc88ebeSGabor Kovesdan bflag = true; 4664dc88ebeSGabor Kovesdan break; 4674dc88ebeSGabor Kovesdan case 'c': 4684dc88ebeSGabor Kovesdan cflag = true; 4694dc88ebeSGabor Kovesdan break; 4704dc88ebeSGabor Kovesdan case 'D': 47127116286SGabor Kovesdan if (strcasecmp(optarg, "skip") == 0) 4724dc88ebeSGabor Kovesdan devbehave = DEV_SKIP; 47327116286SGabor Kovesdan else if (strcasecmp(optarg, "read") == 0) 47427116286SGabor Kovesdan devbehave = DEV_READ; 47597a012f2SGabor Kovesdan else 47697a012f2SGabor Kovesdan errx(2, getstr(3), "--devices"); 4774dc88ebeSGabor Kovesdan break; 4784dc88ebeSGabor Kovesdan case 'd': 47927116286SGabor Kovesdan if (strcasecmp("recurse", optarg) == 0) { 4804dc88ebeSGabor Kovesdan Hflag = true; 4814dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 48227116286SGabor Kovesdan } else if (strcasecmp("skip", optarg) == 0) 4834dc88ebeSGabor Kovesdan dirbehave = DIR_SKIP; 48427116286SGabor Kovesdan else if (strcasecmp("read", optarg) == 0) 48527116286SGabor Kovesdan dirbehave = DIR_READ; 48697a012f2SGabor Kovesdan else 48797a012f2SGabor Kovesdan errx(2, getstr(3), "--directories"); 4884dc88ebeSGabor Kovesdan break; 4894dc88ebeSGabor Kovesdan case 'E': 4904dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 4914dc88ebeSGabor Kovesdan break; 4924dc88ebeSGabor Kovesdan case 'e': 493e411593dSGabor Kovesdan { 494e411593dSGabor Kovesdan char *token; 495cd64c588SGabor Kovesdan char *string = optarg; 496e411593dSGabor Kovesdan 497e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL) 498e411593dSGabor Kovesdan add_pattern(token, strlen(token)); 499e411593dSGabor Kovesdan } 5004dc88ebeSGabor Kovesdan needpattern = 0; 5014dc88ebeSGabor Kovesdan break; 5024dc88ebeSGabor Kovesdan case 'F': 5034dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 5044dc88ebeSGabor Kovesdan break; 5054dc88ebeSGabor Kovesdan case 'f': 5064dc88ebeSGabor Kovesdan read_patterns(optarg); 5074dc88ebeSGabor Kovesdan needpattern = 0; 5084dc88ebeSGabor Kovesdan break; 5094dc88ebeSGabor Kovesdan case 'G': 5104dc88ebeSGabor Kovesdan grepbehave = GREP_BASIC; 5114dc88ebeSGabor Kovesdan break; 5124dc88ebeSGabor Kovesdan case 'H': 5134dc88ebeSGabor Kovesdan Hflag = true; 5144dc88ebeSGabor Kovesdan break; 5154dc88ebeSGabor Kovesdan case 'h': 5164dc88ebeSGabor Kovesdan Hflag = false; 5174dc88ebeSGabor Kovesdan hflag = true; 5184dc88ebeSGabor Kovesdan break; 5194dc88ebeSGabor Kovesdan case 'I': 5204dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 5214dc88ebeSGabor Kovesdan break; 5224dc88ebeSGabor Kovesdan case 'i': 5234dc88ebeSGabor Kovesdan case 'y': 5244dc88ebeSGabor Kovesdan iflag = true; 5254dc88ebeSGabor Kovesdan cflags |= REG_ICASE; 5264dc88ebeSGabor Kovesdan break; 5274dc88ebeSGabor Kovesdan case 'J': 528afbbd357SGabor Kovesdan #ifdef WITHOUT_BZIP2 529afbbd357SGabor Kovesdan errno = EOPNOTSUPP; 530afbbd357SGabor Kovesdan err(2, "bzip2 support was disabled at compile-time"); 531afbbd357SGabor Kovesdan #endif 5324dc88ebeSGabor Kovesdan filebehave = FILE_BZIP; 5334dc88ebeSGabor Kovesdan break; 5344dc88ebeSGabor Kovesdan case 'L': 5354dc88ebeSGabor Kovesdan lflag = false; 53627116286SGabor Kovesdan Lflag = true; 5374dc88ebeSGabor Kovesdan break; 5384dc88ebeSGabor Kovesdan case 'l': 5394dc88ebeSGabor Kovesdan Lflag = false; 54027116286SGabor Kovesdan lflag = true; 5414dc88ebeSGabor Kovesdan break; 5424dc88ebeSGabor Kovesdan case 'm': 5434dc88ebeSGabor Kovesdan mflag = true; 5444dc88ebeSGabor Kovesdan errno = 0; 545924500b7SEitan Adler mlimit = mcount = strtoll(optarg, &ep, 10); 546f20f6f3fSGabor Kovesdan if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 5474dc88ebeSGabor Kovesdan ((errno == EINVAL) && (mcount == 0))) 5484dc88ebeSGabor Kovesdan err(2, NULL); 5494dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 5504dc88ebeSGabor Kovesdan errno = EINVAL; 5514dc88ebeSGabor Kovesdan err(2, NULL); 5524dc88ebeSGabor Kovesdan } 5534dc88ebeSGabor Kovesdan break; 554f20f6f3fSGabor Kovesdan case 'M': 555f20f6f3fSGabor Kovesdan filebehave = FILE_LZMA; 556f20f6f3fSGabor Kovesdan break; 5574dc88ebeSGabor Kovesdan case 'n': 5584dc88ebeSGabor Kovesdan nflag = true; 5594dc88ebeSGabor Kovesdan break; 5604dc88ebeSGabor Kovesdan case 'O': 5614dc88ebeSGabor Kovesdan linkbehave = LINK_EXPLICIT; 5624dc88ebeSGabor Kovesdan break; 5634dc88ebeSGabor Kovesdan case 'o': 5644dc88ebeSGabor Kovesdan oflag = true; 56569a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5664dc88ebeSGabor Kovesdan break; 5674dc88ebeSGabor Kovesdan case 'p': 5684dc88ebeSGabor Kovesdan linkbehave = LINK_SKIP; 5694dc88ebeSGabor Kovesdan break; 5704dc88ebeSGabor Kovesdan case 'q': 5714dc88ebeSGabor Kovesdan qflag = true; 5724dc88ebeSGabor Kovesdan break; 5734dc88ebeSGabor Kovesdan case 'S': 57427116286SGabor Kovesdan linkbehave = LINK_READ; 5754dc88ebeSGabor Kovesdan break; 5764dc88ebeSGabor Kovesdan case 'R': 5774dc88ebeSGabor Kovesdan case 'r': 5784dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 5794dc88ebeSGabor Kovesdan Hflag = true; 5804dc88ebeSGabor Kovesdan break; 5814dc88ebeSGabor Kovesdan case 's': 5824dc88ebeSGabor Kovesdan sflag = true; 5834dc88ebeSGabor Kovesdan break; 5844dc88ebeSGabor Kovesdan case 'U': 5854dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 5864dc88ebeSGabor Kovesdan break; 5874dc88ebeSGabor Kovesdan case 'u': 5884dc88ebeSGabor Kovesdan case MMAP_OPT: 589f20f6f3fSGabor Kovesdan filebehave = FILE_MMAP; 5904dc88ebeSGabor Kovesdan break; 5914dc88ebeSGabor Kovesdan case 'V': 592afbbd357SGabor Kovesdan printf(getstr(9), getprogname(), VERSION); 5934dc88ebeSGabor Kovesdan exit(0); 5944dc88ebeSGabor Kovesdan case 'v': 5954dc88ebeSGabor Kovesdan vflag = true; 5964dc88ebeSGabor Kovesdan break; 5974dc88ebeSGabor Kovesdan case 'w': 5984dc88ebeSGabor Kovesdan wflag = true; 59969a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6004dc88ebeSGabor Kovesdan break; 6014dc88ebeSGabor Kovesdan case 'x': 6024dc88ebeSGabor Kovesdan xflag = true; 60369a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6044dc88ebeSGabor Kovesdan break; 605f20f6f3fSGabor Kovesdan case 'X': 606f20f6f3fSGabor Kovesdan filebehave = FILE_XZ; 607f20f6f3fSGabor Kovesdan break; 6084dc88ebeSGabor Kovesdan case 'Z': 6094dc88ebeSGabor Kovesdan filebehave = FILE_GZIP; 6104dc88ebeSGabor Kovesdan break; 6114dc88ebeSGabor Kovesdan case BIN_OPT: 61227116286SGabor Kovesdan if (strcasecmp("binary", optarg) == 0) 6134dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 61427116286SGabor Kovesdan else if (strcasecmp("without-match", optarg) == 0) 6154dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 61627116286SGabor Kovesdan else if (strcasecmp("text", optarg) == 0) 6174dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 6184dc88ebeSGabor Kovesdan else 61997a012f2SGabor Kovesdan errx(2, getstr(3), "--binary-files"); 6204dc88ebeSGabor Kovesdan break; 6214dc88ebeSGabor Kovesdan case COLOR_OPT: 6224dc88ebeSGabor Kovesdan color = NULL; 62327116286SGabor Kovesdan if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 62427116286SGabor Kovesdan strcasecmp("tty", optarg) == 0 || 62527116286SGabor Kovesdan strcasecmp("if-tty", optarg) == 0) { 62627116286SGabor Kovesdan char *term; 62727116286SGabor Kovesdan 62827116286SGabor Kovesdan term = getenv("TERM"); 62927116286SGabor Kovesdan if (isatty(STDOUT_FILENO) && term != NULL && 63027116286SGabor Kovesdan strcasecmp(term, "dumb") != 0) 63127116286SGabor Kovesdan color = init_color("01;31"); 63227116286SGabor Kovesdan } else if (strcasecmp("always", optarg) == 0 || 63327116286SGabor Kovesdan strcasecmp("yes", optarg) == 0 || 63427116286SGabor Kovesdan strcasecmp("force", optarg) == 0) { 63527116286SGabor Kovesdan color = init_color("01;31"); 63627116286SGabor Kovesdan } else if (strcasecmp("never", optarg) != 0 && 63727116286SGabor Kovesdan strcasecmp("none", optarg) != 0 && 63827116286SGabor Kovesdan strcasecmp("no", optarg) != 0) 63997a012f2SGabor Kovesdan errx(2, getstr(3), "--color"); 64069a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6414dc88ebeSGabor Kovesdan break; 6424dc88ebeSGabor Kovesdan case LABEL_OPT: 6434dc88ebeSGabor Kovesdan label = optarg; 6444dc88ebeSGabor Kovesdan break; 6454dc88ebeSGabor Kovesdan case LINEBUF_OPT: 6464dc88ebeSGabor Kovesdan lbflag = true; 6474dc88ebeSGabor Kovesdan break; 6484dc88ebeSGabor Kovesdan case NULL_OPT: 6494dc88ebeSGabor Kovesdan nullflag = true; 6504dc88ebeSGabor Kovesdan break; 6514dc88ebeSGabor Kovesdan case R_INCLUDE_OPT: 65255e44f51SGabor Kovesdan finclude = true; 65355e44f51SGabor Kovesdan add_fpattern(optarg, INCL_PAT); 6544dc88ebeSGabor Kovesdan break; 6554dc88ebeSGabor Kovesdan case R_EXCLUDE_OPT: 65655e44f51SGabor Kovesdan fexclude = true; 65755e44f51SGabor Kovesdan add_fpattern(optarg, EXCL_PAT); 6584dc88ebeSGabor Kovesdan break; 6594dc88ebeSGabor Kovesdan case R_DINCLUDE_OPT: 66059218eb7SGabor Kovesdan dinclude = true; 66155e44f51SGabor Kovesdan add_dpattern(optarg, INCL_PAT); 6624dc88ebeSGabor Kovesdan break; 6634dc88ebeSGabor Kovesdan case R_DEXCLUDE_OPT: 66459218eb7SGabor Kovesdan dexclude = true; 66555e44f51SGabor Kovesdan add_dpattern(optarg, EXCL_PAT); 6664dc88ebeSGabor Kovesdan break; 6674dc88ebeSGabor Kovesdan case HELP_OPT: 6684dc88ebeSGabor Kovesdan default: 6694dc88ebeSGabor Kovesdan usage(); 6704dc88ebeSGabor Kovesdan } 6714dc88ebeSGabor Kovesdan lastc = c; 6724dc88ebeSGabor Kovesdan newarg = optind != prevoptind; 6734dc88ebeSGabor Kovesdan prevoptind = optind; 6744dc88ebeSGabor Kovesdan } 6754dc88ebeSGabor Kovesdan aargc -= optind; 6764dc88ebeSGabor Kovesdan aargv += optind; 6774dc88ebeSGabor Kovesdan 678f20f6f3fSGabor Kovesdan /* Empty pattern file matches nothing */ 679f20f6f3fSGabor Kovesdan if (!needpattern && (patterns == 0)) 680f20f6f3fSGabor Kovesdan exit(1); 681f20f6f3fSGabor Kovesdan 6824dc88ebeSGabor Kovesdan /* Fail if we don't have any pattern */ 6834dc88ebeSGabor Kovesdan if (aargc == 0 && needpattern) 6844dc88ebeSGabor Kovesdan usage(); 6854dc88ebeSGabor Kovesdan 6864dc88ebeSGabor Kovesdan /* Process patterns from command line */ 6874dc88ebeSGabor Kovesdan if (aargc != 0 && needpattern) { 688e411593dSGabor Kovesdan char *token; 689cd64c588SGabor Kovesdan char *string = *aargv; 690e411593dSGabor Kovesdan 691e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL) 692e411593dSGabor Kovesdan add_pattern(token, strlen(token)); 6934dc88ebeSGabor Kovesdan --aargc; 6944dc88ebeSGabor Kovesdan ++aargv; 6954dc88ebeSGabor Kovesdan } 6964dc88ebeSGabor Kovesdan 6974dc88ebeSGabor Kovesdan switch (grepbehave) { 6984dc88ebeSGabor Kovesdan case GREP_BASIC: 6994dc88ebeSGabor Kovesdan break; 700f20f6f3fSGabor Kovesdan case GREP_FIXED: 701f20f6f3fSGabor Kovesdan /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */ 702f20f6f3fSGabor Kovesdan cflags |= 0020; 703f20f6f3fSGabor Kovesdan break; 7044dc88ebeSGabor Kovesdan case GREP_EXTENDED: 7054dc88ebeSGabor Kovesdan cflags |= REG_EXTENDED; 7064dc88ebeSGabor Kovesdan break; 7074dc88ebeSGabor Kovesdan default: 7084dc88ebeSGabor Kovesdan /* NOTREACHED */ 7094dc88ebeSGabor Kovesdan usage(); 7104dc88ebeSGabor Kovesdan } 7114dc88ebeSGabor Kovesdan 7124dc88ebeSGabor Kovesdan fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 7134dc88ebeSGabor Kovesdan r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 714f20f6f3fSGabor Kovesdan 7154dc88ebeSGabor Kovesdan /* Check if cheating is allowed (always is for fgrep). */ 7164dc88ebeSGabor Kovesdan for (i = 0; i < patterns; ++i) { 717f20f6f3fSGabor Kovesdan if (fastncomp(&fg_pattern[i], pattern[i].pat, 718f20f6f3fSGabor Kovesdan pattern[i].len, cflags) != 0) { 7194dc88ebeSGabor Kovesdan /* Fall back to full regex library */ 720f20f6f3fSGabor Kovesdan c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 7214dc88ebeSGabor Kovesdan if (c != 0) { 7224dc88ebeSGabor Kovesdan regerror(c, &r_pattern[i], re_error, 7234dc88ebeSGabor Kovesdan RE_ERROR_BUF); 7244dc88ebeSGabor Kovesdan errx(2, "%s", re_error); 7254dc88ebeSGabor Kovesdan } 7264dc88ebeSGabor Kovesdan } 7274dc88ebeSGabor Kovesdan } 7284dc88ebeSGabor Kovesdan 7294dc88ebeSGabor Kovesdan if (lbflag) 7304dc88ebeSGabor Kovesdan setlinebuf(stdout); 7314dc88ebeSGabor Kovesdan 7324dc88ebeSGabor Kovesdan if ((aargc == 0 || aargc == 1) && !Hflag) 7334dc88ebeSGabor Kovesdan hflag = true; 7344dc88ebeSGabor Kovesdan 7354dc88ebeSGabor Kovesdan if (aargc == 0) 7364dc88ebeSGabor Kovesdan exit(!procfile("-")); 7374dc88ebeSGabor Kovesdan 7384dc88ebeSGabor Kovesdan if (dirbehave == DIR_RECURSE) 7394dc88ebeSGabor Kovesdan c = grep_tree(aargv); 740c38208adSXin LI else 74155e44f51SGabor Kovesdan for (c = 0; aargc--; ++aargv) { 74255e44f51SGabor Kovesdan if ((finclude || fexclude) && !file_matching(*aargv)) 74355e44f51SGabor Kovesdan continue; 7444dc88ebeSGabor Kovesdan c+= procfile(*aargv); 74555e44f51SGabor Kovesdan } 7464dc88ebeSGabor Kovesdan 7474dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 7484dc88ebeSGabor Kovesdan catclose(catalog); 7494dc88ebeSGabor Kovesdan #endif 7504dc88ebeSGabor Kovesdan 7514dc88ebeSGabor Kovesdan /* Find out the correct return value according to the 7524dc88ebeSGabor Kovesdan results and the command line option. */ 7536f4cbf7cSGabor Kovesdan exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 7544dc88ebeSGabor Kovesdan } 755