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