]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/grep/grep.c
Add missing break statements in r351004.
[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) %s\n",
66 /* 9*/  "%s (BSD grep, GNU compatible) %s\n",
67 };
68
69 /* Flags passed to regcomp() and regexec() */
70 int              cflags = REG_NOSUB | REG_NEWLINE;
71 int              eflags = REG_STARTEND;
72
73 /* XXX TODO: Get rid of this flag.
74  * matchall is a gross hack that means that an empty pattern was passed to us.
75  * It is a necessary evil at the moment because our regex(3) implementation
76  * does not allow for empty patterns, as supported by POSIX's definition of
77  * grammar for BREs/EREs. When libregex becomes available, it would be wise
78  * to remove this and let regex(3) handle the dirty details of empty patterns.
79  */
80 bool             matchall;
81
82 /* Searching patterns */
83 unsigned int     patterns;
84 static unsigned int pattern_sz;
85 struct pat      *pattern;
86 regex_t         *r_pattern;
87
88 /* Filename exclusion/inclusion patterns */
89 unsigned int    fpatterns, dpatterns;
90 static unsigned int fpattern_sz, 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 long long Aflag;        /* -A x: print x lines trailing each match */
98 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 long long mcount;       /* count for -m */
108 long long mlimit;       /* requested value for -m */
109 char     fileeol;       /* indicator for eol */
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;
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     file_err;      /* file reading error */
149
150 /*
151  * Prints usage information and returns 2.
152  */
153 static void
154 usage(void)
155 {
156         fprintf(stderr, errstr[3], getprogname());
157         fprintf(stderr, "%s", errstr[4]);
158         fprintf(stderr, "%s", errstr[5]);
159         fprintf(stderr, "%s", errstr[6]);
160         exit(2);
161 }
162
163 static const char       *optstr = "0123456789A:B:C:D:EFGHILOPSRUVabcd:e:f:hilm:nopqrsuvwxyz";
164
165 static const struct option long_options[] =
166 {
167         {"binary-files",        required_argument,      NULL, BIN_OPT},
168         {"help",                no_argument,            NULL, HELP_OPT},
169         {"mmap",                no_argument,            NULL, MMAP_OPT},
170         {"line-buffered",       no_argument,            NULL, LINEBUF_OPT},
171         {"label",               required_argument,      NULL, LABEL_OPT},
172         {"null",                no_argument,            NULL, NULL_OPT},
173         {"color",               optional_argument,      NULL, COLOR_OPT},
174         {"colour",              optional_argument,      NULL, COLOR_OPT},
175         {"exclude",             required_argument,      NULL, R_EXCLUDE_OPT},
176         {"include",             required_argument,      NULL, R_INCLUDE_OPT},
177         {"exclude-dir",         required_argument,      NULL, R_DEXCLUDE_OPT},
178         {"include-dir",         required_argument,      NULL, R_DINCLUDE_OPT},
179         {"after-context",       required_argument,      NULL, 'A'},
180         {"text",                no_argument,            NULL, 'a'},
181         {"before-context",      required_argument,      NULL, 'B'},
182         {"byte-offset",         no_argument,            NULL, 'b'},
183         {"context",             optional_argument,      NULL, 'C'},
184         {"count",               no_argument,            NULL, 'c'},
185         {"devices",             required_argument,      NULL, 'D'},
186         {"directories",         required_argument,      NULL, 'd'},
187         {"extended-regexp",     no_argument,            NULL, 'E'},
188         {"regexp",              required_argument,      NULL, 'e'},
189         {"fixed-strings",       no_argument,            NULL, 'F'},
190         {"file",                required_argument,      NULL, 'f'},
191         {"basic-regexp",        no_argument,            NULL, 'G'},
192         {"no-filename",         no_argument,            NULL, 'h'},
193         {"with-filename",       no_argument,            NULL, 'H'},
194         {"ignore-case",         no_argument,            NULL, 'i'},
195         {"files-with-matches",  no_argument,            NULL, 'l'},
196         {"files-without-match", no_argument,            NULL, 'L'},
197         {"max-count",           required_argument,      NULL, 'm'},
198         {"line-number",         no_argument,            NULL, 'n'},
199         {"only-matching",       no_argument,            NULL, 'o'},
200         {"quiet",               no_argument,            NULL, 'q'},
201         {"silent",              no_argument,            NULL, 'q'},
202         {"recursive",           no_argument,            NULL, 'r'},
203         {"no-messages",         no_argument,            NULL, 's'},
204         {"binary",              no_argument,            NULL, 'U'},
205         {"unix-byte-offsets",   no_argument,            NULL, 'u'},
206         {"invert-match",        no_argument,            NULL, 'v'},
207         {"version",             no_argument,            NULL, 'V'},
208         {"word-regexp",         no_argument,            NULL, 'w'},
209         {"line-regexp",         no_argument,            NULL, 'x'},
210         {"null-data",           no_argument,            NULL, 'z'},
211         {NULL,                  no_argument,            NULL, 0}
212 };
213
214 /*
215  * Adds a searching pattern to the internal array.
216  */
217 static void
218 add_pattern(char *pat, size_t len)
219 {
220
221         /* Do not add further pattern is we already match everything */
222         if (matchall)
223           return;
224
225         /* Check if we can do a shortcut */
226         if (len == 0) {
227                 matchall = true;
228                 for (unsigned int i = 0; i < patterns; i++) {
229                         free(pattern[i].pat);
230                 }
231                 pattern = grep_realloc(pattern, sizeof(struct pat));
232                 pattern[0].pat = NULL;
233                 pattern[0].len = 0;
234                 patterns = 1;
235                 return;
236         }
237         /* Increase size if necessary */
238         if (patterns == pattern_sz) {
239                 pattern_sz *= 2;
240                 pattern = grep_realloc(pattern, ++pattern_sz *
241                     sizeof(struct pat));
242         }
243         if (len > 0 && pat[len - 1] == '\n')
244                 --len;
245         /* pat may not be NUL-terminated */
246         pattern[patterns].pat = grep_malloc(len + 1);
247         memcpy(pattern[patterns].pat, pat, len);
248         pattern[patterns].len = len;
249         pattern[patterns].pat[len] = '\0';
250         ++patterns;
251 }
252
253 /*
254  * Adds a file include/exclude pattern to the internal array.
255  */
256 static void
257 add_fpattern(const char *pat, int mode)
258 {
259
260         /* Increase size if necessary */
261         if (fpatterns == fpattern_sz) {
262                 fpattern_sz *= 2;
263                 fpattern = grep_realloc(fpattern, ++fpattern_sz *
264                     sizeof(struct epat));
265         }
266         fpattern[fpatterns].pat = grep_strdup(pat);
267         fpattern[fpatterns].mode = mode;
268         ++fpatterns;
269 }
270
271 /*
272  * Adds a directory include/exclude pattern to the internal array.
273  */
274 static void
275 add_dpattern(const char *pat, int mode)
276 {
277
278         /* Increase size if necessary */
279         if (dpatterns == dpattern_sz) {
280                 dpattern_sz *= 2;
281                 dpattern = grep_realloc(dpattern, ++dpattern_sz *
282                     sizeof(struct epat));
283         }
284         dpattern[dpatterns].pat = grep_strdup(pat);
285         dpattern[dpatterns].mode = mode;
286         ++dpatterns;
287 }
288
289 /*
290  * Reads searching patterns from a file and adds them with add_pattern().
291  */
292 static void
293 read_patterns(const char *fn)
294 {
295         struct stat st;
296         FILE *f;
297         char *line;
298         size_t len;
299         ssize_t rlen;
300
301         if (strcmp(fn, "-") == 0)
302                 f = stdin;
303         else if ((f = fopen(fn, "r")) == NULL)
304                 err(2, "%s", fn);
305         if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
306                 fclose(f);
307                 return;
308         }
309         len = 0;
310         line = NULL;
311         while ((rlen = getline(&line, &len, f)) != -1) {
312                 if (line[0] == '\0')
313                         continue;
314                 add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
315         }
316
317         free(line);
318         if (ferror(f))
319                 err(2, "%s", fn);
320         if (strcmp(fn, "-") != 0)
321                 fclose(f);
322 }
323
324 static inline const char *
325 init_color(const char *d)
326 {
327         char *c;
328
329         c = getenv("GREP_COLOR");
330         return (c != NULL && c[0] != '\0' ? c : d);
331 }
332
333 int
334 main(int argc, char *argv[])
335 {
336         char **aargv, **eargv, *eopts;
337         char *ep;
338         const char *pn;
339         long long l;
340         unsigned int aargc, eargc, i;
341         int c, lastc, needpattern, newarg, prevoptind;
342         bool matched;
343
344         setlocale(LC_ALL, "");
345
346         /*
347          * Check how we've bene invoked to determine the behavior we should
348          * exhibit. In this way we can have all the functionalities in one
349          * binary without the need of scripting and using ugly hacks.
350          */
351         pn = getprogname();
352         switch (pn[0]) {
353         case 'e':
354                 grepbehave = GREP_EXTENDED;
355                 break;
356         case 'f':
357                 grepbehave = GREP_FIXED;
358                 break;
359         case 'r':
360                 dirbehave = DIR_RECURSE;
361                 Hflag = true;
362                 break;
363         }
364
365         lastc = '\0';
366         newarg = 1;
367         prevoptind = 1;
368         needpattern = 1;
369         fileeol = '\n';
370
371         eopts = getenv("GREP_OPTIONS");
372
373         /* support for extra arguments in GREP_OPTIONS */
374         eargc = 0;
375         if (eopts != NULL && eopts[0] != '\0') {
376                 char *str;
377
378                 /* make an estimation of how many extra arguments we have */
379                 for (unsigned int j = 0; j < strlen(eopts); j++)
380                         if (eopts[j] == ' ')
381                                 eargc++;
382
383                 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
384
385                 eargc = 0;
386                 /* parse extra arguments */
387                 while ((str = strsep(&eopts, " ")) != NULL)
388                         if (str[0] != '\0')
389                                 eargv[eargc++] = grep_strdup(str);
390
391                 aargv = (char **)grep_calloc(eargc + argc + 1,
392                     sizeof(char *));
393
394                 aargv[0] = argv[0];
395                 for (i = 0; i < eargc; i++)
396                         aargv[i + 1] = eargv[i];
397                 for (int j = 1; j < argc; j++, i++)
398                         aargv[i + 1] = argv[j];
399
400                 aargc = eargc + argc;
401         } else {
402                 aargv = argv;
403                 aargc = argc;
404         }
405
406         while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
407             -1)) {
408                 switch (c) {
409                 case '0': case '1': case '2': case '3': case '4':
410                 case '5': case '6': case '7': case '8': case '9':
411                         if (newarg || !isdigit(lastc))
412                                 Aflag = 0;
413                         else if (Aflag > LLONG_MAX / 10 - 1) {
414                                 errno = ERANGE;
415                                 err(2, NULL);
416                         }
417
418                         Aflag = Bflag = (Aflag * 10) + (c - '0');
419                         break;
420                 case 'C':
421                         if (optarg == NULL) {
422                                 Aflag = Bflag = 2;
423                                 break;
424                         }
425                         /* FALLTHROUGH */
426                 case 'A':
427                         /* FALLTHROUGH */
428                 case 'B':
429                         errno = 0;
430                         l = strtoll(optarg, &ep, 10);
431                         if (errno == ERANGE || errno == EINVAL)
432                                 err(2, NULL);
433                         else if (ep[0] != '\0') {
434                                 errno = EINVAL;
435                                 err(2, NULL);
436                         } else if (l < 0) {
437                                 errno = EINVAL;
438                                 err(2, "context argument must be non-negative");
439                         }
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, errstr[2], "--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, errstr[2], "--directories");
475                         break;
476                 case 'E':
477                         grepbehave = GREP_EXTENDED;
478                         break;
479                 case 'e':
480                         {
481                                 char *token;
482                                 char *string = optarg;
483
484                                 while ((token = strsep(&string, "\n")) != NULL)
485                                         add_pattern(token, strlen(token));
486                         }
487                         needpattern = 0;
488                         break;
489                 case 'F':
490                         grepbehave = GREP_FIXED;
491                         break;
492                 case 'f':
493                         read_patterns(optarg);
494                         needpattern = 0;
495                         break;
496                 case 'G':
497                         grepbehave = GREP_BASIC;
498                         break;
499                 case 'H':
500                         Hflag = true;
501                         break;
502                 case 'h':
503                         Hflag = false;
504                         hflag = true;
505                         break;
506                 case 'I':
507                         binbehave = BINFILE_SKIP;
508                         break;
509                 case 'i':
510                 case 'y':
511                         iflag =  true;
512                         cflags |= REG_ICASE;
513                         break;
514                 case 'L':
515                         lflag = false;
516                         Lflag = true;
517                         break;
518                 case 'l':
519                         Lflag = false;
520                         lflag = true;
521                         break;
522                 case 'm':
523                         mflag = true;
524                         errno = 0;
525                         mlimit = mcount = strtoll(optarg, &ep, 10);
526                         if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
527                             ((errno == EINVAL) && (mcount == 0)))
528                                 err(2, NULL);
529                         else if (ep[0] != '\0') {
530                                 errno = EINVAL;
531                                 err(2, NULL);
532                         }
533                         break;
534                 case 'n':
535                         nflag = true;
536                         break;
537                 case 'O':
538                         linkbehave = LINK_EXPLICIT;
539                         break;
540                 case 'o':
541                         oflag = true;
542                         cflags &= ~REG_NOSUB;
543                         break;
544                 case 'p':
545                         linkbehave = LINK_SKIP;
546                         break;
547                 case 'q':
548                         qflag = true;
549                         break;
550                 case 'S':
551                         linkbehave = LINK_READ;
552                         break;
553                 case 'R':
554                 case 'r':
555                         dirbehave = DIR_RECURSE;
556                         Hflag = true;
557                         break;
558                 case 's':
559                         sflag = true;
560                         break;
561                 case 'U':
562                         binbehave = BINFILE_BIN;
563                         break;
564                 case 'u':
565                 case MMAP_OPT:
566                         filebehave = FILE_MMAP;
567                         break;
568                 case 'V':
569 #ifdef WITH_GNU
570                         printf(errstr[9], getprogname(), VERSION);
571 #else
572                         printf(errstr[8], getprogname(), VERSION);
573 #endif
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 'z':
587                         fileeol = '\0';
588                         break;
589                 case BIN_OPT:
590                         if (strcasecmp("binary", optarg) == 0)
591                                 binbehave = BINFILE_BIN;
592                         else if (strcasecmp("without-match", optarg) == 0)
593                                 binbehave = BINFILE_SKIP;
594                         else if (strcasecmp("text", optarg) == 0)
595                                 binbehave = BINFILE_TEXT;
596                         else
597                                 errx(2, errstr[2], "--binary-files");
598                         break;
599                 case COLOR_OPT:
600                         color = NULL;
601                         if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
602                             strcasecmp("tty", optarg) == 0 ||
603                             strcasecmp("if-tty", optarg) == 0) {
604                                 char *term;
605
606                                 term = getenv("TERM");
607                                 if (isatty(STDOUT_FILENO) && term != NULL &&
608                                     strcasecmp(term, "dumb") != 0)
609                                         color = init_color("01;31");
610                         } else if (strcasecmp("always", optarg) == 0 ||
611                             strcasecmp("yes", optarg) == 0 ||
612                             strcasecmp("force", optarg) == 0) {
613                                 color = init_color("01;31");
614                         } else if (strcasecmp("never", optarg) != 0 &&
615                             strcasecmp("none", optarg) != 0 &&
616                             strcasecmp("no", optarg) != 0)
617                                 errx(2, errstr[2], "--color");
618                         cflags &= ~REG_NOSUB;
619                         break;
620                 case LABEL_OPT:
621                         label = optarg;
622                         break;
623                 case LINEBUF_OPT:
624                         lbflag = true;
625                         break;
626                 case NULL_OPT:
627                         nullflag = true;
628                         break;
629                 case R_INCLUDE_OPT:
630                         finclude = true;
631                         add_fpattern(optarg, INCL_PAT);
632                         break;
633                 case R_EXCLUDE_OPT:
634                         fexclude = true;
635                         add_fpattern(optarg, EXCL_PAT);
636                         break;
637                 case R_DINCLUDE_OPT:
638                         dinclude = true;
639                         add_dpattern(optarg, INCL_PAT);
640                         break;
641                 case R_DEXCLUDE_OPT:
642                         dexclude = true;
643                         add_dpattern(optarg, EXCL_PAT);
644                         break;
645                 case HELP_OPT:
646                 default:
647                         usage();
648                 }
649                 lastc = c;
650                 newarg = optind != prevoptind;
651                 prevoptind = optind;
652         }
653         aargc -= optind;
654         aargv += optind;
655
656         /* Empty pattern file matches nothing */
657         if (!needpattern && (patterns == 0))
658                 exit(1);
659
660         /* Fail if we don't have any pattern */
661         if (aargc == 0 && needpattern)
662                 usage();
663
664         /* Process patterns from command line */
665         if (aargc != 0 && needpattern) {
666                 char *token;
667                 char *string = *aargv;
668
669                 while ((token = strsep(&string, "\n")) != NULL)
670                         add_pattern(token, strlen(token));
671                 --aargc;
672                 ++aargv;
673         }
674
675         switch (grepbehave) {
676         case GREP_BASIC:
677                 break;
678         case GREP_FIXED:
679                 /*
680                  * regex(3) implementations that support fixed-string searches generally
681                  * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
682                  * here. If neither are defined, GREP_FIXED later implies that the
683                  * internal literal matcher should be used. Other cflags that have
684                  * the same interpretation as REG_NOSPEC and REG_LITERAL should be
685                  * similarly added here, and grep.h should be amended to take this into
686                  * consideration when defining WITH_INTERNAL_NOSPEC.
687                  */
688 #if defined(REG_NOSPEC)
689                 cflags |= REG_NOSPEC;
690 #elif defined(REG_LITERAL)
691                 cflags |= REG_LITERAL;
692 #endif
693                 break;
694         case GREP_EXTENDED:
695                 cflags |= REG_EXTENDED;
696                 break;
697         default:
698                 /* NOTREACHED */
699                 usage();
700         }
701
702         r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
703
704         /* Don't process any patterns if we have a blank one */
705 #ifdef WITH_INTERNAL_NOSPEC
706         if (!matchall && grepbehave != GREP_FIXED) {
707 #else
708         if (!matchall) {
709 #endif
710                 /* Check if cheating is allowed (always is for fgrep). */
711                 for (i = 0; i < patterns; ++i) {
712                         c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
713                         if (c != 0) {
714                                 regerror(c, &r_pattern[i], re_error,
715                                     RE_ERROR_BUF);
716                                 errx(2, "%s", re_error);
717                         }
718                 }
719         }
720
721         if (lbflag)
722                 setlinebuf(stdout);
723
724         if ((aargc == 0 || aargc == 1) && !Hflag)
725                 hflag = true;
726
727         if (aargc == 0 && dirbehave != DIR_RECURSE)
728                 exit(!procfile("-"));
729
730         if (dirbehave == DIR_RECURSE)
731                 matched = grep_tree(aargv);
732         else
733                 for (matched = false; aargc--; ++aargv) {
734                         if ((finclude || fexclude) && !file_matching(*aargv))
735                                 continue;
736                         if (procfile(*aargv))
737                                 matched = true;
738                 }
739
740         /* Find out the correct return value according to the
741            results and the command line option. */
742         exit(matched ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
743 }