]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/grep/grep.c
stand: TARGET_ARCH is spelled MACHINE_ARCH in Makefiles
[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         /* Check what is the program name of the binary.  In this
347            way we can have all the funcionalities in one binary
348            without the need of scripting and using ugly hacks. */
349         pn = getprogname();
350         if (pn[0] == 'r') {
351                 dirbehave = DIR_RECURSE;
352                 Hflag = true;
353         }
354         switch (pn[0]) {
355         case 'e':
356                 grepbehave = GREP_EXTENDED;
357                 break;
358         case 'f':
359                 grepbehave = GREP_FIXED;
360                 break;
361         }
362
363         lastc = '\0';
364         newarg = 1;
365         prevoptind = 1;
366         needpattern = 1;
367         fileeol = '\n';
368
369         eopts = getenv("GREP_OPTIONS");
370
371         /* support for extra arguments in GREP_OPTIONS */
372         eargc = 0;
373         if (eopts != NULL && eopts[0] != '\0') {
374                 char *str;
375
376                 /* make an estimation of how many extra arguments we have */
377                 for (unsigned int j = 0; j < strlen(eopts); j++)
378                         if (eopts[j] == ' ')
379                                 eargc++;
380
381                 eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
382
383                 eargc = 0;
384                 /* parse extra arguments */
385                 while ((str = strsep(&eopts, " ")) != NULL)
386                         if (str[0] != '\0')
387                                 eargv[eargc++] = grep_strdup(str);
388
389                 aargv = (char **)grep_calloc(eargc + argc + 1,
390                     sizeof(char *));
391
392                 aargv[0] = argv[0];
393                 for (i = 0; i < eargc; i++)
394                         aargv[i + 1] = eargv[i];
395                 for (int j = 1; j < argc; j++, i++)
396                         aargv[i + 1] = argv[j];
397
398                 aargc = eargc + argc;
399         } else {
400                 aargv = argv;
401                 aargc = argc;
402         }
403
404         while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
405             -1)) {
406                 switch (c) {
407                 case '0': case '1': case '2': case '3': case '4':
408                 case '5': case '6': case '7': case '8': case '9':
409                         if (newarg || !isdigit(lastc))
410                                 Aflag = 0;
411                         else if (Aflag > LLONG_MAX / 10 - 1) {
412                                 errno = ERANGE;
413                                 err(2, NULL);
414                         }
415
416                         Aflag = Bflag = (Aflag * 10) + (c - '0');
417                         break;
418                 case 'C':
419                         if (optarg == NULL) {
420                                 Aflag = Bflag = 2;
421                                 break;
422                         }
423                         /* FALLTHROUGH */
424                 case 'A':
425                         /* FALLTHROUGH */
426                 case 'B':
427                         errno = 0;
428                         l = strtoll(optarg, &ep, 10);
429                         if (errno == ERANGE || errno == EINVAL)
430                                 err(2, NULL);
431                         else if (ep[0] != '\0') {
432                                 errno = EINVAL;
433                                 err(2, NULL);
434                         } else if (l < 0) {
435                                 errno = EINVAL;
436                                 err(2, "context argument must be non-negative");
437                         }
438
439                         if (c == 'A')
440                                 Aflag = l;
441                         else if (c == 'B')
442                                 Bflag = l;
443                         else
444                                 Aflag = Bflag = l;
445                         break;
446                 case 'a':
447                         binbehave = BINFILE_TEXT;
448                         break;
449                 case 'b':
450                         bflag = true;
451                         break;
452                 case 'c':
453                         cflag = true;
454                         break;
455                 case 'D':
456                         if (strcasecmp(optarg, "skip") == 0)
457                                 devbehave = DEV_SKIP;
458                         else if (strcasecmp(optarg, "read") == 0)
459                                 devbehave = DEV_READ;
460                         else
461                                 errx(2, errstr[2], "--devices");
462                         break;
463                 case 'd':
464                         if (strcasecmp("recurse", optarg) == 0) {
465                                 Hflag = true;
466                                 dirbehave = DIR_RECURSE;
467                         } else if (strcasecmp("skip", optarg) == 0)
468                                 dirbehave = DIR_SKIP;
469                         else if (strcasecmp("read", optarg) == 0)
470                                 dirbehave = DIR_READ;
471                         else
472                                 errx(2, errstr[2], "--directories");
473                         break;
474                 case 'E':
475                         grepbehave = GREP_EXTENDED;
476                         break;
477                 case 'e':
478                         {
479                                 char *token;
480                                 char *string = optarg;
481
482                                 while ((token = strsep(&string, "\n")) != NULL)
483                                         add_pattern(token, strlen(token));
484                         }
485                         needpattern = 0;
486                         break;
487                 case 'F':
488                         grepbehave = GREP_FIXED;
489                         break;
490                 case 'f':
491                         read_patterns(optarg);
492                         needpattern = 0;
493                         break;
494                 case 'G':
495                         grepbehave = GREP_BASIC;
496                         break;
497                 case 'H':
498                         Hflag = true;
499                         break;
500                 case 'h':
501                         Hflag = false;
502                         hflag = true;
503                         break;
504                 case 'I':
505                         binbehave = BINFILE_SKIP;
506                         break;
507                 case 'i':
508                 case 'y':
509                         iflag =  true;
510                         cflags |= REG_ICASE;
511                         break;
512                 case 'L':
513                         lflag = false;
514                         Lflag = true;
515                         break;
516                 case 'l':
517                         Lflag = false;
518                         lflag = true;
519                         break;
520                 case 'm':
521                         mflag = true;
522                         errno = 0;
523                         mlimit = mcount = strtoll(optarg, &ep, 10);
524                         if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
525                             ((errno == EINVAL) && (mcount == 0)))
526                                 err(2, NULL);
527                         else if (ep[0] != '\0') {
528                                 errno = EINVAL;
529                                 err(2, NULL);
530                         }
531                         break;
532                 case 'n':
533                         nflag = true;
534                         break;
535                 case 'O':
536                         linkbehave = LINK_EXPLICIT;
537                         break;
538                 case 'o':
539                         oflag = true;
540                         cflags &= ~REG_NOSUB;
541                         break;
542                 case 'p':
543                         linkbehave = LINK_SKIP;
544                         break;
545                 case 'q':
546                         qflag = true;
547                         break;
548                 case 'S':
549                         linkbehave = LINK_READ;
550                         break;
551                 case 'R':
552                 case 'r':
553                         dirbehave = DIR_RECURSE;
554                         Hflag = true;
555                         break;
556                 case 's':
557                         sflag = true;
558                         break;
559                 case 'U':
560                         binbehave = BINFILE_BIN;
561                         break;
562                 case 'u':
563                 case MMAP_OPT:
564                         filebehave = FILE_MMAP;
565                         break;
566                 case 'V':
567 #ifdef WITH_GNU
568                         printf(errstr[9], getprogname(), VERSION);
569 #else
570                         printf(errstr[8], getprogname(), VERSION);
571 #endif
572                         exit(0);
573                 case 'v':
574                         vflag = true;
575                         break;
576                 case 'w':
577                         wflag = true;
578                         cflags &= ~REG_NOSUB;
579                         break;
580                 case 'x':
581                         xflag = true;
582                         cflags &= ~REG_NOSUB;
583                         break;
584                 case 'z':
585                         fileeol = '\0';
586                         break;
587                 case BIN_OPT:
588                         if (strcasecmp("binary", optarg) == 0)
589                                 binbehave = BINFILE_BIN;
590                         else if (strcasecmp("without-match", optarg) == 0)
591                                 binbehave = BINFILE_SKIP;
592                         else if (strcasecmp("text", optarg) == 0)
593                                 binbehave = BINFILE_TEXT;
594                         else
595                                 errx(2, errstr[2], "--binary-files");
596                         break;
597                 case COLOR_OPT:
598                         color = NULL;
599                         if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
600                             strcasecmp("tty", optarg) == 0 ||
601                             strcasecmp("if-tty", optarg) == 0) {
602                                 char *term;
603
604                                 term = getenv("TERM");
605                                 if (isatty(STDOUT_FILENO) && term != NULL &&
606                                     strcasecmp(term, "dumb") != 0)
607                                         color = init_color("01;31");
608                         } else if (strcasecmp("always", optarg) == 0 ||
609                             strcasecmp("yes", optarg) == 0 ||
610                             strcasecmp("force", optarg) == 0) {
611                                 color = init_color("01;31");
612                         } else if (strcasecmp("never", optarg) != 0 &&
613                             strcasecmp("none", optarg) != 0 &&
614                             strcasecmp("no", optarg) != 0)
615                                 errx(2, errstr[2], "--color");
616                         cflags &= ~REG_NOSUB;
617                         break;
618                 case LABEL_OPT:
619                         label = optarg;
620                         break;
621                 case LINEBUF_OPT:
622                         lbflag = true;
623                         break;
624                 case NULL_OPT:
625                         nullflag = true;
626                         break;
627                 case R_INCLUDE_OPT:
628                         finclude = true;
629                         add_fpattern(optarg, INCL_PAT);
630                         break;
631                 case R_EXCLUDE_OPT:
632                         fexclude = true;
633                         add_fpattern(optarg, EXCL_PAT);
634                         break;
635                 case R_DINCLUDE_OPT:
636                         dinclude = true;
637                         add_dpattern(optarg, INCL_PAT);
638                         break;
639                 case R_DEXCLUDE_OPT:
640                         dexclude = true;
641                         add_dpattern(optarg, EXCL_PAT);
642                         break;
643                 case HELP_OPT:
644                 default:
645                         usage();
646                 }
647                 lastc = c;
648                 newarg = optind != prevoptind;
649                 prevoptind = optind;
650         }
651         aargc -= optind;
652         aargv += optind;
653
654         /* Empty pattern file matches nothing */
655         if (!needpattern && (patterns == 0))
656                 exit(1);
657
658         /* Fail if we don't have any pattern */
659         if (aargc == 0 && needpattern)
660                 usage();
661
662         /* Process patterns from command line */
663         if (aargc != 0 && needpattern) {
664                 char *token;
665                 char *string = *aargv;
666
667                 while ((token = strsep(&string, "\n")) != NULL)
668                         add_pattern(token, strlen(token));
669                 --aargc;
670                 ++aargv;
671         }
672
673         switch (grepbehave) {
674         case GREP_BASIC:
675                 break;
676         case GREP_FIXED:
677                 /*
678                  * regex(3) implementations that support fixed-string searches generally
679                  * define either REG_NOSPEC or REG_LITERAL. Set the appropriate flag
680                  * here. If neither are defined, GREP_FIXED later implies that the
681                  * internal literal matcher should be used. Other cflags that have
682                  * the same interpretation as REG_NOSPEC and REG_LITERAL should be
683                  * similarly added here, and grep.h should be amended to take this into
684                  * consideration when defining WITH_INTERNAL_NOSPEC.
685                  */
686 #if defined(REG_NOSPEC)
687                 cflags |= REG_NOSPEC;
688 #elif defined(REG_LITERAL)
689                 cflags |= REG_LITERAL;
690 #endif
691                 break;
692         case GREP_EXTENDED:
693                 cflags |= REG_EXTENDED;
694                 break;
695         default:
696                 /* NOTREACHED */
697                 usage();
698         }
699
700         r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
701
702         /* Don't process any patterns if we have a blank one */
703 #ifdef WITH_INTERNAL_NOSPEC
704         if (!matchall && grepbehave != GREP_FIXED) {
705 #else
706         if (!matchall) {
707 #endif
708                 /* Check if cheating is allowed (always is for fgrep). */
709                 for (i = 0; i < patterns; ++i) {
710                         c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
711                         if (c != 0) {
712                                 regerror(c, &r_pattern[i], re_error,
713                                     RE_ERROR_BUF);
714                                 errx(2, "%s", re_error);
715                         }
716                 }
717         }
718
719         if (lbflag)
720                 setlinebuf(stdout);
721
722         if ((aargc == 0 || aargc == 1) && !Hflag)
723                 hflag = true;
724
725         if (aargc == 0 && dirbehave != DIR_RECURSE)
726                 exit(!procfile("-"));
727
728         if (dirbehave == DIR_RECURSE)
729                 matched = grep_tree(aargv);
730         else
731                 for (matched = false; aargc--; ++aargv) {
732                         if ((finclude || fexclude) && !file_matching(*aargv))
733                                 continue;
734                         if (procfile(*aargv))
735                                 matched = true;
736                 }
737
738         /* Find out the correct return value according to the
739            results and the command line option. */
740         exit(matched ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
741 }