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