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