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 543f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 55f20f6f3fSGabor Kovesdan #include "fastmatch.h" 563f39ffc8SEd Maste #endif 574dc88ebeSGabor Kovesdan #include "grep.h" 584dc88ebeSGabor Kovesdan 594dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 604dc88ebeSGabor Kovesdan #include <nl_types.h> 614dc88ebeSGabor Kovesdan nl_catd catalog; 624dc88ebeSGabor Kovesdan #endif 634dc88ebeSGabor Kovesdan 644dc88ebeSGabor Kovesdan /* 654dc88ebeSGabor Kovesdan * Default messags to use when NLS is disabled or no catalogue 664dc88ebeSGabor Kovesdan * is found. 674dc88ebeSGabor Kovesdan */ 684dc88ebeSGabor Kovesdan const char *errstr[] = { 694dc88ebeSGabor Kovesdan "", 704dc88ebeSGabor Kovesdan /* 1*/ "(standard input)", 71*a1852807SKyle Evans /* 2*/ "unknown %s option", 72*a1852807SKyle Evans /* 3*/ "usage: %s [-abcDEFGHhIiLlmnOoPqRSsUVvwxz] [-A num] [-B num] [-C[num]]\n", 73*a1852807SKyle Evans /* 4*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 74*a1852807SKyle Evans /* 5*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 75*a1852807SKyle Evans /* 6*/ "\t[--null] [pattern] [file ...]\n", 76*a1852807SKyle Evans /* 7*/ "Binary file %s matches\n", 77*a1852807SKyle Evans /* 8*/ "%s (BSD grep) %s\n", 78*a1852807SKyle Evans /* 9*/ "%s (BSD grep, GNU compatible) %s\n", 794dc88ebeSGabor Kovesdan }; 804dc88ebeSGabor Kovesdan 814dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */ 828bf46064SEd Maste int cflags = REG_NOSUB | REG_NEWLINE; 834dc88ebeSGabor Kovesdan int eflags = REG_STARTEND; 844dc88ebeSGabor Kovesdan 85a4f3f02bSEd Maste /* XXX TODO: Get rid of this flag. 86a4f3f02bSEd Maste * matchall is a gross hack that means that an empty pattern was passed to us. 87a4f3f02bSEd Maste * It is a necessary evil at the moment because our regex(3) implementation 88a4f3f02bSEd Maste * does not allow for empty patterns, as supported by POSIX's definition of 89a4f3f02bSEd Maste * grammar for BREs/EREs. When libregex becomes available, it would be wise 90a4f3f02bSEd Maste * to remove this and let regex(3) handle the dirty details of empty patterns. 91a4f3f02bSEd Maste */ 924dc88ebeSGabor Kovesdan bool matchall; 934dc88ebeSGabor Kovesdan 944dc88ebeSGabor Kovesdan /* Searching patterns */ 95bf70beceSEd Schouten unsigned int patterns; 96bf70beceSEd Schouten static unsigned int pattern_sz; 97f20f6f3fSGabor Kovesdan struct pat *pattern; 984dc88ebeSGabor Kovesdan regex_t *r_pattern; 993f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 100f20f6f3fSGabor Kovesdan fastmatch_t *fg_pattern; 1013f39ffc8SEd Maste #endif 1024dc88ebeSGabor Kovesdan 1034dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */ 104bf70beceSEd Schouten unsigned int fpatterns, dpatterns; 105bf70beceSEd Schouten static unsigned int fpattern_sz, dpattern_sz; 10655e44f51SGabor Kovesdan struct epat *dpattern, *fpattern; 1074dc88ebeSGabor Kovesdan 1084dc88ebeSGabor Kovesdan /* For regex errors */ 1094dc88ebeSGabor Kovesdan char re_error[RE_ERROR_BUF + 1]; 1104dc88ebeSGabor Kovesdan 1114dc88ebeSGabor Kovesdan /* Command-line flags */ 112b5fc583cSEd Maste long long Aflag; /* -A x: print x lines trailing each match */ 113b5fc583cSEd Maste long long Bflag; /* -B x: print x lines leading each match */ 1144dc88ebeSGabor Kovesdan bool Hflag; /* -H: always print file name */ 1154dc88ebeSGabor Kovesdan bool Lflag; /* -L: only show names of files with no matches */ 1164dc88ebeSGabor Kovesdan bool bflag; /* -b: show block numbers for each match */ 1174dc88ebeSGabor Kovesdan bool cflag; /* -c: only show a count of matching lines */ 1184dc88ebeSGabor Kovesdan bool hflag; /* -h: don't print filename headers */ 1194dc88ebeSGabor Kovesdan bool iflag; /* -i: ignore case */ 1204dc88ebeSGabor Kovesdan bool lflag; /* -l: only show names of files with matches */ 1214dc88ebeSGabor Kovesdan bool mflag; /* -m x: stop reading the files after x matches */ 122f20f6f3fSGabor Kovesdan long long mcount; /* count for -m */ 123924500b7SEitan Adler long long mlimit; /* requested value for -m */ 1245ee1ea02SEd Maste char fileeol; /* indicator for eol */ 1254dc88ebeSGabor Kovesdan bool nflag; /* -n: show line numbers in front of matching lines */ 1264dc88ebeSGabor Kovesdan bool oflag; /* -o: print only matching part */ 1274dc88ebeSGabor Kovesdan bool qflag; /* -q: quiet mode (don't output anything) */ 1284dc88ebeSGabor Kovesdan bool sflag; /* -s: silent mode (ignore errors) */ 1294dc88ebeSGabor Kovesdan bool vflag; /* -v: only show non-matching lines */ 1304dc88ebeSGabor Kovesdan bool wflag; /* -w: pattern must start and end on word boundaries */ 1314dc88ebeSGabor Kovesdan bool xflag; /* -x: pattern must match entire line */ 1324dc88ebeSGabor Kovesdan bool lbflag; /* --line-buffered */ 1334dc88ebeSGabor Kovesdan bool nullflag; /* --null */ 1344dc88ebeSGabor Kovesdan char *label; /* --label */ 13527116286SGabor Kovesdan const char *color; /* --color */ 1364dc88ebeSGabor Kovesdan int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 1374dc88ebeSGabor Kovesdan int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 1384a5b4207SBaptiste Daroussin int filebehave = FILE_STDIO; 13927116286SGabor Kovesdan int devbehave = DEV_READ; /* -D: handling of devices */ 14027116286SGabor Kovesdan int dirbehave = DIR_READ; /* -dRr: handling of directories */ 14127116286SGabor Kovesdan int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 1424dc88ebeSGabor Kovesdan 14359218eb7SGabor Kovesdan bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 14459218eb7SGabor Kovesdan bool fexclude, finclude; /* --exclude and --include */ 14555e44f51SGabor Kovesdan 1464dc88ebeSGabor Kovesdan enum { 1474dc88ebeSGabor Kovesdan BIN_OPT = CHAR_MAX + 1, 1484dc88ebeSGabor Kovesdan COLOR_OPT, 1494dc88ebeSGabor Kovesdan HELP_OPT, 1504dc88ebeSGabor Kovesdan MMAP_OPT, 1514dc88ebeSGabor Kovesdan LINEBUF_OPT, 1524dc88ebeSGabor Kovesdan LABEL_OPT, 1534dc88ebeSGabor Kovesdan NULL_OPT, 1544dc88ebeSGabor Kovesdan R_EXCLUDE_OPT, 1554dc88ebeSGabor Kovesdan R_INCLUDE_OPT, 1564dc88ebeSGabor Kovesdan R_DEXCLUDE_OPT, 1574dc88ebeSGabor Kovesdan R_DINCLUDE_OPT 1584dc88ebeSGabor Kovesdan }; 1594dc88ebeSGabor Kovesdan 16027116286SGabor Kovesdan static inline const char *init_color(const char *); 16127116286SGabor Kovesdan 1624dc88ebeSGabor Kovesdan /* Housekeeping */ 1636f4cbf7cSGabor Kovesdan bool file_err; /* file reading error */ 1644dc88ebeSGabor Kovesdan 1654dc88ebeSGabor Kovesdan /* 1664dc88ebeSGabor Kovesdan * Prints usage information and returns 2. 1674dc88ebeSGabor Kovesdan */ 1684dc88ebeSGabor Kovesdan static void 1694dc88ebeSGabor Kovesdan usage(void) 1704dc88ebeSGabor Kovesdan { 1714a5b4207SBaptiste Daroussin fprintf(stderr, getstr(3), getprogname()); 1724a5b4207SBaptiste Daroussin fprintf(stderr, "%s", getstr(4)); 1734dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(5)); 1744dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(6)); 1754dc88ebeSGabor Kovesdan exit(2); 1764dc88ebeSGabor Kovesdan } 1774dc88ebeSGabor Kovesdan 1784a5b4207SBaptiste Daroussin static const char *optstr = "0123456789A:B:C:D:EFGHILOPSRUVabcd:e:f:hilm:nopqrsuvwxyz"; 1794dc88ebeSGabor Kovesdan 1808375d512SEd Schouten static const struct option long_options[] = 1814dc88ebeSGabor Kovesdan { 1824dc88ebeSGabor Kovesdan {"binary-files", required_argument, NULL, BIN_OPT}, 1834dc88ebeSGabor Kovesdan {"help", no_argument, NULL, HELP_OPT}, 1844dc88ebeSGabor Kovesdan {"mmap", no_argument, NULL, MMAP_OPT}, 1854dc88ebeSGabor Kovesdan {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 1864dc88ebeSGabor Kovesdan {"label", required_argument, NULL, LABEL_OPT}, 1874dc88ebeSGabor Kovesdan {"null", no_argument, NULL, NULL_OPT}, 1884dc88ebeSGabor Kovesdan {"color", optional_argument, NULL, COLOR_OPT}, 1894dc88ebeSGabor Kovesdan {"colour", optional_argument, NULL, COLOR_OPT}, 1904dc88ebeSGabor Kovesdan {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 1914dc88ebeSGabor Kovesdan {"include", required_argument, NULL, R_INCLUDE_OPT}, 1924dc88ebeSGabor Kovesdan {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 1934dc88ebeSGabor Kovesdan {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 1944dc88ebeSGabor Kovesdan {"after-context", required_argument, NULL, 'A'}, 1954dc88ebeSGabor Kovesdan {"text", no_argument, NULL, 'a'}, 1964dc88ebeSGabor Kovesdan {"before-context", required_argument, NULL, 'B'}, 1974dc88ebeSGabor Kovesdan {"byte-offset", no_argument, NULL, 'b'}, 1984dc88ebeSGabor Kovesdan {"context", optional_argument, NULL, 'C'}, 1994dc88ebeSGabor Kovesdan {"count", no_argument, NULL, 'c'}, 2004dc88ebeSGabor Kovesdan {"devices", required_argument, NULL, 'D'}, 2014dc88ebeSGabor Kovesdan {"directories", required_argument, NULL, 'd'}, 2024dc88ebeSGabor Kovesdan {"extended-regexp", no_argument, NULL, 'E'}, 2034dc88ebeSGabor Kovesdan {"regexp", required_argument, NULL, 'e'}, 2044dc88ebeSGabor Kovesdan {"fixed-strings", no_argument, NULL, 'F'}, 2054dc88ebeSGabor Kovesdan {"file", required_argument, NULL, 'f'}, 2064dc88ebeSGabor Kovesdan {"basic-regexp", no_argument, NULL, 'G'}, 2074dc88ebeSGabor Kovesdan {"no-filename", no_argument, NULL, 'h'}, 2084dc88ebeSGabor Kovesdan {"with-filename", no_argument, NULL, 'H'}, 2094dc88ebeSGabor Kovesdan {"ignore-case", no_argument, NULL, 'i'}, 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'}, 2134dc88ebeSGabor Kovesdan {"line-number", no_argument, NULL, 'n'}, 2144dc88ebeSGabor Kovesdan {"only-matching", no_argument, NULL, 'o'}, 2154dc88ebeSGabor Kovesdan {"quiet", no_argument, NULL, 'q'}, 2164dc88ebeSGabor Kovesdan {"silent", no_argument, NULL, 'q'}, 2174dc88ebeSGabor Kovesdan {"recursive", no_argument, NULL, 'r'}, 2184dc88ebeSGabor Kovesdan {"no-messages", no_argument, NULL, 's'}, 2194dc88ebeSGabor Kovesdan {"binary", no_argument, NULL, 'U'}, 2204dc88ebeSGabor Kovesdan {"unix-byte-offsets", no_argument, NULL, 'u'}, 2214dc88ebeSGabor Kovesdan {"invert-match", no_argument, NULL, 'v'}, 2224dc88ebeSGabor Kovesdan {"version", no_argument, NULL, 'V'}, 2234dc88ebeSGabor Kovesdan {"word-regexp", no_argument, NULL, 'w'}, 2244dc88ebeSGabor Kovesdan {"line-regexp", no_argument, NULL, 'x'}, 2255ee1ea02SEd Maste {"null-data", no_argument, NULL, 'z'}, 2264dc88ebeSGabor Kovesdan {NULL, no_argument, NULL, 0} 2274dc88ebeSGabor Kovesdan }; 2284dc88ebeSGabor Kovesdan 2294dc88ebeSGabor Kovesdan /* 2304dc88ebeSGabor Kovesdan * Adds a searching pattern to the internal array. 2314dc88ebeSGabor Kovesdan */ 2324dc88ebeSGabor Kovesdan static void 2334dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len) 2344dc88ebeSGabor Kovesdan { 2354dc88ebeSGabor Kovesdan 236f20f6f3fSGabor Kovesdan /* Do not add further pattern is we already match everything */ 237f20f6f3fSGabor Kovesdan if (matchall) 238f20f6f3fSGabor Kovesdan return; 239f20f6f3fSGabor Kovesdan 2404dc88ebeSGabor Kovesdan /* Check if we can do a shortcut */ 241f20f6f3fSGabor Kovesdan if (len == 0) { 2424dc88ebeSGabor Kovesdan matchall = true; 243f20f6f3fSGabor Kovesdan for (unsigned int i = 0; i < patterns; i++) { 244f20f6f3fSGabor Kovesdan free(pattern[i].pat); 245f20f6f3fSGabor Kovesdan } 246f20f6f3fSGabor Kovesdan pattern = grep_realloc(pattern, sizeof(struct pat)); 247f20f6f3fSGabor Kovesdan pattern[0].pat = NULL; 248f20f6f3fSGabor Kovesdan pattern[0].len = 0; 249f20f6f3fSGabor Kovesdan patterns = 1; 2504dc88ebeSGabor Kovesdan return; 2514dc88ebeSGabor Kovesdan } 2524dc88ebeSGabor Kovesdan /* Increase size if necessary */ 2534dc88ebeSGabor Kovesdan if (patterns == pattern_sz) { 2544dc88ebeSGabor Kovesdan pattern_sz *= 2; 2554dc88ebeSGabor Kovesdan pattern = grep_realloc(pattern, ++pattern_sz * 256f20f6f3fSGabor Kovesdan sizeof(struct pat)); 2574dc88ebeSGabor Kovesdan } 2584dc88ebeSGabor Kovesdan if (len > 0 && pat[len - 1] == '\n') 2594dc88ebeSGabor Kovesdan --len; 2604dc88ebeSGabor Kovesdan /* pat may not be NUL-terminated */ 261f20f6f3fSGabor Kovesdan pattern[patterns].pat = grep_malloc(len + 1); 262f20f6f3fSGabor Kovesdan memcpy(pattern[patterns].pat, pat, len); 263f20f6f3fSGabor Kovesdan pattern[patterns].len = len; 264f20f6f3fSGabor Kovesdan pattern[patterns].pat[len] = '\0'; 2654dc88ebeSGabor Kovesdan ++patterns; 2664dc88ebeSGabor Kovesdan } 2674dc88ebeSGabor Kovesdan 2684dc88ebeSGabor Kovesdan /* 26955e44f51SGabor Kovesdan * Adds a file include/exclude pattern to the internal array. 2704dc88ebeSGabor Kovesdan */ 2714dc88ebeSGabor Kovesdan static void 27255e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode) 2734dc88ebeSGabor Kovesdan { 2744dc88ebeSGabor Kovesdan 2754dc88ebeSGabor Kovesdan /* Increase size if necessary */ 27655e44f51SGabor Kovesdan if (fpatterns == fpattern_sz) { 27755e44f51SGabor Kovesdan fpattern_sz *= 2; 27855e44f51SGabor Kovesdan fpattern = grep_realloc(fpattern, ++fpattern_sz * 2794dc88ebeSGabor Kovesdan sizeof(struct epat)); 2804dc88ebeSGabor Kovesdan } 28155e44f51SGabor Kovesdan fpattern[fpatterns].pat = grep_strdup(pat); 28255e44f51SGabor Kovesdan fpattern[fpatterns].mode = mode; 28355e44f51SGabor Kovesdan ++fpatterns; 28455e44f51SGabor Kovesdan } 28555e44f51SGabor Kovesdan 28655e44f51SGabor Kovesdan /* 28755e44f51SGabor Kovesdan * Adds a directory include/exclude pattern to the internal array. 28855e44f51SGabor Kovesdan */ 28955e44f51SGabor Kovesdan static void 29055e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode) 29155e44f51SGabor Kovesdan { 29255e44f51SGabor Kovesdan 29355e44f51SGabor Kovesdan /* Increase size if necessary */ 29455e44f51SGabor Kovesdan if (dpatterns == dpattern_sz) { 29555e44f51SGabor Kovesdan dpattern_sz *= 2; 29655e44f51SGabor Kovesdan dpattern = grep_realloc(dpattern, ++dpattern_sz * 29755e44f51SGabor Kovesdan sizeof(struct epat)); 29855e44f51SGabor Kovesdan } 29955e44f51SGabor Kovesdan dpattern[dpatterns].pat = grep_strdup(pat); 30055e44f51SGabor Kovesdan dpattern[dpatterns].mode = mode; 30155e44f51SGabor Kovesdan ++dpatterns; 3024dc88ebeSGabor Kovesdan } 3034dc88ebeSGabor Kovesdan 3044dc88ebeSGabor Kovesdan /* 3054dc88ebeSGabor Kovesdan * Reads searching patterns from a file and adds them with add_pattern(). 3064dc88ebeSGabor Kovesdan */ 3074dc88ebeSGabor Kovesdan static void 3084dc88ebeSGabor Kovesdan read_patterns(const char *fn) 3094dc88ebeSGabor Kovesdan { 310f20f6f3fSGabor Kovesdan struct stat st; 3114dc88ebeSGabor Kovesdan FILE *f; 3124dc88ebeSGabor Kovesdan char *line; 3134dc88ebeSGabor Kovesdan size_t len; 314f3f50de6SPedro F. Giffuni ssize_t rlen; 3154dc88ebeSGabor Kovesdan 3164dc88ebeSGabor Kovesdan if ((f = fopen(fn, "r")) == NULL) 3174dc88ebeSGabor Kovesdan err(2, "%s", fn); 318f20f6f3fSGabor Kovesdan if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 319f20f6f3fSGabor Kovesdan fclose(f); 320f20f6f3fSGabor Kovesdan return; 321f20f6f3fSGabor Kovesdan } 322f3f50de6SPedro F. Giffuni len = 0; 323f3f50de6SPedro F. Giffuni line = NULL; 324d204af1eSEd Maste while ((rlen = getline(&line, &len, f)) != -1) { 325d204af1eSEd Maste if (line[0] == '\0') 326d204af1eSEd Maste continue; 3272fa7a2afSPedro F. Giffuni add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); 328d204af1eSEd Maste } 329d204af1eSEd Maste 330f3f50de6SPedro F. Giffuni free(line); 3314dc88ebeSGabor Kovesdan if (ferror(f)) 3324dc88ebeSGabor Kovesdan err(2, "%s", fn); 3334dc88ebeSGabor Kovesdan fclose(f); 3344dc88ebeSGabor Kovesdan } 3354dc88ebeSGabor Kovesdan 33627116286SGabor Kovesdan static inline const char * 33727116286SGabor Kovesdan init_color(const char *d) 33827116286SGabor Kovesdan { 33927116286SGabor Kovesdan char *c; 34027116286SGabor Kovesdan 34127116286SGabor Kovesdan c = getenv("GREP_COLOR"); 342dab19f30SGabor Kovesdan return (c != NULL && c[0] != '\0' ? c : d); 34327116286SGabor Kovesdan } 34427116286SGabor Kovesdan 3454dc88ebeSGabor Kovesdan int 3464dc88ebeSGabor Kovesdan main(int argc, char *argv[]) 3474dc88ebeSGabor Kovesdan { 3484dc88ebeSGabor Kovesdan char **aargv, **eargv, *eopts; 349afbbd357SGabor Kovesdan char *ep; 350afbbd357SGabor Kovesdan const char *pn; 351b5fc583cSEd Maste long long l; 3524dc88ebeSGabor Kovesdan unsigned int aargc, eargc, i; 3534dc88ebeSGabor Kovesdan int c, lastc, needpattern, newarg, prevoptind; 3544dc88ebeSGabor Kovesdan 3554dc88ebeSGabor Kovesdan setlocale(LC_ALL, ""); 3564dc88ebeSGabor Kovesdan 3574dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 3584dc88ebeSGabor Kovesdan catalog = catopen("grep", NL_CAT_LOCALE); 3594dc88ebeSGabor Kovesdan #endif 3604dc88ebeSGabor Kovesdan 3614dc88ebeSGabor Kovesdan /* Check what is the program name of the binary. In this 3624dc88ebeSGabor Kovesdan way we can have all the funcionalities in one binary 3634dc88ebeSGabor Kovesdan without the need of scripting and using ugly hacks. */ 364afbbd357SGabor Kovesdan pn = getprogname(); 3654a5b4207SBaptiste Daroussin if (pn[0] == 'r') { 366491b8b16SEd Maste dirbehave = DIR_RECURSE; 367491b8b16SEd Maste Hflag = true; 368f20f6f3fSGabor Kovesdan } 369f20f6f3fSGabor Kovesdan switch (pn[0]) { 3704dc88ebeSGabor Kovesdan case 'e': 3714dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 3724dc88ebeSGabor Kovesdan break; 3734dc88ebeSGabor Kovesdan case 'f': 3744dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 3754dc88ebeSGabor Kovesdan break; 3764dc88ebeSGabor Kovesdan } 3774dc88ebeSGabor Kovesdan 3784dc88ebeSGabor Kovesdan lastc = '\0'; 3794dc88ebeSGabor Kovesdan newarg = 1; 3804dc88ebeSGabor Kovesdan prevoptind = 1; 3814dc88ebeSGabor Kovesdan needpattern = 1; 3825ee1ea02SEd Maste fileeol = '\n'; 3834dc88ebeSGabor Kovesdan 3844dc88ebeSGabor Kovesdan eopts = getenv("GREP_OPTIONS"); 3854dc88ebeSGabor Kovesdan 38659218eb7SGabor Kovesdan /* support for extra arguments in GREP_OPTIONS */ 38759218eb7SGabor Kovesdan eargc = 0; 388dab19f30SGabor Kovesdan if (eopts != NULL && eopts[0] != '\0') { 3894dc88ebeSGabor Kovesdan char *str; 3904dc88ebeSGabor Kovesdan 39159218eb7SGabor Kovesdan /* make an estimation of how many extra arguments we have */ 39259218eb7SGabor Kovesdan for (unsigned int j = 0; j < strlen(eopts); j++) 39359218eb7SGabor Kovesdan if (eopts[j] == ' ') 3944dc88ebeSGabor Kovesdan eargc++; 3954dc88ebeSGabor Kovesdan 3964dc88ebeSGabor Kovesdan eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 3974dc88ebeSGabor Kovesdan 3984dc88ebeSGabor Kovesdan eargc = 0; 39959218eb7SGabor Kovesdan /* parse extra arguments */ 40059218eb7SGabor Kovesdan while ((str = strsep(&eopts, " ")) != NULL) 401dab19f30SGabor Kovesdan if (str[0] != '\0') 40259218eb7SGabor Kovesdan eargv[eargc++] = grep_strdup(str); 4034dc88ebeSGabor Kovesdan 4040c41ffb3SXin LI aargv = (char **)grep_calloc(eargc + argc + 1, 4050c41ffb3SXin LI sizeof(char *)); 40659218eb7SGabor Kovesdan 4074dc88ebeSGabor Kovesdan aargv[0] = argv[0]; 40859218eb7SGabor Kovesdan for (i = 0; i < eargc; i++) 40959218eb7SGabor Kovesdan aargv[i + 1] = eargv[i]; 41059218eb7SGabor Kovesdan for (int j = 1; j < argc; j++, i++) 41159218eb7SGabor Kovesdan aargv[i + 1] = argv[j]; 4124dc88ebeSGabor Kovesdan 41359218eb7SGabor Kovesdan aargc = eargc + argc; 4144dc88ebeSGabor Kovesdan } else { 4154dc88ebeSGabor Kovesdan aargv = argv; 4164dc88ebeSGabor Kovesdan aargc = argc; 4174dc88ebeSGabor Kovesdan } 4184dc88ebeSGabor Kovesdan 4194dc88ebeSGabor Kovesdan while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 4204dc88ebeSGabor Kovesdan -1)) { 4214dc88ebeSGabor Kovesdan switch (c) { 4224dc88ebeSGabor Kovesdan case '0': case '1': case '2': case '3': case '4': 4234dc88ebeSGabor Kovesdan case '5': case '6': case '7': case '8': case '9': 4244dc88ebeSGabor Kovesdan if (newarg || !isdigit(lastc)) 4254dc88ebeSGabor Kovesdan Aflag = 0; 426b5fc583cSEd Maste else if (Aflag > LLONG_MAX / 10 - 1) { 4274dc88ebeSGabor Kovesdan errno = ERANGE; 4284dc88ebeSGabor Kovesdan err(2, NULL); 4294dc88ebeSGabor Kovesdan } 430b5fc583cSEd Maste 4314dc88ebeSGabor Kovesdan Aflag = Bflag = (Aflag * 10) + (c - '0'); 4324dc88ebeSGabor Kovesdan break; 4334dc88ebeSGabor Kovesdan case 'C': 4344dc88ebeSGabor Kovesdan if (optarg == NULL) { 4354dc88ebeSGabor Kovesdan Aflag = Bflag = 2; 4364dc88ebeSGabor Kovesdan break; 4374dc88ebeSGabor Kovesdan } 4384dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4394dc88ebeSGabor Kovesdan case 'A': 4404dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4414dc88ebeSGabor Kovesdan case 'B': 4424dc88ebeSGabor Kovesdan errno = 0; 443b5fc583cSEd Maste l = strtoll(optarg, &ep, 10); 444b5fc583cSEd Maste if (errno == ERANGE || errno == EINVAL) 4454dc88ebeSGabor Kovesdan err(2, NULL); 4464dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 4474dc88ebeSGabor Kovesdan errno = EINVAL; 4484dc88ebeSGabor Kovesdan err(2, NULL); 449b5fc583cSEd Maste } else if (l < 0) { 450b5fc583cSEd Maste errno = EINVAL; 451b5fc583cSEd Maste err(2, "context argument must be non-negative"); 4524dc88ebeSGabor Kovesdan } 453b5fc583cSEd Maste 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 4764a5b4207SBaptiste Daroussin errx(2, getstr(2), "--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 4874a5b4207SBaptiste Daroussin errx(2, getstr(2), "--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 'L': 5284dc88ebeSGabor Kovesdan lflag = false; 52927116286SGabor Kovesdan Lflag = true; 5304dc88ebeSGabor Kovesdan break; 5314dc88ebeSGabor Kovesdan case 'l': 5324dc88ebeSGabor Kovesdan Lflag = false; 53327116286SGabor Kovesdan lflag = true; 5344dc88ebeSGabor Kovesdan break; 5354dc88ebeSGabor Kovesdan case 'm': 5364dc88ebeSGabor Kovesdan mflag = true; 5374dc88ebeSGabor Kovesdan errno = 0; 538924500b7SEitan Adler mlimit = mcount = strtoll(optarg, &ep, 10); 539f20f6f3fSGabor Kovesdan if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 5404dc88ebeSGabor Kovesdan ((errno == EINVAL) && (mcount == 0))) 5414dc88ebeSGabor Kovesdan err(2, NULL); 5424dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 5434dc88ebeSGabor Kovesdan errno = EINVAL; 5444dc88ebeSGabor Kovesdan err(2, NULL); 5454dc88ebeSGabor Kovesdan } 5464dc88ebeSGabor Kovesdan break; 5474dc88ebeSGabor Kovesdan case 'n': 5484dc88ebeSGabor Kovesdan nflag = true; 5494dc88ebeSGabor Kovesdan break; 5504dc88ebeSGabor Kovesdan case 'O': 5514dc88ebeSGabor Kovesdan linkbehave = LINK_EXPLICIT; 5524dc88ebeSGabor Kovesdan break; 5534dc88ebeSGabor Kovesdan case 'o': 5544dc88ebeSGabor Kovesdan oflag = true; 55569a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5564dc88ebeSGabor Kovesdan break; 5574dc88ebeSGabor Kovesdan case 'p': 5584dc88ebeSGabor Kovesdan linkbehave = LINK_SKIP; 5594dc88ebeSGabor Kovesdan break; 5604dc88ebeSGabor Kovesdan case 'q': 5614dc88ebeSGabor Kovesdan qflag = true; 5624dc88ebeSGabor Kovesdan break; 5634dc88ebeSGabor Kovesdan case 'S': 56427116286SGabor Kovesdan linkbehave = LINK_READ; 5654dc88ebeSGabor Kovesdan break; 5664dc88ebeSGabor Kovesdan case 'R': 5674dc88ebeSGabor Kovesdan case 'r': 5684dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 5694dc88ebeSGabor Kovesdan Hflag = true; 5704dc88ebeSGabor Kovesdan break; 5714dc88ebeSGabor Kovesdan case 's': 5724dc88ebeSGabor Kovesdan sflag = true; 5734dc88ebeSGabor Kovesdan break; 5744dc88ebeSGabor Kovesdan case 'U': 5754dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 5764dc88ebeSGabor Kovesdan break; 5774dc88ebeSGabor Kovesdan case 'u': 5784dc88ebeSGabor Kovesdan case MMAP_OPT: 579f20f6f3fSGabor Kovesdan filebehave = FILE_MMAP; 5804dc88ebeSGabor Kovesdan break; 5814dc88ebeSGabor Kovesdan case 'V': 582cc41ba26SEd Maste #ifdef WITH_GNU 583afbbd357SGabor Kovesdan printf(getstr(9), getprogname(), VERSION); 5844a5b4207SBaptiste Daroussin #else 5854a5b4207SBaptiste Daroussin printf(getstr(8), getprogname(), VERSION); 586cc41ba26SEd Maste #endif 5874dc88ebeSGabor Kovesdan exit(0); 5884dc88ebeSGabor Kovesdan case 'v': 5894dc88ebeSGabor Kovesdan vflag = true; 5904dc88ebeSGabor Kovesdan break; 5914dc88ebeSGabor Kovesdan case 'w': 5924dc88ebeSGabor Kovesdan wflag = true; 59369a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5944dc88ebeSGabor Kovesdan break; 5954dc88ebeSGabor Kovesdan case 'x': 5964dc88ebeSGabor Kovesdan xflag = true; 59769a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5984dc88ebeSGabor Kovesdan break; 5995ee1ea02SEd Maste case 'z': 6005ee1ea02SEd Maste fileeol = '\0'; 6015ee1ea02SEd Maste break; 6024dc88ebeSGabor Kovesdan case BIN_OPT: 60327116286SGabor Kovesdan if (strcasecmp("binary", optarg) == 0) 6044dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 60527116286SGabor Kovesdan else if (strcasecmp("without-match", optarg) == 0) 6064dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 60727116286SGabor Kovesdan else if (strcasecmp("text", optarg) == 0) 6084dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 6094dc88ebeSGabor Kovesdan else 6104a5b4207SBaptiste Daroussin errx(2, getstr(2), "--binary-files"); 6114dc88ebeSGabor Kovesdan break; 6124dc88ebeSGabor Kovesdan case COLOR_OPT: 6134dc88ebeSGabor Kovesdan color = NULL; 61427116286SGabor Kovesdan if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 61527116286SGabor Kovesdan strcasecmp("tty", optarg) == 0 || 61627116286SGabor Kovesdan strcasecmp("if-tty", optarg) == 0) { 61727116286SGabor Kovesdan char *term; 61827116286SGabor Kovesdan 61927116286SGabor Kovesdan term = getenv("TERM"); 62027116286SGabor Kovesdan if (isatty(STDOUT_FILENO) && term != NULL && 62127116286SGabor Kovesdan strcasecmp(term, "dumb") != 0) 62227116286SGabor Kovesdan color = init_color("01;31"); 62327116286SGabor Kovesdan } else if (strcasecmp("always", optarg) == 0 || 62427116286SGabor Kovesdan strcasecmp("yes", optarg) == 0 || 62527116286SGabor Kovesdan strcasecmp("force", optarg) == 0) { 62627116286SGabor Kovesdan color = init_color("01;31"); 62727116286SGabor Kovesdan } else if (strcasecmp("never", optarg) != 0 && 62827116286SGabor Kovesdan strcasecmp("none", optarg) != 0 && 62927116286SGabor Kovesdan strcasecmp("no", optarg) != 0) 6304a5b4207SBaptiste Daroussin errx(2, getstr(2), "--color"); 63169a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 6324dc88ebeSGabor Kovesdan break; 6334dc88ebeSGabor Kovesdan case LABEL_OPT: 6344dc88ebeSGabor Kovesdan label = optarg; 6354dc88ebeSGabor Kovesdan break; 6364dc88ebeSGabor Kovesdan case LINEBUF_OPT: 6374dc88ebeSGabor Kovesdan lbflag = true; 6384dc88ebeSGabor Kovesdan break; 6394dc88ebeSGabor Kovesdan case NULL_OPT: 6404dc88ebeSGabor Kovesdan nullflag = true; 6414dc88ebeSGabor Kovesdan break; 6424dc88ebeSGabor Kovesdan case R_INCLUDE_OPT: 64355e44f51SGabor Kovesdan finclude = true; 64455e44f51SGabor Kovesdan add_fpattern(optarg, INCL_PAT); 6454dc88ebeSGabor Kovesdan break; 6464dc88ebeSGabor Kovesdan case R_EXCLUDE_OPT: 64755e44f51SGabor Kovesdan fexclude = true; 64855e44f51SGabor Kovesdan add_fpattern(optarg, EXCL_PAT); 6494dc88ebeSGabor Kovesdan break; 6504dc88ebeSGabor Kovesdan case R_DINCLUDE_OPT: 65159218eb7SGabor Kovesdan dinclude = true; 65255e44f51SGabor Kovesdan add_dpattern(optarg, INCL_PAT); 6534dc88ebeSGabor Kovesdan break; 6544dc88ebeSGabor Kovesdan case R_DEXCLUDE_OPT: 65559218eb7SGabor Kovesdan dexclude = true; 65655e44f51SGabor Kovesdan add_dpattern(optarg, EXCL_PAT); 6574dc88ebeSGabor Kovesdan break; 6584dc88ebeSGabor Kovesdan case HELP_OPT: 6594dc88ebeSGabor Kovesdan default: 6604dc88ebeSGabor Kovesdan usage(); 6614dc88ebeSGabor Kovesdan } 6624dc88ebeSGabor Kovesdan lastc = c; 6634dc88ebeSGabor Kovesdan newarg = optind != prevoptind; 6644dc88ebeSGabor Kovesdan prevoptind = optind; 6654dc88ebeSGabor Kovesdan } 6664dc88ebeSGabor Kovesdan aargc -= optind; 6674dc88ebeSGabor Kovesdan aargv += optind; 6684dc88ebeSGabor Kovesdan 669f20f6f3fSGabor Kovesdan /* Empty pattern file matches nothing */ 670f20f6f3fSGabor Kovesdan if (!needpattern && (patterns == 0)) 671f20f6f3fSGabor Kovesdan exit(1); 672f20f6f3fSGabor Kovesdan 6734dc88ebeSGabor Kovesdan /* Fail if we don't have any pattern */ 6744dc88ebeSGabor Kovesdan if (aargc == 0 && needpattern) 6754dc88ebeSGabor Kovesdan usage(); 6764dc88ebeSGabor Kovesdan 6774dc88ebeSGabor Kovesdan /* Process patterns from command line */ 6784dc88ebeSGabor Kovesdan if (aargc != 0 && needpattern) { 679e411593dSGabor Kovesdan char *token; 680cd64c588SGabor Kovesdan char *string = *aargv; 681e411593dSGabor Kovesdan 682e411593dSGabor Kovesdan while ((token = strsep(&string, "\n")) != NULL) 683e411593dSGabor Kovesdan add_pattern(token, strlen(token)); 6844dc88ebeSGabor Kovesdan --aargc; 6854dc88ebeSGabor Kovesdan ++aargv; 6864dc88ebeSGabor Kovesdan } 6874dc88ebeSGabor Kovesdan 6884dc88ebeSGabor Kovesdan switch (grepbehave) { 6894dc88ebeSGabor Kovesdan case GREP_BASIC: 6904dc88ebeSGabor Kovesdan break; 691f20f6f3fSGabor Kovesdan case GREP_FIXED: 69205ad8215SKyle Evans /* 69305ad8215SKyle Evans * regex(3) implementations that support fixed-string searches generally 69405ad8215SKyle Evans * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag 69505ad8215SKyle Evans * here. If neither are defined, GREP_FIXED later implies that the 69605ad8215SKyle Evans * internal literal matcher should be used. Other cflags that have 69705ad8215SKyle Evans * the same interpretation as REG_NOSPEC and REG_LITERAL should be 69805ad8215SKyle Evans * similarly added here, and grep.h should be amended to take this into 69905ad8215SKyle Evans * consideration when defining WITH_INTERNAL_NOSPEC. 70005ad8215SKyle Evans */ 701476d2098SEd Maste #if defined(REG_NOSPEC) 702476d2098SEd Maste cflags |= REG_NOSPEC; 703476d2098SEd Maste #elif defined(REG_LITERAL) 704476d2098SEd Maste cflags |= REG_LITERAL; 705476d2098SEd Maste #endif 706f20f6f3fSGabor Kovesdan break; 7074dc88ebeSGabor Kovesdan case GREP_EXTENDED: 7084dc88ebeSGabor Kovesdan cflags |= REG_EXTENDED; 7094dc88ebeSGabor Kovesdan break; 7104dc88ebeSGabor Kovesdan default: 7114dc88ebeSGabor Kovesdan /* NOTREACHED */ 7124dc88ebeSGabor Kovesdan usage(); 7134dc88ebeSGabor Kovesdan } 7144dc88ebeSGabor Kovesdan 7153f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 7164dc88ebeSGabor Kovesdan fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 7173f39ffc8SEd Maste #endif 7184dc88ebeSGabor Kovesdan r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 719f20f6f3fSGabor Kovesdan 720a4f3f02bSEd Maste /* Don't process any patterns if we have a blank one */ 72105ad8215SKyle Evans #ifdef WITH_INTERNAL_NOSPEC 72205ad8215SKyle Evans if (!matchall && grepbehave != GREP_FIXED) { 72305ad8215SKyle Evans #else 724a4f3f02bSEd Maste if (!matchall) { 72505ad8215SKyle Evans #endif 7264dc88ebeSGabor Kovesdan /* Check if cheating is allowed (always is for fgrep). */ 7274dc88ebeSGabor Kovesdan for (i = 0; i < patterns; ++i) { 7283f39ffc8SEd Maste #ifndef WITHOUT_FASTMATCH 729a4f3f02bSEd Maste /* 730a4f3f02bSEd Maste * Attempt compilation with fastmatch regex and 731a4f3f02bSEd Maste * fallback to regex(3) if it fails. 732a4f3f02bSEd Maste */ 733f20f6f3fSGabor Kovesdan if (fastncomp(&fg_pattern[i], pattern[i].pat, 7343f39ffc8SEd Maste pattern[i].len, cflags) == 0) 7353f39ffc8SEd Maste continue; 7363f39ffc8SEd Maste #endif 737f20f6f3fSGabor Kovesdan c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 7384dc88ebeSGabor Kovesdan if (c != 0) { 7394dc88ebeSGabor Kovesdan regerror(c, &r_pattern[i], re_error, 7404dc88ebeSGabor Kovesdan RE_ERROR_BUF); 7414dc88ebeSGabor Kovesdan errx(2, "%s", re_error); 7424dc88ebeSGabor Kovesdan } 7434dc88ebeSGabor Kovesdan } 744a4f3f02bSEd Maste } 7454dc88ebeSGabor Kovesdan 7464dc88ebeSGabor Kovesdan if (lbflag) 7474dc88ebeSGabor Kovesdan setlinebuf(stdout); 7484dc88ebeSGabor Kovesdan 7494dc88ebeSGabor Kovesdan if ((aargc == 0 || aargc == 1) && !Hflag) 7504dc88ebeSGabor Kovesdan hflag = true; 7514dc88ebeSGabor Kovesdan 752a461896aSEd Maste if (aargc == 0 && dirbehave != DIR_RECURSE) 7534dc88ebeSGabor Kovesdan exit(!procfile("-")); 7544dc88ebeSGabor Kovesdan 7554dc88ebeSGabor Kovesdan if (dirbehave == DIR_RECURSE) 7564dc88ebeSGabor Kovesdan c = grep_tree(aargv); 757c38208adSXin LI else 75855e44f51SGabor Kovesdan for (c = 0; aargc--; ++aargv) { 75955e44f51SGabor Kovesdan if ((finclude || fexclude) && !file_matching(*aargv)) 76055e44f51SGabor Kovesdan continue; 7614dc88ebeSGabor Kovesdan c+= procfile(*aargv); 76255e44f51SGabor Kovesdan } 7634dc88ebeSGabor Kovesdan 7644dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 7654dc88ebeSGabor Kovesdan catclose(catalog); 7664dc88ebeSGabor Kovesdan #endif 7674dc88ebeSGabor Kovesdan 7684dc88ebeSGabor Kovesdan /* Find out the correct return value according to the 7694dc88ebeSGabor Kovesdan results and the command line option. */ 7706f4cbf7cSGabor Kovesdan exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 7714dc88ebeSGabor Kovesdan } 772