grep.c revision 245996
1220422Sgabor/* $NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 joerg Exp $ */ 2220422Sgabor/* $FreeBSD: stable/9/usr.bin/grep/grep.c 245996 2013-01-27 19:44:41Z gabor $ */ 3210389Sgabor/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */ 4210389Sgabor 5210389Sgabor/*- 6211496Sdes * Copyright (c) 1999 James Howard and Dag-Erling Co��dan Sm��rgrav 7210389Sgabor * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org> 8210389Sgabor * All rights reserved. 9210389Sgabor * 10210389Sgabor * Redistribution and use in source and binary forms, with or without 11210389Sgabor * modification, are permitted provided that the following conditions 12210389Sgabor * are met: 13210389Sgabor * 1. Redistributions of source code must retain the above copyright 14210389Sgabor * notice, this list of conditions and the following disclaimer. 15210389Sgabor * 2. Redistributions in binary form must reproduce the above copyright 16210389Sgabor * notice, this list of conditions and the following disclaimer in the 17210389Sgabor * documentation and/or other materials provided with the distribution. 18210389Sgabor * 19210389Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20210389Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21210389Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22210389Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23210389Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24210389Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25210389Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26210389Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27210389Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28210389Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29210389Sgabor * SUCH DAMAGE. 30210389Sgabor */ 31210389Sgabor 32210389Sgabor#include <sys/cdefs.h> 33210389Sgabor__FBSDID("$FreeBSD: stable/9/usr.bin/grep/grep.c 245996 2013-01-27 19:44:41Z gabor $"); 34210389Sgabor 35210389Sgabor#include <sys/stat.h> 36210389Sgabor#include <sys/types.h> 37210389Sgabor 38210389Sgabor#include <ctype.h> 39210389Sgabor#include <err.h> 40210389Sgabor#include <errno.h> 41226261Sgabor#include <fcntl.h> 42210389Sgabor#include <getopt.h> 43210389Sgabor#include <limits.h> 44210389Sgabor#include <libgen.h> 45210389Sgabor#include <locale.h> 46210389Sgabor#include <stdbool.h> 47210389Sgabor#include <stdio.h> 48210389Sgabor#include <stdlib.h> 49210389Sgabor#include <string.h> 50210389Sgabor#include <unistd.h> 51210389Sgabor 52226261Sgabor#include "fastmatch.h" 53210389Sgabor#include "grep.h" 54210389Sgabor 55210389Sgabor#ifndef WITHOUT_NLS 56210389Sgabor#include <nl_types.h> 57210389Sgabornl_catd catalog; 58210389Sgabor#endif 59210389Sgabor 60210389Sgabor/* 61210389Sgabor * Default messags to use when NLS is disabled or no catalogue 62210389Sgabor * is found. 63210389Sgabor */ 64210389Sgaborconst char *errstr[] = { 65210389Sgabor "", 66210389Sgabor/* 1*/ "(standard input)", 67210389Sgabor/* 2*/ "cannot read bzip2 compressed file", 68210622Sgabor/* 3*/ "unknown %s option", 69210389Sgabor/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n", 70210389Sgabor/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 71210389Sgabor/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 72210389Sgabor/* 7*/ "\t[--null] [pattern] [file ...]\n", 73210622Sgabor/* 8*/ "Binary file %s matches\n", 74210622Sgabor/* 9*/ "%s (BSD grep) %s\n", 75210389Sgabor}; 76210389Sgabor 77210389Sgabor/* Flags passed to regcomp() and regexec() */ 78223009Sgaborint cflags = REG_NOSUB; 79210389Sgaborint eflags = REG_STARTEND; 80210389Sgabor 81210389Sgabor/* Shortcut for matching all cases like empty regex */ 82210389Sgaborbool matchall; 83210389Sgabor 84210389Sgabor/* Searching patterns */ 85210389Sgaborunsigned int patterns, pattern_sz; 86226261Sgaborstruct pat *pattern; 87210389Sgaborregex_t *r_pattern; 88226261Sgaborfastmatch_t *fg_pattern; 89210389Sgabor 90210389Sgabor/* Filename exclusion/inclusion patterns */ 91210578Sgaborunsigned int fpatterns, fpattern_sz; 92210578Sgaborunsigned int dpatterns, dpattern_sz; 93210578Sgaborstruct epat *dpattern, *fpattern; 94210389Sgabor 95210389Sgabor/* For regex errors */ 96210389Sgaborchar re_error[RE_ERROR_BUF + 1]; 97210389Sgabor 98210389Sgabor/* Command-line flags */ 99210389Sgaborunsigned long long Aflag; /* -A x: print x lines trailing each match */ 100210389Sgaborunsigned long long Bflag; /* -B x: print x lines leading each match */ 101210389Sgaborbool Hflag; /* -H: always print file name */ 102210389Sgaborbool Lflag; /* -L: only show names of files with no matches */ 103210389Sgaborbool bflag; /* -b: show block numbers for each match */ 104210389Sgaborbool cflag; /* -c: only show a count of matching lines */ 105210389Sgaborbool hflag; /* -h: don't print filename headers */ 106210389Sgaborbool iflag; /* -i: ignore case */ 107210389Sgaborbool lflag; /* -l: only show names of files with matches */ 108210389Sgaborbool mflag; /* -m x: stop reading the files after x matches */ 109226261Sgaborlong long mcount; /* count for -m */ 110210389Sgaborbool nflag; /* -n: show line numbers in front of matching lines */ 111210389Sgaborbool oflag; /* -o: print only matching part */ 112210389Sgaborbool qflag; /* -q: quiet mode (don't output anything) */ 113210389Sgaborbool sflag; /* -s: silent mode (ignore errors) */ 114210389Sgaborbool vflag; /* -v: only show non-matching lines */ 115210389Sgaborbool wflag; /* -w: pattern must start and end on word boundaries */ 116210389Sgaborbool xflag; /* -x: pattern must match entire line */ 117210389Sgaborbool lbflag; /* --line-buffered */ 118210389Sgaborbool nullflag; /* --null */ 119210389Sgaborchar *label; /* --label */ 120210461Sgaborconst char *color; /* --color */ 121210389Sgaborint grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 122210389Sgaborint binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 123210389Sgaborint filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 124210461Sgaborint devbehave = DEV_READ; /* -D: handling of devices */ 125210461Sgaborint dirbehave = DIR_READ; /* -dRr: handling of directories */ 126210461Sgaborint linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 127210389Sgabor 128211364Sgaborbool dexclude, dinclude; /* --exclude-dir and --include-dir */ 129211364Sgaborbool fexclude, finclude; /* --exclude and --include */ 130210578Sgabor 131210389Sgaborenum { 132210389Sgabor BIN_OPT = CHAR_MAX + 1, 133210389Sgabor COLOR_OPT, 134210389Sgabor HELP_OPT, 135210389Sgabor MMAP_OPT, 136210389Sgabor LINEBUF_OPT, 137210389Sgabor LABEL_OPT, 138210389Sgabor NULL_OPT, 139210389Sgabor R_EXCLUDE_OPT, 140210389Sgabor R_INCLUDE_OPT, 141210389Sgabor R_DEXCLUDE_OPT, 142210389Sgabor R_DINCLUDE_OPT 143210389Sgabor}; 144210389Sgabor 145210461Sgaborstatic inline const char *init_color(const char *); 146210461Sgabor 147210389Sgabor/* Housekeeping */ 148210389Sgaborbool first = true; /* flag whether we are processing the first match */ 149210389Sgaborbool prev; /* flag whether or not the previous line matched */ 150210389Sgaborint tail; /* lines left to print */ 151229081Sgaborbool file_err; /* file reading error */ 152210389Sgabor 153210389Sgabor/* 154210389Sgabor * Prints usage information and returns 2. 155210389Sgabor */ 156210389Sgaborstatic void 157210389Sgaborusage(void) 158210389Sgabor{ 159226573Sgabor fprintf(stderr, getstr(4), getprogname()); 160210389Sgabor fprintf(stderr, "%s", getstr(5)); 161210389Sgabor fprintf(stderr, "%s", getstr(6)); 162210389Sgabor fprintf(stderr, "%s", getstr(7)); 163210389Sgabor exit(2); 164210389Sgabor} 165210389Sgabor 166226261Sgaborstatic const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy"; 167210389Sgabor 168210389Sgaborstruct option long_options[] = 169210389Sgabor{ 170210389Sgabor {"binary-files", required_argument, NULL, BIN_OPT}, 171210389Sgabor {"help", no_argument, NULL, HELP_OPT}, 172210389Sgabor {"mmap", no_argument, NULL, MMAP_OPT}, 173210389Sgabor {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 174210389Sgabor {"label", required_argument, NULL, LABEL_OPT}, 175210389Sgabor {"null", no_argument, NULL, NULL_OPT}, 176210389Sgabor {"color", optional_argument, NULL, COLOR_OPT}, 177210389Sgabor {"colour", optional_argument, NULL, COLOR_OPT}, 178210389Sgabor {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 179210389Sgabor {"include", required_argument, NULL, R_INCLUDE_OPT}, 180210389Sgabor {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 181210389Sgabor {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 182210389Sgabor {"after-context", required_argument, NULL, 'A'}, 183210389Sgabor {"text", no_argument, NULL, 'a'}, 184210389Sgabor {"before-context", required_argument, NULL, 'B'}, 185210389Sgabor {"byte-offset", no_argument, NULL, 'b'}, 186210389Sgabor {"context", optional_argument, NULL, 'C'}, 187210389Sgabor {"count", no_argument, NULL, 'c'}, 188210389Sgabor {"devices", required_argument, NULL, 'D'}, 189210389Sgabor {"directories", required_argument, NULL, 'd'}, 190210389Sgabor {"extended-regexp", no_argument, NULL, 'E'}, 191210389Sgabor {"regexp", required_argument, NULL, 'e'}, 192210389Sgabor {"fixed-strings", no_argument, NULL, 'F'}, 193210389Sgabor {"file", required_argument, NULL, 'f'}, 194210389Sgabor {"basic-regexp", no_argument, NULL, 'G'}, 195210389Sgabor {"no-filename", no_argument, NULL, 'h'}, 196210389Sgabor {"with-filename", no_argument, NULL, 'H'}, 197210389Sgabor {"ignore-case", no_argument, NULL, 'i'}, 198210389Sgabor {"bz2decompress", no_argument, NULL, 'J'}, 199210389Sgabor {"files-with-matches", no_argument, NULL, 'l'}, 200210389Sgabor {"files-without-match", no_argument, NULL, 'L'}, 201210389Sgabor {"max-count", required_argument, NULL, 'm'}, 202226261Sgabor {"lzma", no_argument, NULL, 'M'}, 203210389Sgabor {"line-number", no_argument, NULL, 'n'}, 204210389Sgabor {"only-matching", no_argument, NULL, 'o'}, 205210389Sgabor {"quiet", no_argument, NULL, 'q'}, 206210389Sgabor {"silent", no_argument, NULL, 'q'}, 207210389Sgabor {"recursive", no_argument, NULL, 'r'}, 208210389Sgabor {"no-messages", no_argument, NULL, 's'}, 209210389Sgabor {"binary", no_argument, NULL, 'U'}, 210210389Sgabor {"unix-byte-offsets", no_argument, NULL, 'u'}, 211210389Sgabor {"invert-match", no_argument, NULL, 'v'}, 212210389Sgabor {"version", no_argument, NULL, 'V'}, 213210389Sgabor {"word-regexp", no_argument, NULL, 'w'}, 214210389Sgabor {"line-regexp", no_argument, NULL, 'x'}, 215226261Sgabor {"xz", no_argument, NULL, 'X'}, 216210389Sgabor {"decompress", no_argument, NULL, 'Z'}, 217210389Sgabor {NULL, no_argument, NULL, 0} 218210389Sgabor}; 219210389Sgabor 220210389Sgabor/* 221210389Sgabor * Adds a searching pattern to the internal array. 222210389Sgabor */ 223210389Sgaborstatic void 224210389Sgaboradd_pattern(char *pat, size_t len) 225210389Sgabor{ 226210389Sgabor 227226261Sgabor /* Do not add further pattern is we already match everything */ 228226261Sgabor if (matchall) 229226261Sgabor return; 230226261Sgabor 231210389Sgabor /* Check if we can do a shortcut */ 232226261Sgabor if (len == 0) { 233210389Sgabor matchall = true; 234226261Sgabor for (unsigned int i = 0; i < patterns; i++) { 235226261Sgabor free(pattern[i].pat); 236226261Sgabor } 237226261Sgabor pattern = grep_realloc(pattern, sizeof(struct pat)); 238226261Sgabor pattern[0].pat = NULL; 239226261Sgabor pattern[0].len = 0; 240226261Sgabor patterns = 1; 241210389Sgabor return; 242210389Sgabor } 243210389Sgabor /* Increase size if necessary */ 244210389Sgabor if (patterns == pattern_sz) { 245210389Sgabor pattern_sz *= 2; 246210389Sgabor pattern = grep_realloc(pattern, ++pattern_sz * 247226261Sgabor sizeof(struct pat)); 248210389Sgabor } 249210389Sgabor if (len > 0 && pat[len - 1] == '\n') 250210389Sgabor --len; 251210389Sgabor /* pat may not be NUL-terminated */ 252226261Sgabor pattern[patterns].pat = grep_malloc(len + 1); 253226261Sgabor memcpy(pattern[patterns].pat, pat, len); 254226261Sgabor pattern[patterns].len = len; 255226261Sgabor pattern[patterns].pat[len] = '\0'; 256210389Sgabor ++patterns; 257210389Sgabor} 258210389Sgabor 259210389Sgabor/* 260210578Sgabor * Adds a file include/exclude pattern to the internal array. 261210389Sgabor */ 262210389Sgaborstatic void 263210578Sgaboradd_fpattern(const char *pat, int mode) 264210389Sgabor{ 265210389Sgabor 266210389Sgabor /* Increase size if necessary */ 267210578Sgabor if (fpatterns == fpattern_sz) { 268210578Sgabor fpattern_sz *= 2; 269210578Sgabor fpattern = grep_realloc(fpattern, ++fpattern_sz * 270210389Sgabor sizeof(struct epat)); 271210389Sgabor } 272210578Sgabor fpattern[fpatterns].pat = grep_strdup(pat); 273210578Sgabor fpattern[fpatterns].mode = mode; 274210578Sgabor ++fpatterns; 275210389Sgabor} 276210389Sgabor 277210389Sgabor/* 278210578Sgabor * Adds a directory include/exclude pattern to the internal array. 279210578Sgabor */ 280210578Sgaborstatic void 281210578Sgaboradd_dpattern(const char *pat, int mode) 282210578Sgabor{ 283210578Sgabor 284210578Sgabor /* Increase size if necessary */ 285210578Sgabor if (dpatterns == dpattern_sz) { 286210578Sgabor dpattern_sz *= 2; 287210578Sgabor dpattern = grep_realloc(dpattern, ++dpattern_sz * 288210578Sgabor sizeof(struct epat)); 289210578Sgabor } 290210578Sgabor dpattern[dpatterns].pat = grep_strdup(pat); 291210578Sgabor dpattern[dpatterns].mode = mode; 292210578Sgabor ++dpatterns; 293210578Sgabor} 294210578Sgabor 295210578Sgabor/* 296210389Sgabor * Reads searching patterns from a file and adds them with add_pattern(). 297210389Sgabor */ 298210389Sgaborstatic void 299210389Sgaborread_patterns(const char *fn) 300210389Sgabor{ 301226261Sgabor struct stat st; 302210389Sgabor FILE *f; 303210389Sgabor char *line; 304210389Sgabor size_t len; 305210389Sgabor 306210389Sgabor if ((f = fopen(fn, "r")) == NULL) 307210389Sgabor err(2, "%s", fn); 308226261Sgabor if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 309226261Sgabor fclose(f); 310226261Sgabor return; 311226261Sgabor } 312226261Sgabor while ((line = fgetln(f, &len)) != NULL) 313226261Sgabor add_pattern(line, line[0] == '\n' ? 0 : len); 314210389Sgabor if (ferror(f)) 315210389Sgabor err(2, "%s", fn); 316210389Sgabor fclose(f); 317210389Sgabor} 318210389Sgabor 319210461Sgaborstatic inline const char * 320210461Sgaborinit_color(const char *d) 321210461Sgabor{ 322210461Sgabor char *c; 323210461Sgabor 324210461Sgabor c = getenv("GREP_COLOR"); 325224937Sgabor return (c != NULL && c[0] != '\0' ? c : d); 326210461Sgabor} 327210461Sgabor 328210389Sgaborint 329210389Sgabormain(int argc, char *argv[]) 330210389Sgabor{ 331210389Sgabor char **aargv, **eargv, *eopts; 332226573Sgabor char *ep; 333226573Sgabor const char *pn; 334210389Sgabor unsigned long long l; 335210389Sgabor unsigned int aargc, eargc, i; 336210389Sgabor int c, lastc, needpattern, newarg, prevoptind; 337210389Sgabor 338210389Sgabor setlocale(LC_ALL, ""); 339210389Sgabor 340210389Sgabor#ifndef WITHOUT_NLS 341210389Sgabor catalog = catopen("grep", NL_CAT_LOCALE); 342210389Sgabor#endif 343210389Sgabor 344210389Sgabor /* Check what is the program name of the binary. In this 345210389Sgabor way we can have all the funcionalities in one binary 346210389Sgabor without the need of scripting and using ugly hacks. */ 347226573Sgabor pn = getprogname(); 348226261Sgabor if (pn[0] == 'b' && pn[1] == 'z') { 349226261Sgabor filebehave = FILE_BZIP; 350226261Sgabor pn += 2; 351226261Sgabor } else if (pn[0] == 'x' && pn[1] == 'z') { 352226261Sgabor filebehave = FILE_XZ; 353226261Sgabor pn += 2; 354226261Sgabor } else if (pn[0] == 'l' && pn[1] == 'z') { 355226261Sgabor filebehave = FILE_LZMA; 356226261Sgabor pn += 2; 357226261Sgabor } else if (pn[0] == 'z') { 358226261Sgabor filebehave = FILE_GZIP; 359226261Sgabor pn += 1; 360226261Sgabor } 361226261Sgabor switch (pn[0]) { 362210389Sgabor case 'e': 363210389Sgabor grepbehave = GREP_EXTENDED; 364210389Sgabor break; 365210389Sgabor case 'f': 366210389Sgabor grepbehave = GREP_FIXED; 367210389Sgabor break; 368210389Sgabor } 369210389Sgabor 370210389Sgabor lastc = '\0'; 371210389Sgabor newarg = 1; 372210389Sgabor prevoptind = 1; 373210389Sgabor needpattern = 1; 374210389Sgabor 375210389Sgabor eopts = getenv("GREP_OPTIONS"); 376210389Sgabor 377211364Sgabor /* support for extra arguments in GREP_OPTIONS */ 378211364Sgabor eargc = 0; 379224937Sgabor if (eopts != NULL && eopts[0] != '\0') { 380210389Sgabor char *str; 381210389Sgabor 382211364Sgabor /* make an estimation of how many extra arguments we have */ 383211364Sgabor for (unsigned int j = 0; j < strlen(eopts); j++) 384211364Sgabor if (eopts[j] == ' ') 385210389Sgabor eargc++; 386210389Sgabor 387210389Sgabor eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 388210389Sgabor 389210389Sgabor eargc = 0; 390211364Sgabor /* parse extra arguments */ 391211364Sgabor while ((str = strsep(&eopts, " ")) != NULL) 392224937Sgabor if (str[0] != '\0') 393224937Sgabor eargv[eargc++] = grep_strdup(str); 394210389Sgabor 395210430Sdelphij aargv = (char **)grep_calloc(eargc + argc + 1, 396210430Sdelphij sizeof(char *)); 397211364Sgabor 398210389Sgabor aargv[0] = argv[0]; 399211364Sgabor for (i = 0; i < eargc; i++) 400211364Sgabor aargv[i + 1] = eargv[i]; 401211364Sgabor for (int j = 1; j < argc; j++, i++) 402211364Sgabor aargv[i + 1] = argv[j]; 403210389Sgabor 404211364Sgabor aargc = eargc + argc; 405210389Sgabor } else { 406210389Sgabor aargv = argv; 407210389Sgabor aargc = argc; 408210389Sgabor } 409210389Sgabor 410210389Sgabor while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 411210389Sgabor -1)) { 412210389Sgabor switch (c) { 413210389Sgabor case '0': case '1': case '2': case '3': case '4': 414210389Sgabor case '5': case '6': case '7': case '8': case '9': 415210389Sgabor if (newarg || !isdigit(lastc)) 416210389Sgabor Aflag = 0; 417210389Sgabor else if (Aflag > LLONG_MAX / 10) { 418210389Sgabor errno = ERANGE; 419210389Sgabor err(2, NULL); 420210389Sgabor } 421210389Sgabor Aflag = Bflag = (Aflag * 10) + (c - '0'); 422210389Sgabor break; 423210389Sgabor case 'C': 424210389Sgabor if (optarg == NULL) { 425210389Sgabor Aflag = Bflag = 2; 426210389Sgabor break; 427210389Sgabor } 428210389Sgabor /* FALLTHROUGH */ 429210389Sgabor case 'A': 430210389Sgabor /* FALLTHROUGH */ 431210389Sgabor case 'B': 432210389Sgabor errno = 0; 433210389Sgabor l = strtoull(optarg, &ep, 10); 434210389Sgabor if (((errno == ERANGE) && (l == ULLONG_MAX)) || 435210389Sgabor ((errno == EINVAL) && (l == 0))) 436210389Sgabor err(2, NULL); 437210389Sgabor else if (ep[0] != '\0') { 438210389Sgabor errno = EINVAL; 439210389Sgabor err(2, NULL); 440210389Sgabor } 441210389Sgabor if (c == 'A') 442210389Sgabor Aflag = l; 443210389Sgabor else if (c == 'B') 444210389Sgabor Bflag = l; 445210389Sgabor else 446210389Sgabor Aflag = Bflag = l; 447210389Sgabor break; 448210389Sgabor case 'a': 449210389Sgabor binbehave = BINFILE_TEXT; 450210389Sgabor break; 451210389Sgabor case 'b': 452210389Sgabor bflag = true; 453210389Sgabor break; 454210389Sgabor case 'c': 455210389Sgabor cflag = true; 456210389Sgabor break; 457210389Sgabor case 'D': 458210461Sgabor if (strcasecmp(optarg, "skip") == 0) 459210389Sgabor devbehave = DEV_SKIP; 460210461Sgabor else if (strcasecmp(optarg, "read") == 0) 461210461Sgabor devbehave = DEV_READ; 462210622Sgabor else 463210622Sgabor errx(2, getstr(3), "--devices"); 464210389Sgabor break; 465210389Sgabor case 'd': 466210461Sgabor if (strcasecmp("recurse", optarg) == 0) { 467210389Sgabor Hflag = true; 468210389Sgabor dirbehave = DIR_RECURSE; 469210461Sgabor } else if (strcasecmp("skip", optarg) == 0) 470210389Sgabor dirbehave = DIR_SKIP; 471210461Sgabor else if (strcasecmp("read", optarg) == 0) 472210461Sgabor dirbehave = DIR_READ; 473210622Sgabor else 474210622Sgabor errx(2, getstr(3), "--directories"); 475210389Sgabor break; 476210389Sgabor case 'E': 477210389Sgabor grepbehave = GREP_EXTENDED; 478210389Sgabor break; 479210389Sgabor case 'e': 480245996Sgabor { 481245996Sgabor char *token; 482245996Sgabor char *string = optarg; 483245996Sgabor 484245996Sgabor while ((token = strsep(&string, "\n")) != NULL) 485245996Sgabor add_pattern(token, strlen(token)); 486245996Sgabor } 487210389Sgabor needpattern = 0; 488210389Sgabor break; 489210389Sgabor case 'F': 490210389Sgabor grepbehave = GREP_FIXED; 491210389Sgabor break; 492210389Sgabor case 'f': 493210389Sgabor read_patterns(optarg); 494210389Sgabor needpattern = 0; 495210389Sgabor break; 496210389Sgabor case 'G': 497210389Sgabor grepbehave = GREP_BASIC; 498210389Sgabor break; 499210389Sgabor case 'H': 500210389Sgabor Hflag = true; 501210389Sgabor break; 502210389Sgabor case 'h': 503210389Sgabor Hflag = false; 504210389Sgabor hflag = true; 505210389Sgabor break; 506210389Sgabor case 'I': 507210389Sgabor binbehave = BINFILE_SKIP; 508210389Sgabor break; 509210389Sgabor case 'i': 510210389Sgabor case 'y': 511210389Sgabor iflag = true; 512210389Sgabor cflags |= REG_ICASE; 513210389Sgabor break; 514210389Sgabor case 'J': 515226573Sgabor#ifdef WITHOUT_BZIP2 516226573Sgabor errno = EOPNOTSUPP; 517226573Sgabor err(2, "bzip2 support was disabled at compile-time"); 518226573Sgabor#endif 519210389Sgabor filebehave = FILE_BZIP; 520210389Sgabor break; 521210389Sgabor case 'L': 522210389Sgabor lflag = false; 523210461Sgabor Lflag = true; 524210389Sgabor break; 525210389Sgabor case 'l': 526210389Sgabor Lflag = false; 527210461Sgabor lflag = true; 528210389Sgabor break; 529210389Sgabor case 'm': 530210389Sgabor mflag = true; 531210389Sgabor errno = 0; 532226261Sgabor mcount = strtoll(optarg, &ep, 10); 533226261Sgabor if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 534210389Sgabor ((errno == EINVAL) && (mcount == 0))) 535210389Sgabor err(2, NULL); 536210389Sgabor else if (ep[0] != '\0') { 537210389Sgabor errno = EINVAL; 538210389Sgabor err(2, NULL); 539210389Sgabor } 540210389Sgabor break; 541226261Sgabor case 'M': 542226261Sgabor filebehave = FILE_LZMA; 543226261Sgabor break; 544210389Sgabor case 'n': 545210389Sgabor nflag = true; 546210389Sgabor break; 547210389Sgabor case 'O': 548210389Sgabor linkbehave = LINK_EXPLICIT; 549210389Sgabor break; 550210389Sgabor case 'o': 551210389Sgabor oflag = true; 552223009Sgabor cflags &= ~REG_NOSUB; 553210389Sgabor break; 554210389Sgabor case 'p': 555210389Sgabor linkbehave = LINK_SKIP; 556210389Sgabor break; 557210389Sgabor case 'q': 558210389Sgabor qflag = true; 559210389Sgabor break; 560210389Sgabor case 'S': 561210461Sgabor linkbehave = LINK_READ; 562210389Sgabor break; 563210389Sgabor case 'R': 564210389Sgabor case 'r': 565210389Sgabor dirbehave = DIR_RECURSE; 566210389Sgabor Hflag = true; 567210389Sgabor break; 568210389Sgabor case 's': 569210389Sgabor sflag = true; 570210389Sgabor break; 571210389Sgabor case 'U': 572210389Sgabor binbehave = BINFILE_BIN; 573210389Sgabor break; 574210389Sgabor case 'u': 575210389Sgabor case MMAP_OPT: 576226261Sgabor filebehave = FILE_MMAP; 577210389Sgabor break; 578210389Sgabor case 'V': 579226573Sgabor printf(getstr(9), getprogname(), VERSION); 580210389Sgabor exit(0); 581210389Sgabor case 'v': 582210389Sgabor vflag = true; 583210389Sgabor break; 584210389Sgabor case 'w': 585210389Sgabor wflag = true; 586223009Sgabor cflags &= ~REG_NOSUB; 587210389Sgabor break; 588210389Sgabor case 'x': 589210389Sgabor xflag = true; 590223009Sgabor cflags &= ~REG_NOSUB; 591210389Sgabor break; 592226261Sgabor case 'X': 593226261Sgabor filebehave = FILE_XZ; 594226261Sgabor break; 595210389Sgabor case 'Z': 596210389Sgabor filebehave = FILE_GZIP; 597210389Sgabor break; 598210389Sgabor case BIN_OPT: 599210461Sgabor if (strcasecmp("binary", optarg) == 0) 600210389Sgabor binbehave = BINFILE_BIN; 601210461Sgabor else if (strcasecmp("without-match", optarg) == 0) 602210389Sgabor binbehave = BINFILE_SKIP; 603210461Sgabor else if (strcasecmp("text", optarg) == 0) 604210389Sgabor binbehave = BINFILE_TEXT; 605210389Sgabor else 606210622Sgabor errx(2, getstr(3), "--binary-files"); 607210389Sgabor break; 608210389Sgabor case COLOR_OPT: 609210461Sgabor color = NULL; 610210461Sgabor if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 611210461Sgabor strcasecmp("tty", optarg) == 0 || 612210461Sgabor strcasecmp("if-tty", optarg) == 0) { 613210461Sgabor char *term; 614210461Sgabor 615210461Sgabor term = getenv("TERM"); 616210461Sgabor if (isatty(STDOUT_FILENO) && term != NULL && 617210461Sgabor strcasecmp(term, "dumb") != 0) 618210461Sgabor color = init_color("01;31"); 619210461Sgabor } else if (strcasecmp("always", optarg) == 0 || 620210461Sgabor strcasecmp("yes", optarg) == 0 || 621210461Sgabor strcasecmp("force", optarg) == 0) { 622210461Sgabor color = init_color("01;31"); 623210461Sgabor } else if (strcasecmp("never", optarg) != 0 && 624210461Sgabor strcasecmp("none", optarg) != 0 && 625210461Sgabor strcasecmp("no", optarg) != 0) 626210622Sgabor errx(2, getstr(3), "--color"); 627223009Sgabor cflags &= ~REG_NOSUB; 628210389Sgabor break; 629210389Sgabor case LABEL_OPT: 630210389Sgabor label = optarg; 631210389Sgabor break; 632210389Sgabor case LINEBUF_OPT: 633210389Sgabor lbflag = true; 634210389Sgabor break; 635210389Sgabor case NULL_OPT: 636210389Sgabor nullflag = true; 637210389Sgabor break; 638210389Sgabor case R_INCLUDE_OPT: 639210578Sgabor finclude = true; 640210578Sgabor add_fpattern(optarg, INCL_PAT); 641210389Sgabor break; 642210389Sgabor case R_EXCLUDE_OPT: 643210578Sgabor fexclude = true; 644210578Sgabor add_fpattern(optarg, EXCL_PAT); 645210389Sgabor break; 646210389Sgabor case R_DINCLUDE_OPT: 647211364Sgabor dinclude = true; 648210578Sgabor add_dpattern(optarg, INCL_PAT); 649210389Sgabor break; 650210389Sgabor case R_DEXCLUDE_OPT: 651211364Sgabor dexclude = true; 652210578Sgabor add_dpattern(optarg, EXCL_PAT); 653210389Sgabor break; 654210389Sgabor case HELP_OPT: 655210389Sgabor default: 656210389Sgabor usage(); 657210389Sgabor } 658210389Sgabor lastc = c; 659210389Sgabor newarg = optind != prevoptind; 660210389Sgabor prevoptind = optind; 661210389Sgabor } 662210389Sgabor aargc -= optind; 663210389Sgabor aargv += optind; 664210389Sgabor 665226261Sgabor /* Empty pattern file matches nothing */ 666226261Sgabor if (!needpattern && (patterns == 0)) 667226261Sgabor exit(1); 668226261Sgabor 669210389Sgabor /* Fail if we don't have any pattern */ 670210389Sgabor if (aargc == 0 && needpattern) 671210389Sgabor usage(); 672210389Sgabor 673210389Sgabor /* Process patterns from command line */ 674210389Sgabor if (aargc != 0 && needpattern) { 675245996Sgabor char *token; 676245996Sgabor char *string = *aargv; 677245996Sgabor 678245996Sgabor while ((token = strsep(&string, "\n")) != NULL) 679245996Sgabor add_pattern(token, strlen(token)); 680210389Sgabor --aargc; 681210389Sgabor ++aargv; 682210389Sgabor } 683210389Sgabor 684210389Sgabor switch (grepbehave) { 685210389Sgabor case GREP_BASIC: 686210389Sgabor break; 687226261Sgabor case GREP_FIXED: 688226261Sgabor /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */ 689226261Sgabor cflags |= 0020; 690226261Sgabor break; 691210389Sgabor case GREP_EXTENDED: 692210389Sgabor cflags |= REG_EXTENDED; 693210389Sgabor break; 694210389Sgabor default: 695210389Sgabor /* NOTREACHED */ 696210389Sgabor usage(); 697210389Sgabor } 698210389Sgabor 699210389Sgabor fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 700210389Sgabor r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 701226261Sgabor 702226261Sgabor /* Check if cheating is allowed (always is for fgrep). */ 703226261Sgabor for (i = 0; i < patterns; ++i) { 704226261Sgabor if (fastncomp(&fg_pattern[i], pattern[i].pat, 705226261Sgabor pattern[i].len, cflags) != 0) { 706226261Sgabor /* Fall back to full regex library */ 707226261Sgabor c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 708226261Sgabor if (c != 0) { 709226261Sgabor regerror(c, &r_pattern[i], re_error, 710226261Sgabor RE_ERROR_BUF); 711226261Sgabor errx(2, "%s", re_error); 712210389Sgabor } 713210389Sgabor } 714210389Sgabor } 715210389Sgabor 716210389Sgabor if (lbflag) 717210389Sgabor setlinebuf(stdout); 718210389Sgabor 719210389Sgabor if ((aargc == 0 || aargc == 1) && !Hflag) 720210389Sgabor hflag = true; 721210389Sgabor 722210389Sgabor if (aargc == 0) 723210389Sgabor exit(!procfile("-")); 724210389Sgabor 725210389Sgabor if (dirbehave == DIR_RECURSE) 726210389Sgabor c = grep_tree(aargv); 727211519Sdelphij else 728210578Sgabor for (c = 0; aargc--; ++aargv) { 729210578Sgabor if ((finclude || fexclude) && !file_matching(*aargv)) 730210578Sgabor continue; 731210389Sgabor c+= procfile(*aargv); 732210578Sgabor } 733210389Sgabor 734210389Sgabor#ifndef WITHOUT_NLS 735210389Sgabor catclose(catalog); 736210389Sgabor#endif 737210389Sgabor 738210389Sgabor /* Find out the correct return value according to the 739210389Sgabor results and the command line option. */ 740229081Sgabor exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 741210389Sgabor} 742