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