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