1 /* $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $ */ 2 /* $FreeBSD$ */ 3 /* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */ 4 5 /*- 6 * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav 7 * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/stat.h> 36 #include <sys/types.h> 37 38 #include <ctype.h> 39 #include <err.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <getopt.h> 43 #include <limits.h> 44 #include <libgen.h> 45 #include <locale.h> 46 #include <stdbool.h> 47 #define _WITH_GETLINE 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "fastmatch.h" 54 #include "grep.h" 55 56 #ifndef WITHOUT_NLS 57 #include <nl_types.h> 58 nl_catd catalog; 59 #endif 60 61 /* 62 * Default messags to use when NLS is disabled or no catalogue 63 * is found. 64 */ 65 const char *errstr[] = { 66 "", 67 /* 1*/ "(standard input)", 68 /* 2*/ "cannot read bzip2 compressed file", 69 /* 3*/ "unknown %s option", 70 /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n", 71 /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 72 /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 73 /* 7*/ "\t[--null] [pattern] [file ...]\n", 74 /* 8*/ "Binary file %s matches\n", 75 /* 9*/ "%s (BSD grep) %s\n", 76 }; 77 78 /* Flags passed to regcomp() and regexec() */ 79 int cflags = REG_NOSUB; 80 int eflags = REG_STARTEND; 81 82 /* Shortcut for matching all cases like empty regex */ 83 bool matchall; 84 85 /* Searching patterns */ 86 unsigned int patterns; 87 static unsigned int pattern_sz; 88 struct pat *pattern; 89 regex_t *r_pattern; 90 fastmatch_t *fg_pattern; 91 92 /* Filename exclusion/inclusion patterns */ 93 unsigned int fpatterns, dpatterns; 94 static unsigned int fpattern_sz, dpattern_sz; 95 struct epat *dpattern, *fpattern; 96 97 /* For regex errors */ 98 char re_error[RE_ERROR_BUF + 1]; 99 100 /* Command-line flags */ 101 unsigned long long Aflag; /* -A x: print x lines trailing each match */ 102 unsigned long long Bflag; /* -B x: print x lines leading each match */ 103 bool Hflag; /* -H: always print file name */ 104 bool Lflag; /* -L: only show names of files with no matches */ 105 bool bflag; /* -b: show block numbers for each match */ 106 bool cflag; /* -c: only show a count of matching lines */ 107 bool hflag; /* -h: don't print filename headers */ 108 bool iflag; /* -i: ignore case */ 109 bool lflag; /* -l: only show names of files with matches */ 110 bool mflag; /* -m x: stop reading the files after x matches */ 111 long long mcount; /* count for -m */ 112 long long mlimit; /* requested value for -m */ 113 bool nflag; /* -n: show line numbers in front of matching lines */ 114 bool oflag; /* -o: print only matching part */ 115 bool qflag; /* -q: quiet mode (don't output anything) */ 116 bool sflag; /* -s: silent mode (ignore errors) */ 117 bool vflag; /* -v: only show non-matching lines */ 118 bool wflag; /* -w: pattern must start and end on word boundaries */ 119 bool xflag; /* -x: pattern must match entire line */ 120 bool lbflag; /* --line-buffered */ 121 bool nullflag; /* --null */ 122 char *label; /* --label */ 123 const char *color; /* --color */ 124 int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 125 int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 126 int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 127 int devbehave = DEV_READ; /* -D: handling of devices */ 128 int dirbehave = DIR_READ; /* -dRr: handling of directories */ 129 int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 130 131 bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 132 bool fexclude, finclude; /* --exclude and --include */ 133 134 enum { 135 BIN_OPT = CHAR_MAX + 1, 136 COLOR_OPT, 137 HELP_OPT, 138 MMAP_OPT, 139 LINEBUF_OPT, 140 LABEL_OPT, 141 NULL_OPT, 142 R_EXCLUDE_OPT, 143 R_INCLUDE_OPT, 144 R_DEXCLUDE_OPT, 145 R_DINCLUDE_OPT 146 }; 147 148 static inline const char *init_color(const char *); 149 150 /* Housekeeping */ 151 bool first = true; /* flag whether we are processing the first match */ 152 bool prev; /* flag whether or not the previous line matched */ 153 int tail; /* lines left to print */ 154 bool file_err; /* file reading error */ 155 156 /* 157 * Prints usage information and returns 2. 158 */ 159 static void 160 usage(void) 161 { 162 fprintf(stderr, getstr(4), getprogname()); 163 fprintf(stderr, "%s", getstr(5)); 164 fprintf(stderr, "%s", getstr(6)); 165 fprintf(stderr, "%s", getstr(7)); 166 exit(2); 167 } 168 169 static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy"; 170 171 static const struct option long_options[] = 172 { 173 {"binary-files", required_argument, NULL, BIN_OPT}, 174 {"help", no_argument, NULL, HELP_OPT}, 175 {"mmap", no_argument, NULL, MMAP_OPT}, 176 {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 177 {"label", required_argument, NULL, LABEL_OPT}, 178 {"null", no_argument, NULL, NULL_OPT}, 179 {"color", optional_argument, NULL, COLOR_OPT}, 180 {"colour", optional_argument, NULL, COLOR_OPT}, 181 {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 182 {"include", required_argument, NULL, R_INCLUDE_OPT}, 183 {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 184 {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 185 {"after-context", required_argument, NULL, 'A'}, 186 {"text", no_argument, NULL, 'a'}, 187 {"before-context", required_argument, NULL, 'B'}, 188 {"byte-offset", no_argument, NULL, 'b'}, 189 {"context", optional_argument, NULL, 'C'}, 190 {"count", no_argument, NULL, 'c'}, 191 {"devices", required_argument, NULL, 'D'}, 192 {"directories", required_argument, NULL, 'd'}, 193 {"extended-regexp", no_argument, NULL, 'E'}, 194 {"regexp", required_argument, NULL, 'e'}, 195 {"fixed-strings", no_argument, NULL, 'F'}, 196 {"file", required_argument, NULL, 'f'}, 197 {"basic-regexp", no_argument, NULL, 'G'}, 198 {"no-filename", no_argument, NULL, 'h'}, 199 {"with-filename", no_argument, NULL, 'H'}, 200 {"ignore-case", no_argument, NULL, 'i'}, 201 {"bz2decompress", no_argument, NULL, 'J'}, 202 {"files-with-matches", no_argument, NULL, 'l'}, 203 {"files-without-match", no_argument, NULL, 'L'}, 204 {"max-count", required_argument, NULL, 'm'}, 205 {"lzma", no_argument, NULL, 'M'}, 206 {"line-number", no_argument, NULL, 'n'}, 207 {"only-matching", no_argument, NULL, 'o'}, 208 {"quiet", no_argument, NULL, 'q'}, 209 {"silent", no_argument, NULL, 'q'}, 210 {"recursive", no_argument, NULL, 'r'}, 211 {"no-messages", no_argument, NULL, 's'}, 212 {"binary", no_argument, NULL, 'U'}, 213 {"unix-byte-offsets", no_argument, NULL, 'u'}, 214 {"invert-match", no_argument, NULL, 'v'}, 215 {"version", no_argument, NULL, 'V'}, 216 {"word-regexp", no_argument, NULL, 'w'}, 217 {"line-regexp", no_argument, NULL, 'x'}, 218 {"xz", no_argument, NULL, 'X'}, 219 {"decompress", no_argument, NULL, 'Z'}, 220 {NULL, no_argument, NULL, 0} 221 }; 222 223 /* 224 * Adds a searching pattern to the internal array. 225 */ 226 static void 227 add_pattern(char *pat, size_t len) 228 { 229 230 /* Do not add further pattern is we already match everything */ 231 if (matchall) 232 return; 233 234 /* Check if we can do a shortcut */ 235 if (len == 0) { 236 matchall = true; 237 for (unsigned int i = 0; i < patterns; i++) { 238 free(pattern[i].pat); 239 } 240 pattern = grep_realloc(pattern, sizeof(struct pat)); 241 pattern[0].pat = NULL; 242 pattern[0].len = 0; 243 patterns = 1; 244 return; 245 } 246 /* Increase size if necessary */ 247 if (patterns == pattern_sz) { 248 pattern_sz *= 2; 249 pattern = grep_realloc(pattern, ++pattern_sz * 250 sizeof(struct pat)); 251 } 252 if (len > 0 && pat[len - 1] == '\n') 253 --len; 254 /* pat may not be NUL-terminated */ 255 pattern[patterns].pat = grep_malloc(len + 1); 256 memcpy(pattern[patterns].pat, pat, len); 257 pattern[patterns].len = len; 258 pattern[patterns].pat[len] = '\0'; 259 ++patterns; 260 } 261 262 /* 263 * Adds a file include/exclude pattern to the internal array. 264 */ 265 static void 266 add_fpattern(const char *pat, int mode) 267 { 268 269 /* Increase size if necessary */ 270 if (fpatterns == fpattern_sz) { 271 fpattern_sz *= 2; 272 fpattern = grep_realloc(fpattern, ++fpattern_sz * 273 sizeof(struct epat)); 274 } 275 fpattern[fpatterns].pat = grep_strdup(pat); 276 fpattern[fpatterns].mode = mode; 277 ++fpatterns; 278 } 279 280 /* 281 * Adds a directory include/exclude pattern to the internal array. 282 */ 283 static void 284 add_dpattern(const char *pat, int mode) 285 { 286 287 /* Increase size if necessary */ 288 if (dpatterns == dpattern_sz) { 289 dpattern_sz *= 2; 290 dpattern = grep_realloc(dpattern, ++dpattern_sz * 291 sizeof(struct epat)); 292 } 293 dpattern[dpatterns].pat = grep_strdup(pat); 294 dpattern[dpatterns].mode = mode; 295 ++dpatterns; 296 } 297 298 /* 299 * Reads searching patterns from a file and adds them with add_pattern(). 300 */ 301 static void 302 read_patterns(const char *fn) 303 { 304 struct stat st; 305 FILE *f; 306 char *line; 307 size_t len; 308 ssize_t rlen; 309 310 if ((f = fopen(fn, "r")) == NULL) 311 err(2, "%s", fn); 312 if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 313 fclose(f); 314 return; 315 } 316 len = 0; 317 line = NULL; 318 while ((rlen = getline(&line, &len, f)) != -1) 319 add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); 320 free(line); 321 if (ferror(f)) 322 err(2, "%s", fn); 323 fclose(f); 324 } 325 326 static inline const char * 327 init_color(const char *d) 328 { 329 char *c; 330 331 c = getenv("GREP_COLOR"); 332 return (c != NULL && c[0] != '\0' ? c : d); 333 } 334 335 int 336 main(int argc, char *argv[]) 337 { 338 char **aargv, **eargv, *eopts; 339 char *ep; 340 const char *pn; 341 unsigned long long l; 342 unsigned int aargc, eargc, i; 343 int c, lastc, needpattern, newarg, prevoptind; 344 345 setlocale(LC_ALL, ""); 346 347 #ifndef WITHOUT_NLS 348 catalog = catopen("grep", NL_CAT_LOCALE); 349 #endif 350 351 /* Check what is the program name of the binary. In this 352 way we can have all the funcionalities in one binary 353 without the need of scripting and using ugly hacks. */ 354 pn = getprogname(); 355 if (pn[0] == 'b' && pn[1] == 'z') { 356 filebehave = FILE_BZIP; 357 pn += 2; 358 } else if (pn[0] == 'x' && pn[1] == 'z') { 359 filebehave = FILE_XZ; 360 pn += 2; 361 } else if (pn[0] == 'l' && pn[1] == 'z') { 362 filebehave = FILE_LZMA; 363 pn += 2; 364 } else if (pn[0] == 'z') { 365 filebehave = FILE_GZIP; 366 pn += 1; 367 } 368 switch (pn[0]) { 369 case 'e': 370 grepbehave = GREP_EXTENDED; 371 break; 372 case 'f': 373 grepbehave = GREP_FIXED; 374 break; 375 } 376 377 lastc = '\0'; 378 newarg = 1; 379 prevoptind = 1; 380 needpattern = 1; 381 382 eopts = getenv("GREP_OPTIONS"); 383 384 /* support for extra arguments in GREP_OPTIONS */ 385 eargc = 0; 386 if (eopts != NULL && eopts[0] != '\0') { 387 char *str; 388 389 /* make an estimation of how many extra arguments we have */ 390 for (unsigned int j = 0; j < strlen(eopts); j++) 391 if (eopts[j] == ' ') 392 eargc++; 393 394 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 395 396 eargc = 0; 397 /* parse extra arguments */ 398 while ((str = strsep(&eopts, " ")) != NULL) 399 if (str[0] != '\0') 400 eargv[eargc++] = grep_strdup(str); 401 402 aargv = (char **)grep_calloc(eargc + argc + 1, 403 sizeof(char *)); 404 405 aargv[0] = argv[0]; 406 for (i = 0; i < eargc; i++) 407 aargv[i + 1] = eargv[i]; 408 for (int j = 1; j < argc; j++, i++) 409 aargv[i + 1] = argv[j]; 410 411 aargc = eargc + argc; 412 } else { 413 aargv = argv; 414 aargc = argc; 415 } 416 417 while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 418 -1)) { 419 switch (c) { 420 case '0': case '1': case '2': case '3': case '4': 421 case '5': case '6': case '7': case '8': case '9': 422 if (newarg || !isdigit(lastc)) 423 Aflag = 0; 424 else if (Aflag > LLONG_MAX / 10) { 425 errno = ERANGE; 426 err(2, NULL); 427 } 428 Aflag = Bflag = (Aflag * 10) + (c - '0'); 429 break; 430 case 'C': 431 if (optarg == NULL) { 432 Aflag = Bflag = 2; 433 break; 434 } 435 /* FALLTHROUGH */ 436 case 'A': 437 /* FALLTHROUGH */ 438 case 'B': 439 errno = 0; 440 l = strtoull(optarg, &ep, 10); 441 if (((errno == ERANGE) && (l == ULLONG_MAX)) || 442 ((errno == EINVAL) && (l == 0))) 443 err(2, NULL); 444 else if (ep[0] != '\0') { 445 errno = EINVAL; 446 err(2, NULL); 447 } 448 if (c == 'A') 449 Aflag = l; 450 else if (c == 'B') 451 Bflag = l; 452 else 453 Aflag = Bflag = l; 454 break; 455 case 'a': 456 binbehave = BINFILE_TEXT; 457 break; 458 case 'b': 459 bflag = true; 460 break; 461 case 'c': 462 cflag = true; 463 break; 464 case 'D': 465 if (strcasecmp(optarg, "skip") == 0) 466 devbehave = DEV_SKIP; 467 else if (strcasecmp(optarg, "read") == 0) 468 devbehave = DEV_READ; 469 else 470 errx(2, getstr(3), "--devices"); 471 break; 472 case 'd': 473 if (strcasecmp("recurse", optarg) == 0) { 474 Hflag = true; 475 dirbehave = DIR_RECURSE; 476 } else if (strcasecmp("skip", optarg) == 0) 477 dirbehave = DIR_SKIP; 478 else if (strcasecmp("read", optarg) == 0) 479 dirbehave = DIR_READ; 480 else 481 errx(2, getstr(3), "--directories"); 482 break; 483 case 'E': 484 grepbehave = GREP_EXTENDED; 485 break; 486 case 'e': 487 { 488 char *token; 489 char *string = optarg; 490 491 while ((token = strsep(&string, "\n")) != NULL) 492 add_pattern(token, strlen(token)); 493 } 494 needpattern = 0; 495 break; 496 case 'F': 497 grepbehave = GREP_FIXED; 498 break; 499 case 'f': 500 read_patterns(optarg); 501 needpattern = 0; 502 break; 503 case 'G': 504 grepbehave = GREP_BASIC; 505 break; 506 case 'H': 507 Hflag = true; 508 break; 509 case 'h': 510 Hflag = false; 511 hflag = true; 512 break; 513 case 'I': 514 binbehave = BINFILE_SKIP; 515 break; 516 case 'i': 517 case 'y': 518 iflag = true; 519 cflags |= REG_ICASE; 520 break; 521 case 'J': 522 #ifdef WITHOUT_BZIP2 523 errno = EOPNOTSUPP; 524 err(2, "bzip2 support was disabled at compile-time"); 525 #endif 526 filebehave = FILE_BZIP; 527 break; 528 case 'L': 529 lflag = false; 530 Lflag = true; 531 break; 532 case 'l': 533 Lflag = false; 534 lflag = true; 535 break; 536 case 'm': 537 mflag = true; 538 errno = 0; 539 mlimit = mcount = strtoll(optarg, &ep, 10); 540 if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 541 ((errno == EINVAL) && (mcount == 0))) 542 err(2, NULL); 543 else if (ep[0] != '\0') { 544 errno = EINVAL; 545 err(2, NULL); 546 } 547 break; 548 case 'M': 549 filebehave = FILE_LZMA; 550 break; 551 case 'n': 552 nflag = true; 553 break; 554 case 'O': 555 linkbehave = LINK_EXPLICIT; 556 break; 557 case 'o': 558 oflag = true; 559 cflags &= ~REG_NOSUB; 560 break; 561 case 'p': 562 linkbehave = LINK_SKIP; 563 break; 564 case 'q': 565 qflag = true; 566 break; 567 case 'S': 568 linkbehave = LINK_READ; 569 break; 570 case 'R': 571 case 'r': 572 dirbehave = DIR_RECURSE; 573 Hflag = true; 574 break; 575 case 's': 576 sflag = true; 577 break; 578 case 'U': 579 binbehave = BINFILE_BIN; 580 break; 581 case 'u': 582 case MMAP_OPT: 583 filebehave = FILE_MMAP; 584 break; 585 case 'V': 586 printf(getstr(9), getprogname(), VERSION); 587 exit(0); 588 case 'v': 589 vflag = true; 590 break; 591 case 'w': 592 wflag = true; 593 cflags &= ~REG_NOSUB; 594 break; 595 case 'x': 596 xflag = true; 597 cflags &= ~REG_NOSUB; 598 break; 599 case 'X': 600 filebehave = FILE_XZ; 601 break; 602 case 'Z': 603 filebehave = FILE_GZIP; 604 break; 605 case BIN_OPT: 606 if (strcasecmp("binary", optarg) == 0) 607 binbehave = BINFILE_BIN; 608 else if (strcasecmp("without-match", optarg) == 0) 609 binbehave = BINFILE_SKIP; 610 else if (strcasecmp("text", optarg) == 0) 611 binbehave = BINFILE_TEXT; 612 else 613 errx(2, getstr(3), "--binary-files"); 614 break; 615 case COLOR_OPT: 616 color = NULL; 617 if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 618 strcasecmp("tty", optarg) == 0 || 619 strcasecmp("if-tty", optarg) == 0) { 620 char *term; 621 622 term = getenv("TERM"); 623 if (isatty(STDOUT_FILENO) && term != NULL && 624 strcasecmp(term, "dumb") != 0) 625 color = init_color("01;31"); 626 } else if (strcasecmp("always", optarg) == 0 || 627 strcasecmp("yes", optarg) == 0 || 628 strcasecmp("force", optarg) == 0) { 629 color = init_color("01;31"); 630 } else if (strcasecmp("never", optarg) != 0 && 631 strcasecmp("none", optarg) != 0 && 632 strcasecmp("no", optarg) != 0) 633 errx(2, getstr(3), "--color"); 634 cflags &= ~REG_NOSUB; 635 break; 636 case LABEL_OPT: 637 label = optarg; 638 break; 639 case LINEBUF_OPT: 640 lbflag = true; 641 break; 642 case NULL_OPT: 643 nullflag = true; 644 break; 645 case R_INCLUDE_OPT: 646 finclude = true; 647 add_fpattern(optarg, INCL_PAT); 648 break; 649 case R_EXCLUDE_OPT: 650 fexclude = true; 651 add_fpattern(optarg, EXCL_PAT); 652 break; 653 case R_DINCLUDE_OPT: 654 dinclude = true; 655 add_dpattern(optarg, INCL_PAT); 656 break; 657 case R_DEXCLUDE_OPT: 658 dexclude = true; 659 add_dpattern(optarg, EXCL_PAT); 660 break; 661 case HELP_OPT: 662 default: 663 usage(); 664 } 665 lastc = c; 666 newarg = optind != prevoptind; 667 prevoptind = optind; 668 } 669 aargc -= optind; 670 aargv += optind; 671 672 /* Empty pattern file matches nothing */ 673 if (!needpattern && (patterns == 0)) 674 exit(1); 675 676 /* Fail if we don't have any pattern */ 677 if (aargc == 0 && needpattern) 678 usage(); 679 680 /* Process patterns from command line */ 681 if (aargc != 0 && needpattern) { 682 char *token; 683 char *string = *aargv; 684 685 while ((token = strsep(&string, "\n")) != NULL) 686 add_pattern(token, strlen(token)); 687 --aargc; 688 ++aargv; 689 } 690 691 switch (grepbehave) { 692 case GREP_BASIC: 693 break; 694 case GREP_FIXED: 695 /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */ 696 cflags |= 0020; 697 break; 698 case GREP_EXTENDED: 699 cflags |= REG_EXTENDED; 700 break; 701 default: 702 /* NOTREACHED */ 703 usage(); 704 } 705 706 fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 707 r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 708 709 /* Check if cheating is allowed (always is for fgrep). */ 710 for (i = 0; i < patterns; ++i) { 711 if (fastncomp(&fg_pattern[i], pattern[i].pat, 712 pattern[i].len, cflags) != 0) { 713 /* Fall back to full regex library */ 714 c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 715 if (c != 0) { 716 regerror(c, &r_pattern[i], re_error, 717 RE_ERROR_BUF); 718 errx(2, "%s", re_error); 719 } 720 } 721 } 722 723 if (lbflag) 724 setlinebuf(stdout); 725 726 if ((aargc == 0 || aargc == 1) && !Hflag) 727 hflag = true; 728 729 if (aargc == 0) 730 exit(!procfile("-")); 731 732 if (dirbehave == DIR_RECURSE) 733 c = grep_tree(aargv); 734 else 735 for (c = 0; aargc--; ++aargv) { 736 if ((finclude || fexclude) && !file_matching(*aargv)) 737 continue; 738 c+= procfile(*aargv); 739 } 740 741 #ifndef WITHOUT_NLS 742 catclose(catalog); 743 #endif 744 745 /* Find out the correct return value according to the 746 results and the command line option. */ 747 exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 748 } 749