]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/grep/grep.c
Import Zstandard 1.2.0
[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  * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
7  * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/stat.h>
36 #include <sys/types.h>
37
38 #include <ctype.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <getopt.h>
43 #include <limits.h>
44 #include <libgen.h>
45 #include <locale.h>
46 #include <stdbool.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #ifndef WITHOUT_FASTMATCH
53 #include "fastmatch.h"
54 #endif
55 #include "grep.h"
56
57 #ifndef WITHOUT_NLS
58 #include <nl_types.h>
59 nl_catd  catalog;
60 #endif
61
62 /*
63  * Default messags to use when NLS is disabled or no catalogue
64  * is found.
65  */
66 const char      *errstr[] = {
67         "",
68 /* 1*/  "(standard input)",
69 /* 2*/  "cannot read bzip2 compressed file",
70 /* 3*/  "unknown %s option",
71 /* 4*/  "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
72 /* 5*/  "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
73 /* 6*/  "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
74 /* 7*/  "\t[--null] [pattern] [file ...]\n",
75 /* 8*/  "Binary file %s matches\n",
76 /* 9*/  "%s (BSD grep) %s\n",
77 /* 10*/ "%s (BSD grep, GNU compatible) %s\n",
78 };
79
80 /* Flags passed to regcomp() and regexec() */
81 int              cflags = REG_NOSUB;
82 int              eflags = REG_STARTEND;
83
84 /* XXX TODO: Get rid of this flag.
85  * matchall is a gross hack that means that an empty pattern was passed to us.
86  * It is a necessary evil at the moment because our regex(3) implementation
87  * does not allow for empty patterns, as supported by POSIX's definition of
88  * grammar for BREs/EREs. When libregex becomes available, it would be wise
89  * to remove this and let regex(3) handle the dirty details of empty patterns.
90  */
91 bool             matchall;
92
93 /* Searching patterns */
94 unsigned int     patterns;
95 static unsigned int pattern_sz;
96 struct pat      *pattern;
97 regex_t         *r_pattern;
98 #ifndef WITHOUT_FASTMATCH
99 fastmatch_t     *fg_pattern;
100 #endif
101
102 /* Filename exclusion/inclusion patterns */
103 unsigned int    fpatterns, dpatterns;
104 static unsigned int fpattern_sz, dpattern_sz;
105 struct epat     *dpattern, *fpattern;
106
107 /* For regex errors  */
108 char     re_error[RE_ERROR_BUF + 1];
109
110 /* Command-line flags */
111 unsigned long long Aflag;       /* -A x: print x lines trailing each match */
112 unsigned long long Bflag;       /* -B x: print x lines leading each match */
113 bool     Hflag;         /* -H: always print file name */
114 bool     Lflag;         /* -L: only show names of files with no matches */
115 bool     bflag;         /* -b: show block numbers for each match */
116 bool     cflag;         /* -c: only show a count of matching lines */
117 bool     hflag;         /* -h: don't print filename headers */
118 bool     iflag;         /* -i: ignore case */
119 bool     lflag;         /* -l: only show names of files with matches */
120 bool     mflag;         /* -m x: stop reading the files after x matches */
121 long long mcount;       /* count for -m */
122 long long mlimit;       /* requested value for -m */
123 char     fileeol;       /* indicator for eol */
124 bool     nflag;         /* -n: show line numbers in front of matching lines */
125 bool     oflag;         /* -o: print only matching part */
126 bool     qflag;         /* -q: quiet mode (don't output anything) */
127 bool     sflag;         /* -s: silent mode (ignore errors) */
128 bool     vflag;         /* -v: only show non-matching lines */
129 bool     wflag;         /* -w: pattern must start and end on word boundaries */
130 bool     xflag;         /* -x: pattern must match entire line */
131 bool     lbflag;        /* --line-buffered */
132 bool     nullflag;      /* --null */
133 char    *label;         /* --label */
134 const char *color;      /* --color */
135 int      grepbehave = GREP_BASIC;       /* -EFGP: type of the regex */
136 int      binbehave = BINFILE_BIN;       /* -aIU: handling of binary files */
137 int      filebehave = FILE_STDIO;       /* -JZ: normal, gzip or bzip2 file */
138 int      devbehave = DEV_READ;          /* -D: handling of devices */
139 int      dirbehave = DIR_READ;          /* -dRr: handling of directories */
140 int      linkbehave = LINK_READ;        /* -OpS: handling of symlinks */
141
142 bool     dexclude, dinclude;    /* --exclude-dir and --include-dir */
143 bool     fexclude, finclude;    /* --exclude and --include */
144
145 enum {
146         BIN_OPT = CHAR_MAX + 1,
147         COLOR_OPT,
148         HELP_OPT,
149         MMAP_OPT,
150         LINEBUF_OPT,
151         LABEL_OPT,
152         NULL_OPT,
153         R_EXCLUDE_OPT,
154         R_INCLUDE_OPT,
155         R_DEXCLUDE_OPT,
156         R_DINCLUDE_OPT
157 };
158
159 static inline const char        *init_color(const char *);
160
161 /* Housekeeping */
162 bool     file_err;      /* file reading error */
163
164 /*
165  * Prints usage information and returns 2.
166  */
167 static void
168 usage(void)
169 {
170         fprintf(stderr, getstr(4), getprogname());
171         fprintf(stderr, "%s", getstr(5));
172         fprintf(stderr, "%s", getstr(6));
173         fprintf(stderr, "%s", getstr(7));
174         exit(2);
175 }
176
177 static const char       *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXyz";
178
179 static const struct option long_options[] =
180 {
181         {"binary-files",        required_argument,      NULL, BIN_OPT},
182         {"help",                no_argument,            NULL, HELP_OPT},
183         {"mmap",                no_argument,            NULL, MMAP_OPT},
184         {"line-buffered",       no_argument,            NULL, LINEBUF_OPT},
185         {"label",               required_argument,      NULL, LABEL_OPT},
186         {"null",                no_argument,            NULL, NULL_OPT},
187         {"color",               optional_argument,      NULL, COLOR_OPT},
188         {"colour",              optional_argument,      NULL, COLOR_OPT},
189         {"exclude",             required_argument,      NULL, R_EXCLUDE_OPT},
190         {"include",             required_argument,      NULL, R_INCLUDE_OPT},
191         {"exclude-dir",         required_argument,      NULL, R_DEXCLUDE_OPT},
192         {"include-dir",         required_argument,      NULL, R_DINCLUDE_OPT},
193         {"after-context",       required_argument,      NULL, 'A'},
194         {"text",                no_argument,            NULL, 'a'},
195         {"before-context",      required_argument,      NULL, 'B'},
196         {"byte-offset",         no_argument,            NULL, 'b'},
197         {"context",             optional_argument,      NULL, 'C'},
198         {"count",               no_argument,            NULL, 'c'},
199         {"devices",             required_argument,      NULL, 'D'},
200         {"directories",         required_argument,      NULL, 'd'},
201         {"extended-regexp",     no_argument,            NULL, 'E'},
202         {"regexp",              required_argument,      NULL, 'e'},
203         {"fixed-strings",       no_argument,            NULL, 'F'},
204         {"file",                required_argument,      NULL, 'f'},
205         {"basic-regexp",        no_argument,            NULL, 'G'},
206         {"no-filename",         no_argument,            NULL, 'h'},
207         {"with-filename",       no_argument,            NULL, 'H'},
208         {"ignore-case",         no_argument,            NULL, 'i'},
209         {"bz2decompress",       no_argument,            NULL, 'J'},
210         {"files-with-matches",  no_argument,            NULL, 'l'},
211         {"files-without-match", no_argument,            NULL, 'L'},
212         {"max-count",           required_argument,      NULL, 'm'},
213         {"lzma",                no_argument,            NULL, 'M'},
214         {"line-number",         no_argument,            NULL, 'n'},
215         {"only-matching",       no_argument,            NULL, 'o'},
216         {"quiet",               no_argument,            NULL, 'q'},
217         {"silent",              no_argument,            NULL, 'q'},
218         {"recursive",           no_argument,            NULL, 'r'},
219         {"no-messages",         no_argument,            NULL, 's'},
220         {"binary",              no_argument,            NULL, 'U'},
221         {"unix-byte-offsets",   no_argument,            NULL, 'u'},
222         {"invert-match",        no_argument,            NULL, 'v'},
223         {"version",             no_argument,            NULL, 'V'},
224         {"word-regexp",         no_argument,            NULL, 'w'},
225         {"line-regexp",         no_argument,            NULL, 'x'},
226         {"xz",                  no_argument,            NULL, 'X'},
227         {"null-data",           no_argument,            NULL, 'z'},
228         {"decompress",          no_argument,            NULL, 'Z'},
229         {NULL,                  no_argument,            NULL, 0}
230 };
231
232 /*
233  * Adds a searching pattern to the internal array.
234  */
235 static void
236 add_pattern(char *pat, size_t len)
237 {
238
239         /* Do not add further pattern is we already match everything */
240         if (matchall)
241           return;
242
243         /* Check if we can do a shortcut */
244         if (len == 0) {
245                 matchall = true;
246                 for (unsigned int i = 0; i < patterns; i++) {
247                         free(pattern[i].pat);
248                 }
249                 pattern = grep_realloc(pattern, sizeof(struct pat));
250                 pattern[0].pat = NULL;
251                 pattern[0].len = 0;
252                 patterns = 1;
253                 return;
254         }
255         /* Increase size if necessary */
256         if (patterns == pattern_sz) {
257                 pattern_sz *= 2;
258                 pattern = grep_realloc(pattern, ++pattern_sz *
259                     sizeof(struct pat));
260         }
261         if (len > 0 && pat[len - 1] == '\n')
262                 --len;
263         /* pat may not be NUL-terminated */
264         pattern[patterns].pat = grep_malloc(len + 1);
265         memcpy(pattern[patterns].pat, pat, len);
266         pattern[patterns].len = len;
267         pattern[patterns].pat[len] = '\0';
268         ++patterns;
269 }
270
271 /*
272  * Adds a file include/exclude pattern to the internal array.
273  */
274 static void
275 add_fpattern(const char *pat, int mode)
276 {
277
278         /* Increase size if necessary */
279         if (fpatterns == fpattern_sz) {
280                 fpattern_sz *= 2;
281                 fpattern = grep_realloc(fpattern, ++fpattern_sz *
282                     sizeof(struct epat));
283         }
284         fpattern[fpatterns].pat = grep_strdup(pat);
285         fpattern[fpatterns].mode = mode;
286         ++fpatterns;
287 }
288
289 /*
290  * Adds a directory include/exclude pattern to the internal array.
291  */
292 static void
293 add_dpattern(const char *pat, int mode)
294 {
295
296         /* Increase size if necessary */
297         if (dpatterns == dpattern_sz) {
298                 dpattern_sz *= 2;
299                 dpattern = grep_realloc(dpattern, ++dpattern_sz *
300                     sizeof(struct epat));
301         }
302         dpattern[dpatterns].pat = grep_strdup(pat);
303         dpattern[dpatterns].mode = mode;
304         ++dpatterns;
305 }
306
307 /*
308  * Reads searching patterns from a file and adds them with add_pattern().
309  */
310 static void
311 read_patterns(const char *fn)
312 {
313         struct stat st;
314         FILE *f;
315         char *line;
316         size_t len;
317         ssize_t rlen;
318
319         if ((f = fopen(fn, "r")) == NULL)
320                 err(2, "%s", fn);
321         if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
322                 fclose(f);
323                 return;
324         }
325         len = 0;
326         line = NULL;
327         while ((rlen = getline(&line, &len, f)) != -1) {
328                 if (line[0] == '\0')
329                         continue;
330                 add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
331         }
332
333         free(line);
334         if (ferror(f))
335                 err(2, "%s", fn);
336         fclose(f);
337 }
338
339 static inline const char *
340 init_color(const char *d)
341 {
342         char *c;
343
344         c = getenv("GREP_COLOR");
345         return (c != NULL && c[0] != '\0' ? c : d);
346 }
347
348 int
349 main(int argc, char *argv[])
350 {
351         char **aargv, **eargv, *eopts;
352         char *ep;
353         const char *pn;
354         unsigned long long l;
355         unsigned int aargc, eargc, i;
356         int c, lastc, needpattern, newarg, prevoptind;
357
358         setlocale(LC_ALL, "");
359
360 #ifndef WITHOUT_NLS
361         catalog = catopen("grep", NL_CAT_LOCALE);
362 #endif
363
364         /* Check what is the program name of the binary.  In this
365            way we can have all the funcionalities in one binary
366            without the need of scripting and using ugly hacks. */
367         pn = getprogname();
368         if (pn[0] == 'b' && pn[1] == 'z') {
369                 filebehave = FILE_BZIP;
370                 pn += 2;
371         } else if (pn[0] == 'x' && pn[1] == 'z') {
372                 filebehave = FILE_XZ;
373                 pn += 2;
374         } else if (pn[0] == 'l' && pn[1] == 'z') {
375                 filebehave = FILE_LZMA;
376                 pn += 2;
377         } else if (pn[0] == 'r') {
378                 dirbehave = DIR_RECURSE;
379                 Hflag = true;
380         } else if (pn[0] == 'z') {
381                 filebehave = FILE_GZIP;
382                 pn += 1;
383         }
384         switch (pn[0]) {
385         case 'e':
386                 grepbehave = GREP_EXTENDED;
387                 break;
388         case 'f':
389                 grepbehave = GREP_FIXED;
390                 break;
391         }
392
393         lastc = '\0';
394         newarg = 1;
395         prevoptind = 1;
396         needpattern = 1;
397         fileeol = '\n';
398
399         eopts = getenv("GREP_OPTIONS");
400
401         /* support for extra arguments in GREP_OPTIONS */
402         eargc = 0;
403         if (eopts != NULL && eopts[0] != '\0') {
404                 char *str;
405
406                 /* make an estimation of how many extra arguments we have */
407                 for (unsigned int j = 0; j < strlen(eopts); j++)
408                         if (eopts[j] == ' ')
409                                 eargc++;
410
411                 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
412
413                 eargc = 0;
414                 /* parse extra arguments */
415                 while ((str = strsep(&eopts, " ")) != NULL)
416                         if (str[0] != '\0')
417                                 eargv[eargc++] = grep_strdup(str);
418
419                 aargv = (char **)grep_calloc(eargc + argc + 1,
420                     sizeof(char *));
421
422                 aargv[0] = argv[0];
423                 for (i = 0; i < eargc; i++)
424                         aargv[i + 1] = eargv[i];
425                 for (int j = 1; j < argc; j++, i++)
426                         aargv[i + 1] = argv[j];
427
428                 aargc = eargc + argc;
429         } else {
430                 aargv = argv;
431                 aargc = argc;
432         }
433
434         while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
435             -1)) {
436                 switch (c) {
437                 case '0': case '1': case '2': case '3': case '4':
438                 case '5': case '6': case '7': case '8': case '9':
439                         if (newarg || !isdigit(lastc))
440                                 Aflag = 0;
441                         else if (Aflag > LLONG_MAX / 10) {
442                                 errno = ERANGE;
443                                 err(2, NULL);
444                         }
445                         Aflag = Bflag = (Aflag * 10) + (c - '0');
446                         break;
447                 case 'C':
448                         if (optarg == NULL) {
449                                 Aflag = Bflag = 2;
450                                 break;
451                         }
452                         /* FALLTHROUGH */
453                 case 'A':
454                         /* FALLTHROUGH */
455                 case 'B':
456                         errno = 0;
457                         l = strtoull(optarg, &ep, 10);
458                         if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
459                             ((errno == EINVAL) && (l == 0)))
460                                 err(2, NULL);
461                         else if (ep[0] != '\0') {
462                                 errno = EINVAL;
463                                 err(2, NULL);
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))
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 #if defined(REG_NOSPEC)
720                 cflags |= REG_NOSPEC;
721 #elif defined(REG_LITERAL)
722                 cflags |= REG_LITERAL;
723 #else
724                 errx(2, "literal expressions not supported at compile time");
725 #endif
726                 break;
727         case GREP_EXTENDED:
728                 cflags |= REG_EXTENDED;
729                 break;
730         default:
731                 /* NOTREACHED */
732                 usage();
733         }
734
735 #ifndef WITHOUT_FASTMATCH
736         fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
737 #endif
738         r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
739
740         /* Don't process any patterns if we have a blank one */
741         if (!matchall) {
742                 /* Check if cheating is allowed (always is for fgrep). */
743                 for (i = 0; i < patterns; ++i) {
744 #ifndef WITHOUT_FASTMATCH
745                         /*
746                          * Attempt compilation with fastmatch regex and
747                          * fallback to regex(3) if it fails.
748                          */
749                         if (fastncomp(&fg_pattern[i], pattern[i].pat,
750                             pattern[i].len, cflags) == 0)
751                                 continue;
752 #endif
753                         c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
754                         if (c != 0) {
755                                 regerror(c, &r_pattern[i], re_error,
756                                     RE_ERROR_BUF);
757                                 errx(2, "%s", re_error);
758                         }
759                 }
760         }
761
762         if (lbflag)
763                 setlinebuf(stdout);
764
765         if ((aargc == 0 || aargc == 1) && !Hflag)
766                 hflag = true;
767
768         if (aargc == 0 && dirbehave != DIR_RECURSE)
769                 exit(!procfile("-"));
770
771         if (dirbehave == DIR_RECURSE)
772                 c = grep_tree(aargv);
773         else
774                 for (c = 0; aargc--; ++aargv) {
775                         if ((finclude || fexclude) && !file_matching(*aargv))
776                                 continue;
777                         c+= procfile(*aargv);
778                 }
779
780 #ifndef WITHOUT_NLS
781         catclose(catalog);
782 #endif
783
784         /* Find out the correct return value according to the
785            results and the command line option. */
786         exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
787 }