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