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