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; 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 unsigned long long Aflag; /* -A x: print x lines trailing each match */ 112 unsigned 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 unsigned 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) { 442 errno = ERANGE; 443 err(2, NULL); 444 } 445 Aflag = Bflag = (Aflag * 10) + (c - '0'); 446 break; 447 case 'C': 448 if (optarg == NULL) { 449 Aflag = Bflag = 2; 450 break; 451 } 452 /* FALLTHROUGH */ 453 case 'A': 454 /* FALLTHROUGH */ 455 case 'B': 456 errno = 0; 457 l = strtoull(optarg, &ep, 10); 458 if (((errno == ERANGE) && (l == ULLONG_MAX)) || 459 ((errno == EINVAL) && (l == 0))) 460 err(2, NULL); 461 else if (ep[0] != '\0') { 462 errno = EINVAL; 463 err(2, NULL); 464 } 465 if (c == 'A') 466 Aflag = l; 467 else if (c == 'B') 468 Bflag = l; 469 else 470 Aflag = Bflag = l; 471 break; 472 case 'a': 473 binbehave = BINFILE_TEXT; 474 break; 475 case 'b': 476 bflag = true; 477 break; 478 case 'c': 479 cflag = true; 480 break; 481 case 'D': 482 if (strcasecmp(optarg, "skip") == 0) 483 devbehave = DEV_SKIP; 484 else if (strcasecmp(optarg, "read") == 0) 485 devbehave = DEV_READ; 486 else 487 errx(2, getstr(3), "--devices"); 488 break; 489 case 'd': 490 if (strcasecmp("recurse", optarg) == 0) { 491 Hflag = true; 492 dirbehave = DIR_RECURSE; 493 } else if (strcasecmp("skip", optarg) == 0) 494 dirbehave = DIR_SKIP; 495 else if (strcasecmp("read", optarg) == 0) 496 dirbehave = DIR_READ; 497 else 498 errx(2, getstr(3), "--directories"); 499 break; 500 case 'E': 501 grepbehave = GREP_EXTENDED; 502 break; 503 case 'e': 504 { 505 char *token; 506 char *string = optarg; 507 508 while ((token = strsep(&string, "\n")) != NULL) 509 add_pattern(token, strlen(token)); 510 } 511 needpattern = 0; 512 break; 513 case 'F': 514 grepbehave = GREP_FIXED; 515 break; 516 case 'f': 517 read_patterns(optarg); 518 needpattern = 0; 519 break; 520 case 'G': 521 grepbehave = GREP_BASIC; 522 break; 523 case 'H': 524 Hflag = true; 525 break; 526 case 'h': 527 Hflag = false; 528 hflag = true; 529 break; 530 case 'I': 531 binbehave = BINFILE_SKIP; 532 break; 533 case 'i': 534 case 'y': 535 iflag = true; 536 cflags |= REG_ICASE; 537 break; 538 case 'J': 539 #ifdef WITHOUT_BZIP2 540 errno = EOPNOTSUPP; 541 err(2, "bzip2 support was disabled at compile-time"); 542 #endif 543 filebehave = FILE_BZIP; 544 break; 545 case 'L': 546 lflag = false; 547 Lflag = true; 548 break; 549 case 'l': 550 Lflag = false; 551 lflag = true; 552 break; 553 case 'm': 554 mflag = true; 555 errno = 0; 556 mlimit = mcount = strtoll(optarg, &ep, 10); 557 if (((errno == ERANGE) && (mcount == LLONG_MAX)) || 558 ((errno == EINVAL) && (mcount == 0))) 559 err(2, NULL); 560 else if (ep[0] != '\0') { 561 errno = EINVAL; 562 err(2, NULL); 563 } 564 break; 565 case 'M': 566 filebehave = FILE_LZMA; 567 break; 568 case 'n': 569 nflag = true; 570 break; 571 case 'O': 572 linkbehave = LINK_EXPLICIT; 573 break; 574 case 'o': 575 oflag = true; 576 cflags &= ~REG_NOSUB; 577 break; 578 case 'p': 579 linkbehave = LINK_SKIP; 580 break; 581 case 'q': 582 qflag = true; 583 break; 584 case 'S': 585 linkbehave = LINK_READ; 586 break; 587 case 'R': 588 case 'r': 589 dirbehave = DIR_RECURSE; 590 Hflag = true; 591 break; 592 case 's': 593 sflag = true; 594 break; 595 case 'U': 596 binbehave = BINFILE_BIN; 597 break; 598 case 'u': 599 case MMAP_OPT: 600 filebehave = FILE_MMAP; 601 break; 602 case 'V': 603 #ifdef WITH_GNU 604 printf(getstr(10), getprogname(), VERSION); 605 #else 606 printf(getstr(9), getprogname(), VERSION); 607 #endif 608 exit(0); 609 case 'v': 610 vflag = true; 611 break; 612 case 'w': 613 wflag = true; 614 cflags &= ~REG_NOSUB; 615 break; 616 case 'x': 617 xflag = true; 618 cflags &= ~REG_NOSUB; 619 break; 620 case 'X': 621 filebehave = FILE_XZ; 622 break; 623 case 'z': 624 fileeol = '\0'; 625 break; 626 case 'Z': 627 filebehave = FILE_GZIP; 628 break; 629 case BIN_OPT: 630 if (strcasecmp("binary", optarg) == 0) 631 binbehave = BINFILE_BIN; 632 else if (strcasecmp("without-match", optarg) == 0) 633 binbehave = BINFILE_SKIP; 634 else if (strcasecmp("text", optarg) == 0) 635 binbehave = BINFILE_TEXT; 636 else 637 errx(2, getstr(3), "--binary-files"); 638 break; 639 case COLOR_OPT: 640 color = NULL; 641 if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 642 strcasecmp("tty", optarg) == 0 || 643 strcasecmp("if-tty", optarg) == 0) { 644 char *term; 645 646 term = getenv("TERM"); 647 if (isatty(STDOUT_FILENO) && term != NULL && 648 strcasecmp(term, "dumb") != 0) 649 color = init_color("01;31"); 650 } else if (strcasecmp("always", optarg) == 0 || 651 strcasecmp("yes", optarg) == 0 || 652 strcasecmp("force", optarg) == 0) { 653 color = init_color("01;31"); 654 } else if (strcasecmp("never", optarg) != 0 && 655 strcasecmp("none", optarg) != 0 && 656 strcasecmp("no", optarg) != 0) 657 errx(2, getstr(3), "--color"); 658 cflags &= ~REG_NOSUB; 659 break; 660 case LABEL_OPT: 661 label = optarg; 662 break; 663 case LINEBUF_OPT: 664 lbflag = true; 665 break; 666 case NULL_OPT: 667 nullflag = true; 668 break; 669 case R_INCLUDE_OPT: 670 finclude = true; 671 add_fpattern(optarg, INCL_PAT); 672 break; 673 case R_EXCLUDE_OPT: 674 fexclude = true; 675 add_fpattern(optarg, EXCL_PAT); 676 break; 677 case R_DINCLUDE_OPT: 678 dinclude = true; 679 add_dpattern(optarg, INCL_PAT); 680 break; 681 case R_DEXCLUDE_OPT: 682 dexclude = true; 683 add_dpattern(optarg, EXCL_PAT); 684 break; 685 case HELP_OPT: 686 default: 687 usage(); 688 } 689 lastc = c; 690 newarg = optind != prevoptind; 691 prevoptind = optind; 692 } 693 aargc -= optind; 694 aargv += optind; 695 696 /* Empty pattern file matches nothing */ 697 if (!needpattern && (patterns == 0)) 698 exit(1); 699 700 /* Fail if we don't have any pattern */ 701 if (aargc == 0 && needpattern) 702 usage(); 703 704 /* Process patterns from command line */ 705 if (aargc != 0 && needpattern) { 706 char *token; 707 char *string = *aargv; 708 709 while ((token = strsep(&string, "\n")) != NULL) 710 add_pattern(token, strlen(token)); 711 --aargc; 712 ++aargv; 713 } 714 715 switch (grepbehave) { 716 case GREP_BASIC: 717 break; 718 case GREP_FIXED: 719 #if defined(REG_NOSPEC) 720 cflags |= REG_NOSPEC; 721 #elif defined(REG_LITERAL) 722 cflags |= REG_LITERAL; 723 #else 724 errx(2, "literal expressions not supported at compile time"); 725 #endif 726 break; 727 case GREP_EXTENDED: 728 cflags |= REG_EXTENDED; 729 break; 730 default: 731 /* NOTREACHED */ 732 usage(); 733 } 734 735 #ifndef WITHOUT_FASTMATCH 736 fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 737 #endif 738 r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 739 740 /* Don't process any patterns if we have a blank one */ 741 if (!matchall) { 742 /* Check if cheating is allowed (always is for fgrep). */ 743 for (i = 0; i < patterns; ++i) { 744 #ifndef WITHOUT_FASTMATCH 745 /* 746 * Attempt compilation with fastmatch regex and 747 * fallback to regex(3) if it fails. 748 */ 749 if (fastncomp(&fg_pattern[i], pattern[i].pat, 750 pattern[i].len, cflags) == 0) 751 continue; 752 #endif 753 c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 754 if (c != 0) { 755 regerror(c, &r_pattern[i], re_error, 756 RE_ERROR_BUF); 757 errx(2, "%s", re_error); 758 } 759 } 760 } 761 762 if (lbflag) 763 setlinebuf(stdout); 764 765 if ((aargc == 0 || aargc == 1) && !Hflag) 766 hflag = true; 767 768 if (aargc == 0 && dirbehave != DIR_RECURSE) 769 exit(!procfile("-")); 770 771 if (dirbehave == DIR_RECURSE) 772 c = grep_tree(aargv); 773 else 774 for (c = 0; aargc--; ++aargv) { 775 if ((finclude || fexclude) && !file_matching(*aargv)) 776 continue; 777 c+= procfile(*aargv); 778 } 779 780 #ifndef WITHOUT_NLS 781 catclose(catalog); 782 #endif 783 784 /* Find out the correct return value according to the 785 results and the command line option. */ 786 exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 787 } 788