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 523f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 53f20f6f3fSGabor Kovesdan #include "fastmatch.h" 543f39ffc8SEd Maste #endif 554dc88ebeSGabor Kovesdan #include "grep.h" 564dc88ebeSGabor Kovesdan 574dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 584dc88ebeSGabor Kovesdan #include <nl_types.h> 594dc88ebeSGabor Kovesdan nl_catd catalog; 604dc88ebeSGabor Kovesdan #endif 614dc88ebeSGabor Kovesdan 624dc88ebeSGabor Kovesdan /* 634dc88ebeSGabor Kovesdan * Default messags to use when NLS is disabled or no catalogue 644dc88ebeSGabor Kovesdan * is found. 654dc88ebeSGabor Kovesdan */ 664dc88ebeSGabor Kovesdan const char *errstr[] = { 674dc88ebeSGabor Kovesdan "", 684dc88ebeSGabor Kovesdan /* 1*/ "(standard input)", 694dc88ebeSGabor Kovesdan /* 2*/ "cannot read bzip2 compressed file", 7097a012f2SGabor Kovesdan /* 3*/ "unknown %s option", 715ee1ea02SEd Maste /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n", 724dc88ebeSGabor Kovesdan /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 734dc88ebeSGabor Kovesdan /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 744dc88ebeSGabor Kovesdan /* 7*/ "\t[--null] [pattern] [file ...]\n", 7597a012f2SGabor Kovesdan /* 8*/ "Binary file %s matches\n", 7697a012f2SGabor Kovesdan /* 9*/ "%s (BSD grep) %s\n", 77cc41ba26SEd Maste /* 10*/ "%s (BSD grep, GNU compatible) %s\n", 784dc88ebeSGabor Kovesdan }; 794dc88ebeSGabor Kovesdan 804dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */ 8169a6d198SGabor Kovesdan int cflags = REG_NOSUB; 824dc88ebeSGabor Kovesdan int eflags = REG_STARTEND; 834dc88ebeSGabor Kovesdan 84*a4f3f02bSEd Maste /* XXX TODO: Get rid of this flag. 85*a4f3f02bSEd Maste * matchall is a gross hack that means that an empty pattern was passed to us. 86*a4f3f02bSEd Maste * It is a necessary evil at the moment because our regex(3) implementation 87*a4f3f02bSEd Maste * does not allow for empty patterns, as supported by POSIX's definition of 88*a4f3f02bSEd Maste * grammar for BREs/EREs. When libregex becomes available, it would be wise 89*a4f3f02bSEd Maste * to remove this and let regex(3) handle the dirty details of empty patterns. 90*a4f3f02bSEd Maste */ 914dc88ebeSGabor Kovesdan bool matchall; 924dc88ebeSGabor Kovesdan 934dc88ebeSGabor Kovesdan /* Searching patterns */ 94bf70beceSEd Schouten unsigned int patterns; 95bf70beceSEd Schouten static unsigned int pattern_sz; 96f20f6f3fSGabor Kovesdan struct pat *pattern; 974dc88ebeSGabor Kovesdan regex_t *r_pattern; 983f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 99f20f6f3fSGabor Kovesdan fastmatch_t *fg_pattern; 1003f39ffc8SEd Maste #endif 1014dc88ebeSGabor Kovesdan 1024dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */ 103bf70beceSEd Schouten unsigned int fpatterns, dpatterns; 104bf70beceSEd Schouten static unsigned int fpattern_sz, dpattern_sz; 10555e44f51SGabor Kovesdan struct epat *dpattern, *fpattern; 1064dc88ebeSGabor Kovesdan 1074dc88ebeSGabor Kovesdan /* For regex errors */ 1084dc88ebeSGabor Kovesdan char re_error[RE_ERROR_BUF + 1]; 1094dc88ebeSGabor Kovesdan 1104dc88ebeSGabor Kovesdan /* Command-line flags */ 1114dc88ebeSGabor Kovesdan unsigned long long Aflag; /* -A x: print x lines trailing each match */ 1124dc88ebeSGabor Kovesdan unsigned long long Bflag; /* -B x: print x lines leading each match */ 1134dc88ebeSGabor Kovesdan bool Hflag; /* -H: always print file name */ 1144dc88ebeSGabor Kovesdan bool Lflag; /* -L: only show names of files with no matches */ 1154dc88ebeSGabor Kovesdan bool bflag; /* -b: show block numbers for each match */ 1164dc88ebeSGabor Kovesdan bool cflag; /* -c: only show a count of matching lines */ 1174dc88ebeSGabor Kovesdan bool hflag; /* -h: don't print filename headers */ 1184dc88ebeSGabor Kovesdan bool iflag; /* -i: ignore case */ 1194dc88ebeSGabor Kovesdan bool lflag; /* -l: only show names of files with matches */ 1204dc88ebeSGabor Kovesdan bool mflag; /* -m x: stop reading the files after x matches */ 121f20f6f3fSGabor Kovesdan long long mcount; /* count for -m */ 122924500b7SEitan Adler long long mlimit; /* requested value for -m */ 1235ee1ea02SEd Maste char fileeol; /* indicator for eol */ 1244dc88ebeSGabor Kovesdan bool nflag; /* -n: show line numbers in front of matching lines */ 1254dc88ebeSGabor Kovesdan bool oflag; /* -o: print only matching part */ 1264dc88ebeSGabor Kovesdan bool qflag; /* -q: quiet mode (don't output anything) */ 1274dc88ebeSGabor Kovesdan bool sflag; /* -s: silent mode (ignore errors) */ 1284dc88ebeSGabor Kovesdan bool vflag; /* -v: only show non-matching lines */ 1294dc88ebeSGabor Kovesdan bool wflag; /* -w: pattern must start and end on word boundaries */ 1304dc88ebeSGabor Kovesdan bool xflag; /* -x: pattern must match entire line */ 1314dc88ebeSGabor Kovesdan bool lbflag; /* --line-buffered */ 1324dc88ebeSGabor Kovesdan bool nullflag; /* --null */ 1334dc88ebeSGabor Kovesdan char *label; /* --label */ 13427116286SGabor Kovesdan const char *color; /* --color */ 1354dc88ebeSGabor Kovesdan int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 1364dc88ebeSGabor Kovesdan int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 1374dc88ebeSGabor Kovesdan int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 13827116286SGabor Kovesdan int devbehave = DEV_READ; /* -D: handling of devices */ 13927116286SGabor Kovesdan int dirbehave = DIR_READ; /* -dRr: handling of directories */ 14027116286SGabor Kovesdan int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 1414dc88ebeSGabor Kovesdan 14259218eb7SGabor Kovesdan bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 14359218eb7SGabor Kovesdan bool fexclude, finclude; /* --exclude and --include */ 14455e44f51SGabor Kovesdan 1454dc88ebeSGabor Kovesdan enum { 1464dc88ebeSGabor Kovesdan BIN_OPT = CHAR_MAX + 1, 1474dc88ebeSGabor Kovesdan COLOR_OPT, 1484dc88ebeSGabor Kovesdan HELP_OPT, 1494dc88ebeSGabor Kovesdan MMAP_OPT, 1504dc88ebeSGabor Kovesdan LINEBUF_OPT, 1514dc88ebeSGabor Kovesdan LABEL_OPT, 1524dc88ebeSGabor Kovesdan NULL_OPT, 1534dc88ebeSGabor Kovesdan R_EXCLUDE_OPT, 1544dc88ebeSGabor Kovesdan R_INCLUDE_OPT, 1554dc88ebeSGabor Kovesdan R_DEXCLUDE_OPT, 1564dc88ebeSGabor Kovesdan R_DINCLUDE_OPT 1574dc88ebeSGabor Kovesdan }; 1584dc88ebeSGabor Kovesdan 15927116286SGabor Kovesdan static inline const char *init_color(const char *); 16027116286SGabor Kovesdan 1614dc88ebeSGabor Kovesdan /* Housekeeping */ 1626f4cbf7cSGabor Kovesdan bool file_err; /* file reading error */ 1634dc88ebeSGabor Kovesdan 1644dc88ebeSGabor Kovesdan /* 1654dc88ebeSGabor Kovesdan * Prints usage information and returns 2. 1664dc88ebeSGabor Kovesdan */ 1674dc88ebeSGabor Kovesdan static void 1684dc88ebeSGabor Kovesdan usage(void) 1694dc88ebeSGabor Kovesdan { 170afbbd357SGabor Kovesdan fprintf(stderr, getstr(4), getprogname()); 1714dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(5)); 1724dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(6)); 1734dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(7)); 1744dc88ebeSGabor Kovesdan exit(2); 1754dc88ebeSGabor Kovesdan } 1764dc88ebeSGabor Kovesdan 1775ee1ea02SEd Maste static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXyz"; 1784dc88ebeSGabor Kovesdan 1798375d512SEd Schouten static const struct option long_options[] = 1804dc88ebeSGabor Kovesdan { 1814dc88ebeSGabor Kovesdan {"binary-files", required_argument, NULL, BIN_OPT}, 1824dc88ebeSGabor Kovesdan {"help", no_argument, NULL, HELP_OPT}, 1834dc88ebeSGabor Kovesdan {"mmap", no_argument, NULL, MMAP_OPT}, 1844dc88ebeSGabor Kovesdan {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 1854dc88ebeSGabor Kovesdan {"label", required_argument, NULL, LABEL_OPT}, 1864dc88ebeSGabor Kovesdan {"null", no_argument, NULL, NULL_OPT}, 1874dc88ebeSGabor Kovesdan {"color", optional_argument, NULL, COLOR_OPT}, 1884dc88ebeSGabor Kovesdan {"colour", optional_argument, NULL, COLOR_OPT}, 1894dc88ebeSGabor Kovesdan {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 1904dc88ebeSGabor Kovesdan {"include", required_argument, NULL, R_INCLUDE_OPT}, 1914dc88ebeSGabor Kovesdan {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 1924dc88ebeSGabor Kovesdan {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 1934dc88ebeSGabor Kovesdan {"after-context", required_argument, NULL, 'A'}, 1944dc88ebeSGabor Kovesdan {"text", no_argument, NULL, 'a'}, 1954dc88ebeSGabor Kovesdan {"before-context", required_argument, NULL, 'B'}, 1964dc88ebeSGabor Kovesdan {"byte-offset", no_argument, NULL, 'b'}, 1974dc88ebeSGabor Kovesdan {"context", optional_argument, NULL, 'C'}, 1984dc88ebeSGabor Kovesdan {"count", no_argument, NULL, 'c'}, 1994dc88ebeSGabor Kovesdan {"devices", required_argument, NULL, 'D'}, 2004dc88ebeSGabor Kovesdan {"directories", required_argument, NULL, 'd'}, 2014dc88ebeSGabor Kovesdan {"extended-regexp", no_argument, NULL, 'E'}, 2024dc88ebeSGabor Kovesdan {"regexp", required_argument, NULL, 'e'}, 2034dc88ebeSGabor Kovesdan {"fixed-strings", no_argument, NULL, 'F'}, 2044dc88ebeSGabor Kovesdan {"file", required_argument, NULL, 'f'}, 2054dc88ebeSGabor Kovesdan {"basic-regexp", no_argument, NULL, 'G'}, 2064dc88ebeSGabor Kovesdan {"no-filename", no_argument, NULL, 'h'}, 2074dc88ebeSGabor Kovesdan {"with-filename", no_argument, NULL, 'H'}, 2084dc88ebeSGabor Kovesdan {"ignore-case", no_argument, NULL, 'i'}, 2094dc88ebeSGabor Kovesdan {"bz2decompress", no_argument, NULL, 'J'}, 2104dc88ebeSGabor Kovesdan {"files-with-matches", no_argument, NULL, 'l'}, 2114dc88ebeSGabor Kovesdan {"files-without-match", no_argument, NULL, 'L'}, 2124dc88ebeSGabor Kovesdan {"max-count", required_argument, NULL, 'm'}, 213f20f6f3fSGabor Kovesdan {"lzma", no_argument, NULL, 'M'}, 2144dc88ebeSGabor Kovesdan {"line-number", no_argument, NULL, 'n'}, 2154dc88ebeSGabor Kovesdan {"only-matching", no_argument, NULL, 'o'}, 2164dc88ebeSGabor Kovesdan {"quiet", no_argument, NULL, 'q'}, 2174dc88ebeSGabor Kovesdan {"silent", no_argument, NULL, 'q'}, 2184dc88ebeSGabor Kovesdan {"recursive", no_argument, NULL, 'r'}, 2194dc88ebeSGabor Kovesdan {"no-messages", no_argument, NULL, 's'}, 2204dc88ebeSGabor Kovesdan {"binary", no_argument, NULL, 'U'}, 2214dc88ebeSGabor Kovesdan {"unix-byte-offsets", no_argument, NULL, 'u'}, 2224dc88ebeSGabor Kovesdan {"invert-match", no_argument, NULL, 'v'}, 2234dc88ebeSGabor Kovesdan {"version", no_argument, NULL, 'V'}, 2244dc88ebeSGabor Kovesdan {"word-regexp", no_argument, NULL, 'w'}, 2254dc88ebeSGabor Kovesdan {"line-regexp", no_argument, NULL, 'x'}, 226f20f6f3fSGabor Kovesdan {"xz", no_argument, NULL, 'X'}, 2275ee1ea02SEd Maste {"null-data", no_argument, NULL, 'z'}, 2284dc88ebeSGabor Kovesdan {"decompress", no_argument, NULL, 'Z'}, 2294dc88ebeSGabor Kovesdan {NULL, no_argument, NULL, 0} 2304dc88ebeSGabor Kovesdan }; 2314dc88ebeSGabor Kovesdan 2324dc88ebeSGabor Kovesdan /* 2334dc88ebeSGabor Kovesdan * Adds a searching pattern to the internal array. 2344dc88ebeSGabor Kovesdan */ 2354dc88ebeSGabor Kovesdan static void 2364dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len) 2374dc88ebeSGabor Kovesdan { 2384dc88ebeSGabor Kovesdan 239f20f6f3fSGabor Kovesdan /* Do not add further pattern is we already match everything */ 240f20f6f3fSGabor Kovesdan if (matchall) 241f20f6f3fSGabor Kovesdan return; 242f20f6f3fSGabor Kovesdan 2434dc88ebeSGabor Kovesdan /* Check if we can do a shortcut */ 244f20f6f3fSGabor Kovesdan if (len == 0) { 2454dc88ebeSGabor Kovesdan matchall = true; 246f20f6f3fSGabor Kovesdan for (unsigned int i = 0; i < patterns; i++) { 247f20f6f3fSGabor Kovesdan free(pattern[i].pat); 248f20f6f3fSGabor Kovesdan } 249f20f6f3fSGabor Kovesdan pattern = grep_realloc(pattern, sizeof(struct pat)); 250f20f6f3fSGabor Kovesdan pattern[0].pat = NULL; 251f20f6f3fSGabor Kovesdan pattern[0].len = 0; 252f20f6f3fSGabor Kovesdan patterns = 1; 2534dc88ebeSGabor Kovesdan return; 2544dc88ebeSGabor Kovesdan } 2554dc88ebeSGabor Kovesdan /* Increase size if necessary */ 2564dc88ebeSGabor Kovesdan if (patterns == pattern_sz) { 2574dc88ebeSGabor Kovesdan pattern_sz *= 2; 2584dc88ebeSGabor Kovesdan pattern = grep_realloc(pattern, ++pattern_sz * 259f20f6f3fSGabor Kovesdan sizeof(struct pat)); 2604dc88ebeSGabor Kovesdan } 2614dc88ebeSGabor Kovesdan if (len > 0 && pat[len - 1] == '\n') 2624dc88ebeSGabor Kovesdan --len; 2634dc88ebeSGabor Kovesdan /* pat may not be NUL-terminated */ 264f20f6f3fSGabor Kovesdan pattern[patterns].pat = grep_malloc(len + 1); 265f20f6f3fSGabor Kovesdan memcpy(pattern[patterns].pat, pat, len); 266f20f6f3fSGabor Kovesdan pattern[patterns].len = len; 267f20f6f3fSGabor Kovesdan pattern[patterns].pat[len] = '\0'; 2684dc88ebeSGabor Kovesdan ++patterns; 2694dc88ebeSGabor Kovesdan } 2704dc88ebeSGabor Kovesdan 2714dc88ebeSGabor Kovesdan /* 27255e44f51SGabor Kovesdan * Adds a file include/exclude pattern to the internal array. 2734dc88ebeSGabor Kovesdan */ 2744dc88ebeSGabor Kovesdan static void 27555e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode) 2764dc88ebeSGabor Kovesdan { 2774dc88ebeSGabor Kovesdan 2784dc88ebeSGabor Kovesdan /* Increase size if necessary */ 27955e44f51SGabor Kovesdan if (fpatterns == fpattern_sz) { 28055e44f51SGabor Kovesdan fpattern_sz *= 2; 28155e44f51SGabor Kovesdan fpattern = grep_realloc(fpattern, ++fpattern_sz * 2824dc88ebeSGabor Kovesdan sizeof(struct epat)); 2834dc88ebeSGabor Kovesdan } 28455e44f51SGabor Kovesdan fpattern[fpatterns].pat = grep_strdup(pat); 28555e44f51SGabor Kovesdan fpattern[fpatterns].mode = mode; 28655e44f51SGabor Kovesdan ++fpatterns; 28755e44f51SGabor Kovesdan } 28855e44f51SGabor Kovesdan 28955e44f51SGabor Kovesdan /* 29055e44f51SGabor Kovesdan * Adds a directory include/exclude pattern to the internal array. 29155e44f51SGabor Kovesdan */ 29255e44f51SGabor Kovesdan static void 29355e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode) 29455e44f51SGabor Kovesdan { 29555e44f51SGabor Kovesdan 29655e44f51SGabor Kovesdan /* Increase size if necessary */ 29755e44f51SGabor Kovesdan if (dpatterns == dpattern_sz) { 29855e44f51SGabor Kovesdan dpattern_sz *= 2; 29955e44f51SGabor Kovesdan dpattern = grep_realloc(dpattern, ++dpattern_sz * 30055e44f51SGabor Kovesdan sizeof(struct epat)); 30155e44f51SGabor Kovesdan } 30255e44f51SGabor Kovesdan dpattern[dpatterns].pat = grep_strdup(pat); 30355e44f51SGabor Kovesdan dpattern[dpatterns].mode = mode; 30455e44f51SGabor Kovesdan ++dpatterns; 3054dc88ebeSGabor Kovesdan } 3064dc88ebeSGabor Kovesdan 3074dc88ebeSGabor Kovesdan /* 3084dc88ebeSGabor Kovesdan * Reads searching patterns from a file and adds them with add_pattern(). 3094dc88ebeSGabor Kovesdan */ 3104dc88ebeSGabor Kovesdan static void 3114dc88ebeSGabor Kovesdan read_patterns(const char *fn) 3124dc88ebeSGabor Kovesdan { 313f20f6f3fSGabor Kovesdan struct stat st; 3144dc88ebeSGabor Kovesdan FILE *f; 3154dc88ebeSGabor Kovesdan char *line; 3164dc88ebeSGabor Kovesdan size_t len; 317f3f50de6SPedro F. Giffuni ssize_t rlen; 3184dc88ebeSGabor Kovesdan 3194dc88ebeSGabor Kovesdan if ((f = fopen(fn, "r")) == NULL) 3204dc88ebeSGabor Kovesdan err(2, "%s", fn); 321f20f6f3fSGabor Kovesdan if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 322f20f6f3fSGabor Kovesdan fclose(f); 323f20f6f3fSGabor Kovesdan return; 324f20f6f3fSGabor Kovesdan } 325f3f50de6SPedro F. Giffuni len = 0; 326f3f50de6SPedro F. Giffuni line = NULL; 327d204af1eSEd Maste while ((rlen = getline(&line, &len, f)) != -1) { 328d204af1eSEd Maste if (line[0] == '\0') 329d204af1eSEd Maste continue; 3302fa7a2afSPedro F. Giffuni add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); 331d204af1eSEd Maste } 332d204af1eSEd Maste 333f3f50de6SPedro F. Giffuni free(line); 3344dc88ebeSGabor Kovesdan if (ferror(f)) 3354dc88ebeSGabor Kovesdan err(2, "%s", fn); 3364dc88ebeSGabor Kovesdan fclose(f); 3374dc88ebeSGabor Kovesdan } 3384dc88ebeSGabor Kovesdan 33927116286SGabor Kovesdan static inline const char * 34027116286SGabor Kovesdan init_color(const char *d) 34127116286SGabor Kovesdan { 34227116286SGabor Kovesdan char *c; 34327116286SGabor Kovesdan 34427116286SGabor Kovesdan c = getenv("GREP_COLOR"); 345dab19f30SGabor Kovesdan return (c != NULL && c[0] != '\0' ? c : d); 34627116286SGabor Kovesdan } 34727116286SGabor Kovesdan 3484dc88ebeSGabor Kovesdan int 3494dc88ebeSGabor Kovesdan main(int argc, char *argv[]) 3504dc88ebeSGabor Kovesdan { 3514dc88ebeSGabor Kovesdan char **aargv, **eargv, *eopts; 352afbbd357SGabor Kovesdan char *ep; 353afbbd357SGabor Kovesdan const char *pn; 3544dc88ebeSGabor Kovesdan unsigned long long l; 3554dc88ebeSGabor Kovesdan unsigned int aargc, eargc, i; 3564dc88ebeSGabor Kovesdan int c, lastc, needpattern, newarg, prevoptind; 3574dc88ebeSGabor Kovesdan 3584dc88ebeSGabor Kovesdan setlocale(LC_ALL, ""); 3594dc88ebeSGabor Kovesdan 3604dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 3614dc88ebeSGabor Kovesdan catalog = catopen("grep", NL_CAT_LOCALE); 3624dc88ebeSGabor Kovesdan #endif 3634dc88ebeSGabor Kovesdan 3644dc88ebeSGabor Kovesdan /* Check what is the program name of the binary. In this 3654dc88ebeSGabor Kovesdan way we can have all the funcionalities in one binary 3664dc88ebeSGabor Kovesdan without the need of scripting and using ugly hacks. */ 367afbbd357SGabor Kovesdan pn = getprogname(); 368f20f6f3fSGabor Kovesdan if (pn[0] == 'b' && pn[1] == 'z') { 369f20f6f3fSGabor Kovesdan filebehave = FILE_BZIP; 370f20f6f3fSGabor Kovesdan pn += 2; 371f20f6f3fSGabor Kovesdan } else if (pn[0] == 'x' && pn[1] == 'z') { 372f20f6f3fSGabor Kovesdan filebehave = FILE_XZ; 373f20f6f3fSGabor Kovesdan pn += 2; 374f20f6f3fSGabor Kovesdan } else if (pn[0] == 'l' && pn[1] == 'z') { 375f20f6f3fSGabor Kovesdan filebehave = FILE_LZMA; 376f20f6f3fSGabor Kovesdan pn += 2; 377491b8b16SEd Maste } else if (pn[0] == 'r') { 378491b8b16SEd Maste dirbehave = DIR_RECURSE; 379491b8b16SEd Maste Hflag = true; 380f20f6f3fSGabor Kovesdan } else if (pn[0] == 'z') { 3814dc88ebeSGabor Kovesdan filebehave = FILE_GZIP; 382f20f6f3fSGabor Kovesdan pn += 1; 383f20f6f3fSGabor Kovesdan } 384f20f6f3fSGabor Kovesdan switch (pn[0]) { 3854dc88ebeSGabor Kovesdan case 'e': 3864dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 3874dc88ebeSGabor Kovesdan break; 3884dc88ebeSGabor Kovesdan case 'f': 3894dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 3904dc88ebeSGabor Kovesdan break; 3914dc88ebeSGabor Kovesdan } 3924dc88ebeSGabor Kovesdan 3934dc88ebeSGabor Kovesdan lastc = '\0'; 3944dc88ebeSGabor Kovesdan newarg = 1; 3954dc88ebeSGabor Kovesdan prevoptind = 1; 3964dc88ebeSGabor Kovesdan needpattern = 1; 3975ee1ea02SEd Maste fileeol = '\n'; 3984dc88ebeSGabor Kovesdan 3994dc88ebeSGabor Kovesdan eopts = getenv("GREP_OPTIONS"); 4004dc88ebeSGabor Kovesdan 40159218eb7SGabor Kovesdan /* support for extra arguments in GREP_OPTIONS */ 40259218eb7SGabor Kovesdan eargc = 0; 403dab19f30SGabor Kovesdan if (eopts != NULL && eopts[0] != '\0') { 4044dc88ebeSGabor Kovesdan char *str; 4054dc88ebeSGabor Kovesdan 40659218eb7SGabor Kovesdan /* make an estimation of how many extra arguments we have */ 40759218eb7SGabor Kovesdan for (unsigned int j = 0; j < strlen(eopts); j++) 40859218eb7SGabor Kovesdan if (eopts[j] == ' ') 4094dc88ebeSGabor Kovesdan eargc++; 4104dc88ebeSGabor Kovesdan 4114dc88ebeSGabor Kovesdan eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 4124dc88ebeSGabor Kovesdan 4134dc88ebeSGabor Kovesdan eargc = 0; 41459218eb7SGabor Kovesdan /* parse extra arguments */ 41559218eb7SGabor Kovesdan while ((str = strsep(&eopts, " ")) != NULL) 416dab19f30SGabor Kovesdan if (str[0] != '\0') 41759218eb7SGabor Kovesdan eargv[eargc++] = grep_strdup(str); 4184dc88ebeSGabor Kovesdan 4190c41ffb3SXin LI aargv = (char **)grep_calloc(eargc + argc + 1, 4200c41ffb3SXin LI sizeof(char *)); 42159218eb7SGabor Kovesdan 4224dc88ebeSGabor Kovesdan aargv[0] = argv[0]; 42359218eb7SGabor Kovesdan for (i = 0; i < eargc; i++) 42459218eb7SGabor Kovesdan aargv[i + 1] = eargv[i]; 42559218eb7SGabor Kovesdan for (int j = 1; j < argc; j++, i++) 42659218eb7SGabor Kovesdan aargv[i + 1] = argv[j]; 4274dc88ebeSGabor Kovesdan 42859218eb7SGabor Kovesdan aargc = eargc + argc; 4294dc88ebeSGabor Kovesdan } else { 4304dc88ebeSGabor Kovesdan aargv = argv; 4314dc88ebeSGabor Kovesdan aargc = argc; 4324dc88ebeSGabor Kovesdan } 4334dc88ebeSGabor Kovesdan 4344dc88ebeSGabor Kovesdan while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 4354dc88ebeSGabor Kovesdan -1)) { 4364dc88ebeSGabor Kovesdan switch (c) { 4374dc88ebeSGabor Kovesdan case '0': case '1': case '2': case '3': case '4': 4384dc88ebeSGabor Kovesdan case '5': case '6': case '7': case '8': case '9': 4394dc88ebeSGabor Kovesdan if (newarg || !isdigit(lastc)) 4404dc88ebeSGabor Kovesdan Aflag = 0; 4414dc88ebeSGabor Kovesdan else if (Aflag > LLONG_MAX / 10) { 4424dc88ebeSGabor Kovesdan errno = ERANGE; 4434dc88ebeSGabor Kovesdan err(2, NULL); 4444dc88ebeSGabor Kovesdan } 4454dc88ebeSGabor Kovesdan Aflag = Bflag = (Aflag * 10) + (c - '0'); 4464dc88ebeSGabor Kovesdan break; 4474dc88ebeSGabor Kovesdan case 'C': 4484dc88ebeSGabor Kovesdan if (optarg == NULL) { 4494dc88ebeSGabor Kovesdan Aflag = Bflag = 2; 4504dc88ebeSGabor Kovesdan break; 4514dc88ebeSGabor Kovesdan } 4524dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4534dc88ebeSGabor Kovesdan case 'A': 4544dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4554dc88ebeSGabor Kovesdan case 'B': 4564dc88ebeSGabor Kovesdan errno = 0; 4574dc88ebeSGabor Kovesdan l = strtoull(optarg, &ep, 10); 4584dc88ebeSGabor Kovesdan if (((errno == ERANGE) && (l == ULLONG_MAX)) || 4594dc88ebeSGabor Kovesdan ((errno == EINVAL) && (l == 0))) 4604dc88ebeSGabor Kovesdan err(2, NULL); 4614dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 4624dc88ebeSGabor Kovesdan errno = EINVAL; 4634dc88ebeSGabor Kovesdan err(2, NULL); 4644dc88ebeSGabor Kovesdan } 4654dc88ebeSGabor Kovesdan if (c == 'A') 4664dc88ebeSGabor Kovesdan Aflag = l; 4674dc88ebeSGabor Kovesdan else if (c == 'B') 4684dc88ebeSGabor Kovesdan Bflag = l; 4694dc88ebeSGabor Kovesdan else 4704dc88ebeSGabor Kovesdan Aflag = Bflag = l; 4714dc88ebeSGabor Kovesdan break; 4724dc88ebeSGabor Kovesdan case 'a': 4734dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 4744dc88ebeSGabor Kovesdan break; 4754dc88ebeSGabor Kovesdan case 'b': 4764dc88ebeSGabor Kovesdan bflag = true; 4774dc88ebeSGabor Kovesdan break; 4784dc88ebeSGabor Kovesdan case 'c': 4794dc88ebeSGabor Kovesdan cflag = true; 4804dc88ebeSGabor Kovesdan break; 4814dc88ebeSGabor Kovesdan case 'D': 48227116286SGabor Kovesdan if (strcasecmp(optarg, "skip") == 0) 4834dc88ebeSGabor Kovesdan devbehave = DEV_SKIP; 48427116286SGabor Kovesdan else if (strcasecmp(optarg, "read") == 0) 48527116286SGabor Kovesdan devbehave = DEV_READ; 48697a012f2SGabor Kovesdan else 48797a012f2SGabor Kovesdan errx(2, getstr(3), "--devices"); 4884dc88ebeSGabor Kovesdan break; 4894dc88ebeSGabor Kovesdan case 'd': 49027116286SGabor Kovesdan if (strcasecmp("recurse", optarg) == 0) { 4914dc88ebeSGabor Kovesdan Hflag = true; 4924dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 49327116286SGabor Kovesdan } else if (strcasecmp("skip", optarg) == 0) 4944dc88ebeSGabor Kovesdan dirbehave = DIR_SKIP; 49527116286SGabor Kovesdan else if (strcasecmp("read", optarg) == 0) 49627116286SGabor Kovesdan dirbehave = DIR_READ; 49797a012f2SGabor Kovesdan else 49897a012f2SGabor Kovesdan errx(2, getstr(3), "--directories"); 4994dc88ebeSGabor Kovesdan break; 5004dc88ebeSGabor Kovesdan case 'E': 5014dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 5024dc88ebeSGabor Kovesdan break; 5034dc88ebeSGabor Kovesdan case 'e': 504e411593dSGabor Kovesdan { 505e411593dSGabor Kovesdan char *token; 506cd64c588SGabor Kovesdan char *string = optarg; 507e411593dSGabor Kovesdan 508e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL) 509e411593dSGabor Kovesdan add_pattern(token, strlen(token)); 510e411593dSGabor Kovesdan } 5114dc88ebeSGabor Kovesdan needpattern = 0; 5124dc88ebeSGabor Kovesdan break; 5134dc88ebeSGabor Kovesdan case 'F': 5144dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 5154dc88ebeSGabor Kovesdan break; 5164dc88ebeSGabor Kovesdan case 'f': 5174dc88ebeSGabor Kovesdan read_patterns(optarg); 5184dc88ebeSGabor Kovesdan needpattern = 0; 5194dc88ebeSGabor Kovesdan break; 5204dc88ebeSGabor Kovesdan case 'G': 5214dc88ebeSGabor Kovesdan grepbehave = GREP_BASIC; 5224dc88ebeSGabor Kovesdan break; 5234dc88ebeSGabor Kovesdan case 'H': 5244dc88ebeSGabor Kovesdan Hflag = true; 5254dc88ebeSGabor Kovesdan break; 5264dc88ebeSGabor Kovesdan case 'h': 5274dc88ebeSGabor Kovesdan Hflag = false; 5284dc88ebeSGabor Kovesdan hflag = true; 5294dc88ebeSGabor Kovesdan break; 5304dc88ebeSGabor Kovesdan case 'I': 5314dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 5324dc88ebeSGabor Kovesdan break; 5334dc88ebeSGabor Kovesdan case 'i': 5344dc88ebeSGabor Kovesdan case 'y': 5354dc88ebeSGabor Kovesdan iflag = true; 5364dc88ebeSGabor Kovesdan cflags |= REG_ICASE; 5374dc88ebeSGabor Kovesdan break; 5384dc88ebeSGabor Kovesdan case 'J': 539afbbd357SGabor Kovesdan #ifdef WITHOUT_BZIP2 540afbbd357SGabor Kovesdan errno = EOPNOTSUPP; 541afbbd357SGabor Kovesdan err(2, "bzip2 support was disabled at compile-time"); 542afbbd357SGabor Kovesdan #endif 5434dc88ebeSGabor Kovesdan filebehave = FILE_BZIP; 5444dc88ebeSGabor Kovesdan break; 5454dc88ebeSGabor Kovesdan case 'L': 5464dc88ebeSGabor Kovesdan lflag = false; 54727116286SGabor Kovesdan Lflag = true; 5484dc88ebeSGabor Kovesdan break; 5494dc88ebeSGabor Kovesdan case 'l': 5504dc88ebeSGabor Kovesdan Lflag = false; 55127116286SGabor Kovesdan lflag = true; 5524dc88ebeSGabor Kovesdan break; 5534dc88ebeSGabor Kovesdan case 'm': 5544dc88ebeSGabor Kovesdan mflag = true; 5554dc88ebeSGabor Kovesdan errno = 0; 556924500b7SEitan Adler mlimit = mcount = strtoll(optarg, &ep, 10); 557f20f6f3fSGabor Kovesdan if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 5584dc88ebeSGabor Kovesdan ((errno == EINVAL) && (mcount == 0))) 5594dc88ebeSGabor Kovesdan err(2, NULL); 5604dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 5614dc88ebeSGabor Kovesdan errno = EINVAL; 5624dc88ebeSGabor Kovesdan err(2, NULL); 5634dc88ebeSGabor Kovesdan } 5644dc88ebeSGabor Kovesdan break; 565f20f6f3fSGabor Kovesdan case 'M': 566f20f6f3fSGabor Kovesdan filebehave = FILE_LZMA; 567f20f6f3fSGabor Kovesdan break; 5684dc88ebeSGabor Kovesdan case 'n': 5694dc88ebeSGabor Kovesdan nflag = true; 5704dc88ebeSGabor Kovesdan break; 5714dc88ebeSGabor Kovesdan case 'O': 5724dc88ebeSGabor Kovesdan linkbehave = LINK_EXPLICIT; 5734dc88ebeSGabor Kovesdan break; 5744dc88ebeSGabor Kovesdan case 'o': 5754dc88ebeSGabor Kovesdan oflag = true; 57669a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5774dc88ebeSGabor Kovesdan break; 5784dc88ebeSGabor Kovesdan case 'p': 5794dc88ebeSGabor Kovesdan linkbehave = LINK_SKIP; 5804dc88ebeSGabor Kovesdan break; 5814dc88ebeSGabor Kovesdan case 'q': 5824dc88ebeSGabor Kovesdan qflag = true; 5834dc88ebeSGabor Kovesdan break; 5844dc88ebeSGabor Kovesdan case 'S': 58527116286SGabor Kovesdan linkbehave = LINK_READ; 5864dc88ebeSGabor Kovesdan break; 5874dc88ebeSGabor Kovesdan case 'R': 5884dc88ebeSGabor Kovesdan case 'r': 5894dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 5904dc88ebeSGabor Kovesdan Hflag = true; 5914dc88ebeSGabor Kovesdan break; 5924dc88ebeSGabor Kovesdan case 's': 5934dc88ebeSGabor Kovesdan sflag = true; 5944dc88ebeSGabor Kovesdan break; 5954dc88ebeSGabor Kovesdan case 'U': 5964dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 5974dc88ebeSGabor Kovesdan break; 5984dc88ebeSGabor Kovesdan case 'u': 5994dc88ebeSGabor Kovesdan case MMAP_OPT: 600f20f6f3fSGabor Kovesdan filebehave = FILE_MMAP; 6014dc88ebeSGabor Kovesdan break; 6024dc88ebeSGabor Kovesdan case 'V': 603cc41ba26SEd Maste #ifdef WITH_GNU 604cc41ba26SEd Maste printf(getstr(10), getprogname(), VERSION); 605cc41ba26SEd Maste #else 606afbbd357SGabor Kovesdan printf(getstr(9), getprogname(), VERSION); 607cc41ba26SEd Maste #endif 6084dc88ebeSGabor Kovesdan exit(0); 6094dc88ebeSGabor Kovesdan case 'v': 6104dc88ebeSGabor Kovesdan vflag = true; 6114dc88ebeSGabor Kovesdan break; 6124dc88ebeSGabor Kovesdan case 'w': 6134dc88ebeSGabor Kovesdan wflag = true; 61469a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6154dc88ebeSGabor Kovesdan break; 6164dc88ebeSGabor Kovesdan case 'x': 6174dc88ebeSGabor Kovesdan xflag = true; 61869a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6194dc88ebeSGabor Kovesdan break; 620f20f6f3fSGabor Kovesdan case 'X': 621f20f6f3fSGabor Kovesdan filebehave = FILE_XZ; 622f20f6f3fSGabor Kovesdan break; 6235ee1ea02SEd Maste case 'z': 6245ee1ea02SEd Maste fileeol = '\0'; 6255ee1ea02SEd Maste break; 6264dc88ebeSGabor Kovesdan case 'Z': 6274dc88ebeSGabor Kovesdan filebehave = FILE_GZIP; 6284dc88ebeSGabor Kovesdan break; 6294dc88ebeSGabor Kovesdan case BIN_OPT: 63027116286SGabor Kovesdan if (strcasecmp("binary", optarg) == 0) 6314dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 63227116286SGabor Kovesdan else if (strcasecmp("without-match", optarg) == 0) 6334dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 63427116286SGabor Kovesdan else if (strcasecmp("text", optarg) == 0) 6354dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 6364dc88ebeSGabor Kovesdan else 63797a012f2SGabor Kovesdan errx(2, getstr(3), "--binary-files"); 6384dc88ebeSGabor Kovesdan break; 6394dc88ebeSGabor Kovesdan case COLOR_OPT: 6404dc88ebeSGabor Kovesdan color = NULL; 64127116286SGabor Kovesdan if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 64227116286SGabor Kovesdan strcasecmp("tty", optarg) == 0 || 64327116286SGabor Kovesdan strcasecmp("if-tty", optarg) == 0) { 64427116286SGabor Kovesdan char *term; 64527116286SGabor Kovesdan 64627116286SGabor Kovesdan term = getenv("TERM"); 64727116286SGabor Kovesdan if (isatty(STDOUT_FILENO) && term != NULL && 64827116286SGabor Kovesdan strcasecmp(term, "dumb") != 0) 64927116286SGabor Kovesdan color = init_color("01;31"); 65027116286SGabor Kovesdan } else if (strcasecmp("always", optarg) == 0 || 65127116286SGabor Kovesdan strcasecmp("yes", optarg) == 0 || 65227116286SGabor Kovesdan strcasecmp("force", optarg) == 0) { 65327116286SGabor Kovesdan color = init_color("01;31"); 65427116286SGabor Kovesdan } else if (strcasecmp("never", optarg) != 0 && 65527116286SGabor Kovesdan strcasecmp("none", optarg) != 0 && 65627116286SGabor Kovesdan strcasecmp("no", optarg) != 0) 65797a012f2SGabor Kovesdan errx(2, getstr(3), "--color"); 65869a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6594dc88ebeSGabor Kovesdan break; 6604dc88ebeSGabor Kovesdan case LABEL_OPT: 6614dc88ebeSGabor Kovesdan label = optarg; 6624dc88ebeSGabor Kovesdan break; 6634dc88ebeSGabor Kovesdan case LINEBUF_OPT: 6644dc88ebeSGabor Kovesdan lbflag = true; 6654dc88ebeSGabor Kovesdan break; 6664dc88ebeSGabor Kovesdan case NULL_OPT: 6674dc88ebeSGabor Kovesdan nullflag = true; 6684dc88ebeSGabor Kovesdan break; 6694dc88ebeSGabor Kovesdan case R_INCLUDE_OPT: 67055e44f51SGabor Kovesdan finclude = true; 67155e44f51SGabor Kovesdan add_fpattern(optarg, INCL_PAT); 6724dc88ebeSGabor Kovesdan break; 6734dc88ebeSGabor Kovesdan case R_EXCLUDE_OPT: 67455e44f51SGabor Kovesdan fexclude = true; 67555e44f51SGabor Kovesdan add_fpattern(optarg, EXCL_PAT); 6764dc88ebeSGabor Kovesdan break; 6774dc88ebeSGabor Kovesdan case R_DINCLUDE_OPT: 67859218eb7SGabor Kovesdan dinclude = true; 67955e44f51SGabor Kovesdan add_dpattern(optarg, INCL_PAT); 6804dc88ebeSGabor Kovesdan break; 6814dc88ebeSGabor Kovesdan case R_DEXCLUDE_OPT: 68259218eb7SGabor Kovesdan dexclude = true; 68355e44f51SGabor Kovesdan add_dpattern(optarg, EXCL_PAT); 6844dc88ebeSGabor Kovesdan break; 6854dc88ebeSGabor Kovesdan case HELP_OPT: 6864dc88ebeSGabor Kovesdan default: 6874dc88ebeSGabor Kovesdan usage(); 6884dc88ebeSGabor Kovesdan } 6894dc88ebeSGabor Kovesdan lastc = c; 6904dc88ebeSGabor Kovesdan newarg = optind != prevoptind; 6914dc88ebeSGabor Kovesdan prevoptind = optind; 6924dc88ebeSGabor Kovesdan } 6934dc88ebeSGabor Kovesdan aargc -= optind; 6944dc88ebeSGabor Kovesdan aargv += optind; 6954dc88ebeSGabor Kovesdan 696f20f6f3fSGabor Kovesdan /* Empty pattern file matches nothing */ 697f20f6f3fSGabor Kovesdan if (!needpattern && (patterns == 0)) 698f20f6f3fSGabor Kovesdan exit(1); 699f20f6f3fSGabor Kovesdan 7004dc88ebeSGabor Kovesdan /* Fail if we don't have any pattern */ 7014dc88ebeSGabor Kovesdan if (aargc == 0 && needpattern) 7024dc88ebeSGabor Kovesdan usage(); 7034dc88ebeSGabor Kovesdan 7044dc88ebeSGabor Kovesdan /* Process patterns from command line */ 7054dc88ebeSGabor Kovesdan if (aargc != 0 && needpattern) { 706e411593dSGabor Kovesdan char *token; 707cd64c588SGabor Kovesdan char *string = *aargv; 708e411593dSGabor Kovesdan 709e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL) 710e411593dSGabor Kovesdan add_pattern(token, strlen(token)); 7114dc88ebeSGabor Kovesdan --aargc; 7124dc88ebeSGabor Kovesdan ++aargv; 7134dc88ebeSGabor Kovesdan } 7144dc88ebeSGabor Kovesdan 7154dc88ebeSGabor Kovesdan switch (grepbehave) { 7164dc88ebeSGabor Kovesdan case GREP_BASIC: 7174dc88ebeSGabor Kovesdan break; 718f20f6f3fSGabor Kovesdan case GREP_FIXED: 719f20f6f3fSGabor Kovesdan /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */ 720f20f6f3fSGabor Kovesdan cflags |= 0020; 721f20f6f3fSGabor Kovesdan break; 7224dc88ebeSGabor Kovesdan case GREP_EXTENDED: 7234dc88ebeSGabor Kovesdan cflags |= REG_EXTENDED; 7244dc88ebeSGabor Kovesdan break; 7254dc88ebeSGabor Kovesdan default: 7264dc88ebeSGabor Kovesdan /* NOTREACHED */ 7274dc88ebeSGabor Kovesdan usage(); 7284dc88ebeSGabor Kovesdan } 7294dc88ebeSGabor Kovesdan 7303f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 7314dc88ebeSGabor Kovesdan fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 7323f39ffc8SEd Maste #endif 7334dc88ebeSGabor Kovesdan r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 734f20f6f3fSGabor Kovesdan 735*a4f3f02bSEd Maste /* Don't process any patterns if we have a blank one */ 736*a4f3f02bSEd Maste if (!matchall) { 7374dc88ebeSGabor Kovesdan /* Check if cheating is allowed (always is for fgrep). */ 7384dc88ebeSGabor Kovesdan for (i = 0; i < patterns; ++i) { 7393f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 740*a4f3f02bSEd Maste /* 741*a4f3f02bSEd Maste * Attempt compilation with fastmatch regex and 742*a4f3f02bSEd Maste * fallback to regex(3) if it fails. 743*a4f3f02bSEd Maste */ 744f20f6f3fSGabor Kovesdan if (fastncomp(&fg_pattern[i], pattern[i].pat, 7453f39ffc8SEd Maste pattern[i].len, cflags) == 0) 7463f39ffc8SEd Maste continue; 7473f39ffc8SEd Maste #endif 748f20f6f3fSGabor Kovesdan c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 7494dc88ebeSGabor Kovesdan if (c != 0) { 7504dc88ebeSGabor Kovesdan regerror(c, &r_pattern[i], re_error, 7514dc88ebeSGabor Kovesdan RE_ERROR_BUF); 7524dc88ebeSGabor Kovesdan errx(2, "%s", re_error); 7534dc88ebeSGabor Kovesdan } 7544dc88ebeSGabor Kovesdan } 755*a4f3f02bSEd Maste } 7564dc88ebeSGabor Kovesdan 7574dc88ebeSGabor Kovesdan if (lbflag) 7584dc88ebeSGabor Kovesdan setlinebuf(stdout); 7594dc88ebeSGabor Kovesdan 7604dc88ebeSGabor Kovesdan if ((aargc == 0 || aargc == 1) && !Hflag) 7614dc88ebeSGabor Kovesdan hflag = true; 7624dc88ebeSGabor Kovesdan 763a461896aSEd Maste if (aargc == 0 && dirbehave != DIR_RECURSE) 7644dc88ebeSGabor Kovesdan exit(!procfile("-")); 7654dc88ebeSGabor Kovesdan 7664dc88ebeSGabor Kovesdan if (dirbehave == DIR_RECURSE) 7674dc88ebeSGabor Kovesdan c = grep_tree(aargv); 768c38208adSXin LI else 76955e44f51SGabor Kovesdan for (c = 0; aargc--; ++aargv) { 77055e44f51SGabor Kovesdan if ((finclude || fexclude) && !file_matching(*aargv)) 77155e44f51SGabor Kovesdan continue; 7724dc88ebeSGabor Kovesdan c+= procfile(*aargv); 77355e44f51SGabor Kovesdan } 7744dc88ebeSGabor Kovesdan 7754dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 7764dc88ebeSGabor Kovesdan catclose(catalog); 7774dc88ebeSGabor Kovesdan #endif 7784dc88ebeSGabor Kovesdan 7794dc88ebeSGabor Kovesdan /* Find out the correct return value according to the 7804dc88ebeSGabor Kovesdan results and the command line option. */ 7816f4cbf7cSGabor Kovesdan exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 7824dc88ebeSGabor Kovesdan } 783