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