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