]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.bin/grep/grep.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / usr.bin / grep / grep.c
1 /*      $NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 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
308         if ((f = fopen(fn, "r")) == NULL)
309                 err(2, "%s", fn);
310         if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
311                 fclose(f);
312                 return;
313         }
314         while ((line = fgetln(f, &len)) != NULL)
315                 add_pattern(line, line[0] == '\n' ? 0 : len);
316         if (ferror(f))
317                 err(2, "%s", fn);
318         fclose(f);
319 }
320
321 static inline const char *
322 init_color(const char *d)
323 {
324         char *c;
325
326         c = getenv("GREP_COLOR");
327         return (c != NULL && c[0] != '\0' ? c : d);
328 }
329
330 int
331 main(int argc, char *argv[])
332 {
333         char **aargv, **eargv, *eopts;
334         char *ep;
335         const char *pn;
336         unsigned long long l;
337         unsigned int aargc, eargc, i;
338         int c, lastc, needpattern, newarg, prevoptind;
339
340         setlocale(LC_ALL, "");
341
342 #ifndef WITHOUT_NLS
343         catalog = catopen("grep", NL_CAT_LOCALE);
344 #endif
345
346         /* Check what is the program name of the binary.  In this
347            way we can have all the funcionalities in one binary
348            without the need of scripting and using ugly hacks. */
349         pn = getprogname();
350         if (pn[0] == 'b' && pn[1] == 'z') {
351                 filebehave = FILE_BZIP;
352                 pn += 2;
353         } else if (pn[0] == 'x' && pn[1] == 'z') {
354                 filebehave = FILE_XZ;
355                 pn += 2;
356         } else if (pn[0] == 'l' && pn[1] == 'z') {
357                 filebehave = FILE_LZMA;
358                 pn += 2;
359         } else if (pn[0] == 'z') {
360                 filebehave = FILE_GZIP;
361                 pn += 1;
362         }
363         switch (pn[0]) {
364         case 'e':
365                 grepbehave = GREP_EXTENDED;
366                 break;
367         case 'f':
368                 grepbehave = GREP_FIXED;
369                 break;
370         }
371
372         lastc = '\0';
373         newarg = 1;
374         prevoptind = 1;
375         needpattern = 1;
376
377         eopts = getenv("GREP_OPTIONS");
378
379         /* support for extra arguments in GREP_OPTIONS */
380         eargc = 0;
381         if (eopts != NULL && eopts[0] != '\0') {
382                 char *str;
383
384                 /* make an estimation of how many extra arguments we have */
385                 for (unsigned int j = 0; j < strlen(eopts); j++)
386                         if (eopts[j] == ' ')
387                                 eargc++;
388
389                 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
390
391                 eargc = 0;
392                 /* parse extra arguments */
393                 while ((str = strsep(&eopts, " ")) != NULL)
394                         if (str[0] != '\0')
395                                 eargv[eargc++] = grep_strdup(str);
396
397                 aargv = (char **)grep_calloc(eargc + argc + 1,
398                     sizeof(char *));
399
400                 aargv[0] = argv[0];
401                 for (i = 0; i < eargc; i++)
402                         aargv[i + 1] = eargv[i];
403                 for (int j = 1; j < argc; j++, i++)
404                         aargv[i + 1] = argv[j];
405
406                 aargc = eargc + argc;
407         } else {
408                 aargv = argv;
409                 aargc = argc;
410         }
411
412         while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
413             -1)) {
414                 switch (c) {
415                 case '0': case '1': case '2': case '3': case '4':
416                 case '5': case '6': case '7': case '8': case '9':
417                         if (newarg || !isdigit(lastc))
418                                 Aflag = 0;
419                         else if (Aflag > LLONG_MAX / 10) {
420                                 errno = ERANGE;
421                                 err(2, NULL);
422                         }
423                         Aflag = Bflag = (Aflag * 10) + (c - '0');
424                         break;
425                 case 'C':
426                         if (optarg == NULL) {
427                                 Aflag = Bflag = 2;
428                                 break;
429                         }
430                         /* FALLTHROUGH */
431                 case 'A':
432                         /* FALLTHROUGH */
433                 case 'B':
434                         errno = 0;
435                         l = strtoull(optarg, &ep, 10);
436                         if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
437                             ((errno == EINVAL) && (l == 0)))
438                                 err(2, NULL);
439                         else if (ep[0] != '\0') {
440                                 errno = EINVAL;
441                                 err(2, NULL);
442                         }
443                         if (c == 'A')
444                                 Aflag = l;
445                         else if (c == 'B')
446                                 Bflag = l;
447                         else
448                                 Aflag = Bflag = l;
449                         break;
450                 case 'a':
451                         binbehave = BINFILE_TEXT;
452                         break;
453                 case 'b':
454                         bflag = true;
455                         break;
456                 case 'c':
457                         cflag = true;
458                         break;
459                 case 'D':
460                         if (strcasecmp(optarg, "skip") == 0)
461                                 devbehave = DEV_SKIP;
462                         else if (strcasecmp(optarg, "read") == 0)
463                                 devbehave = DEV_READ;
464                         else
465                                 errx(2, getstr(3), "--devices");
466                         break;
467                 case 'd':
468                         if (strcasecmp("recurse", optarg) == 0) {
469                                 Hflag = true;
470                                 dirbehave = DIR_RECURSE;
471                         } else if (strcasecmp("skip", optarg) == 0)
472                                 dirbehave = DIR_SKIP;
473                         else if (strcasecmp("read", optarg) == 0)
474                                 dirbehave = DIR_READ;
475                         else
476                                 errx(2, getstr(3), "--directories");
477                         break;
478                 case 'E':
479                         grepbehave = GREP_EXTENDED;
480                         break;
481                 case 'e':
482                         {
483                                 char *token;
484                                 char *string = optarg;
485
486                                 while ((token = strsep(&string, "\n")) != NULL)
487                                         add_pattern(token, strlen(token));
488                         }
489                         needpattern = 0;
490                         break;
491                 case 'F':
492                         grepbehave = GREP_FIXED;
493                         break;
494                 case 'f':
495                         read_patterns(optarg);
496                         needpattern = 0;
497                         break;
498                 case 'G':
499                         grepbehave = GREP_BASIC;
500                         break;
501                 case 'H':
502                         Hflag = true;
503                         break;
504                 case 'h':
505                         Hflag = false;
506                         hflag = true;
507                         break;
508                 case 'I':
509                         binbehave = BINFILE_SKIP;
510                         break;
511                 case 'i':
512                 case 'y':
513                         iflag =  true;
514                         cflags |= REG_ICASE;
515                         break;
516                 case 'J':
517 #ifdef WITHOUT_BZIP2
518                         errno = EOPNOTSUPP;
519                         err(2, "bzip2 support was disabled at compile-time");
520 #endif
521                         filebehave = FILE_BZIP;
522                         break;
523                 case 'L':
524                         lflag = false;
525                         Lflag = true;
526                         break;
527                 case 'l':
528                         Lflag = false;
529                         lflag = true;
530                         break;
531                 case 'm':
532                         mflag = true;
533                         errno = 0;
534                         mlimit = mcount = strtoll(optarg, &ep, 10);
535                         if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
536                             ((errno == EINVAL) && (mcount == 0)))
537                                 err(2, NULL);
538                         else if (ep[0] != '\0') {
539                                 errno = EINVAL;
540                                 err(2, NULL);
541                         }
542                         break;
543                 case 'M':
544                         filebehave = FILE_LZMA;
545                         break;
546                 case 'n':
547                         nflag = true;
548                         break;
549                 case 'O':
550                         linkbehave = LINK_EXPLICIT;
551                         break;
552                 case 'o':
553                         oflag = true;
554                         cflags &= ~REG_NOSUB;
555                         break;
556                 case 'p':
557                         linkbehave = LINK_SKIP;
558                         break;
559                 case 'q':
560                         qflag = true;
561                         break;
562                 case 'S':
563                         linkbehave = LINK_READ;
564                         break;
565                 case 'R':
566                 case 'r':
567                         dirbehave = DIR_RECURSE;
568                         Hflag = true;
569                         break;
570                 case 's':
571                         sflag = true;
572                         break;
573                 case 'U':
574                         binbehave = BINFILE_BIN;
575                         break;
576                 case 'u':
577                 case MMAP_OPT:
578                         filebehave = FILE_MMAP;
579                         break;
580                 case 'V':
581                         printf(getstr(9), getprogname(), VERSION);
582                         exit(0);
583                 case 'v':
584                         vflag = true;
585                         break;
586                 case 'w':
587                         wflag = true;
588                         cflags &= ~REG_NOSUB;
589                         break;
590                 case 'x':
591                         xflag = true;
592                         cflags &= ~REG_NOSUB;
593                         break;
594                 case 'X':
595                         filebehave = FILE_XZ;
596                         break;
597                 case 'Z':
598                         filebehave = FILE_GZIP;
599                         break;
600                 case BIN_OPT:
601                         if (strcasecmp("binary", optarg) == 0)
602                                 binbehave = BINFILE_BIN;
603                         else if (strcasecmp("without-match", optarg) == 0)
604                                 binbehave = BINFILE_SKIP;
605                         else if (strcasecmp("text", optarg) == 0)
606                                 binbehave = BINFILE_TEXT;
607                         else
608                                 errx(2, getstr(3), "--binary-files");
609                         break;
610                 case COLOR_OPT:
611                         color = NULL;
612                         if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
613                             strcasecmp("tty", optarg) == 0 ||
614                             strcasecmp("if-tty", optarg) == 0) {
615                                 char *term;
616
617                                 term = getenv("TERM");
618                                 if (isatty(STDOUT_FILENO) && term != NULL &&
619                                     strcasecmp(term, "dumb") != 0)
620                                         color = init_color("01;31");
621                         } else if (strcasecmp("always", optarg) == 0 ||
622                             strcasecmp("yes", optarg) == 0 ||
623                             strcasecmp("force", optarg) == 0) {
624                                 color = init_color("01;31");
625                         } else if (strcasecmp("never", optarg) != 0 &&
626                             strcasecmp("none", optarg) != 0 &&
627                             strcasecmp("no", optarg) != 0)
628                                 errx(2, getstr(3), "--color");
629                         cflags &= ~REG_NOSUB;
630                         break;
631                 case LABEL_OPT:
632                         label = optarg;
633                         break;
634                 case LINEBUF_OPT:
635                         lbflag = true;
636                         break;
637                 case NULL_OPT:
638                         nullflag = true;
639                         break;
640                 case R_INCLUDE_OPT:
641                         finclude = true;
642                         add_fpattern(optarg, INCL_PAT);
643                         break;
644                 case R_EXCLUDE_OPT:
645                         fexclude = true;
646                         add_fpattern(optarg, EXCL_PAT);
647                         break;
648                 case R_DINCLUDE_OPT:
649                         dinclude = true;
650                         add_dpattern(optarg, INCL_PAT);
651                         break;
652                 case R_DEXCLUDE_OPT:
653                         dexclude = true;
654                         add_dpattern(optarg, EXCL_PAT);
655                         break;
656                 case HELP_OPT:
657                 default:
658                         usage();
659                 }
660                 lastc = c;
661                 newarg = optind != prevoptind;
662                 prevoptind = optind;
663         }
664         aargc -= optind;
665         aargv += optind;
666
667         /* Empty pattern file matches nothing */
668         if (!needpattern && (patterns == 0))
669                 exit(1);
670
671         /* Fail if we don't have any pattern */
672         if (aargc == 0 && needpattern)
673                 usage();
674
675         /* Process patterns from command line */
676         if (aargc != 0 && needpattern) {
677                 char *token;
678                 char *string = *aargv;
679
680                 while ((token = strsep(&string, "\n")) != NULL)
681                         add_pattern(token, strlen(token));
682                 --aargc;
683                 ++aargv;
684         }
685
686         switch (grepbehave) {
687         case GREP_BASIC:
688                 break;
689         case GREP_FIXED:
690                 /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */
691                 cflags |= 0020;
692                 break;
693         case GREP_EXTENDED:
694                 cflags |= REG_EXTENDED;
695                 break;
696         default:
697                 /* NOTREACHED */
698                 usage();
699         }
700
701         fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
702         r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
703
704         /* Check if cheating is allowed (always is for fgrep). */
705         for (i = 0; i < patterns; ++i) {
706                 if (fastncomp(&fg_pattern[i], pattern[i].pat,
707                     pattern[i].len, cflags) != 0) {
708                         /* Fall back to full regex library */
709                         c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
710                         if (c != 0) {
711                                 regerror(c, &r_pattern[i], re_error,
712                                     RE_ERROR_BUF);
713                                 errx(2, "%s", re_error);
714                         }
715                 }
716         }
717
718         if (lbflag)
719                 setlinebuf(stdout);
720
721         if ((aargc == 0 || aargc == 1) && !Hflag)
722                 hflag = true;
723
724         if (aargc == 0)
725                 exit(!procfile("-"));
726
727         if (dirbehave == DIR_RECURSE)
728                 c = grep_tree(aargv);
729         else
730                 for (c = 0; aargc--; ++aargv) {
731                         if ((finclude || fexclude) && !file_matching(*aargv))
732                                 continue;
733                         c+= procfile(*aargv);
734                 }
735
736 #ifndef WITHOUT_NLS
737         catclose(catalog);
738 #endif
739
740         /* Find out the correct return value according to the
741            results and the command line option. */
742         exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
743 }