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 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 308 if ((f = fopen(fn, "r")) == NULL) 309 err(2, "%s", fn); 310 if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 311 fclose(f); 312 return; 313 } 314 while ((line = fgetln(f, &len)) != NULL) 315 add_pattern(line, line[0] == '\n' ? 0 : len); 316 if (ferror(f)) 317 err(2, "%s", fn); 318 fclose(f); 319 } 320 321 static inline const char * 322 init_color(const char *d) 323 { 324 char *c; 325 326 c = getenv("GREP_COLOR"); 327 return (c != NULL && c[0] != '\0' ? c : d); 328 } 329 330 int 331 main(int argc, char *argv[]) 332 { 333 char **aargv, **eargv, *eopts; 334 char *ep; 335 const char *pn; 336 unsigned long long l; 337 unsigned int aargc, eargc, i; 338 int c, lastc, needpattern, newarg, prevoptind; 339 340 setlocale(LC_ALL, ""); 341 342 #ifndef WITHOUT_NLS 343 catalog = catopen("grep", NL_CAT_LOCALE); 344 #endif 345 346 /* Check what is the program name of the binary. In this 347 way we can have all the funcionalities in one binary 348 without the need of scripting and using ugly hacks. */ 349 pn = getprogname(); 350 if (pn[0] == 'b' && pn[1] == 'z') { 351 filebehave = FILE_BZIP; 352 pn += 2; 353 } else if (pn[0] == 'x' && pn[1] == 'z') { 354 filebehave = FILE_XZ; 355 pn += 2; 356 } else if (pn[0] == 'l' && pn[1] == 'z') { 357 filebehave = FILE_LZMA; 358 pn += 2; 359 } else if (pn[0] == 'z') { 360 filebehave = FILE_GZIP; 361 pn += 1; 362 } 363 switch (pn[0]) { 364 case 'e': 365 grepbehave = GREP_EXTENDED; 366 break; 367 case 'f': 368 grepbehave = GREP_FIXED; 369 break; 370 } 371 372 lastc = '\0'; 373 newarg = 1; 374 prevoptind = 1; 375 needpattern = 1; 376 377 eopts = getenv("GREP_OPTIONS"); 378 379 /* support for extra arguments in GREP_OPTIONS */ 380 eargc = 0; 381 if (eopts != NULL && eopts[0] != '\0') { 382 char *str; 383 384 /* make an estimation of how many extra arguments we have */ 385 for (unsigned int j = 0; j < strlen(eopts); j++) 386 if (eopts[j] == ' ') 387 eargc++; 388 389 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 390 391 eargc = 0; 392 /* parse extra arguments */ 393 while ((str = strsep(&eopts, " ")) != NULL) 394 if (str[0] != '\0') 395 eargv[eargc++] = grep_strdup(str); 396 397 aargv = (char **)grep_calloc(eargc + argc + 1, 398 sizeof(char *)); 399 400 aargv[0] = argv[0]; 401 for (i = 0; i < eargc; i++) 402 aargv[i + 1] = eargv[i]; 403 for (int j = 1; j < argc; j++, i++) 404 aargv[i + 1] = argv[j]; 405 406 aargc = eargc + argc; 407 } else { 408 aargv = argv; 409 aargc = argc; 410 } 411 412 while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 413 -1)) { 414 switch (c) { 415 case '0': case '1': case '2': case '3': case '4': 416 case '5': case '6': case '7': case '8': case '9': 417 if (newarg || !isdigit(lastc)) 418 Aflag = 0; 419 else if (Aflag > LLONG_MAX / 10) { 420 errno = ERANGE; 421 err(2, NULL); 422 } 423 Aflag = Bflag = (Aflag * 10) + (c - '0'); 424 break; 425 case 'C': 426 if (optarg == NULL) { 427 Aflag = Bflag = 2; 428 break; 429 } 430 /* FALLTHROUGH */ 431 case 'A': 432 /* FALLTHROUGH */ 433 case 'B': 434 errno = 0; 435 l = strtoull(optarg, &ep, 10); 436 if (((errno == ERANGE) && (l == ULLONG_MAX)) || 437 ((errno == EINVAL) && (l == 0))) 438 err(2, NULL); 439 else if (ep[0] != '\0') { 440 errno = EINVAL; 441 err(2, NULL); 442 } 443 if (c == 'A') 444 Aflag = l; 445 else if (c == 'B') 446 Bflag = l; 447 else 448 Aflag = Bflag = l; 449 break; 450 case 'a': 451 binbehave = BINFILE_TEXT; 452 break; 453 case 'b': 454 bflag = true; 455 break; 456 case 'c': 457 cflag = true; 458 break; 459 case 'D': 460 if (strcasecmp(optarg, "skip") == 0) 461 devbehave = DEV_SKIP; 462 else if (strcasecmp(optarg, "read") == 0) 463 devbehave = DEV_READ; 464 else 465 errx(2, getstr(3), "--devices"); 466 break; 467 case 'd': 468 if (strcasecmp("recurse", optarg) == 0) { 469 Hflag = true; 470 dirbehave = DIR_RECURSE; 471 } else if (strcasecmp("skip", optarg) == 0) 472 dirbehave = DIR_SKIP; 473 else if (strcasecmp("read", optarg) == 0) 474 dirbehave = DIR_READ; 475 else 476 errx(2, getstr(3), "--directories"); 477 break; 478 case 'E': 479 grepbehave = GREP_EXTENDED; 480 break; 481 case 'e': 482 { 483 char *token; 484 char *string = optarg; 485 486 while ((token = strsep(&string, "\n")) != NULL) 487 add_pattern(token, strlen(token)); 488 } 489 needpattern = 0; 490 break; 491 case 'F': 492 grepbehave = GREP_FIXED; 493 break; 494 case 'f': 495 read_patterns(optarg); 496 needpattern = 0; 497 break; 498 case 'G': 499 grepbehave = GREP_BASIC; 500 break; 501 case 'H': 502 Hflag = true; 503 break; 504 case 'h': 505 Hflag = false; 506 hflag = true; 507 break; 508 case 'I': 509 binbehave = BINFILE_SKIP; 510 break; 511 case 'i': 512 case 'y': 513 iflag = true; 514 cflags |= REG_ICASE; 515 break; 516 case 'J': 517 #ifdef WITHOUT_BZIP2 518 errno = EOPNOTSUPP; 519 err(2, "bzip2 support was disabled at compile-time"); 520 #endif 521 filebehave = FILE_BZIP; 522 break; 523 case 'L': 524 lflag = false; 525 Lflag = true; 526 break; 527 case 'l': 528 Lflag = false; 529 lflag = true; 530 break; 531 case 'm': 532 mflag = true; 533 errno = 0; 534 mlimit = mcount = strtoll(optarg, &ep, 10); 535 if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 536 ((errno == EINVAL) && (mcount == 0))) 537 err(2, NULL); 538 else if (ep[0] != '\0') { 539 errno = EINVAL; 540 err(2, NULL); 541 } 542 break; 543 case 'M': 544 filebehave = FILE_LZMA; 545 break; 546 case 'n': 547 nflag = true; 548 break; 549 case 'O': 550 linkbehave = LINK_EXPLICIT; 551 break; 552 case 'o': 553 oflag = true; 554 cflags &= ~REG_NOSUB; 555 break; 556 case 'p': 557 linkbehave = LINK_SKIP; 558 break; 559 case 'q': 560 qflag = true; 561 break; 562 case 'S': 563 linkbehave = LINK_READ; 564 break; 565 case 'R': 566 case 'r': 567 dirbehave = DIR_RECURSE; 568 Hflag = true; 569 break; 570 case 's': 571 sflag = true; 572 break; 573 case 'U': 574 binbehave = BINFILE_BIN; 575 break; 576 case 'u': 577 case MMAP_OPT: 578 filebehave = FILE_MMAP; 579 break; 580 case 'V': 581 printf(getstr(9), getprogname(), VERSION); 582 exit(0); 583 case 'v': 584 vflag = true; 585 break; 586 case 'w': 587 wflag = true; 588 cflags &= ~REG_NOSUB; 589 break; 590 case 'x': 591 xflag = true; 592 cflags &= ~REG_NOSUB; 593 break; 594 case 'X': 595 filebehave = FILE_XZ; 596 break; 597 case 'Z': 598 filebehave = FILE_GZIP; 599 break; 600 case BIN_OPT: 601 if (strcasecmp("binary", optarg) == 0) 602 binbehave = BINFILE_BIN; 603 else if (strcasecmp("without-match", optarg) == 0) 604 binbehave = BINFILE_SKIP; 605 else if (strcasecmp("text", optarg) == 0) 606 binbehave = BINFILE_TEXT; 607 else 608 errx(2, getstr(3), "--binary-files"); 609 break; 610 case COLOR_OPT: 611 color = NULL; 612 if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 613 strcasecmp("tty", optarg) == 0 || 614 strcasecmp("if-tty", optarg) == 0) { 615 char *term; 616 617 term = getenv("TERM"); 618 if (isatty(STDOUT_FILENO) && term != NULL && 619 strcasecmp(term, "dumb") != 0) 620 color = init_color("01;31"); 621 } else if (strcasecmp("always", optarg) == 0 || 622 strcasecmp("yes", optarg) == 0 || 623 strcasecmp("force", optarg) == 0) { 624 color = init_color("01;31"); 625 } else if (strcasecmp("never", optarg) != 0 && 626 strcasecmp("none", optarg) != 0 && 627 strcasecmp("no", optarg) != 0) 628 errx(2, getstr(3), "--color"); 629 cflags &= ~REG_NOSUB; 630 break; 631 case LABEL_OPT: 632 label = optarg; 633 break; 634 case LINEBUF_OPT: 635 lbflag = true; 636 break; 637 case NULL_OPT: 638 nullflag = true; 639 break; 640 case R_INCLUDE_OPT: 641 finclude = true; 642 add_fpattern(optarg, INCL_PAT); 643 break; 644 case R_EXCLUDE_OPT: 645 fexclude = true; 646 add_fpattern(optarg, EXCL_PAT); 647 break; 648 case R_DINCLUDE_OPT: 649 dinclude = true; 650 add_dpattern(optarg, INCL_PAT); 651 break; 652 case R_DEXCLUDE_OPT: 653 dexclude = true; 654 add_dpattern(optarg, EXCL_PAT); 655 break; 656 case HELP_OPT: 657 default: 658 usage(); 659 } 660 lastc = c; 661 newarg = optind != prevoptind; 662 prevoptind = optind; 663 } 664 aargc -= optind; 665 aargv += optind; 666 667 /* Empty pattern file matches nothing */ 668 if (!needpattern && (patterns == 0)) 669 exit(1); 670 671 /* Fail if we don't have any pattern */ 672 if (aargc == 0 && needpattern) 673 usage(); 674 675 /* Process patterns from command line */ 676 if (aargc != 0 && needpattern) { 677 char *token; 678 char *string = *aargv; 679 680 while ((token = strsep(&string, "\n")) != NULL) 681 add_pattern(token, strlen(token)); 682 --aargc; 683 ++aargv; 684 } 685 686 switch (grepbehave) { 687 case GREP_BASIC: 688 break; 689 case GREP_FIXED: 690 /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */ 691 cflags |= 0020; 692 break; 693 case GREP_EXTENDED: 694 cflags |= REG_EXTENDED; 695 break; 696 default: 697 /* NOTREACHED */ 698 usage(); 699 } 700 701 fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 702 r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 703 704 /* Check if cheating is allowed (always is for fgrep). */ 705 for (i = 0; i < patterns; ++i) { 706 if (fastncomp(&fg_pattern[i], pattern[i].pat, 707 pattern[i].len, cflags) != 0) { 708 /* Fall back to full regex library */ 709 c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 710 if (c != 0) { 711 regerror(c, &r_pattern[i], re_error, 712 RE_ERROR_BUF); 713 errx(2, "%s", re_error); 714 } 715 } 716 } 717 718 if (lbflag) 719 setlinebuf(stdout); 720 721 if ((aargc == 0 || aargc == 1) && !Hflag) 722 hflag = true; 723 724 if (aargc == 0) 725 exit(!procfile("-")); 726 727 if (dirbehave == DIR_RECURSE) 728 c = grep_tree(aargv); 729 else 730 for (c = 0; aargc--; ++aargv) { 731 if ((finclude || fexclude) && !file_matching(*aargv)) 732 continue; 733 c+= procfile(*aargv); 734 } 735 736 #ifndef WITHOUT_NLS 737 catclose(catalog); 738 #endif 739 740 /* Find out the correct return value according to the 741 results and the command line option. */ 742 exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 743 } 744