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