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