Home | History | Annotate | Line # | Download | only in grep
grep.c revision 1.2
      1  1.2  cjep /*	$NetBSD: grep.c,v 1.2 2004/05/05 14:34:55 cjep Exp $	*/
      2  1.2  cjep 
      3  1.1  cjep /*-
      4  1.1  cjep  * Copyright (c) 1999 James Howard and Dag-Erling Codan Smrgrav
      5  1.1  cjep  * All rights reserved.
      6  1.1  cjep  *
      7  1.1  cjep  * Redistribution and use in source and binary forms, with or without
      8  1.1  cjep  * modification, are permitted provided that the following conditions
      9  1.1  cjep  * are met:
     10  1.1  cjep  * 1. Redistributions of source code must retain the above copyright
     11  1.1  cjep  *    notice, this list of conditions and the following disclaimer.
     12  1.1  cjep  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  cjep  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  cjep  *    documentation and/or other materials provided with the distribution.
     15  1.1  cjep  *
     16  1.1  cjep  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  1.1  cjep  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1  cjep  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1  cjep  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  1.1  cjep  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.1  cjep  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  1.1  cjep  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  1.1  cjep  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  1.1  cjep  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  1.1  cjep  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  1.1  cjep  * SUCH DAMAGE.
     27  1.1  cjep  *
     28  1.1  cjep  */
     29  1.2  cjep 
     30  1.2  cjep 
     31  1.2  cjep 
     32  1.2  cjep #include <sys/cdefs.h>
     33  1.2  cjep #ifndef lint
     34  1.2  cjep __RCSID("$NetBSD: grep.c,v 1.2 2004/05/05 14:34:55 cjep Exp $");
     35  1.2  cjep #endif /* not lint */
     36  1.1  cjep 
     37  1.1  cjep #include <sys/types.h>
     38  1.1  cjep #include <sys/stat.h>
     39  1.1  cjep 
     40  1.1  cjep #include <err.h>
     41  1.1  cjep #include <errno.h>
     42  1.1  cjep #include <getopt.h>
     43  1.2  cjep #include <limits.h>
     44  1.1  cjep #include <regex.h>
     45  1.1  cjep #include <stdio.h>
     46  1.1  cjep #include <stdlib.h>
     47  1.1  cjep #include <string.h>
     48  1.1  cjep #include <unistd.h>
     49  1.1  cjep 
     50  1.1  cjep #include "grep.h"
     51  1.1  cjep 
     52  1.2  cjep /*
     53  1.2  cjep  * Upper bound of number of digits to represent an int in decimal
     54  1.2  cjep  *  2^8n <= 10^3n. Allow a terminator.
     55  1.2  cjep  */
     56  1.2  cjep #define MAX_BUF_DIGITS	(sizeof(int) * 3) + 1
     57  1.2  cjep 
     58  1.1  cjep /* Flags passed to regcomp() and regexec() */
     59  1.2  cjep int cflags = REG_BASIC;
     60  1.2  cjep int eflags = REG_STARTEND;
     61  1.1  cjep 
     62  1.2  cjep int matchall;	/* shortcut */
     63  1.2  cjep int patterns, pattern_sz;
     64  1.2  cjep char **pattern;
     65  1.1  cjep regex_t	*r_pattern;
     66  1.1  cjep 
     67  1.1  cjep /* For regex errors  */
     68  1.2  cjep char re_error[RE_ERROR_BUF + 1];
     69  1.1  cjep 
     70  1.1  cjep /* Command-line flags */
     71  1.2  cjep int Aflag;		/* -A x: print x lines trailing each match */
     72  1.2  cjep int Bflag;		/* -B x: print x lines leading each match */
     73  1.2  cjep int Eflag;		/* -E: interpret pattern as extended regexp */
     74  1.2  cjep int Fflag;		/* -F: interpret pattern as list of fixed strings */
     75  1.2  cjep int Gflag;		/* -G: interpret pattern as basic regexp */
     76  1.2  cjep int Hflag;		/* -H: Always print filenames */
     77  1.2  cjep int Lflag;		/* -L: only show names of files with no matches */
     78  1.2  cjep /*int Pflag;		*//* -P: if -r, no symlinks are followed */
     79  1.2  cjep /*int Sflag;		*//* -S: if -r, follow all symlinks */
     80  1.2  cjep int bflag;		/* -b: show block numbers for each match */
     81  1.2  cjep int cflag;		/* -c: only show a count of matching lines */
     82  1.2  cjep int hflag;		/* -h: Never print filenames. -H overrides */
     83  1.2  cjep int lflag;		/* -l: only show names of files with matches */
     84  1.2  cjep int mflag;		/* -m: specify maximum line matches (per file) */
     85  1.2  cjep int nflag;		/* -n: show line numbers in front of matching lines */
     86  1.2  cjep int oflag;		/* -o: only print out matches */
     87  1.2  cjep int qflag;		/* -q: quiet mode (don't output anything) */
     88  1.2  cjep int sflag;		/* -s: silent mode (ignore errors) */
     89  1.2  cjep int vflag;		/* -v: only show non-matching lines */
     90  1.2  cjep int wflag;		/* -w: pattern must start and end on word boundaries */
     91  1.2  cjep int xflag;		/* -x: pattern must match entire line */
     92  1.2  cjep int lbflag;		/* --line-buffered */
     93  1.2  cjep 
     94  1.2  cjep int colours = 0;	/* Attempt to use terminal colours */
     95  1.2  cjep const char *grep_colour = "01;32"; /* Default colour string, green */
     96  1.2  cjep char *uc;
     97  1.2  cjep 
     98  1.2  cjep /* Characters to print after filenames */
     99  1.2  cjep char fn_endchar = '\n';
    100  1.2  cjep char fn_colonchar = ':';
    101  1.2  cjep char fn_dashchar = '-';
    102  1.2  cjep char line_endchar = '\n';	/* End of line character */
    103  1.2  cjep 
    104  1.2  cjep int maxcount = 0;		/* Maximum line matches per file */
    105  1.2  cjep int output_filenames = 0;
    106  1.2  cjep 
    107  1.2  cjep /* Argv[0] flags */
    108  1.2  cjep int zgrep;		/* If we are invoked as zgrep */
    109  1.2  cjep 
    110  1.2  cjep int binbehave = BIN_FILE_BIN;
    111  1.2  cjep int dirbehave = GREP_READ;
    112  1.2  cjep int devbehave = GREP_READ;
    113  1.2  cjep /*int linkbehave = LINK_FOLLOW;*/
    114  1.2  cjep char *stdin_label;
    115  1.2  cjep 
    116  1.2  cjep enum {
    117  1.2  cjep 	BIN_OPT = CHAR_MAX + 1,
    118  1.2  cjep 	HELP_OPT,
    119  1.2  cjep 	LABEL_OPT,
    120  1.2  cjep 	MMAP_OPT,
    121  1.2  cjep 	LINK_OPT,
    122  1.2  cjep 	COLOUR_OPT,
    123  1.2  cjep 	LINEBUF_OPT
    124  1.2  cjep };
    125  1.1  cjep 
    126  1.1  cjep /* Housekeeping */
    127  1.2  cjep int first;		/* flag whether or not this is our first match */
    128  1.2  cjep int tail;		/* lines left to print */
    129  1.1  cjep 
    130  1.1  cjep static void
    131  1.1  cjep usage(void)
    132  1.1  cjep {
    133  1.1  cjep 	fprintf(stderr, "usage: %s %s %s\n",
    134  1.2  cjep 		getprogname(),
    135  1.2  cjep 		"[-[ABC] num] [-EFGHILVZabcdhilnoqrsvwxz]",
    136  1.2  cjep 		"[-D action] [-d action] [-e pattern] [-f file]");
    137  1.1  cjep 	exit(2);
    138  1.1  cjep }
    139  1.1  cjep 
    140  1.2  cjep static char *optstr = "0123456789A:B:C:D:EFGHILUVZabcd:e:f:hilm:noqrsuvwxyz";
    141  1.1  cjep 
    142  1.2  cjep struct option long_options[] =
    143  1.1  cjep {
    144  1.2  cjep 	{"binary-files",	required_argument, NULL, BIN_OPT},
    145  1.2  cjep 	{"help",		no_argument, 	   NULL, HELP_OPT},
    146  1.2  cjep 	{"label",		required_argument, NULL, LABEL_OPT},
    147  1.2  cjep 	{"mmap",		no_argument, 	   NULL, MMAP_OPT},
    148  1.2  cjep 	{"line-buffered",	no_argument, 	   NULL, LINEBUF_OPT},
    149  1.2  cjep /*	{"links",		required_argument, NULL, LINK_OPT},*/
    150  1.1  cjep 	{"after-context",       required_argument, NULL, 'A'},
    151  1.1  cjep 	{"before-context",      required_argument, NULL, 'B'},
    152  1.2  cjep 	{"color",		optional_argument, NULL, COLOUR_OPT},
    153  1.2  cjep 	{"colour",		optional_argument, NULL, COLOUR_OPT},
    154  1.1  cjep 	{"context",             optional_argument, NULL, 'C'},
    155  1.2  cjep 	{"devices",		required_argument, NULL, 'D'},
    156  1.2  cjep 	{"extended-regexp",     no_argument,       NULL, 'E'},
    157  1.2  cjep 	{"fixed-strings",       no_argument,       NULL, 'F'},
    158  1.2  cjep 	{"fixed-regexp",	no_argument,       NULL, 'F'},
    159  1.2  cjep 	{"basic-regexp",        no_argument,       NULL, 'G'},
    160  1.2  cjep 	{"with-filename",	no_argument,	   NULL, 'H'},
    161  1.2  cjep 	{"files-without-match", no_argument,       NULL, 'L'},
    162  1.2  cjep 	{"binary",              no_argument,       NULL, 'U'},
    163  1.1  cjep 	{"version",             no_argument,       NULL, 'V'},
    164  1.2  cjep 	{"null",		no_argument,	   NULL, 'Z'},
    165  1.2  cjep 	{"text",                no_argument,       NULL, 'a'},
    166  1.1  cjep 	{"byte-offset",         no_argument,       NULL, 'b'},
    167  1.1  cjep 	{"count",               no_argument,       NULL, 'c'},
    168  1.2  cjep 	{"directories",		required_argument, NULL, 'd'},
    169  1.1  cjep 	{"regexp",              required_argument, NULL, 'e'},
    170  1.1  cjep 	{"file",                required_argument, NULL, 'f'},
    171  1.1  cjep 	{"no-filename",         no_argument,       NULL, 'h'},
    172  1.1  cjep 	{"ignore-case",         no_argument,       NULL, 'i'},
    173  1.1  cjep 	{"files-with-matches",  no_argument,       NULL, 'l'},
    174  1.2  cjep 	{"max-count",		required_argument, NULL, 'm'},
    175  1.1  cjep 	{"line-number",         no_argument,       NULL, 'n'},
    176  1.2  cjep 	{"only-matching",	no_argument,	   NULL, 'o'},
    177  1.1  cjep 	{"quiet",               no_argument,       NULL, 'q'},
    178  1.1  cjep 	{"silent",              no_argument,       NULL, 'q'},
    179  1.1  cjep 	{"recursive",           no_argument,       NULL, 'r'},
    180  1.1  cjep 	{"no-messages",         no_argument,       NULL, 's'},
    181  1.2  cjep 	{"unix-byte-offsets",   no_argument,       NULL, 'u'},
    182  1.2  cjep 	{"invert-match",        no_argument,       NULL, 'v'},
    183  1.1  cjep 	{"word-regexp",         no_argument,       NULL, 'w'},
    184  1.1  cjep 	{"line-regexp",         no_argument,       NULL, 'x'},
    185  1.2  cjep 	{"null-data",		no_argument,	   NULL, 'z'},
    186  1.2  cjep 
    187  1.1  cjep 	{NULL,                  no_argument,       NULL, 0}
    188  1.1  cjep };
    189  1.1  cjep 
    190  1.1  cjep static void
    191  1.1  cjep add_pattern(char *pat, size_t len)
    192  1.1  cjep {
    193  1.1  cjep 	if (len == 0 || matchall) {
    194  1.1  cjep 		matchall = 1;
    195  1.1  cjep 		return;
    196  1.1  cjep 	}
    197  1.1  cjep 	if (patterns == pattern_sz) {
    198  1.1  cjep 		pattern_sz *= 2;
    199  1.2  cjep 		pattern = grep_realloc(pattern, ++pattern_sz * sizeof(*pattern));
    200  1.1  cjep 	}
    201  1.2  cjep 	if (pat[len - 1] == '\n')
    202  1.1  cjep 		--len;
    203  1.2  cjep 	pattern[patterns] = grep_malloc(len + 1);
    204  1.1  cjep 	strncpy(pattern[patterns], pat, len);
    205  1.1  cjep 	pattern[patterns][len] = '\0';
    206  1.1  cjep 	++patterns;
    207  1.1  cjep }
    208  1.1  cjep 
    209  1.1  cjep static void
    210  1.1  cjep read_patterns(char *fn)
    211  1.1  cjep {
    212  1.1  cjep 	FILE *f;
    213  1.1  cjep 	char *line;
    214  1.1  cjep 	size_t len;
    215  1.1  cjep 	int nl;
    216  1.1  cjep 
    217  1.1  cjep 	if ((f = fopen(fn, "r")) == NULL)
    218  1.2  cjep 		err(2, "%s", fn);
    219  1.1  cjep 	nl = 0;
    220  1.1  cjep 	while ((line = fgetln(f, &len)) != NULL) {
    221  1.1  cjep 		if (*line == '\n') {
    222  1.1  cjep 			++nl;
    223  1.1  cjep 			continue;
    224  1.1  cjep 		}
    225  1.1  cjep 		if (nl) {
    226  1.1  cjep 			matchall = 1;
    227  1.1  cjep 			break;
    228  1.1  cjep 		}
    229  1.1  cjep 		nl = 0;
    230  1.1  cjep 		add_pattern(line, len);
    231  1.1  cjep 	}
    232  1.1  cjep 	if (ferror(f))
    233  1.2  cjep 		err(2, "%s", fn);
    234  1.1  cjep 	fclose(f);
    235  1.1  cjep }
    236  1.1  cjep 
    237  1.2  cjep static int
    238  1.2  cjep check_context_arg(char const *str) {
    239  1.2  cjep 	char *ep;
    240  1.2  cjep 	long lval;
    241  1.2  cjep 
    242  1.2  cjep 	errno = 0;
    243  1.2  cjep 	lval = strtol(str, &ep, 10);
    244  1.2  cjep 
    245  1.2  cjep 	if (str[0] == '\0' || *ep != '\0')
    246  1.2  cjep 		errx(2, "Invalid context argument");
    247  1.2  cjep 
    248  1.2  cjep 	if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) ||
    249  1.2  cjep  	    (lval > INT_MAX || lval < INT_MIN))
    250  1.2  cjep 		errx(2, "Context argument out of range");
    251  1.2  cjep 
    252  1.2  cjep 	return lval;
    253  1.2  cjep 
    254  1.2  cjep }
    255  1.2  cjep 
    256  1.2  cjep static int
    257  1.2  cjep grep_getopt(int argc, char *const *argv)
    258  1.2  cjep {
    259  1.2  cjep 	int c, ptr;
    260  1.2  cjep 	char buffer[MAX_BUF_DIGITS];
    261  1.2  cjep 
    262  1.2  cjep 	ptr = 0;
    263  1.2  cjep 	while (c = getopt_long(argc, argv, optstr, long_options,
    264  1.2  cjep 		(int *)NULL), '0' <= c &&
    265  1.2  cjep 		c <= '9' && ptr < MAX_BUF_DIGITS) {
    266  1.2  cjep 
    267  1.2  cjep 		/* Avoid leading zeros */
    268  1.2  cjep 		if (ptr != 0 || (ptr == 0 && c != '0'))
    269  1.2  cjep 			buffer[ptr++] = c;
    270  1.2  cjep 	}
    271  1.2  cjep 
    272  1.2  cjep 	if (ptr >= MAX_BUF_DIGITS)
    273  1.2  cjep 		errx(2, "Context argument out of range");
    274  1.2  cjep 
    275  1.2  cjep 	if (ptr) {
    276  1.2  cjep 		buffer[ptr] = '\0';	/* We now have a string of digits */
    277  1.2  cjep 		Aflag = Bflag = check_context_arg(buffer);
    278  1.2  cjep 	}
    279  1.2  cjep 
    280  1.2  cjep 	return c;
    281  1.2  cjep }
    282  1.2  cjep 
    283  1.1  cjep int
    284  1.1  cjep main(int argc, char *argv[])
    285  1.1  cjep {
    286  1.2  cjep 	const char *progname;
    287  1.1  cjep 	int c, i;
    288  1.2  cjep 	struct stat sb;
    289  1.2  cjep 
    290  1.2  cjep 	stdin_label = "(standard input)";
    291  1.1  cjep 
    292  1.2  cjep 	progname = getprogname();
    293  1.2  cjep 	switch (progname[0]) {
    294  1.2  cjep 	case 'e':
    295  1.2  cjep 		Eflag++;
    296  1.2  cjep 		break;
    297  1.2  cjep 	case 'f':
    298  1.2  cjep 		Fflag++;
    299  1.2  cjep 		break;
    300  1.2  cjep 	case 'g':
    301  1.2  cjep 		Gflag++;
    302  1.2  cjep 		break;
    303  1.2  cjep 	case 'z':
    304  1.2  cjep 		zgrep++;
    305  1.2  cjep 		switch (progname[1]) {
    306  1.2  cjep 		case 'e':
    307  1.2  cjep 			Eflag++;
    308  1.2  cjep 			break;
    309  1.2  cjep 		case 'f':
    310  1.2  cjep 			Fflag++;
    311  1.2  cjep 			break;
    312  1.2  cjep 		case 'g':
    313  1.2  cjep 			Gflag++;
    314  1.2  cjep 			break;
    315  1.2  cjep 		}
    316  1.2  cjep 		break;
    317  1.2  cjep 	}
    318  1.2  cjep 
    319  1.2  cjep 	while ((c = grep_getopt(argc, argv)) != -1) {
    320  1.1  cjep 
    321  1.1  cjep 		switch (c) {
    322  1.2  cjep 
    323  1.1  cjep 		case 'A':
    324  1.2  cjep 			Aflag = check_context_arg(optarg);
    325  1.1  cjep 			break;
    326  1.1  cjep 		case 'B':
    327  1.2  cjep 			Bflag = check_context_arg(optarg);
    328  1.1  cjep 			break;
    329  1.1  cjep 		case 'C':
    330  1.1  cjep 			if (optarg == NULL)
    331  1.1  cjep 				Aflag = Bflag = 2;
    332  1.1  cjep 			else
    333  1.2  cjep 				Aflag = Bflag = check_context_arg(optarg);
    334  1.2  cjep 			break;
    335  1.2  cjep 		case 'D':
    336  1.2  cjep 			if (strcmp("read", optarg) == 0)
    337  1.2  cjep 				devbehave = GREP_READ;
    338  1.2  cjep 			else if (strcmp("skip", optarg) == 0)
    339  1.2  cjep 				devbehave = GREP_SKIP;
    340  1.2  cjep 			else {
    341  1.2  cjep 				 errx(2, "Unknown device option");
    342  1.2  cjep 			}
    343  1.1  cjep 			break;
    344  1.2  cjep 
    345  1.1  cjep 		case 'E':
    346  1.2  cjep 			Fflag = Gflag = 0;
    347  1.1  cjep 			Eflag++;
    348  1.1  cjep 			break;
    349  1.1  cjep 		case 'F':
    350  1.2  cjep 			Eflag = Gflag = 0;
    351  1.1  cjep 			Fflag++;
    352  1.1  cjep 			break;
    353  1.1  cjep 		case 'G':
    354  1.2  cjep 			Eflag = Fflag = 0;
    355  1.1  cjep 			Gflag++;
    356  1.1  cjep 			break;
    357  1.1  cjep 		case 'H':
    358  1.2  cjep 			Hflag = 1;
    359  1.2  cjep 			break;
    360  1.2  cjep 		case 'I':
    361  1.2  cjep 			binbehave = BIN_FILE_SKIP;
    362  1.1  cjep 			break;
    363  1.1  cjep 		case 'L':
    364  1.1  cjep 			lflag = 0;
    365  1.1  cjep 			Lflag = qflag = 1;
    366  1.1  cjep 			break;
    367  1.2  cjep /*		case 'P':
    368  1.2  cjep 			linkbehave = LINK_SKIP;
    369  1.1  cjep 			break;
    370  1.1  cjep 		case 'S':
    371  1.2  cjep 			linkbehave = LINK_FOLLOW;
    372  1.2  cjep 			break;*/
    373  1.1  cjep 		case 'R':
    374  1.1  cjep 		case 'r':
    375  1.2  cjep 			dirbehave = GREP_RECURSE;
    376  1.1  cjep 			break;
    377  1.1  cjep 		case 'U':
    378  1.1  cjep 		case 'u':
    379  1.1  cjep 			/* these are here for compatability */
    380  1.1  cjep 			break;
    381  1.1  cjep 		case 'V':
    382  1.2  cjep 			fprintf(stdout, "grep version %s\n", VERSION);
    383  1.2  cjep 			exit(0);
    384  1.1  cjep 			break;
    385  1.1  cjep 		case 'Z':
    386  1.2  cjep 			fn_colonchar = fn_endchar = fn_dashchar = 0;
    387  1.1  cjep 			break;
    388  1.1  cjep 		case 'a':
    389  1.2  cjep 			binbehave = BIN_FILE_TEXT;
    390  1.1  cjep 			break;
    391  1.1  cjep 		case 'b':
    392  1.1  cjep 			bflag = 1;
    393  1.1  cjep 			break;
    394  1.1  cjep 		case 'c':
    395  1.1  cjep 			cflag = 1;
    396  1.1  cjep 			break;
    397  1.2  cjep 		case 'd':
    398  1.2  cjep 			if (strcmp("read", optarg) == 0)
    399  1.2  cjep 				dirbehave = GREP_READ;
    400  1.2  cjep 			else if (strcmp("skip", optarg) == 0)
    401  1.2  cjep 				dirbehave = GREP_SKIP;
    402  1.2  cjep 			else if (strcmp("recurse", optarg) == 0)
    403  1.2  cjep 				dirbehave = GREP_RECURSE;
    404  1.2  cjep 			else {
    405  1.2  cjep 				errx(2, "Unknown directory option\n");
    406  1.2  cjep 			}
    407  1.2  cjep 			break;
    408  1.2  cjep 
    409  1.1  cjep 		case 'e':
    410  1.1  cjep 			add_pattern(optarg, strlen(optarg));
    411  1.1  cjep 			break;
    412  1.1  cjep 		case 'f':
    413  1.1  cjep 			read_patterns(optarg);
    414  1.1  cjep 			break;
    415  1.1  cjep 		case 'h':
    416  1.1  cjep 			hflag = 1;
    417  1.1  cjep 			break;
    418  1.1  cjep 		case 'i':
    419  1.1  cjep 		case 'y':
    420  1.1  cjep 			cflags |= REG_ICASE;
    421  1.1  cjep 			break;
    422  1.1  cjep 		case 'l':
    423  1.1  cjep 			Lflag = 0;
    424  1.1  cjep 			lflag = qflag = 1;
    425  1.1  cjep 			break;
    426  1.2  cjep 		case 'm':
    427  1.2  cjep 			mflag = 1;
    428  1.2  cjep 			maxcount = strtol(optarg, (char **)NULL, 10);
    429  1.2  cjep 			break;
    430  1.1  cjep 		case 'n':
    431  1.1  cjep 			nflag = 1;
    432  1.1  cjep 			break;
    433  1.1  cjep 		case 'o':
    434  1.1  cjep 			oflag = 1;
    435  1.1  cjep 			break;
    436  1.1  cjep 		case 'q':
    437  1.1  cjep 			qflag = 1;
    438  1.1  cjep 			break;
    439  1.1  cjep 		case 's':
    440  1.1  cjep 			sflag = 1;
    441  1.1  cjep 			break;
    442  1.1  cjep 		case 'v':
    443  1.1  cjep 			vflag = 1;
    444  1.1  cjep 			break;
    445  1.1  cjep 		case 'w':
    446  1.1  cjep 			wflag = 1;
    447  1.1  cjep 			break;
    448  1.1  cjep 		case 'x':
    449  1.1  cjep 			xflag = 1;
    450  1.1  cjep 			break;
    451  1.2  cjep 		case 'z':
    452  1.2  cjep 			line_endchar = 0;
    453  1.2  cjep 			break;
    454  1.2  cjep 		case BIN_OPT:
    455  1.2  cjep 			if (strcmp("binary", optarg) == 0)
    456  1.2  cjep 				binbehave = BIN_FILE_BIN;
    457  1.2  cjep 			else if (strcmp("without-match", optarg) == 0)
    458  1.2  cjep 				binbehave = BIN_FILE_SKIP;
    459  1.2  cjep 			else if (strcmp("text", optarg) == 0)
    460  1.2  cjep 				binbehave = BIN_FILE_TEXT;
    461  1.2  cjep 			else {
    462  1.2  cjep                                 errx(2, "Unknown binary-files option\n");
    463  1.2  cjep 			}
    464  1.2  cjep                         break;
    465  1.2  cjep 
    466  1.2  cjep 		case COLOUR_OPT:
    467  1.2  cjep 			if (optarg == NULL || strcmp("auto", optarg) == 0 ||
    468  1.2  cjep 			      strcmp("tty", optarg) == 0 ||
    469  1.2  cjep 			      strcmp("if-tty", optarg) == 0) {
    470  1.2  cjep 
    471  1.2  cjep 				/* Check that stdout is a terminal */
    472  1.2  cjep 				if (isatty(STDOUT_FILENO) &&
    473  1.2  cjep 					getenv("TERM") &&
    474  1.2  cjep 					strcmp(getenv("TERM"), "dumb") != 0)
    475  1.2  cjep 						colours = 1;
    476  1.2  cjep 				else
    477  1.2  cjep 					colours = 0;
    478  1.2  cjep 
    479  1.2  cjep 			} else if (strcmp("always", optarg) == 0 ||
    480  1.2  cjep 				   strcmp("yes", optarg) == 0 ||
    481  1.2  cjep 				   strcmp("force", optarg) == 0)
    482  1.2  cjep 				colours = 1;
    483  1.2  cjep 			else if (strcmp("never", optarg) == 0 ||
    484  1.2  cjep 				 strcmp("no", optarg) == 0 ||
    485  1.2  cjep 				 strcmp("none", optarg) == 0)
    486  1.2  cjep 				colours = 0;
    487  1.2  cjep 			else
    488  1.2  cjep 				errx(2, "Unknown color option\n");
    489  1.2  cjep 
    490  1.2  cjep 			uc = getenv("GREP_COLOR");
    491  1.2  cjep 			if (colours == 1 && uc != NULL && *uc != '\0')
    492  1.2  cjep 				grep_colour = uc;
    493  1.2  cjep 			break;
    494  1.2  cjep 		case LABEL_OPT:
    495  1.2  cjep 			stdin_label = optarg;
    496  1.2  cjep 			break;
    497  1.2  cjep 		case MMAP_OPT:
    498  1.2  cjep 			break;
    499  1.2  cjep /*
    500  1.2  cjep  * 		case LINK_OPT:
    501  1.2  cjep  * 			if (strcmp("explicit", optarg) == 0)
    502  1.2  cjep  * 				linkbehave = LINK_EXPLICIT;
    503  1.2  cjep  * 			else if (strcmp("follow", optarg) == 0)
    504  1.2  cjep  * 				linkbehave = LINK_FOLLOW;
    505  1.2  cjep  * 			else if (strcmp("skip", optarg) == 0)
    506  1.2  cjep  * 				linkbehave = LINK_SKIP;
    507  1.2  cjep  *                         else {
    508  1.2  cjep  *                                 errx(2, "Unknown links option\n");
    509  1.2  cjep  * 			}
    510  1.2  cjep  *                         break;
    511  1.2  cjep  */
    512  1.2  cjep 		case LINEBUF_OPT:
    513  1.2  cjep 			lbflag = 1;
    514  1.2  cjep 			break;
    515  1.2  cjep 
    516  1.2  cjep 		case HELP_OPT:
    517  1.1  cjep 		default:
    518  1.1  cjep 			usage();
    519  1.1  cjep 		}
    520  1.2  cjep 
    521  1.1  cjep 	}
    522  1.2  cjep 
    523  1.1  cjep 	argc -= optind;
    524  1.1  cjep 	argv += optind;
    525  1.1  cjep 
    526  1.1  cjep 	if (argc == 0 && patterns == 0)
    527  1.1  cjep 		usage();
    528  1.1  cjep 	if (patterns == 0) {
    529  1.1  cjep 		add_pattern(*argv, strlen(*argv));
    530  1.1  cjep 		--argc;
    531  1.1  cjep 		++argv;
    532  1.1  cjep 	}
    533  1.1  cjep 
    534  1.2  cjep 	if (Eflag)
    535  1.2  cjep 		cflags |= REG_EXTENDED;
    536  1.2  cjep 	else if (Fflag)
    537  1.2  cjep 		cflags |= REG_NOSPEC;
    538  1.2  cjep 	r_pattern = grep_malloc(patterns * sizeof(*r_pattern));
    539  1.1  cjep 	for (i = 0; i < patterns; ++i) {
    540  1.1  cjep 		if ((c = regcomp(&r_pattern[i], pattern[i], cflags))) {
    541  1.1  cjep 			regerror(c, &r_pattern[i], re_error, RE_ERROR_BUF);
    542  1.2  cjep 			errx(2, "%s", re_error);
    543  1.1  cjep 		}
    544  1.1  cjep 	}
    545  1.1  cjep 
    546  1.2  cjep 	if ((argc > 1 && !hflag) || Hflag)
    547  1.2  cjep 		output_filenames = 1;
    548  1.1  cjep 
    549  1.2  cjep 	if (argc == 1 && !hflag && dirbehave == GREP_RECURSE)
    550  1.2  cjep 		if (!stat(*argv, &sb) && (sb.st_mode & S_IFMT) == S_IFDIR)
    551  1.2  cjep 			output_filenames = 1;
    552  1.2  cjep 
    553  1.1  cjep 	if (argc == 0)
    554  1.1  cjep 		exit(!procfile(NULL));
    555  1.2  cjep 
    556  1.2  cjep 	if (lbflag)
    557  1.2  cjep 		setlinebuf(stdout);
    558  1.2  cjep 
    559  1.2  cjep 	if (dirbehave == GREP_RECURSE)
    560  1.1  cjep 		c = grep_tree(argv);
    561  1.1  cjep 	else
    562  1.1  cjep 		for (c = 0; argc--; ++argv)
    563  1.1  cjep 			c += procfile(*argv);
    564  1.1  cjep 
    565  1.1  cjep 	exit(!c);
    566  1.1  cjep }
    567