]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/grep/grep.c
zfs: merge openzfs/zfs@887a3c533
[FreeBSD/FreeBSD.git] / usr.bin / grep / grep.c
1 /*      $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $   */
2 /*      $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $  */
3
4 /*-
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * Copyright (c) 1999 James Howard and Dag-Erling Smørgrav
8  * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.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 const char      *errstr[] = {
54         "",
55 /* 1*/  "(standard input)",
56 /* 2*/  "unknown %s option",
57 /* 3*/  "usage: %s [-abcDEFGHhIiLlmnOopqRSsUVvwxz] [-A num] [-B num] [-C num]\n",
58 /* 4*/  "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
59 /* 5*/  "\t[--context=num] [--directories=action] [--label] [--line-buffered]\n",
60 /* 6*/  "\t[--null] [pattern] [file ...]\n",
61 /* 7*/  "Binary file %s matches\n",
62 /* 8*/  "%s (BSD grep, GNU compatible) %s\n",
63 };
64
65 /* Flags passed to regcomp() and regexec() */
66 int              cflags = REG_NOSUB | REG_NEWLINE;
67 int              eflags = REG_STARTEND;
68
69 bool             matchall;
70
71 /* Searching patterns */
72 unsigned int     patterns;
73 static unsigned int pattern_sz;
74 struct pat      *pattern;
75 regex_t         *r_pattern;
76
77 /* Filename exclusion/inclusion patterns */
78 unsigned int    fpatterns, dpatterns;
79 static unsigned int fpattern_sz, dpattern_sz;
80 struct epat     *dpattern, *fpattern;
81
82 /* For regex errors  */
83 char     re_error[RE_ERROR_BUF + 1];
84
85 /* Command-line flags */
86 long long Aflag;        /* -A x: print x lines trailing each match */
87 long long Bflag;        /* -B x: print x lines leading each match */
88 bool     Hflag;         /* -H: always print file name */
89 bool     Lflag;         /* -L: only show names of files with no matches */
90 bool     bflag;         /* -b: show block numbers for each match */
91 bool     cflag;         /* -c: only show a count of matching lines */
92 bool     hflag;         /* -h: don't print filename headers */
93 bool     iflag;         /* -i: ignore case */
94 bool     lflag;         /* -l: only show names of files with matches */
95 bool     mflag;         /* -m x: stop reading the files after x matches */
96 long long mcount;       /* count for -m */
97 long long mlimit;       /* requested value for -m */
98 char     fileeol;       /* indicator for eol */
99 bool     nflag;         /* -n: show line numbers in front of matching lines */
100 bool     oflag;         /* -o: print only matching part */
101 bool     qflag;         /* -q: quiet mode (don't output anything) */
102 bool     sflag;         /* -s: silent mode (ignore errors) */
103 bool     vflag;         /* -v: only show non-matching lines */
104 bool     wflag;         /* -w: pattern must start and end on word boundaries */
105 bool     xflag;         /* -x: pattern must match entire line */
106 bool     lbflag;        /* --line-buffered */
107 bool     nullflag;      /* --null */
108 char    *label;         /* --label */
109 const char *color;      /* --color */
110 int      grepbehave = GREP_BASIC;       /* -EFG: type of the regex */
111 int      binbehave = BINFILE_BIN;       /* -aIU: handling of binary files */
112 int      filebehave = FILE_STDIO;
113 int      devbehave = DEV_READ;          /* -D: handling of devices */
114 int      dirbehave = DIR_READ;          /* -dRr: handling of directories */
115 int      linkbehave = LINK_READ;        /* -OpS: handling of symlinks */
116
117 bool     dexclude, dinclude;    /* --exclude-dir and --include-dir */
118 bool     fexclude, finclude;    /* --exclude and --include */
119
120 enum {
121         BIN_OPT = CHAR_MAX + 1,
122         COLOR_OPT,
123         HELP_OPT,
124         MMAP_OPT,
125         LINEBUF_OPT,
126         LABEL_OPT,
127         NULL_OPT,
128         R_EXCLUDE_OPT,
129         R_INCLUDE_OPT,
130         R_DEXCLUDE_OPT,
131         R_DINCLUDE_OPT
132 };
133
134 static inline const char        *init_color(const char *);
135
136 /* Housekeeping */
137 bool     file_err;      /* file reading error */
138
139 /*
140  * Prints usage information and returns 2.
141  */
142 static void
143 usage(void)
144 {
145         fprintf(stderr, errstr[3], getprogname());
146         fprintf(stderr, "%s", errstr[4]);
147         fprintf(stderr, "%s", errstr[5]);
148         fprintf(stderr, "%s", errstr[6]);
149         exit(2);
150 }
151
152 static const char       *optstr = "0123456789A:B:C:D:EFGHILOSRUVabcd:e:f:hilm:nopqrsuvwxyz";
153
154 static const struct option long_options[] =
155 {
156         {"binary-files",        required_argument,      NULL, BIN_OPT},
157         {"help",                no_argument,            NULL, HELP_OPT},
158         {"mmap",                no_argument,            NULL, MMAP_OPT},
159         {"line-buffered",       no_argument,            NULL, LINEBUF_OPT},
160         {"label",               required_argument,      NULL, LABEL_OPT},
161         {"null",                no_argument,            NULL, NULL_OPT},
162         {"color",               optional_argument,      NULL, COLOR_OPT},
163         {"colour",              optional_argument,      NULL, COLOR_OPT},
164         {"exclude",             required_argument,      NULL, R_EXCLUDE_OPT},
165         {"include",             required_argument,      NULL, R_INCLUDE_OPT},
166         {"exclude-dir",         required_argument,      NULL, R_DEXCLUDE_OPT},
167         {"include-dir",         required_argument,      NULL, R_DINCLUDE_OPT},
168         {"after-context",       required_argument,      NULL, 'A'},
169         {"text",                no_argument,            NULL, 'a'},
170         {"before-context",      required_argument,      NULL, 'B'},
171         {"byte-offset",         no_argument,            NULL, 'b'},
172         {"context",             optional_argument,      NULL, 'C'},
173         {"count",               no_argument,            NULL, 'c'},
174         {"devices",             required_argument,      NULL, 'D'},
175         {"directories",         required_argument,      NULL, 'd'},
176         {"extended-regexp",     no_argument,            NULL, 'E'},
177         {"regexp",              required_argument,      NULL, 'e'},
178         {"fixed-strings",       no_argument,            NULL, 'F'},
179         {"file",                required_argument,      NULL, 'f'},
180         {"basic-regexp",        no_argument,            NULL, 'G'},
181         {"no-filename",         no_argument,            NULL, 'h'},
182         {"with-filename",       no_argument,            NULL, 'H'},
183         {"ignore-case",         no_argument,            NULL, 'i'},
184         {"files-with-matches",  no_argument,            NULL, 'l'},
185         {"files-without-match", no_argument,            NULL, 'L'},
186         {"max-count",           required_argument,      NULL, 'm'},
187         {"line-number",         no_argument,            NULL, 'n'},
188         {"only-matching",       no_argument,            NULL, 'o'},
189         {"quiet",               no_argument,            NULL, 'q'},
190         {"silent",              no_argument,            NULL, 'q'},
191         {"recursive",           no_argument,            NULL, 'r'},
192         {"no-messages",         no_argument,            NULL, 's'},
193         {"binary",              no_argument,            NULL, 'U'},
194         {"unix-byte-offsets",   no_argument,            NULL, 'u'},
195         {"invert-match",        no_argument,            NULL, 'v'},
196         {"version",             no_argument,            NULL, 'V'},
197         {"word-regexp",         no_argument,            NULL, 'w'},
198         {"line-regexp",         no_argument,            NULL, 'x'},
199         {"null-data",           no_argument,            NULL, 'z'},
200         {NULL,                  no_argument,            NULL, 0}
201 };
202
203 /*
204  * Adds a searching pattern to the internal array.
205  */
206 static void
207 add_pattern(char *pat, size_t len)
208 {
209
210         /* Check if we can do a shortcut */
211         if (len == 0) {
212                 matchall = true;
213                 return;
214         }
215         /* Increase size if necessary */
216         if (patterns == pattern_sz) {
217                 pattern_sz *= 2;
218                 pattern = grep_realloc(pattern, ++pattern_sz *
219                     sizeof(struct pat));
220         }
221         if (len > 0 && pat[len - 1] == '\n')
222                 --len;
223         /* pat may not be NUL-terminated */
224         pattern[patterns].pat = grep_malloc(len + 1);
225         memcpy(pattern[patterns].pat, pat, len);
226         pattern[patterns].len = len;
227         pattern[patterns].pat[len] = '\0';
228         ++patterns;
229 }
230
231 /*
232  * Adds a file include/exclude pattern to the internal array.
233  */
234 static void
235 add_fpattern(const char *pat, int mode)
236 {
237
238         /* Increase size if necessary */
239         if (fpatterns == fpattern_sz) {
240                 fpattern_sz *= 2;
241                 fpattern = grep_realloc(fpattern, ++fpattern_sz *
242                     sizeof(struct epat));
243         }
244         fpattern[fpatterns].pat = grep_strdup(pat);
245         fpattern[fpatterns].mode = mode;
246         ++fpatterns;
247 }
248
249 /*
250  * Adds a directory include/exclude pattern to the internal array.
251  */
252 static void
253 add_dpattern(const char *pat, int mode)
254 {
255
256         /* Increase size if necessary */
257         if (dpatterns == dpattern_sz) {
258                 dpattern_sz *= 2;
259                 dpattern = grep_realloc(dpattern, ++dpattern_sz *
260                     sizeof(struct epat));
261         }
262         dpattern[dpatterns].pat = grep_strdup(pat);
263         dpattern[dpatterns].mode = mode;
264         ++dpatterns;
265 }
266
267 /*
268  * Reads searching patterns from a file and adds them with add_pattern().
269  */
270 static void
271 read_patterns(const char *fn)
272 {
273         struct stat st;
274         FILE *f;
275         char *line;
276         size_t len;
277         ssize_t rlen;
278
279         if (strcmp(fn, "-") == 0)
280                 f = stdin;
281         else if ((f = fopen(fn, "r")) == NULL)
282                 err(2, "%s", fn);
283         if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
284                 fclose(f);
285                 return;
286         }
287         len = 0;
288         line = NULL;
289         while ((rlen = getline(&line, &len, f)) != -1) {
290                 if (line[0] == '\0')
291                         continue;
292                 add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
293         }
294
295         free(line);
296         if (ferror(f))
297                 err(2, "%s", fn);
298         if (strcmp(fn, "-") != 0)
299                 fclose(f);
300 }
301
302 static inline const char *
303 init_color(const char *d)
304 {
305         char *c;
306
307         c = getenv("GREP_COLOR");
308         return (c != NULL && c[0] != '\0' ? c : d);
309 }
310
311 int
312 main(int argc, char *argv[])
313 {
314         char **aargv, **eargv, *eopts;
315         char *ep;
316         const char *pn;
317         long long l;
318         unsigned int aargc, eargc, i;
319         int c, lastc, needpattern, newarg, prevoptind;
320         bool matched;
321
322         setlocale(LC_ALL, "");
323
324         /*
325          * Check how we've bene invoked to determine the behavior we should
326          * exhibit. In this way we can have all the functionalities in one
327          * binary without the need of scripting and using ugly hacks.
328          */
329         pn = getprogname();
330         switch (pn[0]) {
331         case 'e':
332                 grepbehave = GREP_EXTENDED;
333                 break;
334         case 'f':
335                 grepbehave = GREP_FIXED;
336                 break;
337         case 'r':
338                 dirbehave = DIR_RECURSE;
339                 Hflag = true;
340                 break;
341         }
342
343         lastc = '\0';
344         newarg = 1;
345         prevoptind = 1;
346         needpattern = 1;
347         fileeol = '\n';
348
349         eopts = getenv("GREP_OPTIONS");
350
351         /* support for extra arguments in GREP_OPTIONS */
352         eargc = 0;
353         if (eopts != NULL && eopts[0] != '\0') {
354                 char *str;
355
356                 /* make an estimation of how many extra arguments we have */
357                 for (unsigned int j = 0; j < strlen(eopts); j++)
358                         if (eopts[j] == ' ')
359                                 eargc++;
360
361                 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
362
363                 eargc = 0;
364                 /* parse extra arguments */
365                 while ((str = strsep(&eopts, " ")) != NULL)
366                         if (str[0] != '\0')
367                                 eargv[eargc++] = grep_strdup(str);
368
369                 aargv = (char **)grep_calloc(eargc + argc + 1,
370                     sizeof(char *));
371
372                 aargv[0] = argv[0];
373                 for (i = 0; i < eargc; i++)
374                         aargv[i + 1] = eargv[i];
375                 for (int j = 1; j < argc; j++, i++)
376                         aargv[i + 1] = argv[j];
377
378                 aargc = eargc + argc;
379         } else {
380                 aargv = argv;
381                 aargc = argc;
382         }
383
384         while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
385             -1)) {
386                 switch (c) {
387                 case '0': case '1': case '2': case '3': case '4':
388                 case '5': case '6': case '7': case '8': case '9':
389                         if (newarg || !isdigit(lastc))
390                                 Aflag = 0;
391                         else if (Aflag > LLONG_MAX / 10 - 1) {
392                                 errno = ERANGE;
393                                 err(2, NULL);
394                         }
395
396                         Aflag = Bflag = (Aflag * 10) + (c - '0');
397                         break;
398                 case 'C':
399                         if (optarg == NULL) {
400                                 Aflag = Bflag = 2;
401                                 break;
402                         }
403                         /* FALLTHROUGH */
404                 case 'A':
405                         /* FALLTHROUGH */
406                 case 'B':
407                         errno = 0;
408                         l = strtoll(optarg, &ep, 10);
409                         if (errno == ERANGE || errno == EINVAL)
410                                 err(2, NULL);
411                         else if (ep[0] != '\0') {
412                                 errno = EINVAL;
413                                 err(2, NULL);
414                         } else if (l < 0) {
415                                 errno = EINVAL;
416                                 err(2, "context argument must be non-negative");
417                         }
418
419                         if (c == 'A')
420                                 Aflag = l;
421                         else if (c == 'B')
422                                 Bflag = l;
423                         else
424                                 Aflag = Bflag = l;
425                         break;
426                 case 'a':
427                         binbehave = BINFILE_TEXT;
428                         break;
429                 case 'b':
430                         bflag = true;
431                         break;
432                 case 'c':
433                         cflag = true;
434                         break;
435                 case 'D':
436                         if (strcasecmp(optarg, "skip") == 0)
437                                 devbehave = DEV_SKIP;
438                         else if (strcasecmp(optarg, "read") == 0)
439                                 devbehave = DEV_READ;
440                         else
441                                 errx(2, errstr[2], "--devices");
442                         break;
443                 case 'd':
444                         if (strcasecmp("recurse", optarg) == 0) {
445                                 Hflag = true;
446                                 dirbehave = DIR_RECURSE;
447                         } else if (strcasecmp("skip", optarg) == 0)
448                                 dirbehave = DIR_SKIP;
449                         else if (strcasecmp("read", optarg) == 0)
450                                 dirbehave = DIR_READ;
451                         else
452                                 errx(2, errstr[2], "--directories");
453                         break;
454                 case 'E':
455                         grepbehave = GREP_EXTENDED;
456                         break;
457                 case 'e':
458                         {
459                                 char *token;
460                                 char *string = optarg;
461
462                                 while ((token = strsep(&string, "\n")) != NULL)
463                                         add_pattern(token, strlen(token));
464                         }
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 'L':
493                         lflag = false;
494                         Lflag = true;
495                         break;
496                 case 'l':
497                         Lflag = false;
498                         lflag = true;
499                         break;
500                 case 'm':
501                         mflag = true;
502                         errno = 0;
503                         mlimit = mcount = strtoll(optarg, &ep, 10);
504                         if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
505                             ((errno == EINVAL) && (mcount == 0)))
506                                 err(2, NULL);
507                         else if (ep[0] != '\0') {
508                                 errno = EINVAL;
509                                 err(2, NULL);
510                         }
511                         break;
512                 case 'n':
513                         nflag = true;
514                         break;
515                 case 'O':
516                         linkbehave = LINK_EXPLICIT;
517                         break;
518                 case 'o':
519                         oflag = true;
520                         cflags &= ~REG_NOSUB;
521                         break;
522                 case 'p':
523                         linkbehave = LINK_SKIP;
524                         break;
525                 case 'q':
526                         qflag = true;
527                         break;
528                 case 'S':
529                         linkbehave = LINK_READ;
530                         break;
531                 case 'R':
532                 case 'r':
533                         dirbehave = DIR_RECURSE;
534                         Hflag = true;
535                         break;
536                 case 's':
537                         sflag = true;
538                         break;
539                 case 'U':
540                         binbehave = BINFILE_BIN;
541                         break;
542                 case 'u':
543                 case MMAP_OPT:
544                         filebehave = FILE_MMAP;
545                         break;
546                 case 'V':
547                         printf(errstr[8], getprogname(), VERSION);
548                         exit(0);
549                 case 'v':
550                         vflag = true;
551                         break;
552                 case 'w':
553                         wflag = true;
554                         cflags &= ~REG_NOSUB;
555                         break;
556                 case 'x':
557                         xflag = true;
558                         cflags &= ~REG_NOSUB;
559                         break;
560                 case 'z':
561                         fileeol = '\0';
562                         cflags &= ~REG_NEWLINE;
563                         break;
564                 case BIN_OPT:
565                         if (strcasecmp("binary", optarg) == 0)
566                                 binbehave = BINFILE_BIN;
567                         else if (strcasecmp("without-match", optarg) == 0)
568                                 binbehave = BINFILE_SKIP;
569                         else if (strcasecmp("text", optarg) == 0)
570                                 binbehave = BINFILE_TEXT;
571                         else
572                                 errx(2, errstr[2], "--binary-files");
573                         break;
574                 case COLOR_OPT:
575                         color = NULL;
576                         if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
577                             strcasecmp("tty", optarg) == 0 ||
578                             strcasecmp("if-tty", optarg) == 0) {
579                                 char *term;
580
581                                 term = getenv("TERM");
582                                 if (isatty(STDOUT_FILENO) && term != NULL &&
583                                     strcasecmp(term, "dumb") != 0)
584                                         color = init_color("01;31");
585                         } else if (strcasecmp("always", optarg) == 0 ||
586                             strcasecmp("yes", optarg) == 0 ||
587                             strcasecmp("force", optarg) == 0) {
588                                 color = init_color("01;31");
589                         } else if (strcasecmp("never", optarg) != 0 &&
590                             strcasecmp("none", optarg) != 0 &&
591                             strcasecmp("no", optarg) != 0)
592                                 errx(2, errstr[2], "--color");
593                         cflags &= ~REG_NOSUB;
594                         break;
595                 case LABEL_OPT:
596                         label = optarg;
597                         break;
598                 case LINEBUF_OPT:
599                         lbflag = true;
600                         break;
601                 case NULL_OPT:
602                         nullflag = true;
603                         break;
604                 case R_INCLUDE_OPT:
605                         finclude = true;
606                         add_fpattern(optarg, INCL_PAT);
607                         break;
608                 case R_EXCLUDE_OPT:
609                         fexclude = true;
610                         add_fpattern(optarg, EXCL_PAT);
611                         break;
612                 case R_DINCLUDE_OPT:
613                         dinclude = true;
614                         add_dpattern(optarg, INCL_PAT);
615                         break;
616                 case R_DEXCLUDE_OPT:
617                         dexclude = true;
618                         add_dpattern(optarg, EXCL_PAT);
619                         break;
620                 case HELP_OPT:
621                 default:
622                         usage();
623                 }
624                 lastc = c;
625                 newarg = optind != prevoptind;
626                 prevoptind = optind;
627         }
628         aargc -= optind;
629         aargv += optind;
630
631         /* xflag takes precedence, don't confuse the matching bits. */
632         if (wflag && xflag)
633                 wflag = false;
634
635         /* Fail if we don't have any pattern */
636         if (aargc == 0 && needpattern)
637                 usage();
638
639         /* Process patterns from command line */
640         if (aargc != 0 && needpattern) {
641                 char *token;
642                 char *string = *aargv;
643
644                 while ((token = strsep(&string, "\n")) != NULL)
645                         add_pattern(token, strlen(token));
646                 --aargc;
647                 ++aargv;
648         }
649
650         switch (grepbehave) {
651         case GREP_BASIC:
652                 break;
653         case GREP_FIXED:
654                 /*
655                  * regex(3) implementations that support fixed-string searches generally
656                  * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
657                  * here. If neither are defined, GREP_FIXED later implies that the
658                  * internal literal matcher should be used. Other cflags that have
659                  * the same interpretation as REG_NOSPEC and REG_LITERAL should be
660                  * similarly added here, and grep.h should be amended to take this into
661                  * consideration when defining WITH_INTERNAL_NOSPEC.
662                  */
663 #if defined(REG_NOSPEC)
664                 cflags |= REG_NOSPEC;
665 #elif defined(REG_LITERAL)
666                 cflags |= REG_LITERAL;
667 #endif
668                 break;
669         case GREP_EXTENDED:
670                 cflags |= REG_EXTENDED;
671                 break;
672         default:
673                 /* NOTREACHED */
674                 usage();
675         }
676
677         r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
678
679 #ifdef WITH_INTERNAL_NOSPEC
680         if (grepbehave != GREP_FIXED) {
681 #else
682         {
683 #endif
684                 /* Check if cheating is allowed (always is for fgrep). */
685                 for (i = 0; i < patterns; ++i) {
686                         c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
687                         if (c != 0) {
688                                 regerror(c, &r_pattern[i], re_error,
689                                     RE_ERROR_BUF);
690                                 errx(2, "%s", re_error);
691                         }
692                 }
693         }
694
695         if (lbflag)
696                 setlinebuf(stdout);
697
698         if ((aargc == 0 || aargc == 1) && !Hflag)
699                 hflag = true;
700
701         initqueue();
702
703         if (aargc == 0 && dirbehave != DIR_RECURSE)
704                 exit(!procfile("-"));
705
706         if (dirbehave == DIR_RECURSE)
707                 matched = grep_tree(aargv);
708         else
709                 for (matched = false; aargc--; ++aargv) {
710                         if ((finclude || fexclude) && !file_matching(*aargv))
711                                 continue;
712                         if (procfile(*aargv))
713                                 matched = true;
714                 }
715
716         if (Lflag)
717                 matched = !matched;
718
719         /*
720          * Calculate the correct return value according to the
721          * results and the command line option.
722          */
723         exit(matched ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
724 }