1/* $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $ */ 2/* $FreeBSD: stable/11/usr.bin/grep/grep.c 354628 2019-11-11 19:54:08Z kevans $ */ 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: stable/11/usr.bin/grep/grep.c 354628 2019-11-11 19:54:08Z kevans $"); 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#define _WITH_GETLINE 50#include <stdio.h> 51#include <stdlib.h> 52#include <string.h> 53#include <unistd.h> 54 55#ifndef WITHOUT_FASTMATCH 56#include "fastmatch.h" 57#endif 58#include "grep.h" 59 60#ifndef WITHOUT_NLS 61#include <nl_types.h> 62nl_catd catalog; 63#endif 64 65/* 66 * Default messags to use when NLS is disabled or no catalogue 67 * is found. 68 */ 69const char *errstr[] = { 70 "", 71/* 1*/ "(standard input)", 72/* 2*/ "cannot read bzip2 compressed file", 73/* 3*/ "unknown %s option", 74/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n", 75/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 76/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 77/* 7*/ "\t[--null] [pattern] [file ...]\n", 78/* 8*/ "Binary file %s matches\n", 79/* 9*/ "%s (BSD grep) %s\n", 80/* 10*/ "%s (BSD grep, GNU compatible) %s\n", 81}; 82 83/* Flags passed to regcomp() and regexec() */ 84int cflags = REG_NOSUB | REG_NEWLINE; 85int eflags = REG_STARTEND; 86 87/* XXX TODO: Get rid of this flag. 88 * matchall is a gross hack that means that an empty pattern was passed to us. 89 * It is a necessary evil at the moment because our regex(3) implementation 90 * does not allow for empty patterns, as supported by POSIX's definition of 91 * grammar for BREs/EREs. When libregex becomes available, it would be wise 92 * to remove this and let regex(3) handle the dirty details of empty patterns. 93 */ 94bool matchall; 95 96/* Searching patterns */ 97unsigned int patterns; 98static unsigned int pattern_sz; 99struct pat *pattern; 100regex_t *r_pattern; 101#ifndef WITHOUT_FASTMATCH 102fastmatch_t *fg_pattern; 103#endif 104 105/* Filename exclusion/inclusion patterns */ 106unsigned int fpatterns, dpatterns; 107static unsigned int fpattern_sz, dpattern_sz; 108struct epat *dpattern, *fpattern; 109 110/* For regex errors */ 111char re_error[RE_ERROR_BUF + 1]; 112 113/* Command-line flags */ 114long long Aflag; /* -A x: print x lines trailing each match */ 115long long Bflag; /* -B x: print x lines leading each match */ 116bool Hflag; /* -H: always print file name */ 117bool Lflag; /* -L: only show names of files with no matches */ 118bool bflag; /* -b: show block numbers for each match */ 119bool cflag; /* -c: only show a count of matching lines */ 120bool hflag; /* -h: don't print filename headers */ 121bool iflag; /* -i: ignore case */ 122bool lflag; /* -l: only show names of files with matches */ 123bool mflag; /* -m x: stop reading the files after x matches */ 124long long mcount; /* count for -m */ 125long long mlimit; /* requested value for -m */ 126char fileeol; /* indicator for eol */ 127bool nflag; /* -n: show line numbers in front of matching lines */ 128bool oflag; /* -o: print only matching part */ 129bool qflag; /* -q: quiet mode (don't output anything) */ 130bool sflag; /* -s: silent mode (ignore errors) */ 131bool vflag; /* -v: only show non-matching lines */ 132bool wflag; /* -w: pattern must start and end on word boundaries */ 133bool xflag; /* -x: pattern must match entire line */ 134bool lbflag; /* --line-buffered */ 135bool nullflag; /* --null */ 136char *label; /* --label */ 137const char *color; /* --color */ 138int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 139int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 140int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 141int devbehave = DEV_READ; /* -D: handling of devices */ 142int dirbehave = DIR_READ; /* -dRr: handling of directories */ 143int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 144 145bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 146bool fexclude, finclude; /* --exclude and --include */ 147 148enum { 149 BIN_OPT = CHAR_MAX + 1, 150 COLOR_OPT, 151 HELP_OPT, 152 MMAP_OPT, 153 LINEBUF_OPT, 154 LABEL_OPT, 155 NULL_OPT, 156 R_EXCLUDE_OPT, 157 R_INCLUDE_OPT, 158 R_DEXCLUDE_OPT, 159 R_DINCLUDE_OPT 160}; 161 162static inline const char *init_color(const char *); 163 164/* Housekeeping */ 165bool file_err; /* file reading error */ 166 167/* 168 * Prints usage information and returns 2. 169 */ 170static void 171usage(void) 172{ 173 fprintf(stderr, getstr(4), getprogname()); 174 fprintf(stderr, "%s", getstr(5)); 175 fprintf(stderr, "%s", getstr(6)); 176 fprintf(stderr, "%s", getstr(7)); 177 exit(2); 178} 179 180static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXyz"; 181 182static const struct option long_options[] = 183{ 184 {"binary-files", required_argument, NULL, BIN_OPT}, 185 {"help", no_argument, NULL, HELP_OPT}, 186 {"mmap", no_argument, NULL, MMAP_OPT}, 187 {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 188 {"label", required_argument, NULL, LABEL_OPT}, 189 {"null", no_argument, NULL, NULL_OPT}, 190 {"color", optional_argument, NULL, COLOR_OPT}, 191 {"colour", optional_argument, NULL, COLOR_OPT}, 192 {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 193 {"include", required_argument, NULL, R_INCLUDE_OPT}, 194 {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 195 {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 196 {"after-context", required_argument, NULL, 'A'}, 197 {"text", no_argument, NULL, 'a'}, 198 {"before-context", required_argument, NULL, 'B'}, 199 {"byte-offset", no_argument, NULL, 'b'}, 200 {"context", optional_argument, NULL, 'C'}, 201 {"count", no_argument, NULL, 'c'}, 202 {"devices", required_argument, NULL, 'D'}, 203 {"directories", required_argument, NULL, 'd'}, 204 {"extended-regexp", no_argument, NULL, 'E'}, 205 {"regexp", required_argument, NULL, 'e'}, 206 {"fixed-strings", no_argument, NULL, 'F'}, 207 {"file", required_argument, NULL, 'f'}, 208 {"basic-regexp", no_argument, NULL, 'G'}, 209 {"no-filename", no_argument, NULL, 'h'}, 210 {"with-filename", no_argument, NULL, 'H'}, 211 {"ignore-case", no_argument, NULL, 'i'}, 212 {"bz2decompress", no_argument, NULL, 'J'}, 213 {"files-with-matches", no_argument, NULL, 'l'}, 214 {"files-without-match", no_argument, NULL, 'L'}, 215 {"max-count", required_argument, NULL, 'm'}, 216 {"lzma", no_argument, NULL, 'M'}, 217 {"line-number", no_argument, NULL, 'n'}, 218 {"only-matching", no_argument, NULL, 'o'}, 219 {"quiet", no_argument, NULL, 'q'}, 220 {"silent", no_argument, NULL, 'q'}, 221 {"recursive", no_argument, NULL, 'r'}, 222 {"no-messages", no_argument, NULL, 's'}, 223 {"binary", no_argument, NULL, 'U'}, 224 {"unix-byte-offsets", no_argument, NULL, 'u'}, 225 {"invert-match", no_argument, NULL, 'v'}, 226 {"version", no_argument, NULL, 'V'}, 227 {"word-regexp", no_argument, NULL, 'w'}, 228 {"line-regexp", no_argument, NULL, 'x'}, 229 {"xz", no_argument, NULL, 'X'}, 230 {"null-data", no_argument, NULL, 'z'}, 231 {"decompress", no_argument, NULL, 'Z'}, 232 {NULL, no_argument, NULL, 0} 233}; 234 235/* 236 * Adds a searching pattern to the internal array. 237 */ 238static void 239add_pattern(char *pat, size_t len) 240{ 241 242 /* Check if we can do a shortcut */ 243 if (len == 0) { 244 matchall = true; 245 return; 246 } 247 /* Increase size if necessary */ 248 if (patterns == pattern_sz) { 249 pattern_sz *= 2; 250 pattern = grep_realloc(pattern, ++pattern_sz * 251 sizeof(struct pat)); 252 } 253 if (len > 0 && pat[len - 1] == '\n') 254 --len; 255 /* pat may not be NUL-terminated */ 256 pattern[patterns].pat = grep_malloc(len + 1); 257 memcpy(pattern[patterns].pat, pat, len); 258 pattern[patterns].len = len; 259 pattern[patterns].pat[len] = '\0'; 260 ++patterns; 261} 262 263/* 264 * Adds a file include/exclude pattern to the internal array. 265 */ 266static void 267add_fpattern(const char *pat, int mode) 268{ 269 270 /* Increase size if necessary */ 271 if (fpatterns == fpattern_sz) { 272 fpattern_sz *= 2; 273 fpattern = grep_realloc(fpattern, ++fpattern_sz * 274 sizeof(struct epat)); 275 } 276 fpattern[fpatterns].pat = grep_strdup(pat); 277 fpattern[fpatterns].mode = mode; 278 ++fpatterns; 279} 280 281/* 282 * Adds a directory include/exclude pattern to the internal array. 283 */ 284static void 285add_dpattern(const char *pat, int mode) 286{ 287 288 /* Increase size if necessary */ 289 if (dpatterns == dpattern_sz) { 290 dpattern_sz *= 2; 291 dpattern = grep_realloc(dpattern, ++dpattern_sz * 292 sizeof(struct epat)); 293 } 294 dpattern[dpatterns].pat = grep_strdup(pat); 295 dpattern[dpatterns].mode = mode; 296 ++dpatterns; 297} 298 299/* 300 * Reads searching patterns from a file and adds them with add_pattern(). 301 */ 302static void 303read_patterns(const char *fn) 304{ 305 struct stat st; 306 FILE *f; 307 char *line; 308 size_t len; 309 ssize_t rlen; 310 311 if (strcmp(fn, "-") == 0) 312 f = stdin; 313 else if ((f = fopen(fn, "r")) == NULL) 314 err(2, "%s", fn); 315 if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) { 316 fclose(f); 317 return; 318 } 319 len = 0; 320 line = NULL; 321 while ((rlen = getline(&line, &len, f)) != -1) { 322 if (line[0] == '\0') 323 continue; 324 add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen); 325 } 326 327 free(line); 328 if (ferror(f)) 329 err(2, "%s", fn); 330 if (strcmp(fn, "-") != 0) 331 fclose(f); 332} 333 334static inline const char * 335init_color(const char *d) 336{ 337 char *c; 338 339 c = getenv("GREP_COLOR"); 340 return (c != NULL && c[0] != '\0' ? c : d); 341} 342 343int 344main(int argc, char *argv[]) 345{ 346 char **aargv, **eargv, *eopts; 347 char *ep; 348 const char *pn; 349 long long l; 350 unsigned int aargc, eargc, i; 351 int c, lastc, needpattern, newarg, prevoptind; 352 bool matched; 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 - 1) { 438 errno = ERANGE; 439 err(2, NULL); 440 } 441 442 Aflag = Bflag = (Aflag * 10) + (c - '0'); 443 break; 444 case 'C': 445 if (optarg == NULL) { 446 Aflag = Bflag = 2; 447 break; 448 } 449 /* FALLTHROUGH */ 450 case 'A': 451 /* FALLTHROUGH */ 452 case 'B': 453 errno = 0; 454 l = strtoll(optarg, &ep, 10); 455 if (errno == ERANGE || errno == EINVAL) 456 err(2, NULL); 457 else if (ep[0] != '\0') { 458 errno = EINVAL; 459 err(2, NULL); 460 } else if (l < 0) { 461 errno = EINVAL; 462 err(2, "context argument must be non-negative"); 463 } 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) && !matchall) 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 /* 720 * regex(3) implementations that support fixed-string searches generally 721 * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag 722 * here. If neither are defined, GREP_FIXED later implies that the 723 * internal literal matcher should be used. Other cflags that have 724 * the same interpretation as REG_NOSPEC and REG_LITERAL should be 725 * similarly added here, and grep.h should be amended to take this into 726 * consideration when defining WITH_INTERNAL_NOSPEC. 727 */ 728#if defined(REG_NOSPEC) 729 cflags |= REG_NOSPEC; 730#elif defined(REG_LITERAL) 731 cflags |= REG_LITERAL; 732#endif 733 break; 734 case GREP_EXTENDED: 735 cflags |= REG_EXTENDED; 736 break; 737 default: 738 /* NOTREACHED */ 739 usage(); 740 } 741 742#ifndef WITHOUT_FASTMATCH 743 fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 744#endif 745 r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 746 747#ifdef WITH_INTERNAL_NOSPEC 748 if (grepbehave != GREP_FIXED) { 749#else 750 { 751#endif 752 /* Check if cheating is allowed (always is for fgrep). */ 753 for (i = 0; i < patterns; ++i) { 754#ifndef WITHOUT_FASTMATCH 755 /* 756 * Attempt compilation with fastmatch regex and 757 * fallback to regex(3) if it fails. 758 */ 759 if (fastncomp(&fg_pattern[i], pattern[i].pat, 760 pattern[i].len, cflags) == 0) 761 continue; 762#endif 763 c = regcomp(&r_pattern[i], pattern[i].pat, cflags); 764 if (c != 0) { 765 regerror(c, &r_pattern[i], re_error, 766 RE_ERROR_BUF); 767 errx(2, "%s", re_error); 768 } 769 } 770 } 771 772 if (lbflag) 773 setlinebuf(stdout); 774 775 if ((aargc == 0 || aargc == 1) && !Hflag) 776 hflag = true; 777 778 if (aargc == 0 && dirbehave != DIR_RECURSE) 779 exit(!procfile("-")); 780 781 if (dirbehave == DIR_RECURSE) 782 matched = grep_tree(aargv); 783 else 784 for (matched = false; aargc--; ++aargv) { 785 if ((finclude || fexclude) && !file_matching(*aargv)) 786 continue; 787 if (procfile(*aargv)) 788 matched = true; 789 } 790 791#ifndef WITHOUT_NLS 792 catclose(catalog); 793#endif 794 795 /* Find out the correct return value according to the 796 results and the command line option. */ 797 if (Lflag) 798 matched = !matched; 799 800 exit(matched ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); 801} 802