]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/grep/grep.c
Import mandoc snapshot 2017-06-08
[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 | REG_NEWLINE;
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 long long Aflag;        /* -A x: print x lines trailing each match */
112 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         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 - 1) {
442                                 errno = ERANGE;
443                                 err(2, NULL);
444                         }
445
446                         Aflag = Bflag = (Aflag * 10) + (c - '0');
447                         break;
448                 case 'C':
449                         if (optarg == NULL) {
450                                 Aflag = Bflag = 2;
451                                 break;
452                         }
453                         /* FALLTHROUGH */
454                 case 'A':
455                         /* FALLTHROUGH */
456                 case 'B':
457                         errno = 0;
458                         l = strtoll(optarg, &ep, 10);
459                         if (errno == ERANGE || errno == EINVAL)
460                                 err(2, NULL);
461                         else if (ep[0] != '\0') {
462                                 errno = EINVAL;
463                                 err(2, NULL);
464                         } else if (l < 0) {
465                                 errno = EINVAL;
466                                 err(2, "context argument must be non-negative");
467                         }
468
469                         if (c == 'A')
470                                 Aflag = l;
471                         else if (c == 'B')
472                                 Bflag = l;
473                         else
474                                 Aflag = Bflag = l;
475                         break;
476                 case 'a':
477                         binbehave = BINFILE_TEXT;
478                         break;
479                 case 'b':
480                         bflag = true;
481                         break;
482                 case 'c':
483                         cflag = true;
484                         break;
485                 case 'D':
486                         if (strcasecmp(optarg, "skip") == 0)
487                                 devbehave = DEV_SKIP;
488                         else if (strcasecmp(optarg, "read") == 0)
489                                 devbehave = DEV_READ;
490                         else
491                                 errx(2, getstr(3), "--devices");
492                         break;
493                 case 'd':
494                         if (strcasecmp("recurse", optarg) == 0) {
495                                 Hflag = true;
496                                 dirbehave = DIR_RECURSE;
497                         } else if (strcasecmp("skip", optarg) == 0)
498                                 dirbehave = DIR_SKIP;
499                         else if (strcasecmp("read", optarg) == 0)
500                                 dirbehave = DIR_READ;
501                         else
502                                 errx(2, getstr(3), "--directories");
503                         break;
504                 case 'E':
505                         grepbehave = GREP_EXTENDED;
506                         break;
507                 case 'e':
508                         {
509                                 char *token;
510                                 char *string = optarg;
511
512                                 while ((token = strsep(&string, "\n")) != NULL)
513                                         add_pattern(token, strlen(token));
514                         }
515                         needpattern = 0;
516                         break;
517                 case 'F':
518                         grepbehave = GREP_FIXED;
519                         break;
520                 case 'f':
521                         read_patterns(optarg);
522                         needpattern = 0;
523                         break;
524                 case 'G':
525                         grepbehave = GREP_BASIC;
526                         break;
527                 case 'H':
528                         Hflag = true;
529                         break;
530                 case 'h':
531                         Hflag = false;
532                         hflag = true;
533                         break;
534                 case 'I':
535                         binbehave = BINFILE_SKIP;
536                         break;
537                 case 'i':
538                 case 'y':
539                         iflag =  true;
540                         cflags |= REG_ICASE;
541                         break;
542                 case 'J':
543 #ifdef WITHOUT_BZIP2
544                         errno = EOPNOTSUPP;
545                         err(2, "bzip2 support was disabled at compile-time");
546 #endif
547                         filebehave = FILE_BZIP;
548                         break;
549                 case 'L':
550                         lflag = false;
551                         Lflag = true;
552                         break;
553                 case 'l':
554                         Lflag = false;
555                         lflag = true;
556                         break;
557                 case 'm':
558                         mflag = true;
559                         errno = 0;
560                         mlimit = mcount = strtoll(optarg, &ep, 10);
561                         if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
562                             ((errno == EINVAL) && (mcount == 0)))
563                                 err(2, NULL);
564                         else if (ep[0] != '\0') {
565                                 errno = EINVAL;
566                                 err(2, NULL);
567                         }
568                         break;
569                 case 'M':
570                         filebehave = FILE_LZMA;
571                         break;
572                 case 'n':
573                         nflag = true;
574                         break;
575                 case 'O':
576                         linkbehave = LINK_EXPLICIT;
577                         break;
578                 case 'o':
579                         oflag = true;
580                         cflags &= ~REG_NOSUB;
581                         break;
582                 case 'p':
583                         linkbehave = LINK_SKIP;
584                         break;
585                 case 'q':
586                         qflag = true;
587                         break;
588                 case 'S':
589                         linkbehave = LINK_READ;
590                         break;
591                 case 'R':
592                 case 'r':
593                         dirbehave = DIR_RECURSE;
594                         Hflag = true;
595                         break;
596                 case 's':
597                         sflag = true;
598                         break;
599                 case 'U':
600                         binbehave = BINFILE_BIN;
601                         break;
602                 case 'u':
603                 case MMAP_OPT:
604                         filebehave = FILE_MMAP;
605                         break;
606                 case 'V':
607 #ifdef WITH_GNU
608                         printf(getstr(10), getprogname(), VERSION);
609 #else
610                         printf(getstr(9), getprogname(), VERSION);
611 #endif
612                         exit(0);
613                 case 'v':
614                         vflag = true;
615                         break;
616                 case 'w':
617                         wflag = true;
618                         cflags &= ~REG_NOSUB;
619                         break;
620                 case 'x':
621                         xflag = true;
622                         cflags &= ~REG_NOSUB;
623                         break;
624                 case 'X':
625                         filebehave = FILE_XZ;
626                         break;
627                 case 'z':
628                         fileeol = '\0';
629                         break;
630                 case 'Z':
631                         filebehave = FILE_GZIP;
632                         break;
633                 case BIN_OPT:
634                         if (strcasecmp("binary", optarg) == 0)
635                                 binbehave = BINFILE_BIN;
636                         else if (strcasecmp("without-match", optarg) == 0)
637                                 binbehave = BINFILE_SKIP;
638                         else if (strcasecmp("text", optarg) == 0)
639                                 binbehave = BINFILE_TEXT;
640                         else
641                                 errx(2, getstr(3), "--binary-files");
642                         break;
643                 case COLOR_OPT:
644                         color = NULL;
645                         if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
646                             strcasecmp("tty", optarg) == 0 ||
647                             strcasecmp("if-tty", optarg) == 0) {
648                                 char *term;
649
650                                 term = getenv("TERM");
651                                 if (isatty(STDOUT_FILENO) && term != NULL &&
652                                     strcasecmp(term, "dumb") != 0)
653                                         color = init_color("01;31");
654                         } else if (strcasecmp("always", optarg) == 0 ||
655                             strcasecmp("yes", optarg) == 0 ||
656                             strcasecmp("force", optarg) == 0) {
657                                 color = init_color("01;31");
658                         } else if (strcasecmp("never", optarg) != 0 &&
659                             strcasecmp("none", optarg) != 0 &&
660                             strcasecmp("no", optarg) != 0)
661                                 errx(2, getstr(3), "--color");
662                         cflags &= ~REG_NOSUB;
663                         break;
664                 case LABEL_OPT:
665                         label = optarg;
666                         break;
667                 case LINEBUF_OPT:
668                         lbflag = true;
669                         break;
670                 case NULL_OPT:
671                         nullflag = true;
672                         break;
673                 case R_INCLUDE_OPT:
674                         finclude = true;
675                         add_fpattern(optarg, INCL_PAT);
676                         break;
677                 case R_EXCLUDE_OPT:
678                         fexclude = true;
679                         add_fpattern(optarg, EXCL_PAT);
680                         break;
681                 case R_DINCLUDE_OPT:
682                         dinclude = true;
683                         add_dpattern(optarg, INCL_PAT);
684                         break;
685                 case R_DEXCLUDE_OPT:
686                         dexclude = true;
687                         add_dpattern(optarg, EXCL_PAT);
688                         break;
689                 case HELP_OPT:
690                 default:
691                         usage();
692                 }
693                 lastc = c;
694                 newarg = optind != prevoptind;
695                 prevoptind = optind;
696         }
697         aargc -= optind;
698         aargv += optind;
699
700         /* Empty pattern file matches nothing */
701         if (!needpattern && (patterns == 0))
702                 exit(1);
703
704         /* Fail if we don't have any pattern */
705         if (aargc == 0 && needpattern)
706                 usage();
707
708         /* Process patterns from command line */
709         if (aargc != 0 && needpattern) {
710                 char *token;
711                 char *string = *aargv;
712
713                 while ((token = strsep(&string, "\n")) != NULL)
714                         add_pattern(token, strlen(token));
715                 --aargc;
716                 ++aargv;
717         }
718
719         switch (grepbehave) {
720         case GREP_BASIC:
721                 break;
722         case GREP_FIXED:
723 #if defined(REG_NOSPEC)
724                 cflags |= REG_NOSPEC;
725 #elif defined(REG_LITERAL)
726                 cflags |= REG_LITERAL;
727 #else
728                 errx(2, "literal expressions not supported at compile time");
729 #endif
730                 break;
731         case GREP_EXTENDED:
732                 cflags |= REG_EXTENDED;
733                 break;
734         default:
735                 /* NOTREACHED */
736                 usage();
737         }
738
739 #ifndef WITHOUT_FASTMATCH
740         fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
741 #endif
742         r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
743
744         /* Don't process any patterns if we have a blank one */
745         if (!matchall) {
746                 /* Check if cheating is allowed (always is for fgrep). */
747                 for (i = 0; i < patterns; ++i) {
748 #ifndef WITHOUT_FASTMATCH
749                         /*
750                          * Attempt compilation with fastmatch regex and
751                          * fallback to regex(3) if it fails.
752                          */
753                         if (fastncomp(&fg_pattern[i], pattern[i].pat,
754                             pattern[i].len, cflags) == 0)
755                                 continue;
756 #endif
757                         c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
758                         if (c != 0) {
759                                 regerror(c, &r_pattern[i], re_error,
760                                     RE_ERROR_BUF);
761                                 errx(2, "%s", re_error);
762                         }
763                 }
764         }
765
766         if (lbflag)
767                 setlinebuf(stdout);
768
769         if ((aargc == 0 || aargc == 1) && !Hflag)
770                 hflag = true;
771
772         if (aargc == 0 && dirbehave != DIR_RECURSE)
773                 exit(!procfile("-"));
774
775         if (dirbehave == DIR_RECURSE)
776                 c = grep_tree(aargv);
777         else
778                 for (c = 0; aargc--; ++aargv) {
779                         if ((finclude || fexclude) && !file_matching(*aargv))
780                                 continue;
781                         c+= procfile(*aargv);
782                 }
783
784 #ifndef WITHOUT_NLS
785         catclose(catalog);
786 #endif
787
788         /* Find out the correct return value according to the
789            results and the command line option. */
790         exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
791 }