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