1b66a823bSGabor Kovesdan /* $NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 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> 414dc88ebeSGabor Kovesdan #include <getopt.h> 424dc88ebeSGabor Kovesdan #include <limits.h> 434dc88ebeSGabor Kovesdan #include <libgen.h> 444dc88ebeSGabor Kovesdan #include <locale.h> 454dc88ebeSGabor Kovesdan #include <stdbool.h> 464dc88ebeSGabor Kovesdan #include <stdio.h> 474dc88ebeSGabor Kovesdan #include <stdlib.h> 484dc88ebeSGabor Kovesdan #include <string.h> 494dc88ebeSGabor Kovesdan #include <unistd.h> 504dc88ebeSGabor Kovesdan 514dc88ebeSGabor Kovesdan #include "grep.h" 524dc88ebeSGabor Kovesdan 534dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 544dc88ebeSGabor Kovesdan #include <nl_types.h> 554dc88ebeSGabor Kovesdan nl_catd catalog; 564dc88ebeSGabor Kovesdan #endif 574dc88ebeSGabor Kovesdan 584dc88ebeSGabor Kovesdan /* 594dc88ebeSGabor Kovesdan * Default messags to use when NLS is disabled or no catalogue 604dc88ebeSGabor Kovesdan * is found. 614dc88ebeSGabor Kovesdan */ 624dc88ebeSGabor Kovesdan const char *errstr[] = { 634dc88ebeSGabor Kovesdan "", 644dc88ebeSGabor Kovesdan /* 1*/ "(standard input)", 654dc88ebeSGabor Kovesdan /* 2*/ "cannot read bzip2 compressed file", 6697a012f2SGabor Kovesdan /* 3*/ "unknown %s option", 674dc88ebeSGabor Kovesdan /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n", 684dc88ebeSGabor Kovesdan /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 694dc88ebeSGabor Kovesdan /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 704dc88ebeSGabor Kovesdan /* 7*/ "\t[--null] [pattern] [file ...]\n", 7197a012f2SGabor Kovesdan /* 8*/ "Binary file %s matches\n", 7297a012f2SGabor Kovesdan /* 9*/ "%s (BSD grep) %s\n", 734dc88ebeSGabor Kovesdan }; 744dc88ebeSGabor Kovesdan 754dc88ebeSGabor Kovesdan /* Flags passed to regcomp() and regexec() */ 76*69a6d198SGabor Kovesdan int cflags = REG_NOSUB; 774dc88ebeSGabor Kovesdan int eflags = REG_STARTEND; 784dc88ebeSGabor Kovesdan 794dc88ebeSGabor Kovesdan /* Shortcut for matching all cases like empty regex */ 804dc88ebeSGabor Kovesdan bool matchall; 814dc88ebeSGabor Kovesdan 824dc88ebeSGabor Kovesdan /* Searching patterns */ 834dc88ebeSGabor Kovesdan unsigned int patterns, pattern_sz; 844dc88ebeSGabor Kovesdan char **pattern; 854dc88ebeSGabor Kovesdan regex_t *r_pattern; 864dc88ebeSGabor Kovesdan fastgrep_t *fg_pattern; 874dc88ebeSGabor Kovesdan 884dc88ebeSGabor Kovesdan /* Filename exclusion/inclusion patterns */ 8955e44f51SGabor Kovesdan unsigned int fpatterns, fpattern_sz; 9055e44f51SGabor Kovesdan unsigned int dpatterns, dpattern_sz; 9155e44f51SGabor Kovesdan struct epat *dpattern, *fpattern; 924dc88ebeSGabor Kovesdan 934dc88ebeSGabor Kovesdan /* For regex errors */ 944dc88ebeSGabor Kovesdan char re_error[RE_ERROR_BUF + 1]; 954dc88ebeSGabor Kovesdan 964dc88ebeSGabor Kovesdan /* Command-line flags */ 974dc88ebeSGabor Kovesdan unsigned long long Aflag; /* -A x: print x lines trailing each match */ 984dc88ebeSGabor Kovesdan unsigned long long Bflag; /* -B x: print x lines leading each match */ 994dc88ebeSGabor Kovesdan bool Hflag; /* -H: always print file name */ 1004dc88ebeSGabor Kovesdan bool Lflag; /* -L: only show names of files with no matches */ 1014dc88ebeSGabor Kovesdan bool bflag; /* -b: show block numbers for each match */ 1024dc88ebeSGabor Kovesdan bool cflag; /* -c: only show a count of matching lines */ 1034dc88ebeSGabor Kovesdan bool hflag; /* -h: don't print filename headers */ 1044dc88ebeSGabor Kovesdan bool iflag; /* -i: ignore case */ 1054dc88ebeSGabor Kovesdan bool lflag; /* -l: only show names of files with matches */ 1064dc88ebeSGabor Kovesdan bool mflag; /* -m x: stop reading the files after x matches */ 1074dc88ebeSGabor Kovesdan unsigned long long mcount; /* count for -m */ 1084dc88ebeSGabor Kovesdan bool nflag; /* -n: show line numbers in front of matching lines */ 1094dc88ebeSGabor Kovesdan bool oflag; /* -o: print only matching part */ 1104dc88ebeSGabor Kovesdan bool qflag; /* -q: quiet mode (don't output anything) */ 1114dc88ebeSGabor Kovesdan bool sflag; /* -s: silent mode (ignore errors) */ 1124dc88ebeSGabor Kovesdan bool vflag; /* -v: only show non-matching lines */ 1134dc88ebeSGabor Kovesdan bool wflag; /* -w: pattern must start and end on word boundaries */ 1144dc88ebeSGabor Kovesdan bool xflag; /* -x: pattern must match entire line */ 1154dc88ebeSGabor Kovesdan bool lbflag; /* --line-buffered */ 1164dc88ebeSGabor Kovesdan bool nullflag; /* --null */ 1174dc88ebeSGabor Kovesdan char *label; /* --label */ 11827116286SGabor Kovesdan const char *color; /* --color */ 1194dc88ebeSGabor Kovesdan int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 1204dc88ebeSGabor Kovesdan int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 1214dc88ebeSGabor Kovesdan int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 12227116286SGabor Kovesdan int devbehave = DEV_READ; /* -D: handling of devices */ 12327116286SGabor Kovesdan int dirbehave = DIR_READ; /* -dRr: handling of directories */ 12427116286SGabor Kovesdan int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 1254dc88ebeSGabor Kovesdan 12659218eb7SGabor Kovesdan bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 12759218eb7SGabor Kovesdan bool fexclude, finclude; /* --exclude and --include */ 12855e44f51SGabor Kovesdan 1294dc88ebeSGabor Kovesdan enum { 1304dc88ebeSGabor Kovesdan BIN_OPT = CHAR_MAX + 1, 1314dc88ebeSGabor Kovesdan COLOR_OPT, 1324dc88ebeSGabor Kovesdan HELP_OPT, 1334dc88ebeSGabor Kovesdan MMAP_OPT, 1344dc88ebeSGabor Kovesdan LINEBUF_OPT, 1354dc88ebeSGabor Kovesdan LABEL_OPT, 1364dc88ebeSGabor Kovesdan NULL_OPT, 1374dc88ebeSGabor Kovesdan R_EXCLUDE_OPT, 1384dc88ebeSGabor Kovesdan R_INCLUDE_OPT, 1394dc88ebeSGabor Kovesdan R_DEXCLUDE_OPT, 1404dc88ebeSGabor Kovesdan R_DINCLUDE_OPT 1414dc88ebeSGabor Kovesdan }; 1424dc88ebeSGabor Kovesdan 14327116286SGabor Kovesdan static inline const char *init_color(const char *); 14427116286SGabor Kovesdan 1454dc88ebeSGabor Kovesdan /* Housekeeping */ 1464dc88ebeSGabor Kovesdan bool first = true; /* flag whether we are processing the first match */ 1474dc88ebeSGabor Kovesdan bool prev; /* flag whether or not the previous line matched */ 1484dc88ebeSGabor Kovesdan int tail; /* lines left to print */ 1494dc88ebeSGabor Kovesdan bool notfound; /* file not found */ 1504dc88ebeSGabor Kovesdan 1514dc88ebeSGabor Kovesdan extern char *__progname; 1524dc88ebeSGabor Kovesdan 1534dc88ebeSGabor Kovesdan /* 1544dc88ebeSGabor Kovesdan * Prints usage information and returns 2. 1554dc88ebeSGabor Kovesdan */ 1564dc88ebeSGabor Kovesdan static void 1574dc88ebeSGabor Kovesdan usage(void) 1584dc88ebeSGabor Kovesdan { 1594dc88ebeSGabor Kovesdan fprintf(stderr, getstr(4), __progname); 1604dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(5)); 1614dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(5)); 1624dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(6)); 1634dc88ebeSGabor Kovesdan fprintf(stderr, "%s", getstr(7)); 1644dc88ebeSGabor Kovesdan exit(2); 1654dc88ebeSGabor Kovesdan } 1664dc88ebeSGabor Kovesdan 1674dc88ebeSGabor Kovesdan static const char *optstr = "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxy"; 1684dc88ebeSGabor Kovesdan 1694dc88ebeSGabor Kovesdan struct option long_options[] = 1704dc88ebeSGabor Kovesdan { 1714dc88ebeSGabor Kovesdan {"binary-files", required_argument, NULL, BIN_OPT}, 1724dc88ebeSGabor Kovesdan {"help", no_argument, NULL, HELP_OPT}, 1734dc88ebeSGabor Kovesdan {"mmap", no_argument, NULL, MMAP_OPT}, 1744dc88ebeSGabor Kovesdan {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 1754dc88ebeSGabor Kovesdan {"label", required_argument, NULL, LABEL_OPT}, 1764dc88ebeSGabor Kovesdan {"null", no_argument, NULL, NULL_OPT}, 1774dc88ebeSGabor Kovesdan {"color", optional_argument, NULL, COLOR_OPT}, 1784dc88ebeSGabor Kovesdan {"colour", optional_argument, NULL, COLOR_OPT}, 1794dc88ebeSGabor Kovesdan {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 1804dc88ebeSGabor Kovesdan {"include", required_argument, NULL, R_INCLUDE_OPT}, 1814dc88ebeSGabor Kovesdan {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 1824dc88ebeSGabor Kovesdan {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 1834dc88ebeSGabor Kovesdan {"after-context", required_argument, NULL, 'A'}, 1844dc88ebeSGabor Kovesdan {"text", no_argument, NULL, 'a'}, 1854dc88ebeSGabor Kovesdan {"before-context", required_argument, NULL, 'B'}, 1864dc88ebeSGabor Kovesdan {"byte-offset", no_argument, NULL, 'b'}, 1874dc88ebeSGabor Kovesdan {"context", optional_argument, NULL, 'C'}, 1884dc88ebeSGabor Kovesdan {"count", no_argument, NULL, 'c'}, 1894dc88ebeSGabor Kovesdan {"devices", required_argument, NULL, 'D'}, 1904dc88ebeSGabor Kovesdan {"directories", required_argument, NULL, 'd'}, 1914dc88ebeSGabor Kovesdan {"extended-regexp", no_argument, NULL, 'E'}, 1924dc88ebeSGabor Kovesdan {"regexp", required_argument, NULL, 'e'}, 1934dc88ebeSGabor Kovesdan {"fixed-strings", no_argument, NULL, 'F'}, 1944dc88ebeSGabor Kovesdan {"file", required_argument, NULL, 'f'}, 1954dc88ebeSGabor Kovesdan {"basic-regexp", no_argument, NULL, 'G'}, 1964dc88ebeSGabor Kovesdan {"no-filename", no_argument, NULL, 'h'}, 1974dc88ebeSGabor Kovesdan {"with-filename", no_argument, NULL, 'H'}, 1984dc88ebeSGabor Kovesdan {"ignore-case", no_argument, NULL, 'i'}, 1994dc88ebeSGabor Kovesdan {"bz2decompress", no_argument, NULL, 'J'}, 2004dc88ebeSGabor Kovesdan {"files-with-matches", no_argument, NULL, 'l'}, 2014dc88ebeSGabor Kovesdan {"files-without-match", no_argument, NULL, 'L'}, 2024dc88ebeSGabor Kovesdan {"max-count", required_argument, NULL, 'm'}, 2034dc88ebeSGabor Kovesdan {"line-number", no_argument, NULL, 'n'}, 2044dc88ebeSGabor Kovesdan {"only-matching", no_argument, NULL, 'o'}, 2054dc88ebeSGabor Kovesdan {"quiet", no_argument, NULL, 'q'}, 2064dc88ebeSGabor Kovesdan {"silent", no_argument, NULL, 'q'}, 2074dc88ebeSGabor Kovesdan {"recursive", no_argument, NULL, 'r'}, 2084dc88ebeSGabor Kovesdan {"no-messages", no_argument, NULL, 's'}, 2094dc88ebeSGabor Kovesdan {"binary", no_argument, NULL, 'U'}, 2104dc88ebeSGabor Kovesdan {"unix-byte-offsets", no_argument, NULL, 'u'}, 2114dc88ebeSGabor Kovesdan {"invert-match", no_argument, NULL, 'v'}, 2124dc88ebeSGabor Kovesdan {"version", no_argument, NULL, 'V'}, 2134dc88ebeSGabor Kovesdan {"word-regexp", no_argument, NULL, 'w'}, 2144dc88ebeSGabor Kovesdan {"line-regexp", no_argument, NULL, 'x'}, 2154dc88ebeSGabor Kovesdan {"decompress", no_argument, NULL, 'Z'}, 2164dc88ebeSGabor Kovesdan {NULL, no_argument, NULL, 0} 2174dc88ebeSGabor Kovesdan }; 2184dc88ebeSGabor Kovesdan 2194dc88ebeSGabor Kovesdan /* 2204dc88ebeSGabor Kovesdan * Adds a searching pattern to the internal array. 2214dc88ebeSGabor Kovesdan */ 2224dc88ebeSGabor Kovesdan static void 2234dc88ebeSGabor Kovesdan add_pattern(char *pat, size_t len) 2244dc88ebeSGabor Kovesdan { 2254dc88ebeSGabor Kovesdan 2264dc88ebeSGabor Kovesdan /* Check if we can do a shortcut */ 2274dc88ebeSGabor Kovesdan if (len == 0 || matchall) { 2284dc88ebeSGabor Kovesdan matchall = true; 2294dc88ebeSGabor Kovesdan return; 2304dc88ebeSGabor Kovesdan } 2314dc88ebeSGabor Kovesdan /* Increase size if necessary */ 2324dc88ebeSGabor Kovesdan if (patterns == pattern_sz) { 2334dc88ebeSGabor Kovesdan pattern_sz *= 2; 2344dc88ebeSGabor Kovesdan pattern = grep_realloc(pattern, ++pattern_sz * 2354dc88ebeSGabor Kovesdan sizeof(*pattern)); 2364dc88ebeSGabor Kovesdan } 2374dc88ebeSGabor Kovesdan if (len > 0 && pat[len - 1] == '\n') 2384dc88ebeSGabor Kovesdan --len; 2394dc88ebeSGabor Kovesdan /* pat may not be NUL-terminated */ 2404dc88ebeSGabor Kovesdan pattern[patterns] = grep_malloc(len + 1); 24159218eb7SGabor Kovesdan memcpy(pattern[patterns], pat, len); 24259218eb7SGabor Kovesdan pattern[patterns][len] = '\0'; 2434dc88ebeSGabor Kovesdan ++patterns; 2444dc88ebeSGabor Kovesdan } 2454dc88ebeSGabor Kovesdan 2464dc88ebeSGabor Kovesdan /* 24755e44f51SGabor Kovesdan * Adds a file include/exclude pattern to the internal array. 2484dc88ebeSGabor Kovesdan */ 2494dc88ebeSGabor Kovesdan static void 25055e44f51SGabor Kovesdan add_fpattern(const char *pat, int mode) 2514dc88ebeSGabor Kovesdan { 2524dc88ebeSGabor Kovesdan 2534dc88ebeSGabor Kovesdan /* Increase size if necessary */ 25455e44f51SGabor Kovesdan if (fpatterns == fpattern_sz) { 25555e44f51SGabor Kovesdan fpattern_sz *= 2; 25655e44f51SGabor Kovesdan fpattern = grep_realloc(fpattern, ++fpattern_sz * 2574dc88ebeSGabor Kovesdan sizeof(struct epat)); 2584dc88ebeSGabor Kovesdan } 25955e44f51SGabor Kovesdan fpattern[fpatterns].pat = grep_strdup(pat); 26055e44f51SGabor Kovesdan fpattern[fpatterns].mode = mode; 26155e44f51SGabor Kovesdan ++fpatterns; 26255e44f51SGabor Kovesdan } 26355e44f51SGabor Kovesdan 26455e44f51SGabor Kovesdan /* 26555e44f51SGabor Kovesdan * Adds a directory include/exclude pattern to the internal array. 26655e44f51SGabor Kovesdan */ 26755e44f51SGabor Kovesdan static void 26855e44f51SGabor Kovesdan add_dpattern(const char *pat, int mode) 26955e44f51SGabor Kovesdan { 27055e44f51SGabor Kovesdan 27155e44f51SGabor Kovesdan /* Increase size if necessary */ 27255e44f51SGabor Kovesdan if (dpatterns == dpattern_sz) { 27355e44f51SGabor Kovesdan dpattern_sz *= 2; 27455e44f51SGabor Kovesdan dpattern = grep_realloc(dpattern, ++dpattern_sz * 27555e44f51SGabor Kovesdan sizeof(struct epat)); 27655e44f51SGabor Kovesdan } 27755e44f51SGabor Kovesdan dpattern[dpatterns].pat = grep_strdup(pat); 27855e44f51SGabor Kovesdan dpattern[dpatterns].mode = mode; 27955e44f51SGabor Kovesdan ++dpatterns; 2804dc88ebeSGabor Kovesdan } 2814dc88ebeSGabor Kovesdan 2824dc88ebeSGabor Kovesdan /* 2834dc88ebeSGabor Kovesdan * Reads searching patterns from a file and adds them with add_pattern(). 2844dc88ebeSGabor Kovesdan */ 2854dc88ebeSGabor Kovesdan static void 2864dc88ebeSGabor Kovesdan read_patterns(const char *fn) 2874dc88ebeSGabor Kovesdan { 2884dc88ebeSGabor Kovesdan FILE *f; 2894dc88ebeSGabor Kovesdan char *line; 2904dc88ebeSGabor Kovesdan size_t len; 2914dc88ebeSGabor Kovesdan 2924dc88ebeSGabor Kovesdan if ((f = fopen(fn, "r")) == NULL) 2934dc88ebeSGabor Kovesdan err(2, "%s", fn); 2944dc88ebeSGabor Kovesdan while ((line = fgetln(f, &len)) != NULL) 2954dc88ebeSGabor Kovesdan add_pattern(line, *line == '\n' ? 0 : len); 2964dc88ebeSGabor Kovesdan if (ferror(f)) 2974dc88ebeSGabor Kovesdan err(2, "%s", fn); 2984dc88ebeSGabor Kovesdan fclose(f); 2994dc88ebeSGabor Kovesdan } 3004dc88ebeSGabor Kovesdan 30127116286SGabor Kovesdan static inline const char * 30227116286SGabor Kovesdan init_color(const char *d) 30327116286SGabor Kovesdan { 30427116286SGabor Kovesdan char *c; 30527116286SGabor Kovesdan 30627116286SGabor Kovesdan c = getenv("GREP_COLOR"); 30727116286SGabor Kovesdan return (c != NULL ? c : d); 30827116286SGabor Kovesdan } 30927116286SGabor Kovesdan 3104dc88ebeSGabor Kovesdan int 3114dc88ebeSGabor Kovesdan main(int argc, char *argv[]) 3124dc88ebeSGabor Kovesdan { 3134dc88ebeSGabor Kovesdan char **aargv, **eargv, *eopts; 3144dc88ebeSGabor Kovesdan char *ep; 3154dc88ebeSGabor Kovesdan unsigned long long l; 3164dc88ebeSGabor Kovesdan unsigned int aargc, eargc, i; 3174dc88ebeSGabor Kovesdan int c, lastc, needpattern, newarg, prevoptind; 3184dc88ebeSGabor Kovesdan 3194dc88ebeSGabor Kovesdan setlocale(LC_ALL, ""); 3204dc88ebeSGabor Kovesdan 3214dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 3224dc88ebeSGabor Kovesdan catalog = catopen("grep", NL_CAT_LOCALE); 3234dc88ebeSGabor Kovesdan #endif 3244dc88ebeSGabor Kovesdan 3254dc88ebeSGabor Kovesdan /* Check what is the program name of the binary. In this 3264dc88ebeSGabor Kovesdan way we can have all the funcionalities in one binary 3274dc88ebeSGabor Kovesdan without the need of scripting and using ugly hacks. */ 3284dc88ebeSGabor Kovesdan switch (__progname[0]) { 3294dc88ebeSGabor Kovesdan case 'e': 3304dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 3314dc88ebeSGabor Kovesdan break; 3324dc88ebeSGabor Kovesdan case 'f': 3334dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 3344dc88ebeSGabor Kovesdan break; 3354dc88ebeSGabor Kovesdan case 'g': 3364dc88ebeSGabor Kovesdan grepbehave = GREP_BASIC; 3374dc88ebeSGabor Kovesdan break; 3384dc88ebeSGabor Kovesdan case 'z': 3394dc88ebeSGabor Kovesdan filebehave = FILE_GZIP; 3404dc88ebeSGabor Kovesdan switch(__progname[1]) { 3414dc88ebeSGabor Kovesdan case 'e': 3424dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 3434dc88ebeSGabor Kovesdan break; 3444dc88ebeSGabor Kovesdan case 'f': 3454dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 3464dc88ebeSGabor Kovesdan break; 3474dc88ebeSGabor Kovesdan case 'g': 3484dc88ebeSGabor Kovesdan grepbehave = GREP_BASIC; 3494dc88ebeSGabor Kovesdan break; 3504dc88ebeSGabor Kovesdan } 3514dc88ebeSGabor Kovesdan break; 3524dc88ebeSGabor Kovesdan } 3534dc88ebeSGabor Kovesdan 3544dc88ebeSGabor Kovesdan lastc = '\0'; 3554dc88ebeSGabor Kovesdan newarg = 1; 3564dc88ebeSGabor Kovesdan prevoptind = 1; 3574dc88ebeSGabor Kovesdan needpattern = 1; 3584dc88ebeSGabor Kovesdan 3594dc88ebeSGabor Kovesdan eopts = getenv("GREP_OPTIONS"); 3604dc88ebeSGabor Kovesdan 36159218eb7SGabor Kovesdan /* support for extra arguments in GREP_OPTIONS */ 36259218eb7SGabor Kovesdan eargc = 0; 3634dc88ebeSGabor Kovesdan if (eopts != NULL) { 3644dc88ebeSGabor Kovesdan char *str; 3654dc88ebeSGabor Kovesdan 36659218eb7SGabor Kovesdan /* make an estimation of how many extra arguments we have */ 36759218eb7SGabor Kovesdan for (unsigned int j = 0; j < strlen(eopts); j++) 36859218eb7SGabor Kovesdan if (eopts[j] == ' ') 3694dc88ebeSGabor Kovesdan eargc++; 3704dc88ebeSGabor Kovesdan 3714dc88ebeSGabor Kovesdan eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 3724dc88ebeSGabor Kovesdan 3734dc88ebeSGabor Kovesdan eargc = 0; 37459218eb7SGabor Kovesdan /* parse extra arguments */ 37559218eb7SGabor Kovesdan while ((str = strsep(&eopts, " ")) != NULL) 37659218eb7SGabor Kovesdan eargv[eargc++] = grep_strdup(str); 3774dc88ebeSGabor Kovesdan 3780c41ffb3SXin LI aargv = (char **)grep_calloc(eargc + argc + 1, 3790c41ffb3SXin LI sizeof(char *)); 38059218eb7SGabor Kovesdan 3814dc88ebeSGabor Kovesdan aargv[0] = argv[0]; 38259218eb7SGabor Kovesdan for (i = 0; i < eargc; i++) 38359218eb7SGabor Kovesdan aargv[i + 1] = eargv[i]; 38459218eb7SGabor Kovesdan for (int j = 1; j < argc; j++, i++) 38559218eb7SGabor Kovesdan aargv[i + 1] = argv[j]; 3864dc88ebeSGabor Kovesdan 38759218eb7SGabor Kovesdan aargc = eargc + argc; 3884dc88ebeSGabor Kovesdan } else { 3894dc88ebeSGabor Kovesdan aargv = argv; 3904dc88ebeSGabor Kovesdan aargc = argc; 3914dc88ebeSGabor Kovesdan } 3924dc88ebeSGabor Kovesdan 3934dc88ebeSGabor Kovesdan while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 3944dc88ebeSGabor Kovesdan -1)) { 3954dc88ebeSGabor Kovesdan switch (c) { 3964dc88ebeSGabor Kovesdan case '0': case '1': case '2': case '3': case '4': 3974dc88ebeSGabor Kovesdan case '5': case '6': case '7': case '8': case '9': 3984dc88ebeSGabor Kovesdan if (newarg || !isdigit(lastc)) 3994dc88ebeSGabor Kovesdan Aflag = 0; 4004dc88ebeSGabor Kovesdan else if (Aflag > LLONG_MAX / 10) { 4014dc88ebeSGabor Kovesdan errno = ERANGE; 4024dc88ebeSGabor Kovesdan err(2, NULL); 4034dc88ebeSGabor Kovesdan } 4044dc88ebeSGabor Kovesdan Aflag = Bflag = (Aflag * 10) + (c - '0'); 4054dc88ebeSGabor Kovesdan break; 4064dc88ebeSGabor Kovesdan case 'C': 4074dc88ebeSGabor Kovesdan if (optarg == NULL) { 4084dc88ebeSGabor Kovesdan Aflag = Bflag = 2; 4094dc88ebeSGabor Kovesdan break; 4104dc88ebeSGabor Kovesdan } 4114dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4124dc88ebeSGabor Kovesdan case 'A': 4134dc88ebeSGabor Kovesdan /* FALLTHROUGH */ 4144dc88ebeSGabor Kovesdan case 'B': 4154dc88ebeSGabor Kovesdan errno = 0; 4164dc88ebeSGabor Kovesdan l = strtoull(optarg, &ep, 10); 4174dc88ebeSGabor Kovesdan if (((errno == ERANGE) && (l == ULLONG_MAX)) || 4184dc88ebeSGabor Kovesdan ((errno == EINVAL) && (l == 0))) 4194dc88ebeSGabor Kovesdan err(2, NULL); 4204dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 4214dc88ebeSGabor Kovesdan errno = EINVAL; 4224dc88ebeSGabor Kovesdan err(2, NULL); 4234dc88ebeSGabor Kovesdan } 4244dc88ebeSGabor Kovesdan if (c == 'A') 4254dc88ebeSGabor Kovesdan Aflag = l; 4264dc88ebeSGabor Kovesdan else if (c == 'B') 4274dc88ebeSGabor Kovesdan Bflag = l; 4284dc88ebeSGabor Kovesdan else 4294dc88ebeSGabor Kovesdan Aflag = Bflag = l; 4304dc88ebeSGabor Kovesdan break; 4314dc88ebeSGabor Kovesdan case 'a': 4324dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 4334dc88ebeSGabor Kovesdan break; 4344dc88ebeSGabor Kovesdan case 'b': 4354dc88ebeSGabor Kovesdan bflag = true; 4364dc88ebeSGabor Kovesdan break; 4374dc88ebeSGabor Kovesdan case 'c': 4384dc88ebeSGabor Kovesdan cflag = true; 4394dc88ebeSGabor Kovesdan break; 4404dc88ebeSGabor Kovesdan case 'D': 44127116286SGabor Kovesdan if (strcasecmp(optarg, "skip") == 0) 4424dc88ebeSGabor Kovesdan devbehave = DEV_SKIP; 44327116286SGabor Kovesdan else if (strcasecmp(optarg, "read") == 0) 44427116286SGabor Kovesdan devbehave = DEV_READ; 44597a012f2SGabor Kovesdan else 44697a012f2SGabor Kovesdan errx(2, getstr(3), "--devices"); 4474dc88ebeSGabor Kovesdan break; 4484dc88ebeSGabor Kovesdan case 'd': 44927116286SGabor Kovesdan if (strcasecmp("recurse", optarg) == 0) { 4504dc88ebeSGabor Kovesdan Hflag = true; 4514dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 45227116286SGabor Kovesdan } else if (strcasecmp("skip", optarg) == 0) 4534dc88ebeSGabor Kovesdan dirbehave = DIR_SKIP; 45427116286SGabor Kovesdan else if (strcasecmp("read", optarg) == 0) 45527116286SGabor Kovesdan dirbehave = DIR_READ; 45697a012f2SGabor Kovesdan else 45797a012f2SGabor Kovesdan errx(2, getstr(3), "--directories"); 4584dc88ebeSGabor Kovesdan break; 4594dc88ebeSGabor Kovesdan case 'E': 4604dc88ebeSGabor Kovesdan grepbehave = GREP_EXTENDED; 4614dc88ebeSGabor Kovesdan break; 4624dc88ebeSGabor Kovesdan case 'e': 4634dc88ebeSGabor Kovesdan add_pattern(optarg, strlen(optarg)); 4644dc88ebeSGabor Kovesdan needpattern = 0; 4654dc88ebeSGabor Kovesdan break; 4664dc88ebeSGabor Kovesdan case 'F': 4674dc88ebeSGabor Kovesdan grepbehave = GREP_FIXED; 4684dc88ebeSGabor Kovesdan break; 4694dc88ebeSGabor Kovesdan case 'f': 4704dc88ebeSGabor Kovesdan read_patterns(optarg); 4714dc88ebeSGabor Kovesdan needpattern = 0; 4724dc88ebeSGabor Kovesdan break; 4734dc88ebeSGabor Kovesdan case 'G': 4744dc88ebeSGabor Kovesdan grepbehave = GREP_BASIC; 4754dc88ebeSGabor Kovesdan break; 4764dc88ebeSGabor Kovesdan case 'H': 4774dc88ebeSGabor Kovesdan Hflag = true; 4784dc88ebeSGabor Kovesdan break; 4794dc88ebeSGabor Kovesdan case 'h': 4804dc88ebeSGabor Kovesdan Hflag = false; 4814dc88ebeSGabor Kovesdan hflag = true; 4824dc88ebeSGabor Kovesdan break; 4834dc88ebeSGabor Kovesdan case 'I': 4844dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 4854dc88ebeSGabor Kovesdan break; 4864dc88ebeSGabor Kovesdan case 'i': 4874dc88ebeSGabor Kovesdan case 'y': 4884dc88ebeSGabor Kovesdan iflag = true; 4894dc88ebeSGabor Kovesdan cflags |= REG_ICASE; 4904dc88ebeSGabor Kovesdan break; 4914dc88ebeSGabor Kovesdan case 'J': 4924dc88ebeSGabor Kovesdan filebehave = FILE_BZIP; 4934dc88ebeSGabor Kovesdan break; 4944dc88ebeSGabor Kovesdan case 'L': 4954dc88ebeSGabor Kovesdan lflag = false; 49627116286SGabor Kovesdan Lflag = true; 4974dc88ebeSGabor Kovesdan break; 4984dc88ebeSGabor Kovesdan case 'l': 4994dc88ebeSGabor Kovesdan Lflag = false; 50027116286SGabor Kovesdan lflag = true; 5014dc88ebeSGabor Kovesdan break; 5024dc88ebeSGabor Kovesdan case 'm': 5034dc88ebeSGabor Kovesdan mflag = true; 5044dc88ebeSGabor Kovesdan errno = 0; 5054dc88ebeSGabor Kovesdan mcount = strtoull(optarg, &ep, 10); 5064dc88ebeSGabor Kovesdan if (((errno == ERANGE) && (mcount == ULLONG_MAX)) || 5074dc88ebeSGabor Kovesdan ((errno == EINVAL) && (mcount == 0))) 5084dc88ebeSGabor Kovesdan err(2, NULL); 5094dc88ebeSGabor Kovesdan else if (ep[0] != '\0') { 5104dc88ebeSGabor Kovesdan errno = EINVAL; 5114dc88ebeSGabor Kovesdan err(2, NULL); 5124dc88ebeSGabor Kovesdan } 5134dc88ebeSGabor Kovesdan break; 5144dc88ebeSGabor Kovesdan case 'n': 5154dc88ebeSGabor Kovesdan nflag = true; 5164dc88ebeSGabor Kovesdan break; 5174dc88ebeSGabor Kovesdan case 'O': 5184dc88ebeSGabor Kovesdan linkbehave = LINK_EXPLICIT; 5194dc88ebeSGabor Kovesdan break; 5204dc88ebeSGabor Kovesdan case 'o': 5214dc88ebeSGabor Kovesdan oflag = true; 522*69a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5234dc88ebeSGabor Kovesdan break; 5244dc88ebeSGabor Kovesdan case 'p': 5254dc88ebeSGabor Kovesdan linkbehave = LINK_SKIP; 5264dc88ebeSGabor Kovesdan break; 5274dc88ebeSGabor Kovesdan case 'q': 5284dc88ebeSGabor Kovesdan qflag = true; 5294dc88ebeSGabor Kovesdan break; 5304dc88ebeSGabor Kovesdan case 'S': 53127116286SGabor Kovesdan linkbehave = LINK_READ; 5324dc88ebeSGabor Kovesdan break; 5334dc88ebeSGabor Kovesdan case 'R': 5344dc88ebeSGabor Kovesdan case 'r': 5354dc88ebeSGabor Kovesdan dirbehave = DIR_RECURSE; 5364dc88ebeSGabor Kovesdan Hflag = true; 5374dc88ebeSGabor Kovesdan break; 5384dc88ebeSGabor Kovesdan case 's': 5394dc88ebeSGabor Kovesdan sflag = true; 5404dc88ebeSGabor Kovesdan break; 5414dc88ebeSGabor Kovesdan case 'U': 5424dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 5434dc88ebeSGabor Kovesdan break; 5444dc88ebeSGabor Kovesdan case 'u': 5454dc88ebeSGabor Kovesdan case MMAP_OPT: 5464dc88ebeSGabor Kovesdan /* noop, compatibility */ 5474dc88ebeSGabor Kovesdan break; 5484dc88ebeSGabor Kovesdan case 'V': 54997a012f2SGabor Kovesdan printf(getstr(9), __progname, VERSION); 5504dc88ebeSGabor Kovesdan exit(0); 5514dc88ebeSGabor Kovesdan case 'v': 5524dc88ebeSGabor Kovesdan vflag = true; 5534dc88ebeSGabor Kovesdan break; 5544dc88ebeSGabor Kovesdan case 'w': 5554dc88ebeSGabor Kovesdan wflag = true; 556*69a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5574dc88ebeSGabor Kovesdan break; 5584dc88ebeSGabor Kovesdan case 'x': 5594dc88ebeSGabor Kovesdan xflag = true; 560*69a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5614dc88ebeSGabor Kovesdan break; 5624dc88ebeSGabor Kovesdan case 'Z': 5634dc88ebeSGabor Kovesdan filebehave = FILE_GZIP; 5644dc88ebeSGabor Kovesdan break; 5654dc88ebeSGabor Kovesdan case BIN_OPT: 56627116286SGabor Kovesdan if (strcasecmp("binary", optarg) == 0) 5674dc88ebeSGabor Kovesdan binbehave = BINFILE_BIN; 56827116286SGabor Kovesdan else if (strcasecmp("without-match", optarg) == 0) 5694dc88ebeSGabor Kovesdan binbehave = BINFILE_SKIP; 57027116286SGabor Kovesdan else if (strcasecmp("text", optarg) == 0) 5714dc88ebeSGabor Kovesdan binbehave = BINFILE_TEXT; 5724dc88ebeSGabor Kovesdan else 57397a012f2SGabor Kovesdan errx(2, getstr(3), "--binary-files"); 5744dc88ebeSGabor Kovesdan break; 5754dc88ebeSGabor Kovesdan case COLOR_OPT: 5764dc88ebeSGabor Kovesdan color = NULL; 57727116286SGabor Kovesdan if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 57827116286SGabor Kovesdan strcasecmp("tty", optarg) == 0 || 57927116286SGabor Kovesdan strcasecmp("if-tty", optarg) == 0) { 58027116286SGabor Kovesdan char *term; 58127116286SGabor Kovesdan 58227116286SGabor Kovesdan term = getenv("TERM"); 58327116286SGabor Kovesdan if (isatty(STDOUT_FILENO) && term != NULL && 58427116286SGabor Kovesdan strcasecmp(term, "dumb") != 0) 58527116286SGabor Kovesdan color = init_color("01;31"); 58627116286SGabor Kovesdan } else if (strcasecmp("always", optarg) == 0 || 58727116286SGabor Kovesdan strcasecmp("yes", optarg) == 0 || 58827116286SGabor Kovesdan strcasecmp("force", optarg) == 0) { 58927116286SGabor Kovesdan color = init_color("01;31"); 59027116286SGabor Kovesdan } else if (strcasecmp("never", optarg) != 0 && 59127116286SGabor Kovesdan strcasecmp("none", optarg) != 0 && 59227116286SGabor Kovesdan strcasecmp("no", optarg) != 0) 59397a012f2SGabor Kovesdan errx(2, getstr(3), "--color"); 594*69a6d198SGabor Kovesdan cflags &= ~REG_NOSUB; 5954dc88ebeSGabor Kovesdan break; 5964dc88ebeSGabor Kovesdan case LABEL_OPT: 5974dc88ebeSGabor Kovesdan label = optarg; 5984dc88ebeSGabor Kovesdan break; 5994dc88ebeSGabor Kovesdan case LINEBUF_OPT: 6004dc88ebeSGabor Kovesdan lbflag = true; 6014dc88ebeSGabor Kovesdan break; 6024dc88ebeSGabor Kovesdan case NULL_OPT: 6034dc88ebeSGabor Kovesdan nullflag = true; 6044dc88ebeSGabor Kovesdan break; 6054dc88ebeSGabor Kovesdan case R_INCLUDE_OPT: 60655e44f51SGabor Kovesdan finclude = true; 60755e44f51SGabor Kovesdan add_fpattern(optarg, INCL_PAT); 6084dc88ebeSGabor Kovesdan break; 6094dc88ebeSGabor Kovesdan case R_EXCLUDE_OPT: 61055e44f51SGabor Kovesdan fexclude = true; 61155e44f51SGabor Kovesdan add_fpattern(optarg, EXCL_PAT); 6124dc88ebeSGabor Kovesdan break; 6134dc88ebeSGabor Kovesdan case R_DINCLUDE_OPT: 61459218eb7SGabor Kovesdan dinclude = true; 61555e44f51SGabor Kovesdan add_dpattern(optarg, INCL_PAT); 6164dc88ebeSGabor Kovesdan break; 6174dc88ebeSGabor Kovesdan case R_DEXCLUDE_OPT: 61859218eb7SGabor Kovesdan dexclude = true; 61955e44f51SGabor Kovesdan add_dpattern(optarg, EXCL_PAT); 6204dc88ebeSGabor Kovesdan break; 6214dc88ebeSGabor Kovesdan case HELP_OPT: 6224dc88ebeSGabor Kovesdan default: 6234dc88ebeSGabor Kovesdan usage(); 6244dc88ebeSGabor Kovesdan } 6254dc88ebeSGabor Kovesdan lastc = c; 6264dc88ebeSGabor Kovesdan newarg = optind != prevoptind; 6274dc88ebeSGabor Kovesdan prevoptind = optind; 6284dc88ebeSGabor Kovesdan } 6294dc88ebeSGabor Kovesdan aargc -= optind; 6304dc88ebeSGabor Kovesdan aargv += optind; 6314dc88ebeSGabor Kovesdan 6324dc88ebeSGabor Kovesdan /* Fail if we don't have any pattern */ 6334dc88ebeSGabor Kovesdan if (aargc == 0 && needpattern) 6344dc88ebeSGabor Kovesdan usage(); 6354dc88ebeSGabor Kovesdan 6364dc88ebeSGabor Kovesdan /* Process patterns from command line */ 6374dc88ebeSGabor Kovesdan if (aargc != 0 && needpattern) { 6384dc88ebeSGabor Kovesdan add_pattern(*aargv, strlen(*aargv)); 6394dc88ebeSGabor Kovesdan --aargc; 6404dc88ebeSGabor Kovesdan ++aargv; 6414dc88ebeSGabor Kovesdan } 6424dc88ebeSGabor Kovesdan 6434dc88ebeSGabor Kovesdan switch (grepbehave) { 6444dc88ebeSGabor Kovesdan case GREP_FIXED: 6454dc88ebeSGabor Kovesdan case GREP_BASIC: 6464dc88ebeSGabor Kovesdan break; 6474dc88ebeSGabor Kovesdan case GREP_EXTENDED: 6484dc88ebeSGabor Kovesdan cflags |= REG_EXTENDED; 6494dc88ebeSGabor Kovesdan break; 6504dc88ebeSGabor Kovesdan default: 6514dc88ebeSGabor Kovesdan /* NOTREACHED */ 6524dc88ebeSGabor Kovesdan usage(); 6534dc88ebeSGabor Kovesdan } 6544dc88ebeSGabor Kovesdan 6554dc88ebeSGabor Kovesdan fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 6564dc88ebeSGabor Kovesdan r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 6574dc88ebeSGabor Kovesdan /* 6584dc88ebeSGabor Kovesdan * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance. 6594dc88ebeSGabor Kovesdan * Optimizations should be done there. 6604dc88ebeSGabor Kovesdan */ 6614dc88ebeSGabor Kovesdan /* Check if cheating is allowed (always is for fgrep). */ 6624dc88ebeSGabor Kovesdan if (grepbehave == GREP_FIXED) { 6634dc88ebeSGabor Kovesdan for (i = 0; i < patterns; ++i) 6644dc88ebeSGabor Kovesdan fgrepcomp(&fg_pattern[i], pattern[i]); 6654dc88ebeSGabor Kovesdan } else { 6664dc88ebeSGabor Kovesdan for (i = 0; i < patterns; ++i) { 6674dc88ebeSGabor Kovesdan if (fastcomp(&fg_pattern[i], pattern[i])) { 6684dc88ebeSGabor Kovesdan /* Fall back to full regex library */ 6694dc88ebeSGabor Kovesdan c = regcomp(&r_pattern[i], pattern[i], cflags); 6704dc88ebeSGabor Kovesdan if (c != 0) { 6714dc88ebeSGabor Kovesdan regerror(c, &r_pattern[i], re_error, 6724dc88ebeSGabor Kovesdan RE_ERROR_BUF); 6734dc88ebeSGabor Kovesdan errx(2, "%s", re_error); 6744dc88ebeSGabor Kovesdan } 6754dc88ebeSGabor Kovesdan } 6764dc88ebeSGabor Kovesdan } 6774dc88ebeSGabor Kovesdan } 6784dc88ebeSGabor Kovesdan 6794dc88ebeSGabor Kovesdan if (lbflag) 6804dc88ebeSGabor Kovesdan setlinebuf(stdout); 6814dc88ebeSGabor Kovesdan 6824dc88ebeSGabor Kovesdan if ((aargc == 0 || aargc == 1) && !Hflag) 6834dc88ebeSGabor Kovesdan hflag = true; 6844dc88ebeSGabor Kovesdan 6854dc88ebeSGabor Kovesdan if (aargc == 0) 6864dc88ebeSGabor Kovesdan exit(!procfile("-")); 6874dc88ebeSGabor Kovesdan 6884dc88ebeSGabor Kovesdan if (dirbehave == DIR_RECURSE) 6894dc88ebeSGabor Kovesdan c = grep_tree(aargv); 690c38208adSXin LI else 69155e44f51SGabor Kovesdan for (c = 0; aargc--; ++aargv) { 69255e44f51SGabor Kovesdan if ((finclude || fexclude) && !file_matching(*aargv)) 69355e44f51SGabor Kovesdan continue; 6944dc88ebeSGabor Kovesdan c+= procfile(*aargv); 69555e44f51SGabor Kovesdan } 6964dc88ebeSGabor Kovesdan 6974dc88ebeSGabor Kovesdan #ifndef WITHOUT_NLS 6984dc88ebeSGabor Kovesdan catclose(catalog); 6994dc88ebeSGabor Kovesdan #endif 7004dc88ebeSGabor Kovesdan 7014dc88ebeSGabor Kovesdan /* Find out the correct return value according to the 7024dc88ebeSGabor Kovesdan results and the command line option. */ 7034dc88ebeSGabor Kovesdan exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1)); 7044dc88ebeSGabor Kovesdan } 705