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