grep.c revision 210578
1329462Skib/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */ 21817Sdg 31817Sdg/*- 41817Sdg * Copyright (c) 1999 James Howard and Dag-Erling Co�dan Sm�rgrav 51817Sdg * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org> 6329462Skib * All rights reserved. 7329462Skib * 8329462Skib * Redistribution and use in source and binary forms, with or without 9329462Skib * modification, are permitted provided that the following conditions 10329462Skib * are met: 11329462Skib * 1. Redistributions of source code must retain the above copyright 12329462Skib * notice, this list of conditions and the following disclaimer. 131817Sdg * 2. Redistributions in binary form must reproduce the above copyright 141817Sdg * notice, this list of conditions and the following disclaimer in the 151817Sdg * documentation and/or other materials provided with the distribution. 161817Sdg * 171817Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181817Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191817Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201817Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211817Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221817Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231817Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241817Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251817Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261817Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271817Sdg * SUCH DAMAGE. 281817Sdg */ 291817Sdg 301817Sdg#include <sys/cdefs.h> 311817Sdg__FBSDID("$FreeBSD: head/usr.bin/grep/grep.c 210578 2010-07-29 00:11:14Z gabor $"); 321817Sdg 331817Sdg#include <sys/stat.h> 341817Sdg#include <sys/types.h> 351817Sdg 361817Sdg#include <ctype.h> 3750477Speter#include <err.h> 381817Sdg#include <errno.h> 391817Sdg#include <getopt.h> 402579Sbde#include <limits.h> 412579Sbde#include <libgen.h> 422123Sjkh#include <locale.h> 4316029Speter#include <stdbool.h> 442579Sbde#include <stdio.h> 4518961Sbde#include <stdlib.h> 4613107Sbde#include <string.h> 4725083Sjdp#include <unistd.h> 48163726Sbde 4925083Sjdp#include "grep.h" 5025083Sjdp 51163726Sbde#ifndef WITHOUT_NLS 5225083Sjdp#include <nl_types.h> 5325083Sjdpnl_catd catalog; 5425083Sjdp#endif 55114349Speter 5622636Sbde/* 5725083Sjdp * Default messags to use when NLS is disabled or no catalogue 5822636Sbde * is found. 59114349Speter */ 6022636Sbdeconst char *errstr[] = { 6125083Sjdp "", 62757Sdg/* 1*/ "(standard input)", 6325083Sjdp/* 2*/ "cannot read bzip2 compressed file", 6446548Sbde/* 3*/ "unknown --color option", 6513107Sbde/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n", 6618961Sbde/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 67757Sdg/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 68171914Sjkoshy/* 7*/ "\t[--null] [pattern] [file ...]\n", 69171914Sjkoshy/* 8*/ "unknown --binary-files option", 70757Sdg/* 9*/ "Binary file %s matches\n", 71757Sdg/*10*/ "%s (BSD grep) %s\n", 7246548Sbde}; 7313107Sbde 7413107Sbde/* Flags passed to regcomp() and regexec() */ 7513107Sbdeint cflags = 0; 7613107Sbdeint eflags = REG_STARTEND; 7713107Sbde 7813107Sbde/* Shortcut for matching all cases like empty regex */ 7913107Sbdebool matchall; 8013107Sbde 8146548Sbde/* Searching patterns */ 8218961Sbdeunsigned int patterns, pattern_sz; 8318961Sbdechar **pattern; 8446548Sbderegex_t *r_pattern; 8518961Sbdefastgrep_t *fg_pattern; 8618961Sbde 8713107Sbde/* Filename exclusion/inclusion patterns */ 8846548Sbdeunsigned int fpatterns, fpattern_sz; 8946548Sbdeunsigned int dpatterns, dpattern_sz; 9013107Sbdestruct epat *dpattern, *fpattern; 9118961Sbde 9246548Sbde/* For regex errors */ 9346548Sbdechar re_error[RE_ERROR_BUF + 1]; 9418961Sbde 9518961Sbde/* Command-line flags */ 9613107Sbdeunsigned long long Aflag; /* -A x: print x lines trailing each match */ 9713107Sbdeunsigned long long Bflag; /* -B x: print x lines leading each match */ 9813107Sbdebool Hflag; /* -H: always print file name */ 9913107Sbdebool Lflag; /* -L: only show names of files with no matches */ 10013107Sbdebool bflag; /* -b: show block numbers for each match */ 10113107Sbdebool cflag; /* -c: only show a count of matching lines */ 10213107Sbdebool hflag; /* -h: don't print filename headers */ 10313107Sbdebool iflag; /* -i: ignore case */ 10413107Sbdebool lflag; /* -l: only show names of files with matches */ 10518961Sbdebool mflag; /* -m x: stop reading the files after x matches */ 10618961Sbdeunsigned long long mcount; /* count for -m */ 10718961Sbdebool nflag; /* -n: show line numbers in front of matching lines */ 10818961Sbdebool oflag; /* -o: print only matching part */ 109757Sdgbool qflag; /* -q: quiet mode (don't output anything) */ 11013107Sbdebool sflag; /* -s: silent mode (ignore errors) */ 11118961Sbdebool vflag; /* -v: only show non-matching lines */ 11218961Sbdebool wflag; /* -w: pattern must start and end on word boundaries */ 11318961Sbdebool xflag; /* -x: pattern must match entire line */ 11418961Sbdebool lbflag; /* --line-buffered */ 11513107Sbdebool nullflag; /* --null */ 116122940Speterchar *label; /* --label */ 11713107Sbdeconst char *color; /* --color */ 11813107Sbdeint grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 119163722Sbdeint binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 120163726Sbdeint filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 12118961Sbdeint devbehave = DEV_READ; /* -D: handling of devices */ 122163722Sbdeint dirbehave = DIR_READ; /* -dRr: handling of directories */ 123163722Sbdeint linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 124163722Sbde 12518961Sbdebool dexclude, dinclude; /* --exclude amd --include */ 12618961Sbdebool fexclude, finclude; /* --exclude-dir and --include-dir */ 127757Sdg 128757Sdgenum { 129757Sdg BIN_OPT = CHAR_MAX + 1, 13013107Sbde COLOR_OPT, 13113107Sbde HELP_OPT, 132757Sdg MMAP_OPT, 13313107Sbde LINEBUF_OPT, 13418961Sbde LABEL_OPT, 13518961Sbde NULL_OPT, 13613107Sbde R_EXCLUDE_OPT, 13713107Sbde R_INCLUDE_OPT, 1381321Sdg R_DEXCLUDE_OPT, 13913107Sbde R_DINCLUDE_OPT 14013107Sbde}; 14113107Sbde 142757Sdgstatic inline const char *init_color(const char *); 143274489Sscottl 144274489Sscottl/* Housekeeping */ 145274489Sscottlbool first = true; /* flag whether we are processing the first match */ 146274489Sscottlbool prev; /* flag whether or not the previous line matched */ 147274489Sscottlint tail; /* lines left to print */ 148274489Sscottlbool notfound; /* file not found */ 149274489Sscottl 150274489Sscottlextern char *__progname; 151274489Sscottl 152274489Sscottl/* 153122849Speter * Prints usage information and returns 2. 154122849Speter */ 155329462Skibstatic void 156329462Skibusage(void) 157329462Skib{ 158329462Skib fprintf(stderr, getstr(4), __progname); 159329462Skib fprintf(stderr, "%s", getstr(5)); 160329462Skib fprintf(stderr, "%s", getstr(5)); 161329462Skib fprintf(stderr, "%s", getstr(6)); 162329462Skib fprintf(stderr, "%s", getstr(7)); 163156699Speter exit(2); 164122849Speter} 165122849Speter 166122849Speterstatic const char *optstr = "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxy"; 167122849Speter 168329462Skibstruct option long_options[] = 169329462Skib{ 170329462Skib {"binary-files", required_argument, NULL, BIN_OPT}, 171329462Skib {"help", no_argument, NULL, HELP_OPT}, 172329462Skib {"mmap", no_argument, NULL, MMAP_OPT}, 173329462Skib {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 174153241Sjhb {"label", required_argument, NULL, LABEL_OPT}, 175329462Skib {"null", no_argument, NULL, NULL_OPT}, 176329462Skib {"color", optional_argument, NULL, COLOR_OPT}, 177329462Skib {"colour", optional_argument, NULL, COLOR_OPT}, 178329462Skib {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 179329462Skib {"include", required_argument, NULL, R_INCLUDE_OPT}, 180329462Skib {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 181329462Skib {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 182329462Skib {"after-context", required_argument, NULL, 'A'}, 183153241Sjhb {"text", no_argument, NULL, 'a'}, 184329462Skib {"before-context", required_argument, NULL, 'B'}, 185329462Skib {"byte-offset", no_argument, NULL, 'b'}, 186329462Skib {"context", optional_argument, NULL, 'C'}, 187329462Skib {"count", no_argument, NULL, 'c'}, 188329462Skib {"devices", required_argument, NULL, 'D'}, 189329462Skib {"directories", required_argument, NULL, 'd'}, 190329462Skib {"extended-regexp", no_argument, NULL, 'E'}, 191329462Skib {"regexp", required_argument, NULL, 'e'}, 192329462Skib {"fixed-strings", no_argument, NULL, 'F'}, 193329462Skib {"file", required_argument, NULL, 'f'}, 194153241Sjhb {"basic-regexp", no_argument, NULL, 'G'}, 195329462Skib {"no-filename", no_argument, NULL, 'h'}, 196329462Skib {"with-filename", no_argument, NULL, 'H'}, 197335570Skib {"ignore-case", no_argument, NULL, 'i'}, 198335570Skib {"bz2decompress", no_argument, NULL, 'J'}, 199329462Skib {"files-with-matches", no_argument, NULL, 'l'}, 200329462Skib {"files-without-match", no_argument, NULL, 'L'}, 201329462Skib {"max-count", required_argument, NULL, 'm'}, 202335570Skib {"line-number", no_argument, NULL, 'n'}, 203329462Skib {"only-matching", no_argument, NULL, 'o'}, 204329462Skib {"quiet", no_argument, NULL, 'q'}, 205329462Skib {"silent", no_argument, NULL, 'q'}, 206329462Skib {"recursive", no_argument, NULL, 'r'}, 207329462Skib {"no-messages", no_argument, NULL, 's'}, 208329462Skib {"binary", no_argument, NULL, 'U'}, 209329462Skib {"unix-byte-offsets", no_argument, NULL, 'u'}, 210329462Skib {"invert-match", no_argument, NULL, 'v'}, 211329462Skib {"version", no_argument, NULL, 'V'}, 212329462Skib {"word-regexp", no_argument, NULL, 'w'}, 213329462Skib {"line-regexp", no_argument, NULL, 'x'}, 214329462Skib {"decompress", no_argument, NULL, 'Z'}, 215329462Skib {NULL, no_argument, NULL, 0} 216329462Skib}; 217329462Skib 218329462Skib/* 219329462Skib * Adds a searching pattern to the internal array. 220329462Skib */ 221329462Skibstatic void 222329462Skibadd_pattern(char *pat, size_t len) 223329462Skib{ 224334330Sjhb 225329462Skib /* Check if we can do a shortcut */ 226334330Sjhb if (len == 0 || matchall) { 227329462Skib matchall = true; 228329462Skib return; 229329462Skib } 230329462Skib /* Increase size if necessary */ 231329462Skib if (patterns == pattern_sz) { 232329462Skib pattern_sz *= 2; 233329462Skib pattern = grep_realloc(pattern, ++pattern_sz * 234329462Skib sizeof(*pattern)); 235334330Sjhb } 236329462Skib if (len > 0 && pat[len - 1] == '\n') 237334330Sjhb --len; 238329462Skib /* pat may not be NUL-terminated */ 239329462Skib pattern[patterns] = grep_malloc(len + 1); 240329462Skib strlcpy(pattern[patterns], pat, len + 1); 241329462Skib ++patterns; 242329462Skib} 243329462Skib 244329462Skib/* 245329462Skib * Adds a file include/exclude pattern to the internal array. 246329462Skib */ 247329462Skibstatic void 248329462Skibadd_fpattern(const char *pat, int mode) 249329462Skib{ 250329462Skib 251329462Skib /* Increase size if necessary */ 252329462Skib if (fpatterns == fpattern_sz) { 253329462Skib fpattern_sz *= 2; 254329462Skib fpattern = grep_realloc(fpattern, ++fpattern_sz * 255329462Skib sizeof(struct epat)); 256329462Skib } 257329462Skib fpattern[fpatterns].pat = grep_strdup(pat); 258329462Skib fpattern[fpatterns].mode = mode; 259329462Skib ++fpatterns; 260329462Skib} 261334327Skib 262329462Skib/* 263329462Skib * Adds a directory include/exclude pattern to the internal array. 264329462Skib */ 265329462Skibstatic void 266329462Skibadd_dpattern(const char *pat, int mode) 267329462Skib{ 268329462Skib 269329462Skib /* Increase size if necessary */ 270329462Skib if (dpatterns == dpattern_sz) { 271329462Skib dpattern_sz *= 2; 272329462Skib dpattern = grep_realloc(dpattern, ++dpattern_sz * 273329462Skib sizeof(struct epat)); 274329462Skib } 275329462Skib dpattern[dpatterns].pat = grep_strdup(pat); 276329462Skib dpattern[dpatterns].mode = mode; 277329462Skib ++dpatterns; 278329462Skib} 279329462Skib 280329462Skib/* 281329462Skib * Reads searching patterns from a file and adds them with add_pattern(). 282329462Skib */ 283329462Skibstatic void 284329462Skibread_patterns(const char *fn) 285329462Skib{ 286329462Skib FILE *f; 287329462Skib char *line; 288329462Skib size_t len; 289122849Speter 290122849Speter if ((f = fopen(fn, "r")) == NULL) 291263002Sroyger err(2, "%s", fn); 292263002Sroyger while ((line = fgetln(f, &len)) != NULL) 293263002Sroyger add_pattern(line, *line == '\n' ? 0 : len); 294263002Sroyger if (ferror(f)) 295263002Sroyger err(2, "%s", fn); 296263002Sroyger fclose(f); 297263002Sroyger} 298263002Sroyger 299263002Sroygerstatic inline const char * 300263002Sroygerinit_color(const char *d) 301263002Sroyger{ 302263002Sroyger char *c; 303263002Sroyger 304263002Sroyger c = getenv("GREP_COLOR"); 305263002Sroyger return (c != NULL ? c : d); 306263002Sroyger} 307263002Sroyger 308263002Sroygerint 309263002Sroygermain(int argc, char *argv[]) 310263002Sroyger{ 311263002Sroyger char **aargv, **eargv, *eopts; 312263002Sroyger char *ep; 313263002Sroyger unsigned long long l; 314263002Sroyger unsigned int aargc, eargc, i; 315263002Sroyger int c, lastc, needpattern, newarg, prevoptind; 316263002Sroyger 3172579Sbde setlocale(LC_ALL, ""); 318 319#ifndef WITHOUT_NLS 320 catalog = catopen("grep", NL_CAT_LOCALE); 321#endif 322 323 /* Check what is the program name of the binary. In this 324 way we can have all the funcionalities in one binary 325 without the need of scripting and using ugly hacks. */ 326 switch (__progname[0]) { 327 case 'e': 328 grepbehave = GREP_EXTENDED; 329 break; 330 case 'f': 331 grepbehave = GREP_FIXED; 332 break; 333 case 'g': 334 grepbehave = GREP_BASIC; 335 break; 336 case 'z': 337 filebehave = FILE_GZIP; 338 switch(__progname[1]) { 339 case 'e': 340 grepbehave = GREP_EXTENDED; 341 break; 342 case 'f': 343 grepbehave = GREP_FIXED; 344 break; 345 case 'g': 346 grepbehave = GREP_BASIC; 347 break; 348 } 349 break; 350 } 351 352 lastc = '\0'; 353 newarg = 1; 354 prevoptind = 1; 355 needpattern = 1; 356 357 eopts = getenv("GREP_OPTIONS"); 358 359 eargc = 1; 360 if (eopts != NULL) { 361 char *str; 362 363 for(i = 0; i < strlen(eopts); i++) 364 if (eopts[i] == ' ') 365 eargc++; 366 367 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 368 369 str = strtok(eopts, " "); 370 eargc = 0; 371 372 while(str != NULL) { 373 eargv[++eargc] = (char *)grep_malloc(sizeof(char) * 374 (strlen(str) + 1)); 375 strlcpy(eargv[eargc], str, strlen(str) + 1); 376 str = strtok(NULL, " "); 377 } 378 eargv[++eargc] = NULL; 379 380 aargv = (char **)grep_calloc(eargc + argc + 1, 381 sizeof(char *)); 382 aargv[0] = argv[0]; 383 384 for(i = 1; i < eargc; i++) 385 aargv[i] = eargv[i]; 386 for(int j = 1; j < argc; j++) 387 aargv[i++] = argv[j]; 388 389 aargc = eargc + argc - 1; 390 391 } else { 392 aargv = argv; 393 aargc = argc; 394 } 395 396 while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 397 -1)) { 398 switch (c) { 399 case '0': case '1': case '2': case '3': case '4': 400 case '5': case '6': case '7': case '8': case '9': 401 if (newarg || !isdigit(lastc)) 402 Aflag = 0; 403 else if (Aflag > LLONG_MAX / 10) { 404 errno = ERANGE; 405 err(2, NULL); 406 } 407 Aflag = Bflag = (Aflag * 10) + (c - '0'); 408 break; 409 case 'C': 410 if (optarg == NULL) { 411 Aflag = Bflag = 2; 412 break; 413 } 414 /* FALLTHROUGH */ 415 case 'A': 416 /* FALLTHROUGH */ 417 case 'B': 418 errno = 0; 419 l = strtoull(optarg, &ep, 10); 420 if (((errno == ERANGE) && (l == ULLONG_MAX)) || 421 ((errno == EINVAL) && (l == 0))) 422 err(2, NULL); 423 else if (ep[0] != '\0') { 424 errno = EINVAL; 425 err(2, NULL); 426 } 427 if (c == 'A') 428 Aflag = l; 429 else if (c == 'B') 430 Bflag = l; 431 else 432 Aflag = Bflag = l; 433 break; 434 case 'a': 435 binbehave = BINFILE_TEXT; 436 break; 437 case 'b': 438 bflag = true; 439 break; 440 case 'c': 441 cflag = true; 442 break; 443 case 'D': 444 if (strcasecmp(optarg, "skip") == 0) 445 devbehave = DEV_SKIP; 446 else if (strcasecmp(optarg, "read") == 0) 447 devbehave = DEV_READ; 448 else { 449 errno = EINVAL; 450 err(2, NULL); 451 } 452 break; 453 case 'd': 454 if (strcasecmp("recurse", optarg) == 0) { 455 Hflag = true; 456 dirbehave = DIR_RECURSE; 457 } else if (strcasecmp("skip", optarg) == 0) 458 dirbehave = DIR_SKIP; 459 else if (strcasecmp("read", optarg) == 0) 460 dirbehave = DIR_READ; 461 else { 462 errno = EINVAL; 463 err(2, NULL); 464 } 465 break; 466 case 'E': 467 grepbehave = GREP_EXTENDED; 468 break; 469 case 'e': 470 add_pattern(optarg, strlen(optarg)); 471 needpattern = 0; 472 break; 473 case 'F': 474 grepbehave = GREP_FIXED; 475 break; 476 case 'f': 477 read_patterns(optarg); 478 needpattern = 0; 479 break; 480 case 'G': 481 grepbehave = GREP_BASIC; 482 break; 483 case 'H': 484 Hflag = true; 485 break; 486 case 'h': 487 Hflag = false; 488 hflag = true; 489 break; 490 case 'I': 491 binbehave = BINFILE_SKIP; 492 break; 493 case 'i': 494 case 'y': 495 iflag = true; 496 cflags |= REG_ICASE; 497 break; 498 case 'J': 499 filebehave = FILE_BZIP; 500 break; 501 case 'L': 502 lflag = false; 503 Lflag = true; 504 break; 505 case 'l': 506 Lflag = false; 507 lflag = true; 508 break; 509 case 'm': 510 mflag = true; 511 errno = 0; 512 mcount = strtoull(optarg, &ep, 10); 513 if (((errno == ERANGE) && (mcount == ULLONG_MAX)) || 514 ((errno == EINVAL) && (mcount == 0))) 515 err(2, NULL); 516 else if (ep[0] != '\0') { 517 errno = EINVAL; 518 err(2, NULL); 519 } 520 break; 521 case 'n': 522 nflag = true; 523 break; 524 case 'O': 525 linkbehave = LINK_EXPLICIT; 526 break; 527 case 'o': 528 oflag = true; 529 break; 530 case 'p': 531 linkbehave = LINK_SKIP; 532 break; 533 case 'q': 534 qflag = true; 535 break; 536 case 'S': 537 linkbehave = LINK_READ; 538 break; 539 case 'R': 540 case 'r': 541 dirbehave = DIR_RECURSE; 542 Hflag = true; 543 break; 544 case 's': 545 sflag = true; 546 break; 547 case 'U': 548 binbehave = BINFILE_BIN; 549 break; 550 case 'u': 551 case MMAP_OPT: 552 /* noop, compatibility */ 553 break; 554 case 'V': 555 printf(getstr(10), __progname, VERSION); 556 exit(0); 557 case 'v': 558 vflag = true; 559 break; 560 case 'w': 561 wflag = true; 562 break; 563 case 'x': 564 xflag = true; 565 break; 566 case 'Z': 567 filebehave = FILE_GZIP; 568 break; 569 case BIN_OPT: 570 if (strcasecmp("binary", optarg) == 0) 571 binbehave = BINFILE_BIN; 572 else if (strcasecmp("without-match", optarg) == 0) 573 binbehave = BINFILE_SKIP; 574 else if (strcasecmp("text", optarg) == 0) 575 binbehave = BINFILE_TEXT; 576 else 577 errx(2, "%s", getstr(8)); 578 break; 579 case COLOR_OPT: 580 color = NULL; 581 if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 582 strcasecmp("tty", optarg) == 0 || 583 strcasecmp("if-tty", optarg) == 0) { 584 char *term; 585 586 term = getenv("TERM"); 587 if (isatty(STDOUT_FILENO) && term != NULL && 588 strcasecmp(term, "dumb") != 0) 589 color = init_color("01;31"); 590 } else if (strcasecmp("always", optarg) == 0 || 591 strcasecmp("yes", optarg) == 0 || 592 strcasecmp("force", optarg) == 0) { 593 color = init_color("01;31"); 594 } else if (strcasecmp("never", optarg) != 0 && 595 strcasecmp("none", optarg) != 0 && 596 strcasecmp("no", optarg) != 0) 597 errx(2, "%s", getstr(3)); 598 break; 599 case LABEL_OPT: 600 label = optarg; 601 break; 602 case LINEBUF_OPT: 603 lbflag = true; 604 break; 605 case NULL_OPT: 606 nullflag = true; 607 break; 608 case R_INCLUDE_OPT: 609 finclude = true; 610 add_fpattern(optarg, INCL_PAT); 611 break; 612 case R_EXCLUDE_OPT: 613 fexclude = true; 614 add_fpattern(optarg, EXCL_PAT); 615 break; 616 case R_DINCLUDE_OPT: 617 dexclude = true; 618 add_dpattern(optarg, INCL_PAT); 619 break; 620 case R_DEXCLUDE_OPT: 621 dinclude = true; 622 add_dpattern(optarg, EXCL_PAT); 623 break; 624 case HELP_OPT: 625 default: 626 usage(); 627 } 628 lastc = c; 629 newarg = optind != prevoptind; 630 prevoptind = optind; 631 } 632 aargc -= optind; 633 aargv += optind; 634 635 /* Fail if we don't have any pattern */ 636 if (aargc == 0 && needpattern) 637 usage(); 638 639 /* Process patterns from command line */ 640 if (aargc != 0 && needpattern) { 641 add_pattern(*aargv, strlen(*aargv)); 642 --aargc; 643 ++aargv; 644 } 645 646 switch (grepbehave) { 647 case GREP_FIXED: 648 case GREP_BASIC: 649 break; 650 case GREP_EXTENDED: 651 cflags |= REG_EXTENDED; 652 break; 653 default: 654 /* NOTREACHED */ 655 usage(); 656 } 657 658 fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 659 r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 660/* 661 * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance. 662 * Optimizations should be done there. 663 */ 664 /* Check if cheating is allowed (always is for fgrep). */ 665 if (grepbehave == GREP_FIXED) { 666 for (i = 0; i < patterns; ++i) 667 fgrepcomp(&fg_pattern[i], pattern[i]); 668 } else { 669 for (i = 0; i < patterns; ++i) { 670 if (fastcomp(&fg_pattern[i], pattern[i])) { 671 /* Fall back to full regex library */ 672 c = regcomp(&r_pattern[i], pattern[i], cflags); 673 if (c != 0) { 674 regerror(c, &r_pattern[i], re_error, 675 RE_ERROR_BUF); 676 errx(2, "%s", re_error); 677 } 678 } 679 } 680 } 681 682 if (lbflag) 683 setlinebuf(stdout); 684 685 if ((aargc == 0 || aargc == 1) && !Hflag) 686 hflag = true; 687 688 if (aargc == 0) 689 exit(!procfile("-")); 690 691 if (dirbehave == DIR_RECURSE) 692 c = grep_tree(aargv); 693 else 694 for (c = 0; aargc--; ++aargv) { 695 if ((finclude || fexclude) && !file_matching(*aargv)) 696 continue; 697 c+= procfile(*aargv); 698 } 699 700#ifndef WITHOUT_NLS 701 catclose(catalog); 702#endif 703 704 /* Find out the correct return value according to the 705 results and the command line option. */ 706 exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1)); 707} 708