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