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