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