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