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