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