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