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