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