grep.c revision 141847
153451Speter/* grep.c - main driver file for grep.
2126435Sache   Copyright 1992, 1997-1999, 2000 Free Software Foundation, Inc.
353451Speter
453451Speter   This program is free software; you can redistribute it and/or modify
553451Speter   it under the terms of the GNU General Public License as published by
653451Speter   the Free Software Foundation; either version 2, or (at your option)
753451Speter   any later version.
853451Speter
953451Speter   This program is distributed in the hope that it will be useful,
1053451Speter   but WITHOUT ANY WARRANTY; without even the implied warranty of
1153451Speter   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1253451Speter   GNU General Public License for more details.
1353451Speter
1453451Speter   You should have received a copy of the GNU General Public License
1553451Speter   along with this program; if not, write to the Free Software
1653477Sobrien   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1753477Sobrien   02111-1307, USA.  */
1853451Speter
1953477Sobrien/* Written July 1992 by Mike Haertel.  */
2053477Sobrien/* Builtin decompression 1997 by Wolfram Schneider <wosch@FreeBSD.org>.  */
2153451Speter
2253477Sobrien/* $FreeBSD: head/gnu/usr.bin/grep/grep.c 141847 2005-02-13 23:07:30Z obrien $ */
2353451Speter
2453477Sobrien#ifdef HAVE_CONFIG_H
2553477Sobrien# include <config.h>
2653451Speter#endif
2753451Speter#include <sys/types.h>
2853477Sobrien#include <sys/stat.h>
2953477Sobrien#if defined(HAVE_MMAP)
3053477Sobrien# include <sys/mman.h>
3153451Speter#endif
3253477Sobrien#if defined(HAVE_SETRLIMIT)
3353477Sobrien# include <sys/time.h>
3453477Sobrien# include <sys/resource.h>
3553451Speter#endif
36131564Stjr#if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H && defined HAVE_MBRTOWC
37131564Stjr/* We can handle multibyte string.  */
38131564Stjr# define MBS_SUPPORT
39131564Stjr# include <wchar.h>
40131564Stjr# include <wctype.h>
41131564Stjr#endif
4253477Sobrien#include <stdio.h>
4353477Sobrien#include "system.h"
4453477Sobrien#include "getopt.h"
4553451Speter#include "getpagesize.h"
4653451Speter#include "grep.h"
4753477Sobrien#include "savedir.h"
48131557Stjr#include "xstrtol.h"
49131557Stjr#include "xalloc.h"
50131557Stjr#include "error.h"
51131557Stjr#include "exclude.h"
52131557Stjr#include "closeout.h"
5353451Speter
5453451Speter#undef MAX
5553451Speter#define MAX(A,B) ((A) > (B) ? (A) : (B))
5653451Speter
5753477Sobrienstruct stats
5853477Sobrien{
59131557Stjr  struct stats const *parent;
6053477Sobrien  struct stat stat;
6153477Sobrien};
6253451Speter
6353477Sobrien/* base of chain of stat buffers, used to detect directory loops */
6453477Sobrienstatic struct stats stats_base;
6553451Speter
6653477Sobrien/* if non-zero, display usage information and exit */
6753477Sobrienstatic int show_help;
6853451Speter
6953477Sobrien/* If non-zero, print the version on standard output and exit.  */
7053477Sobrienstatic int show_version;
7153451Speter
72131557Stjr/* If nonzero, suppress diagnostics for nonexistent or unreadable files.  */
73131557Stjrstatic int suppress_errors;
74131557Stjr
7555379Sobrien/* If nonzero, use mmap if possible.  */
7655379Sobrienstatic int mmap_option;
7755379Sobrien
7855404Sru/* If zero, output nulls after filenames.  */
7955404Srustatic int filename_mask;
8055404Sru
81131557Stjr/* If nonzero, use grep_color marker.  */
82131557Stjrstatic int color_option;
83131557Stjr
84131557Stjr/* If nonzero, show only the part of a line matching the expression. */
85131557Stjrstatic int only_matching;
86131557Stjr
87131557Stjr/* The color string used.  The user can overwrite it using the environment
88131557Stjr   variable GREP_COLOR.  The default is to print red.  */
89131557Stjrstatic const char *grep_color = "01;31";
90131557Stjr
91131557Stjrstatic struct exclude *excluded_patterns;
92131557Stjrstatic struct exclude *included_patterns;
9355379Sobrien/* Short options.  */
9455379Sobrienstatic char const short_options[] =
95131557Stjr"0123456789A:B:C:D:EFGHIJPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz";
9655379Sobrien
9756233Sru/* Non-boolean long options that have no corresponding short equivalents.  */
9856233Sruenum
9956233Sru{
100131557Stjr  BINARY_FILES_OPTION = CHAR_MAX + 1,
101131557Stjr  COLOR_OPTION,
102131557Stjr  INCLUDE_OPTION,
103131557Stjr  EXCLUDE_OPTION,
104131557Stjr  EXCLUDE_FROM_OPTION,
105131557Stjr  LINE_BUFFERED_OPTION,
106131557Stjr  LABEL_OPTION
10756233Sru};
10856233Sru
10953477Sobrien/* Long options equivalences. */
110131557Stjrstatic struct option const long_options[] =
11153477Sobrien{
11253477Sobrien  {"after-context", required_argument, NULL, 'A'},
11353477Sobrien  {"basic-regexp", no_argument, NULL, 'G'},
11453477Sobrien  {"before-context", required_argument, NULL, 'B'},
11556233Sru  {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},
11653477Sobrien  {"byte-offset", no_argument, NULL, 'b'},
117131557Stjr  {"context", required_argument, NULL, 'C'},
118131557Stjr  {"color", optional_argument, NULL, COLOR_OPTION},
119131557Stjr  {"colour", optional_argument, NULL, COLOR_OPTION},
12053477Sobrien  {"count", no_argument, NULL, 'c'},
121131557Stjr  {"devices", required_argument, NULL, 'D'},
12253477Sobrien  {"directories", required_argument, NULL, 'd'},
12353477Sobrien  {"extended-regexp", no_argument, NULL, 'E'},
124131557Stjr  {"exclude", required_argument, NULL, EXCLUDE_OPTION},
125131557Stjr  {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION},
12653477Sobrien  {"file", required_argument, NULL, 'f'},
12753477Sobrien  {"files-with-matches", no_argument, NULL, 'l'},
12853477Sobrien  {"files-without-match", no_argument, NULL, 'L'},
12953477Sobrien  {"fixed-regexp", no_argument, NULL, 'F'},
13053477Sobrien  {"fixed-strings", no_argument, NULL, 'F'},
13153477Sobrien  {"help", no_argument, &show_help, 1},
132131557Stjr  {"include", required_argument, NULL, INCLUDE_OPTION},
13353477Sobrien  {"ignore-case", no_argument, NULL, 'i'},
134131557Stjr  {"label", required_argument, NULL, LABEL_OPTION},
135131557Stjr  {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION},
13653477Sobrien  {"line-number", no_argument, NULL, 'n'},
13753477Sobrien  {"line-regexp", no_argument, NULL, 'x'},
138131557Stjr  {"max-count", required_argument, NULL, 'm'},
13955379Sobrien  {"mmap", no_argument, &mmap_option, 1},
14053477Sobrien  {"no-filename", no_argument, NULL, 'h'},
14153477Sobrien  {"no-messages", no_argument, NULL, 's'},
142103372Sobrien  {"bz2decompress", no_argument, NULL, 'J'},
14355379Sobrien#if HAVE_LIBZ > 0
14455404Sru  {"decompress", no_argument, NULL, 'Z'},
14555404Sru  {"null", no_argument, &filename_mask, 0},
14655379Sobrien#else
14755379Sobrien  {"null", no_argument, NULL, 'Z'},
14855379Sobrien#endif
14955379Sobrien  {"null-data", no_argument, NULL, 'z'},
150131557Stjr  {"only-matching", no_argument, NULL, 'o'},
151131557Stjr  {"perl-regexp", no_argument, NULL, 'P'},
15253477Sobrien  {"quiet", no_argument, NULL, 'q'},
15353477Sobrien  {"recursive", no_argument, NULL, 'r'},
154131557Stjr  {"recursive", no_argument, NULL, 'R'},
15553477Sobrien  {"regexp", required_argument, NULL, 'e'},
15655379Sobrien  {"invert-match", no_argument, NULL, 'v'},
15753477Sobrien  {"silent", no_argument, NULL, 'q'},
15853477Sobrien  {"text", no_argument, NULL, 'a'},
15953477Sobrien  {"binary", no_argument, NULL, 'U'},
16053477Sobrien  {"unix-byte-offsets", no_argument, NULL, 'u'},
16153477Sobrien  {"version", no_argument, NULL, 'V'},
16253477Sobrien  {"with-filename", no_argument, NULL, 'H'},
16353477Sobrien  {"word-regexp", no_argument, NULL, 'w'},
16453477Sobrien  {0, 0, 0, 0}
16553477Sobrien};
16653451Speter
16753451Speter/* Define flags declared in grep.h. */
16853451Speterint match_icase;
16953451Speterint match_words;
17053451Speterint match_lines;
17155379Sobrienunsigned char eolbyte;
17253451Speter
17353451Speter/* For error messages. */
174131557Stjr/* The name the program was run with, stripped of any leading path. */
175131557Stjrchar *program_name;
17653477Sobrienstatic char const *filename;
17753451Speterstatic int errseen;
17853451Speter
17953477Sobrien/* How to handle directories.  */
18053477Sobrienstatic enum
18153477Sobrien  {
18253477Sobrien    READ_DIRECTORIES,
18353477Sobrien    RECURSE_DIRECTORIES,
18453477Sobrien    SKIP_DIRECTORIES
185131557Stjr  } directories = READ_DIRECTORIES;
18653477Sobrien
187131557Stjr/* How to handle devices. */
188131557Stjrstatic enum
189131557Stjr  {
190131557Stjr    READ_DEVICES,
191131557Stjr    SKIP_DEVICES
192131557Stjr  } devices = READ_DEVICES;
193131557Stjr
194131557Stjrstatic int grepdir PARAMS ((char const *, struct stats const *));
195131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
19653477Sobrienstatic inline int undossify_input PARAMS ((register char *, size_t));
19753477Sobrien#endif
19853477Sobrien
19953477Sobrien/* Functions we'll use to search. */
200131557Stjrstatic void (*compile) PARAMS ((char const *, size_t));
201131576Stjrstatic size_t (*execute) PARAMS ((char const *, size_t, struct mb_cache *,
202131576Stjr				  size_t *, int));
20353477Sobrien
204131557Stjr/* Like error, but suppress the diagnostic if requested.  */
20553451Speterstatic void
206131557Stjrsuppressible_error (char const *mesg, int errnum)
20753451Speter{
208131557Stjr  if (! suppress_errors)
209131557Stjr    error (0, errnum, "%s", mesg);
21053451Speter  errseen = 1;
21153451Speter}
21253451Speter
21353477Sobrien/* Convert STR to a positive integer, storing the result in *OUT.
214131557Stjr   STR must be a valid context length argument; report an error if it
215131557Stjr   isn't.  */
216131557Stjrstatic void
217131557Stjrcontext_length_arg (char const *str, int *out)
21853477Sobrien{
219131557Stjr  uintmax_t value;
220131557Stjr  if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK
221131557Stjr	 && 0 <= (*out = value)
222131557Stjr	 && *out == value))
223131557Stjr    {
224131557Stjr      error (2, 0, "%s: %s\n", str, _("invalid context length argument"));
225131557Stjr    }
22653477Sobrien}
22753477Sobrien
22853477Sobrien
22953451Speter/* Hairy buffering mechanism for grep.  The intent is to keep
23053451Speter   all reads aligned on a page boundary and multiples of the
231131557Stjr   page size, unless a read yields a partial page.  */
23253451Speter
23353451Speterstatic char *buffer;		/* Base of buffer. */
234131557Stjrstatic size_t bufalloc;		/* Allocated buffer size, counting slop. */
235131557Stjr#define INITIAL_BUFSIZE 32768	/* Initial buffer size, not counting slop. */
23653451Speterstatic int bufdesc;		/* File descriptor. */
23753451Speterstatic char *bufbeg;		/* Beginning of user-visible stuff. */
23853451Speterstatic char *buflim;		/* Limit of user-visible stuff. */
23953477Sobrienstatic size_t pagesize;		/* alignment of memory pages */
24055379Sobrienstatic off_t bufoffset;		/* Read offset; defined on regular files.  */
241131557Stjrstatic off_t after_last_match;	/* Pointer after last matching line that
242131557Stjr				   would have been output if we were
243131557Stjr				   outputting characters. */
24453451Speter
24553477Sobrien#if defined(HAVE_MMAP)
24655379Sobrienstatic int bufmapped;		/* True if buffer is memory-mapped.  */
24753477Sobrienstatic off_t initial_bufoffset;	/* Initial value of bufoffset. */
248131557Stjr#else
249131557Stjr# define bufmapped 0
25053451Speter#endif
25153451Speter
252103372Sobrien#include <bzlib.h>
253103372Sobrienstatic BZFILE* bzbufdesc;	/* libbz2 file handle. */
254103372Sobrienstatic int BZflag;		/* uncompress before searching. */
25553451Speter#if HAVE_LIBZ > 0
25653451Speter#include <zlib.h>
25753477Sobrienstatic gzFile gzbufdesc;	/* zlib file descriptor. */
25853477Sobrienstatic int Zflag;		/* uncompress before searching. */
25953451Speter#endif
26053451Speter
26153477Sobrien/* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be
26253477Sobrien   an integer or a pointer.  Both args must be free of side effects.  */
26353477Sobrien#define ALIGN_TO(val, alignment) \
26453477Sobrien  ((size_t) (val) % (alignment) == 0 \
26553477Sobrien   ? (val) \
26653477Sobrien   : (val) + ((alignment) - (size_t) (val) % (alignment)))
26753477Sobrien
26853477Sobrien/* Reset the buffer for a new file, returning zero if we should skip it.
26953477Sobrien   Initialize on the first time through. */
27053477Sobrienstatic int
27156920Srureset (int fd, char const *file, struct stats *stats)
27253451Speter{
273131557Stjr  if (! pagesize)
27453451Speter    {
27553477Sobrien      pagesize = getpagesize ();
276131557Stjr      if (pagesize == 0 || 2 * pagesize + 1 <= pagesize)
27753477Sobrien	abort ();
278131557Stjr      bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1;
279131557Stjr      buffer = xmalloc (bufalloc);
28053451Speter    }
281103372Sobrien  if (BZflag)
282103372Sobrien    {
283103372Sobrien    bzbufdesc = BZ2_bzdopen(fd, "r");
284103372Sobrien    if (bzbufdesc == NULL)
285131557Stjr      error(2, 0, _("memory exhausted"));
286103372Sobrien    }
28753451Speter#if HAVE_LIBZ > 0
28855379Sobrien  if (Zflag)
28955379Sobrien    {
29053451Speter    gzbufdesc = gzdopen(fd, "r");
29153477Sobrien    if (gzbufdesc == NULL)
292131557Stjr      error(2, 0, _("memory exhausted"));
29355379Sobrien    }
29453451Speter#endif
29555379Sobrien
296131557Stjr  bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);
297131557Stjr  bufbeg[-1] = eolbyte;
29853477Sobrien  bufdesc = fd;
29953477Sobrien
30055379Sobrien  if (fstat (fd, &stats->stat) != 0)
30155379Sobrien    {
302131557Stjr      error (0, errno, "fstat");
30355379Sobrien      return 0;
30455379Sobrien    }
30553477Sobrien  if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
30653477Sobrien    return 0;
307131557Stjr#ifndef DJGPP
308131557Stjr  if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode)))
309131557Stjr#else
310131557Stjr  if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode)))
311131557Stjr#endif
312131557Stjr    return 0;
31353477Sobrien  if (
314103372Sobrien      BZflag ||
31553451Speter#if HAVE_LIBZ > 0
31653477Sobrien      Zflag ||
31753451Speter#endif
31855379Sobrien      S_ISREG (stats->stat.st_mode))
31955379Sobrien    {
32055379Sobrien      if (file)
32155379Sobrien	bufoffset = 0;
32255379Sobrien      else
32355379Sobrien	{
32455379Sobrien	  bufoffset = lseek (fd, 0, SEEK_CUR);
32555379Sobrien	  if (bufoffset < 0)
32655379Sobrien	    {
327131557Stjr	      error (0, errno, "lseek");
32855379Sobrien	      return 0;
32955379Sobrien	    }
33055379Sobrien	}
331131557Stjr#if defined(HAVE_MMAP)
33255379Sobrien      initial_bufoffset = bufoffset;
33355379Sobrien      bufmapped = mmap_option && bufoffset % pagesize == 0;
33455379Sobrien#endif
33555379Sobrien    }
33653451Speter  else
33753451Speter    {
338131557Stjr#if defined(HAVE_MMAP)
33955379Sobrien      bufmapped = 0;
34055379Sobrien#endif
34153451Speter    }
34253477Sobrien  return 1;
34353451Speter}
34453451Speter
34553451Speter/* Read new stuff into the buffer, saving the specified
34653451Speter   amount of old stuff.  When we're done, 'bufbeg' points
34753451Speter   to the beginning of the buffer contents, and 'buflim'
34855379Sobrien   points just after the end.  Return zero if there's an error.  */
34953451Speterstatic int
350131557Stjrfillbuf (size_t save, struct stats const *stats)
35153451Speter{
35255379Sobrien  size_t fillsize = 0;
35355379Sobrien  int cc = 1;
354131557Stjr  char *readbuf;
35555379Sobrien  size_t readsize;
35653451Speter
357131557Stjr  /* Offset from start of buffer to start of old stuff
35855379Sobrien     that we want to save.  */
359131557Stjr  size_t saved_offset = buflim - save - buffer;
36055379Sobrien
361131557Stjr  if (pagesize <= buffer + bufalloc - buflim)
36253451Speter    {
363131557Stjr      readbuf = buflim;
364131557Stjr      bufbeg = buflim - save;
365131557Stjr    }
366131557Stjr  else
367131557Stjr    {
368131557Stjr      size_t minsize = save + pagesize;
369131557Stjr      size_t newsize;
37055379Sobrien      size_t newalloc;
371131557Stjr      char *newbuf;
37253477Sobrien
373131557Stjr      /* Grow newsize until it is at least as great as minsize.  */
374131557Stjr      for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)
375131557Stjr	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)
376131557Stjr	  xalloc_die ();
377131557Stjr
378131557Stjr      /* Try not to allocate more memory than the file size indicates,
379131557Stjr	 as that might cause unnecessary memory exhaustion if the file
380131557Stjr	 is large.  However, do not use the original file size as a
381131557Stjr	 heuristic if we've already read past the file end, as most
382131557Stjr	 likely the file is growing.  */
38355379Sobrien      if (S_ISREG (stats->stat.st_mode))
38455379Sobrien	{
38555379Sobrien	  off_t to_be_read = stats->stat.st_size - bufoffset;
386131557Stjr	  off_t maxsize_off = save + to_be_read;
387131557Stjr	  if (0 <= to_be_read && to_be_read <= maxsize_off
388131557Stjr	      && maxsize_off == (size_t) maxsize_off
389131557Stjr	      && minsize <= (size_t) maxsize_off
390131557Stjr	      && (size_t) maxsize_off < newsize)
391131557Stjr	    newsize = maxsize_off;
39255379Sobrien	}
39355379Sobrien
394131557Stjr      /* Add enough room so that the buffer is aligned and has room
395131557Stjr	 for byte sentinels fore and aft.  */
396131557Stjr      newalloc = newsize + pagesize + 1;
39755379Sobrien
398131557Stjr      newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
399131557Stjr      readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);
400131557Stjr      bufbeg = readbuf - save;
401131557Stjr      memmove (bufbeg, buffer + saved_offset, save);
402131557Stjr      bufbeg[-1] = eolbyte;
403131557Stjr      if (newbuf != buffer)
40455379Sobrien	{
405131557Stjr	  free (buffer);
406131557Stjr	  buffer = newbuf;
40755379Sobrien	}
40853451Speter    }
40953451Speter
410131557Stjr  readsize = buffer + bufalloc - readbuf;
411131557Stjr  readsize -= readsize % pagesize;
41255379Sobrien
41353477Sobrien#if defined(HAVE_MMAP)
41455379Sobrien  if (bufmapped)
41553451Speter    {
41655379Sobrien      size_t mmapsize = readsize;
41755379Sobrien
41855379Sobrien      /* Don't mmap past the end of the file; some hosts don't allow this.
41955379Sobrien	 Use `read' on the last page.  */
42055379Sobrien      if (stats->stat.st_size - bufoffset < mmapsize)
42153451Speter	{
42255379Sobrien	  mmapsize = stats->stat.st_size - bufoffset;
42355379Sobrien	  mmapsize -= mmapsize % pagesize;
42453451Speter	}
42555379Sobrien
42655379Sobrien      if (mmapsize
427131557Stjr	  && (mmap ((caddr_t) readbuf, mmapsize,
42855379Sobrien		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
42955379Sobrien		    bufdesc, bufoffset)
43055379Sobrien	      != (caddr_t) -1))
43153451Speter	{
43255379Sobrien	  /* Do not bother to use madvise with MADV_SEQUENTIAL or
43355379Sobrien	     MADV_WILLNEED on the mmapped memory.  One might think it
43455379Sobrien	     would help, but it slows us down about 30% on SunOS 4.1.  */
43555379Sobrien	  fillsize = mmapsize;
43655379Sobrien	}
43755379Sobrien      else
43855379Sobrien	{
43955379Sobrien	  /* Stop using mmap on this file.  Synchronize the file
44055379Sobrien	     offset.  Do not warn about mmap failures.  On some hosts
44155379Sobrien	     (e.g. Solaris 2.5) mmap can fail merely because some
44255379Sobrien	     other process has an advisory read lock on the file.
44355379Sobrien	     There's no point alarming the user about this misfeature.  */
44453451Speter	  bufmapped = 0;
44555379Sobrien	  if (bufoffset != initial_bufoffset
44655379Sobrien	      && lseek (bufdesc, bufoffset, SEEK_SET) < 0)
44755379Sobrien	    {
448131557Stjr	      error (0, errno, "lseek");
44955379Sobrien	      cc = 0;
45055379Sobrien	    }
45153451Speter	}
45255379Sobrien    }
45355379Sobrien#endif /*HAVE_MMAP*/
45455379Sobrien
45555379Sobrien  if (! fillsize)
45655379Sobrien    {
45755379Sobrien      ssize_t bytesread;
45855379Sobrien      do
459104555Sobrien	if (BZflag && bzbufdesc)
460103372Sobrien	  {
461104555Sobrien	    int bzerr;
462131557Stjr	    bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize);
463104555Sobrien
464104555Sobrien	    switch (bzerr)
465104555Sobrien	      {
466104555Sobrien	      case BZ_OK:
467104555Sobrien	      case BZ_STREAM_END:
468104555Sobrien		/* ok */
469104555Sobrien		break;
470104555Sobrien	      case BZ_DATA_ERROR_MAGIC:
471104555Sobrien		BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL;
472104555Sobrien		lseek (bufdesc, 0, SEEK_SET);
473131557Stjr		bytesread = read (bufdesc, readbuf, readsize);
474104555Sobrien		break;
475104555Sobrien	      default:
476104555Sobrien		bytesread = 0;
477104555Sobrien		break;
478104555Sobrien	      }
479103372Sobrien	  }
480103372Sobrien	else
48153451Speter#if HAVE_LIBZ > 0
48255379Sobrien	if (Zflag)
483131557Stjr	  bytesread = gzread (gzbufdesc, readbuf, readsize);
48455379Sobrien	else
48555379Sobrien#endif
486131557Stjr	  bytesread = read (bufdesc, readbuf, readsize);
48755379Sobrien      while (bytesread < 0 && errno == EINTR);
48855379Sobrien      if (bytesread < 0)
48955379Sobrien	cc = 0;
49053477Sobrien      else
49155379Sobrien	fillsize = bytesread;
49253451Speter    }
49355379Sobrien
49455379Sobrien  bufoffset += fillsize;
495131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
49655379Sobrien  if (fillsize)
497131557Stjr    fillsize = undossify_input (readbuf, fillsize);
49853451Speter#endif
499131557Stjr  buflim = readbuf + fillsize;
50053451Speter  return cc;
50153451Speter}
50253451Speter
50353451Speter/* Flags controlling the style of output. */
50456233Srustatic enum
505131557Stjr{
506131557Stjr  BINARY_BINARY_FILES,
507131557Stjr  TEXT_BINARY_FILES,
508131557Stjr  WITHOUT_MATCH_BINARY_FILES
509131557Stjr} binary_files;		/* How to handle binary files.  */
510131557Stjr
511131557Stjrstatic int filename_mask;	/* If zero, output nulls after filenames.  */
51253451Speterstatic int out_quiet;		/* Suppress all normal output. */
51353451Speterstatic int out_invert;		/* Print nonmatching stuff. */
51453451Speterstatic int out_file;		/* Print filenames. */
51553451Speterstatic int out_line;		/* Print line numbers. */
51653451Speterstatic int out_byte;		/* Print byte offsets. */
51753451Speterstatic int out_before;		/* Lines of leading context. */
51853451Speterstatic int out_after;		/* Lines of trailing context. */
51953477Sobrienstatic int count_matches;	/* Count matching lines.  */
52053477Sobrienstatic int list_files;		/* List matching files.  */
52153477Sobrienstatic int no_filenames;	/* Suppress file names.  */
522131557Stjrstatic off_t max_count;		/* Stop after outputting this many
523131557Stjr				   lines from an input file.  */
524131557Stjrstatic int line_buffered;       /* If nonzero, use line buffering, i.e.
525131557Stjr				   fflush everyline out.  */
526131557Stjrstatic char *label = NULL;      /* Fake filename for stdin */
52753451Speter
528131557Stjr
52953451Speter/* Internal variables to keep track of byte count, context, etc. */
530131557Stjrstatic uintmax_t totalcc;	/* Total character count before bufbeg. */
531131557Stjrstatic char const *lastnl;	/* Pointer after last newline counted. */
532131557Stjrstatic char const *lastout;	/* Pointer after last character output;
53353451Speter				   NULL if no character has been output
53453451Speter				   or if it's conceptually before bufbeg. */
535131557Stjrstatic uintmax_t totalnl;	/* Total newline count before lastnl. */
536131557Stjrstatic off_t outleft;		/* Maximum number of lines to be output.  */
537131557Stjrstatic int pending;		/* Pending lines of output.
538131557Stjr				   Always kept 0 if out_quiet is true.  */
539131557Stjrstatic int done_on_match;	/* Stop scanning file on first match.  */
540131557Stjrstatic int exit_on_match;	/* Exit on first match.  */
54153451Speter
542131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
54353477Sobrien# include "dosbuf.c"
54453477Sobrien#endif
54553477Sobrien
546131557Stjr/* Add two numbers that count input bytes or lines, and report an
547131557Stjr   error if the addition overflows.  */
548131557Stjrstatic uintmax_t
549131557Stjradd_count (uintmax_t a, uintmax_t b)
550131557Stjr{
551131557Stjr  uintmax_t sum = a + b;
552131557Stjr  if (sum < a)
553131557Stjr    error (2, 0, _("input is too large to count"));
554131557Stjr  return sum;
555131557Stjr}
556131557Stjr
55753451Speterstatic void
558131557Stjrnlscan (char const *lim)
55953451Speter{
560131557Stjr  size_t newlines = 0;
561131557Stjr  char const *beg;
562131557Stjr  for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++)
563131557Stjr    newlines++;
564131557Stjr  totalnl = add_count (totalnl, newlines);
56555379Sobrien  lastnl = lim;
56653451Speter}
56753451Speter
568131557Stjr/* Print a byte offset, followed by a character separator.  */
56953451Speterstatic void
570131557Stjrprint_offset_sep (uintmax_t pos, char sep)
57153477Sobrien{
572131557Stjr  /* Do not rely on printf to print pos, since uintmax_t may be longer
573131557Stjr     than long, and long long is not portable.  */
57453477Sobrien
57553477Sobrien  char buf[sizeof pos * CHAR_BIT];
57653477Sobrien  char *p = buf + sizeof buf - 1;
57753477Sobrien  *p = sep;
57853477Sobrien
57953477Sobrien  do
58053477Sobrien    *--p = '0' + pos % 10;
58153477Sobrien  while ((pos /= 10) != 0);
58253477Sobrien
58353477Sobrien  fwrite (p, 1, buf + sizeof buf - p, stdout);
58453477Sobrien}
58553477Sobrien
58653477Sobrienstatic void
587131576Stjrprline (char const *beg, char const *lim, int sep, struct mb_cache *mb_cache)
58853451Speter{
58953451Speter  if (out_file)
59055379Sobrien    printf ("%s%c", filename, sep & filename_mask);
59153451Speter  if (out_line)
59253451Speter    {
59353477Sobrien      nlscan (beg);
594131557Stjr      totalnl = add_count (totalnl, 1);
595131557Stjr      print_offset_sep (totalnl, sep);
59653451Speter      lastnl = lim;
59753451Speter    }
59853451Speter  if (out_byte)
59953477Sobrien    {
600131557Stjr      uintmax_t pos = add_count (totalcc, beg - bufbeg);
601131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
60253477Sobrien      pos = dossified_pos (pos);
60353477Sobrien#endif
60453477Sobrien      print_offset_sep (pos, sep);
60553477Sobrien    }
606131557Stjr  if (only_matching)
607131557Stjr    {
608131557Stjr      size_t match_size;
609131557Stjr      size_t match_offset;
610131576Stjr      while ((match_offset = (*execute) (beg, lim - beg, mb_cache,
611131576Stjr					 &match_size, 1))
612131557Stjr	  != (size_t) -1)
613131557Stjr        {
614131557Stjr	  char const *b = beg + match_offset;
615131557Stjr	  if (b == lim)
616131557Stjr	    break;
617131557Stjr	  if (match_size == 0)
618131557Stjr	    break;
619131557Stjr	  if(color_option)
620131557Stjr	    printf("\33[%sm", grep_color);
621131557Stjr	  fwrite(b, sizeof (char), match_size, stdout);
622131557Stjr	  if(color_option)
623131557Stjr	    fputs("\33[00m", stdout);
624131557Stjr	  fputs("\n", stdout);
625131557Stjr	  beg = b + match_size;
626131557Stjr        }
627131557Stjr      lastout = lim;
628131557Stjr      if(line_buffered)
629131557Stjr	fflush(stdout);
630131557Stjr      return;
631131557Stjr    }
632131557Stjr  if (color_option)
633131557Stjr    {
634131557Stjr      size_t match_size;
635131557Stjr      size_t match_offset;
636131557Stjr      if(match_icase)
637131557Stjr        {
638131557Stjr	  /* Yuck, this is tricky */
639131557Stjr          char *buf = (char*) xmalloc (lim - beg);
640131557Stjr	  char *ibeg = buf;
641131557Stjr	  char *ilim = ibeg + (lim - beg);
642131557Stjr	  int i;
643131557Stjr	  for (i = 0; i < lim - beg; i++)
644131557Stjr	    ibeg[i] = tolower (beg[i]);
645131576Stjr	  while ((match_offset = (*execute) (ibeg, ilim-ibeg, mb_cache,
646131576Stjr					     &match_size, 1))
647131557Stjr		 != (size_t) -1)
648131557Stjr	    {
649131557Stjr	      char const *b = beg + match_offset;
650131557Stjr	      if (b == lim)
651131557Stjr		break;
652131557Stjr	      fwrite (beg, sizeof (char), match_offset, stdout);
653131557Stjr	      printf ("\33[%sm", grep_color);
654131557Stjr	      fwrite (b, sizeof (char), match_size, stdout);
655131557Stjr	      fputs ("\33[00m", stdout);
656131557Stjr	      beg = b + match_size;
657131557Stjr	      ibeg = ibeg + match_offset + match_size;
658131557Stjr	    }
659131557Stjr	  fwrite (beg, 1, lim - beg, stdout);
660131557Stjr	  free (buf);
661131557Stjr	  lastout = lim;
662131557Stjr	  return;
663131557Stjr	}
664131576Stjr      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, mb_cache,
665131576Stjr						    &match_size, 1))
666131557Stjr	     != (size_t) -1)
667131557Stjr	{
668131557Stjr	  char const *b = beg + match_offset;
669131557Stjr	  /* Avoid matching the empty line at the end of the buffer. */
670131557Stjr	  if (b == lim)
671131557Stjr	    break;
672131557Stjr	  /* Avoid hanging on grep --color "" foo */
673131557Stjr	  if (match_size == 0)
674131557Stjr	    break;
675131557Stjr	  fwrite (beg, sizeof (char), match_offset, stdout);
676131557Stjr	  printf ("\33[%sm", grep_color);
677131557Stjr	  fwrite (b, sizeof (char), match_size, stdout);
678131557Stjr	  fputs ("\33[00m", stdout);
679131557Stjr	  beg = b + match_size;
680131557Stjr	}
681131557Stjr    }
68253477Sobrien  fwrite (beg, 1, lim - beg, stdout);
68353477Sobrien  if (ferror (stdout))
684131557Stjr    error (0, errno, _("writing output"));
68553451Speter  lastout = lim;
686131557Stjr  if (line_buffered)
687131557Stjr    fflush (stdout);
68853451Speter}
68953451Speter
690131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends
691131557Stjr   at the next matching line when OUTLEFT is 0.  */
69253451Speterstatic void
693131576Stjrprpending (char const *lim, struct mb_cache *mb_cache)
69453451Speter{
69553451Speter  if (!lastout)
69653451Speter    lastout = bufbeg;
69753451Speter  while (pending > 0 && lastout < lim)
69853451Speter    {
699131557Stjr      char const *nl = memchr (lastout, eolbyte, lim - lastout);
700131557Stjr      size_t match_size;
70153451Speter      --pending;
702131557Stjr      if (outleft
703131576Stjr	  || (((*execute) (lastout, nl - lastout, mb_cache,
704131576Stjr			   &match_size, 0) == (size_t) -1)
705131557Stjr	      == !out_invert))
706131576Stjr	prline (lastout, nl + 1, '-', mb_cache);
70753451Speter      else
708131557Stjr	pending = 0;
70953451Speter    }
71053451Speter}
71153451Speter
71253451Speter/* Print the lines between BEG and LIM.  Deal with context crap.
713131557Stjr   If NLINESP is non-null, store a count of lines between BEG and LIM.  */
71453451Speterstatic void
715131576Stjrprtext (char const *beg, char const *lim, int *nlinesp,
716131576Stjr	struct mb_cache *mb_cache)
71753451Speter{
71853451Speter  static int used;		/* avoid printing "--" before any output */
719131557Stjr  char const *bp, *p;
72055379Sobrien  char eol = eolbyte;
72153451Speter  int i, n;
72253451Speter
72353451Speter  if (!out_quiet && pending > 0)
724131576Stjr    prpending (beg, mb_cache);
72553451Speter
72653451Speter  p = beg;
72753451Speter
72853451Speter  if (!out_quiet)
72953451Speter    {
73053451Speter      /* Deal with leading context crap. */
73153451Speter
73253451Speter      bp = lastout ? lastout : bufbeg;
73353451Speter      for (i = 0; i < out_before; ++i)
73453451Speter	if (p > bp)
73553451Speter	  do
73653451Speter	    --p;
737131557Stjr	  while (p[-1] != eol);
73853451Speter
73953451Speter      /* We only print the "--" separator if our output is
74053451Speter	 discontiguous from the last output in the file. */
74153451Speter      if ((out_before || out_after) && used && p != lastout)
74253477Sobrien	puts ("--");
74353451Speter
74453451Speter      while (p < beg)
74553451Speter	{
746131557Stjr	  char const *nl = memchr (p, eol, beg - p);
747131557Stjr	  nl++;
748131576Stjr	  prline (p, nl, '-', mb_cache);
749131557Stjr	  p = nl;
75053451Speter	}
75153451Speter    }
75253451Speter
75353451Speter  if (nlinesp)
75453451Speter    {
75553451Speter      /* Caller wants a line count. */
756131557Stjr      for (n = 0; p < lim && n < outleft; n++)
75753451Speter	{
758131557Stjr	  char const *nl = memchr (p, eol, lim - p);
759131557Stjr	  nl++;
76053451Speter	  if (!out_quiet)
761131576Stjr	    prline (p, nl, ':', mb_cache);
76253451Speter	  p = nl;
76353451Speter	}
76453451Speter      *nlinesp = n;
765131557Stjr
766131557Stjr      /* relying on it that this function is never called when outleft = 0.  */
767131557Stjr      after_last_match = bufoffset - (buflim - p);
76853451Speter    }
76953451Speter  else
77053451Speter    if (!out_quiet)
771131576Stjr      prline (beg, lim, ':', mb_cache);
77253451Speter
77355379Sobrien  pending = out_quiet ? 0 : out_after;
77453451Speter  used = 1;
77553451Speter}
77653451Speter
77753451Speter/* Scan the specified portion of the buffer, matching lines (or
77853451Speter   between matching lines if OUT_INVERT is true).  Return a count of
77953451Speter   lines printed. */
78053451Speterstatic int
781131576Stjrgrepbuf (char const *beg, char const *lim, struct mb_cache *mb_cache)
78253451Speter{
78353451Speter  int nlines, n;
784131557Stjr  register char const *p;
785131557Stjr  size_t match_offset;
786131557Stjr  size_t match_size;
78753451Speter
78853451Speter  nlines = 0;
78953451Speter  p = beg;
790131576Stjr  while ((match_offset = (*execute) (p, lim - p, mb_cache,
791131576Stjr				     &match_size, 0)) != (size_t) -1)
79253451Speter    {
793131557Stjr      char const *b = p + match_offset;
794131557Stjr      char const *endp = b + match_size;
79553451Speter      /* Avoid matching the empty line at the end of the buffer. */
796131557Stjr      if (b == lim)
79753451Speter	break;
79853451Speter      if (!out_invert)
79953451Speter	{
800131576Stjr	  prtext (b, endp, (int *) 0, mb_cache);
801131557Stjr	  nlines++;
802131557Stjr          outleft--;
803131557Stjr	  if (!outleft || done_on_match)
804131557Stjr	    {
805131557Stjr	      if (exit_on_match)
806131557Stjr		exit (0);
807131557Stjr	      after_last_match = bufoffset - (buflim - endp);
808131557Stjr	      return nlines;
809131557Stjr	    }
81053451Speter	}
81153451Speter      else if (p < b)
81253451Speter	{
813131576Stjr	  prtext (p, b, &n, mb_cache);
81453451Speter	  nlines += n;
815131557Stjr          outleft -= n;
816131557Stjr	  if (!outleft)
817131557Stjr	    return nlines;
81853451Speter	}
81953451Speter      p = endp;
82053451Speter    }
82153451Speter  if (out_invert && p < lim)
82253451Speter    {
823131576Stjr      prtext (p, lim, &n, mb_cache);
82453451Speter      nlines += n;
825131557Stjr      outleft -= n;
82653451Speter    }
82753451Speter  return nlines;
82853451Speter}
82953451Speter
83053477Sobrien/* Search a given file.  Normally, return a count of lines printed;
83153477Sobrien   but if the file is a directory and we search it recursively, then
83253477Sobrien   return -2 if there was a match, and -1 otherwise.  */
83353451Speterstatic int
83456920Srugrep (int fd, char const *file, struct stats *stats)
83553451Speter{
83653451Speter  int nlines, i;
83753477Sobrien  int not_text;
83853451Speter  size_t residue, save;
839131557Stjr  char oldc;
840131557Stjr  char *beg;
841131557Stjr  char *lim;
84255379Sobrien  char eol = eolbyte;
843131576Stjr  struct mb_cache mb_cache;
84453451Speter
845131576Stjr  memset (&mb_cache, 0, sizeof (mb_cache));
84653477Sobrien  if (!reset (fd, file, stats))
84753477Sobrien    return 0;
84853451Speter
84953477Sobrien  if (file && directories == RECURSE_DIRECTORIES
85053477Sobrien      && S_ISDIR (stats->stat.st_mode))
85153477Sobrien    {
85253477Sobrien      /* Close fd now, so that we don't open a lot of file descriptors
85353477Sobrien	 when we recurse deeply.  */
854104555Sobrien      if (BZflag && bzbufdesc)
855103372Sobrien	BZ2_bzclose(bzbufdesc);
856103372Sobrien      else
85753477Sobrien#if HAVE_LIBZ > 0
85853477Sobrien      if (Zflag)
85953477Sobrien	gzclose(gzbufdesc);
86053477Sobrien      else
86153477Sobrien#endif
86253477Sobrien      if (close (fd) != 0)
863131557Stjr	error (0, errno, "%s", file);
86453477Sobrien      return grepdir (file, stats) - 2;
86553477Sobrien    }
86653477Sobrien
86753451Speter  totalcc = 0;
86853451Speter  lastout = 0;
86953451Speter  totalnl = 0;
870131557Stjr  outleft = max_count;
871131557Stjr  after_last_match = 0;
87253451Speter  pending = 0;
87353451Speter
87453451Speter  nlines = 0;
87553451Speter  residue = 0;
87653451Speter  save = 0;
87753451Speter
87855379Sobrien  if (! fillbuf (save, stats))
87953451Speter    {
880131557Stjr      if (! is_EISDIR (errno, file))
881131557Stjr	suppressible_error (filename, errno);
88256233Sru      return 0;
88353477Sobrien    }
88453451Speter
88556233Sru  not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
88656233Sru	       || binary_files == WITHOUT_MATCH_BINARY_FILES)
88755379Sobrien	      && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
88856233Sru  if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
88956233Sru    return 0;
89053477Sobrien  done_on_match += not_text;
89153477Sobrien  out_quiet += not_text;
89253451Speter
89353477Sobrien  for (;;)
89453477Sobrien    {
89553451Speter      lastnl = bufbeg;
89653451Speter      if (lastout)
89753451Speter	lastout = bufbeg;
898131557Stjr
899131557Stjr      beg = bufbeg + save;
900131557Stjr
901131557Stjr      /* no more data to scan (eof) except for maybe a residue -> break */
902131557Stjr      if (beg == buflim)
90353451Speter	break;
904131557Stjr
905131557Stjr      /* Determine new residue (the length of an incomplete line at the end of
906131557Stjr         the buffer, 0 means there is no incomplete last line).  */
907131557Stjr      oldc = beg[-1];
908131557Stjr      beg[-1] = eol;
909131557Stjr      for (lim = buflim; lim[-1] != eol; lim--)
910131557Stjr	continue;
911131557Stjr      beg[-1] = oldc;
912131557Stjr      if (lim == beg)
913131557Stjr	lim = beg - residue;
914131557Stjr      beg -= residue;
91553451Speter      residue = buflim - lim;
916131557Stjr
91753451Speter      if (beg < lim)
91853451Speter	{
919131557Stjr	  if (outleft)
920131576Stjr	    nlines += grepbuf (beg, lim, &mb_cache);
92153451Speter	  if (pending)
922131576Stjr	    prpending (lim, &mb_cache);
923131557Stjr	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
92453477Sobrien	    goto finish_grep;
92553451Speter	}
926131557Stjr
927131557Stjr      /* The last OUT_BEFORE lines at the end of the buffer will be needed as
928131557Stjr	 leading context if there is a matching line at the begin of the
929131557Stjr	 next data. Make beg point to their begin.  */
93053451Speter      i = 0;
93153451Speter      beg = lim;
93253451Speter      while (i < out_before && beg > bufbeg && beg != lastout)
93353451Speter	{
93453451Speter	  ++i;
93553451Speter	  do
93653451Speter	    --beg;
937131557Stjr	  while (beg[-1] != eol);
93853451Speter	}
939131557Stjr
940131557Stjr      /* detect if leading context is discontinuous from last printed line.  */
94153451Speter      if (beg != lastout)
94253451Speter	lastout = 0;
943131557Stjr
944131557Stjr      /* Handle some details and read more data to scan.  */
94553451Speter      save = residue + lim - beg;
946131557Stjr      if (out_byte)
947131557Stjr	totalcc = add_count (totalcc, buflim - bufbeg - save);
94853451Speter      if (out_line)
94953477Sobrien	nlscan (beg);
950131576Stjr      if (mb_cache.wcs_buf)
951131576Stjr	free (mb_cache.wcs_buf);
952131576Stjr      if (mb_cache.mblen_buf)
953131576Stjr	free (mb_cache.mblen_buf);
954131576Stjr      memset (&mb_cache, 0, sizeof (mb_cache));
95555379Sobrien      if (! fillbuf (save, stats))
95653477Sobrien	{
957131557Stjr	  if (! is_EISDIR (errno, file))
958131557Stjr	    suppressible_error (filename, errno);
95953477Sobrien	  goto finish_grep;
96053477Sobrien	}
96153451Speter    }
96253451Speter  if (residue)
96353451Speter    {
96456920Sru      *buflim++ = eol;
965131557Stjr      if (outleft)
966131576Stjr	nlines += grepbuf (bufbeg + save - residue, buflim, &mb_cache);
96753451Speter      if (pending)
968131576Stjr        prpending (buflim, &mb_cache);
96953451Speter    }
97053477Sobrien
97153477Sobrien finish_grep:
97253477Sobrien  done_on_match -= not_text;
97353477Sobrien  out_quiet -= not_text;
97453477Sobrien  if ((not_text & ~out_quiet) && nlines != 0)
97553477Sobrien    printf (_("Binary file %s matches\n"), filename);
976131576Stjr
977131576Stjr  if (mb_cache.wcs_buf)
978131576Stjr    free (mb_cache.wcs_buf);
979131576Stjr  if (mb_cache.mblen_buf)
980131576Stjr    free (mb_cache.mblen_buf);
98153451Speter  return nlines;
98253451Speter}
98353451Speter
98453477Sobrienstatic int
98556920Srugrepfile (char const *file, struct stats *stats)
98653477Sobrien{
98753477Sobrien  int desc;
98853477Sobrien  int count;
98953477Sobrien  int status;
99053477Sobrien
99153477Sobrien  if (! file)
99253477Sobrien    {
99353477Sobrien      desc = 0;
994131557Stjr      filename = label ? label : _("(standard input)");
99553477Sobrien    }
99653477Sobrien  else
99753477Sobrien    {
99855379Sobrien      while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR)
99955379Sobrien	continue;
100053477Sobrien
100153477Sobrien      if (desc < 0)
100253477Sobrien	{
100353477Sobrien	  int e = errno;
1004131557Stjr
100553477Sobrien	  if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
100653477Sobrien	    {
100753477Sobrien	      if (stat (file, &stats->stat) != 0)
100853477Sobrien		{
1009131557Stjr		  error (0, errno, "%s", file);
101053477Sobrien		  return 1;
101153477Sobrien		}
101253477Sobrien
101353477Sobrien	      return grepdir (file, stats);
101453477Sobrien	    }
1015131557Stjr
101653477Sobrien	  if (!suppress_errors)
101753477Sobrien	    {
101853477Sobrien	      if (directories == SKIP_DIRECTORIES)
101953477Sobrien		switch (e)
102053477Sobrien		  {
1021131557Stjr#if defined(EISDIR)
102253477Sobrien		  case EISDIR:
102353477Sobrien		    return 1;
102453451Speter#endif
102553477Sobrien		  case EACCES:
102653477Sobrien		    /* When skipping directories, don't worry about
102753477Sobrien		       directories that can't be opened.  */
1028131557Stjr		    if (isdir (file))
102953477Sobrien		      return 1;
103053477Sobrien		    break;
103153477Sobrien		  }
103253477Sobrien	    }
103353477Sobrien
1034131557Stjr	  suppressible_error (file, e);
103553477Sobrien	  return 1;
103653477Sobrien	}
103753477Sobrien
103853477Sobrien      filename = file;
103953477Sobrien    }
104053477Sobrien
1041131557Stjr#if defined(SET_BINARY)
104253477Sobrien  /* Set input to binary mode.  Pipes are simulated with files
104353477Sobrien     on DOS, so this includes the case of "foo | grep bar".  */
104453477Sobrien  if (!isatty (desc))
104553477Sobrien    SET_BINARY (desc);
104653477Sobrien#endif
104753477Sobrien
104853477Sobrien  count = grep (desc, file, stats);
104953477Sobrien  if (count < 0)
105053477Sobrien    status = count + 2;
105153477Sobrien  else
105253477Sobrien    {
105353477Sobrien      if (count_matches)
105453477Sobrien	{
105553477Sobrien	  if (out_file)
105655379Sobrien	    printf ("%s%c", filename, ':' & filename_mask);
105753477Sobrien	  printf ("%d\n", count);
105853477Sobrien	}
105953477Sobrien
106055379Sobrien      status = !count;
106155379Sobrien      if (list_files == 1 - 2 * status)
106255379Sobrien	printf ("%s%c", filename, '\n' & filename_mask);
106353477Sobrien
1064104555Sobrien      if (BZflag && bzbufdesc)
1065103372Sobrien	BZ2_bzclose(bzbufdesc);
1066103372Sobrien      else
106753451Speter#if HAVE_LIBZ > 0
106853477Sobrien      if (Zflag)
106953477Sobrien	gzclose(gzbufdesc);
107053477Sobrien      else
107153451Speter#endif
1072131557Stjr      if (! file)
1073131557Stjr	{
1074131557Stjr	  off_t required_offset = outleft ? bufoffset : after_last_match;
1075131557Stjr	  if ((bufmapped || required_offset != bufoffset)
1076131557Stjr	      && lseek (desc, required_offset, SEEK_SET) < 0
1077131557Stjr	      && S_ISREG (stats->stat.st_mode))
1078131557Stjr	    error (0, errno, "%s", filename);
1079131557Stjr	}
1080131557Stjr      else
108155379Sobrien	while (close (desc) != 0)
108255379Sobrien	  if (errno != EINTR)
108355379Sobrien	    {
1084131557Stjr	      error (0, errno, "%s", file);
108555379Sobrien	      break;
108655379Sobrien	    }
108753477Sobrien    }
108853451Speter
108953477Sobrien  return status;
109053477Sobrien}
109153477Sobrien
109253477Sobrienstatic int
1093131557Stjrgrepdir (char const *dir, struct stats const *stats)
109453477Sobrien{
109553477Sobrien  int status = 1;
1096131557Stjr  struct stats const *ancestor;
109753477Sobrien  char *name_space;
109853477Sobrien
1099131557Stjr  /* Mingw32 does not support st_ino.  No known working hosts use zero
1100131557Stjr     for st_ino, so assume that the Mingw32 bug applies if it's zero.  */
1101131557Stjr  if (stats->stat.st_ino)
1102131557Stjr    for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
1103131557Stjr      if (ancestor->stat.st_ino == stats->stat.st_ino
1104131557Stjr	  && ancestor->stat.st_dev == stats->stat.st_dev)
1105131557Stjr	{
1106131557Stjr	  if (!suppress_errors)
1107141847Sobrien	    error (0, 0, _("warning: %s: %s"), dir,
110853477Sobrien		   _("recursive directory loop"));
1109131557Stjr	  return 1;
1110131557Stjr	}
111153477Sobrien
1112131557Stjr  name_space = savedir (dir, stats->stat.st_size, included_patterns,
1113131557Stjr			excluded_patterns);
111453477Sobrien
111553477Sobrien  if (! name_space)
111653477Sobrien    {
111753477Sobrien      if (errno)
1118131557Stjr	suppressible_error (dir, errno);
111953477Sobrien      else
1120131557Stjr	xalloc_die ();
112153477Sobrien    }
112253477Sobrien  else
112353477Sobrien    {
112453477Sobrien      size_t dirlen = strlen (dir);
112553477Sobrien      int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
112653477Sobrien			   || IS_SLASH (dir[dirlen - 1]));
112753477Sobrien      char *file = NULL;
1128131557Stjr      char const *namep = name_space;
112953477Sobrien      struct stats child;
113053477Sobrien      child.parent = stats;
113153477Sobrien      out_file += !no_filenames;
113253477Sobrien      while (*namep)
113353477Sobrien	{
113453477Sobrien	  size_t namelen = strlen (namep);
113553477Sobrien	  file = xrealloc (file, dirlen + 1 + namelen + 1);
113653477Sobrien	  strcpy (file, dir);
113753477Sobrien	  file[dirlen] = '/';
113853477Sobrien	  strcpy (file + dirlen + needs_slash, namep);
113953477Sobrien	  namep += namelen + 1;
114053477Sobrien	  status &= grepfile (file, &child);
114153477Sobrien	}
114253477Sobrien      out_file -= !no_filenames;
114353477Sobrien      if (file)
114453477Sobrien        free (file);
114553477Sobrien      free (name_space);
114653477Sobrien    }
114753477Sobrien
114853477Sobrien  return status;
114953477Sobrien}
115053477Sobrien
115153451Speterstatic void
115256920Sruusage (int status)
115353451Speter{
115453477Sobrien  if (status != 0)
115553477Sobrien    {
1156131557Stjr      fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
1157131557Stjr	       program_name);
1158131557Stjr      fprintf (stderr, _("Try `%s --help' for more information.\n"),
1159131557Stjr	       program_name);
116053477Sobrien    }
116153477Sobrien  else
116253477Sobrien    {
1163131557Stjr      printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name);
116453477Sobrien      printf (_("\
116553477SobrienSearch for PATTERN in each FILE or standard input.\n\
116656920SruExample: %s -i 'hello world' menu.h main.c\n\
116753477Sobrien\n\
1168131557StjrRegexp selection and interpretation:\n"), program_name);
116955379Sobrien      printf (_("\
117053477Sobrien  -E, --extended-regexp     PATTERN is an extended regular expression\n\
117155379Sobrien  -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
1172131557Stjr  -G, --basic-regexp        PATTERN is a basic regular expression\n\
1173131557Stjr  -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
117455379Sobrien      printf (_("\
117553477Sobrien  -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
117653477Sobrien  -f, --file=FILE           obtain PATTERN from FILE\n\
117753477Sobrien  -i, --ignore-case         ignore case distinctions\n\
117853477Sobrien  -w, --word-regexp         force PATTERN to match only whole words\n\
117955379Sobrien  -x, --line-regexp         force PATTERN to match only whole lines\n\
118055379Sobrien  -z, --null-data           a data line ends in 0 byte, not newline\n"));
118153477Sobrien      printf (_("\
118253477Sobrien\n\
118353477SobrienMiscellaneous:\n\
118453477Sobrien  -s, --no-messages         suppress error messages\n\
118555379Sobrien  -v, --invert-match        select non-matching lines\n\
118653477Sobrien  -V, --version             print version information and exit\n\
118755379Sobrien      --help                display this help and exit\n\
1188103372Sobrien  -J, --bz2decompress       decompress bzip2'ed input before searching\n\
118953477Sobrien  -Z, --decompress          decompress input before searching (HAVE_LIBZ=1)\n\
119055379Sobrien      --mmap                use memory-mapped input if possible\n"));
119153477Sobrien      printf (_("\
119253477Sobrien\n\
119353477SobrienOutput control:\n\
1194131557Stjr  -m, --max-count=NUM       stop after NUM matches\n\
119553477Sobrien  -b, --byte-offset         print the byte offset with output lines\n\
119653477Sobrien  -n, --line-number         print line number with output lines\n\
1197131557Stjr      --line-buffered       flush output on every line\n\
119853477Sobrien  -H, --with-filename       print the filename for each match\n\
119953477Sobrien  -h, --no-filename         suppress the prefixing filename on output\n\
1200131557Stjr      --label=LABEL         print LABEL as filename for standard input\n\
1201131557Stjr  -o, --only-matching       show only the part of a line matching PATTERN\n\
120253477Sobrien  -q, --quiet, --silent     suppress all normal output\n\
120356233Sru      --binary-files=TYPE   assume that binary files are TYPE\n\
1204131557Stjr                            TYPE is 'binary', 'text', or 'without-match'\n\
120556920Sru  -a, --text                equivalent to --binary-files=text\n\
120656920Sru  -I                        equivalent to --binary-files=without-match\n\
120753477Sobrien  -d, --directories=ACTION  how to handle directories\n\
1208131557Stjr                            ACTION is 'read', 'recurse', or 'skip'\n\
1209131557Stjr  -D, --devices=ACTION      how to handle devices, FIFOs and sockets\n\
1210131557Stjr                            ACTION is 'read' or 'skip'\n\
1211131557Stjr  -R, -r, --recursive       equivalent to --directories=recurse\n\
1212131557Stjr      --include=PATTERN     files that match PATTERN will be examined\n\
1213131557Stjr      --exclude=PATTERN     files that match PATTERN will be skipped.\n\
1214131557Stjr      --exclude-from=FILE   files that match PATTERN in FILE will be skipped.\n\
121553477Sobrien  -L, --files-without-match only print FILE names containing no match\n\
121653477Sobrien  -l, --files-with-matches  only print FILE names containing matches\n\
121755379Sobrien  -c, --count               only print a count of matching lines per FILE\n\
121855379Sobrien      --null                print 0 byte after FILE name\n"));
121953477Sobrien      printf (_("\
122053477Sobrien\n\
122153477SobrienContext control:\n\
122253477Sobrien  -B, --before-context=NUM  print NUM lines of leading context\n\
122353477Sobrien  -A, --after-context=NUM   print NUM lines of trailing context\n\
1224131557Stjr  -C, --context=NUM         print NUM lines of output context\n\
122553477Sobrien  -NUM                      same as --context=NUM\n\
1226131557Stjr      --color[=WHEN],\n\
1227131557Stjr      --colour[=WHEN]       use markers to distinguish the matching string\n\
1228131557Stjr                            WHEN may be `always', `never' or `auto'.\n\
122953477Sobrien  -U, --binary              do not strip CR characters at EOL (MSDOS)\n\
123053477Sobrien  -u, --unix-byte-offsets   report offsets as if CRs were not there (MSDOS)\n\
123153477Sobrien\n\
123255379Sobrien`egrep' means `grep -E'.  `fgrep' means `grep -F'.\n\
123355379SobrienWith no FILE, or when FILE is -, read standard input.  If less than\n\
123455379Sobrientwo FILEs given, assume -h.  Exit status is 0 if match, 1 if no match,\n\
123555379Sobrienand 2 if trouble.\n"));
123653477Sobrien      printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n"));
123753477Sobrien    }
123853477Sobrien  exit (status);
123953451Speter}
124053451Speter
124155379Sobrien/* Set the matcher to M, reporting any conflicts.  */
124255379Sobrienstatic void
124356920Srusetmatcher (char const *m)
124455379Sobrien{
124555379Sobrien  if (matcher && strcmp (matcher, m) != 0)
1246131557Stjr    error (2, 0, _("conflicting matchers specified"));
124755379Sobrien  matcher = m;
124855379Sobrien}
124955379Sobrien
125053451Speter/* Go through the matchers vector and look for the specified matcher.
125153451Speter   If we find it, install it in compile and execute, and return 1.  */
125253477Sobrienstatic int
125356920Sruinstall_matcher (char const *name)
125453451Speter{
125553451Speter  int i;
1256131557Stjr#if defined(HAVE_SETRLIMIT)
125753477Sobrien  struct rlimit rlim;
125853477Sobrien#endif
125953451Speter
1260131557Stjr  for (i = 0; matchers[i].compile; i++)
126153477Sobrien    if (strcmp (name, matchers[i].name) == 0)
126253451Speter      {
126353451Speter	compile = matchers[i].compile;
126453451Speter	execute = matchers[i].execute;
1265131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
126653477Sobrien	/* I think every platform needs to do this, so that regex.c
126753477Sobrien	   doesn't oveflow the stack.  The default value of
126853477Sobrien	   `re_max_failures' is too large for some platforms: it needs
126953477Sobrien	   more than 3MB-large stack.
127053477Sobrien
127153477Sobrien	   The test for HAVE_SETRLIMIT should go into `configure'.  */
127253477Sobrien	if (!getrlimit (RLIMIT_STACK, &rlim))
127353477Sobrien	  {
127453477Sobrien	    long newlim;
127553477Sobrien	    extern long int re_max_failures; /* from regex.c */
127653477Sobrien
127753477Sobrien	    /* Approximate the amount regex.c needs, plus some more.  */
127853477Sobrien	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
127953477Sobrien	    if (newlim > rlim.rlim_max)
128053477Sobrien	      {
128153477Sobrien		newlim = rlim.rlim_max;
128253477Sobrien		re_max_failures = newlim / (2 * 20 * sizeof (char *));
128353477Sobrien	      }
128453477Sobrien	    if (rlim.rlim_cur < newlim)
1285131557Stjr	      {
1286131557Stjr		rlim.rlim_cur = newlim;
1287131557Stjr		setrlimit (RLIMIT_STACK, &rlim);
1288131557Stjr	      }
128953477Sobrien	  }
129053477Sobrien#endif
129153451Speter	return 1;
129253451Speter      }
129353451Speter  return 0;
129453451Speter}
129553451Speter
129653705Sobrien/* Find the white-space-separated options specified by OPTIONS, and
129753705Sobrien   using BUF to store copies of these options, set ARGV[0], ARGV[1],
129853705Sobrien   etc. to the option copies.  Return the number N of options found.
129953705Sobrien   Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
130053705Sobrien   etc.  Backslash can be used to escape whitespace (and backslashes).  */
130153705Sobrienstatic int
130256920Sruprepend_args (char const *options, char *buf, char **argv)
130353705Sobrien{
130453705Sobrien  char const *o = options;
130553705Sobrien  char *b = buf;
130653705Sobrien  int n = 0;
130753705Sobrien
130853705Sobrien  for (;;)
130953705Sobrien    {
131053705Sobrien      while (ISSPACE ((unsigned char) *o))
131153705Sobrien	o++;
131253705Sobrien      if (!*o)
131353705Sobrien	return n;
131453705Sobrien      if (argv)
131553705Sobrien	argv[n] = b;
131653705Sobrien      n++;
131753705Sobrien
131853705Sobrien      do
131953705Sobrien	if ((*b++ = *o++) == '\\' && *o)
132053705Sobrien	  b[-1] = *o++;
132153705Sobrien      while (*o && ! ISSPACE ((unsigned char) *o));
132253705Sobrien
132353705Sobrien      *b++ = '\0';
132453705Sobrien    }
132553705Sobrien}
132653705Sobrien
132753705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument
132853705Sobrien   vector of a main program with argument count *PARGC and argument
132953705Sobrien   vector *PARGV.  */
133053705Sobrienstatic void
133156920Sruprepend_default_options (char const *options, int *pargc, char ***pargv)
133253705Sobrien{
133353705Sobrien  if (options)
133453705Sobrien    {
133553705Sobrien      char *buf = xmalloc (strlen (options) + 1);
133653705Sobrien      int prepended = prepend_args (options, buf, (char **) NULL);
133753705Sobrien      int argc = *pargc;
133853705Sobrien      char * const *argv = *pargv;
133953705Sobrien      char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
134053705Sobrien      *pargc = prepended + argc;
134153705Sobrien      *pargv = pp;
134253705Sobrien      *pp++ = *argv++;
134353705Sobrien      pp += prepend_args (options, buf, pp);
134453705Sobrien      while ((*pp++ = *argv++))
134553705Sobrien	continue;
134653705Sobrien    }
134753705Sobrien}
134853705Sobrien
1349131557Stjr/* Get the next non-digit option from ARGC and ARGV.
1350131557Stjr   Return -1 if there are no more options.
1351131557Stjr   Process any digit options that were encountered on the way,
1352131557Stjr   and store the resulting integer into *DEFAULT_CONTEXT.  */
1353131557Stjrstatic int
1354131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context)
1355131557Stjr{
1356131557Stjr  int opt;
1357131557Stjr  char buf[sizeof (uintmax_t) * CHAR_BIT + 4];
1358131557Stjr  char *p = buf;
1359131557Stjr
1360131557Stjr  /* Set buf[0] to anything but '0', for the leading-zero test below.  */
1361131557Stjr  buf[0] = '\0';
1362131557Stjr
1363131557Stjr  while (opt = getopt_long (argc, argv, short_options, long_options, NULL),
1364131557Stjr	 '0' <= opt && opt <= '9')
1365131557Stjr    {
1366131557Stjr      /* Suppress trivial leading zeros, to avoid incorrect
1367131557Stjr	 diagnostic on strings like 00000000000.  */
1368131557Stjr      p -= buf[0] == '0';
1369131557Stjr
1370131557Stjr      *p++ = opt;
1371131557Stjr      if (p == buf + sizeof buf - 4)
1372131557Stjr	{
1373131557Stjr	  /* Too many digits.  Append "..." to make context_length_arg
1374131557Stjr	     complain about "X...", where X contains the digits seen
1375131557Stjr	     so far.  */
1376131557Stjr	  strcpy (p, "...");
1377131557Stjr	  p += 3;
1378131557Stjr	  break;
1379131557Stjr	}
1380131557Stjr    }
1381131557Stjr  if (p != buf)
1382131557Stjr    {
1383131557Stjr      *p = '\0';
1384131557Stjr      context_length_arg (buf, default_context);
1385131557Stjr    }
1386131557Stjr
1387131557Stjr  return opt;
1388131557Stjr}
1389131557Stjr
139053451Speterint
139156920Srumain (int argc, char **argv)
139253451Speter{
139353451Speter  char *keys;
139453451Speter  size_t keycc, oldcc, keyalloc;
139553477Sobrien  int with_filenames;
139653477Sobrien  int opt, cc, status;
139756920Sru  int default_context;
139853451Speter  FILE *fp;
139953451Speter  extern char *optarg;
140053451Speter  extern int optind;
140153477Sobrien
140253477Sobrien  initialize_main (&argc, &argv);
1403131557Stjr  program_name = argv[0];
1404131557Stjr  if (program_name && strrchr (program_name, '/'))
1405131557Stjr    program_name = strrchr (program_name, '/') + 1;
140653477Sobrien
140753477Sobrien#if HAVE_LIBZ > 0
1408131557Stjr  if (program_name[0] == 'z') {
140953477Sobrien    Zflag = 1;
1410131557Stjr    ++program_name;
141153477Sobrien  }
141253451Speter#endif
1413131557Stjr  if (program_name[0] == 'b') {
1414103372Sobrien    BZflag = 1;
1415131557Stjr    ++program_name;
1416103372Sobrien  }
141753451Speter
141853477Sobrien#if defined(__MSDOS__) || defined(_WIN32)
141953477Sobrien  /* DOS and MS-Windows use backslashes as directory separators, and usually
142053477Sobrien     have an .exe suffix.  They also have case-insensitive filesystems.  */
1421131557Stjr  if (program_name)
142253477Sobrien    {
1423131557Stjr      char *p = program_name;
142453477Sobrien      char *bslash = strrchr (argv[0], '\\');
142553477Sobrien
1426131557Stjr      if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
1427131557Stjr	program_name = bslash + 1;
1428131557Stjr      else if (program_name == argv[0]
142953477Sobrien	       && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
1430131557Stjr	program_name = argv[0] + 2;
143153477Sobrien
143253477Sobrien      /* Collapse the letter-case, so `strcmp' could be used hence.  */
143353477Sobrien      for ( ; *p; p++)
143453477Sobrien	if (*p >= 'A' && *p <= 'Z')
143553477Sobrien	  *p += 'a' - 'A';
143653477Sobrien
143753477Sobrien      /* Remove the .exe extension, if any.  */
1438131557Stjr      if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
143953477Sobrien	*p = '\0';
144053477Sobrien    }
144153451Speter#endif
144253451Speter
144353451Speter  keys = NULL;
144453451Speter  keycc = 0;
144553477Sobrien  with_filenames = 0;
144655379Sobrien  eolbyte = '\n';
144755379Sobrien  filename_mask = ~0;
144853477Sobrien
1449131557Stjr  max_count = TYPE_MAXIMUM (off_t);
1450131557Stjr
145153477Sobrien  /* The value -1 means to use DEFAULT_CONTEXT. */
145253477Sobrien  out_after = out_before = -1;
145353477Sobrien  /* Default before/after context: chaged by -C/-NUM options */
145453477Sobrien  default_context = 0;
1455131557Stjr  /* Changed by -o option */
1456131557Stjr  only_matching = 0;
145753477Sobrien
1458131557Stjr  /* Internationalization. */
1459131557Stjr#if defined(HAVE_SETLOCALE)
146053477Sobrien  setlocale (LC_ALL, "");
146153451Speter#endif
1462131557Stjr#if defined(ENABLE_NLS)
146353477Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
146453477Sobrien  textdomain (PACKAGE);
146553451Speter#endif
146653451Speter
1467131557Stjr  atexit (close_stdout);
1468131557Stjr
146953705Sobrien  prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
147053705Sobrien
1471131557Stjr  while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1)
147253451Speter    switch (opt)
147353451Speter      {
147453451Speter      case 'A':
1475131557Stjr	context_length_arg (optarg, &out_after);
147653451Speter	break;
1477131557Stjr
147853451Speter      case 'B':
1479131557Stjr	context_length_arg (optarg, &out_before);
148053451Speter	break;
1481131557Stjr
148253451Speter      case 'C':
148353477Sobrien	/* Set output match context, but let any explicit leading or
148453477Sobrien	   trailing amount specified with -A or -B stand. */
1485131557Stjr	context_length_arg (optarg, &default_context);
1486131557Stjr	break;
1487131557Stjr
1488131557Stjr      case 'D':
1489131557Stjr	if (strcmp (optarg, "read") == 0)
1490131557Stjr	  devices = READ_DEVICES;
1491131557Stjr	else if (strcmp (optarg, "skip") == 0)
1492131557Stjr	  devices = SKIP_DEVICES;
149353477Sobrien	else
1494131557Stjr	  error (2, 0, _("unknown devices method"));
149553451Speter	break;
1496131557Stjr
149753451Speter      case 'E':
149855379Sobrien	setmatcher ("egrep");
149953451Speter	break;
1500131557Stjr
150153451Speter      case 'F':
150255379Sobrien	setmatcher ("fgrep");
150353451Speter	break;
1504131557Stjr
1505131557Stjr      case 'P':
1506131557Stjr	setmatcher ("perl");
1507131557Stjr	break;
1508131557Stjr
150953451Speter      case 'G':
151055379Sobrien	setmatcher ("grep");
151153451Speter	break;
1512131557Stjr
151353477Sobrien      case 'H':
151453477Sobrien	with_filenames = 1;
151553477Sobrien	break;
1516131557Stjr
151756920Sru      case 'I':
151856920Sru	binary_files = WITHOUT_MATCH_BINARY_FILES;
151956920Sru	break;
1520103372Sobrien      case 'J':
1521104555Sobrien	if (Zflag)
1522104555Sobrien	  {
1523104555Sobrien	    printf (_("Cannot mix -Z and -J.\n"));
1524104555Sobrien	    usage (2);
1525104555Sobrien	  }
1526103372Sobrien	BZflag = 1;
1527103372Sobrien	break;
1528131557Stjr
152955379Sobrien      case 'U':
1530131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
153153477Sobrien	dos_use_file_type = DOS_BINARY;
153255379Sobrien#endif
153353477Sobrien	break;
1534131557Stjr
153553477Sobrien      case 'u':
1536131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
153753477Sobrien	dos_report_unix_offset = 1;
153855379Sobrien#endif
153953477Sobrien	break;
1540131557Stjr
154153451Speter      case 'V':
154253477Sobrien	show_version = 1;
154353451Speter	break;
1544131557Stjr
154553451Speter      case 'X':
154655379Sobrien	setmatcher (optarg);
154753451Speter	break;
1548131557Stjr
154953451Speter      case 'a':
155056233Sru	binary_files = TEXT_BINARY_FILES;
155153451Speter	break;
1552131557Stjr
155353451Speter      case 'b':
155453451Speter	out_byte = 1;
155553451Speter	break;
1556131557Stjr
155753451Speter      case 'c':
155853451Speter	count_matches = 1;
155953451Speter	break;
1560131557Stjr
156153477Sobrien      case 'd':
156253477Sobrien	if (strcmp (optarg, "read") == 0)
156353477Sobrien	  directories = READ_DIRECTORIES;
156453477Sobrien	else if (strcmp (optarg, "skip") == 0)
156553477Sobrien	  directories = SKIP_DIRECTORIES;
156653477Sobrien	else if (strcmp (optarg, "recurse") == 0)
156753477Sobrien	  directories = RECURSE_DIRECTORIES;
156853477Sobrien	else
1569131557Stjr	  error (2, 0, _("unknown directories method"));
157053477Sobrien	break;
1571131557Stjr
157253451Speter      case 'e':
157353477Sobrien	cc = strlen (optarg);
157453477Sobrien	keys = xrealloc (keys, keycc + cc + 1);
157553477Sobrien	strcpy (&keys[keycc], optarg);
157653451Speter	keycc += cc;
157753477Sobrien	keys[keycc++] = '\n';
157853451Speter	break;
1579131557Stjr
158053451Speter      case 'f':
158153477Sobrien	fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
158253451Speter	if (!fp)
1583131557Stjr	  error (2, errno, "%s", optarg);
158453477Sobrien	for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
158553451Speter	  ;
158653477Sobrien	keys = xrealloc (keys, keyalloc);
158753451Speter	oldcc = keycc;
158853477Sobrien	while (!feof (fp)
158953477Sobrien	       && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
159053451Speter	  {
159153451Speter	    keycc += cc;
159253477Sobrien	    if (keycc == keyalloc - 1)
159353477Sobrien	      keys = xrealloc (keys, keyalloc *= 2);
159453451Speter	  }
159553451Speter	if (fp != stdin)
159653451Speter	  fclose(fp);
159753477Sobrien	/* Append final newline if file ended in non-newline. */
159853477Sobrien	if (oldcc != keycc && keys[keycc - 1] != '\n')
159953477Sobrien	  keys[keycc++] = '\n';
160053451Speter	break;
1601131557Stjr
160253451Speter      case 'h':
160353451Speter	no_filenames = 1;
160453451Speter	break;
1605131557Stjr
160653451Speter      case 'i':
160753451Speter      case 'y':			/* For old-timers . . . */
160853451Speter	match_icase = 1;
160953451Speter	break;
1610131557Stjr
161153451Speter      case 'L':
161253451Speter	/* Like -l, except list files that don't contain matches.
161353451Speter	   Inspired by the same option in Hume's gre. */
161453451Speter	list_files = -1;
161553451Speter	break;
1616131557Stjr
161753451Speter      case 'l':
161853451Speter	list_files = 1;
161953451Speter	break;
1620131557Stjr
1621131557Stjr      case 'm':
1622131557Stjr	{
1623131557Stjr	  uintmax_t value;
1624131557Stjr	  switch (xstrtoumax (optarg, 0, 10, &value, ""))
1625131557Stjr	    {
1626131557Stjr	    case LONGINT_OK:
1627131557Stjr	      max_count = value;
1628131557Stjr	      if (0 <= max_count && max_count == value)
1629131557Stjr		break;
1630131557Stjr	      /* Fall through.  */
1631131557Stjr	    case LONGINT_OVERFLOW:
1632131557Stjr	      max_count = TYPE_MAXIMUM (off_t);
1633131557Stjr	      break;
1634131557Stjr
1635131557Stjr	    default:
1636131557Stjr	      error (2, 0, _("invalid max count"));
1637131557Stjr	    }
1638131557Stjr	}
1639131557Stjr	break;
1640131557Stjr
164153451Speter      case 'n':
164253451Speter	out_line = 1;
164353451Speter	break;
1644131557Stjr
1645131557Stjr      case 'o':
1646131557Stjr	only_matching = 1;
1647131557Stjr	break;
1648131557Stjr
164953451Speter      case 'q':
1650131557Stjr	exit_on_match = 1;
1651131557Stjr	close_stdout_set_status(0);
165253451Speter	break;
1653131557Stjr
165453478Sobrien      case 'R':
165553477Sobrien      case 'r':
165653477Sobrien	directories = RECURSE_DIRECTORIES;
165753477Sobrien	break;
1658131557Stjr
165953451Speter      case 's':
166053451Speter	suppress_errors = 1;
166153451Speter	break;
1662131557Stjr
166353451Speter      case 'v':
166453451Speter	out_invert = 1;
166553451Speter	break;
1666131557Stjr
166753451Speter      case 'w':
166853451Speter	match_words = 1;
166953451Speter	break;
1670131557Stjr
167153451Speter      case 'x':
167253451Speter	match_lines = 1;
167353451Speter	break;
1674131557Stjr
167555379Sobrien      case 'Z':
167655379Sobrien#if HAVE_LIBZ > 0
1677104555Sobrien	if (BZflag)
1678104555Sobrien	  {
1679104555Sobrien	    printf (_("Cannot mix -J and -Z.\n"));
1680104555Sobrien	    usage (2);
1681104555Sobrien	  }
168255379Sobrien	Zflag = 1;
168355379Sobrien#else
168455379Sobrien	filename_mask = 0;
168555379Sobrien#endif
168655379Sobrien	break;
1687131557Stjr
168855379Sobrien      case 'z':
168955379Sobrien	eolbyte = '\0';
169055379Sobrien	break;
1691131557Stjr
169256233Sru      case BINARY_FILES_OPTION:
169356233Sru	if (strcmp (optarg, "binary") == 0)
169456233Sru	  binary_files = BINARY_BINARY_FILES;
169556233Sru	else if (strcmp (optarg, "text") == 0)
169656233Sru	  binary_files = TEXT_BINARY_FILES;
169756233Sru	else if (strcmp (optarg, "without-match") == 0)
169856233Sru	  binary_files = WITHOUT_MATCH_BINARY_FILES;
169956233Sru	else
1700131557Stjr	  error (2, 0, _("unknown binary-files type"));
170156233Sru	break;
1702131557Stjr
1703131557Stjr      case COLOR_OPTION:
1704131557Stjr        if(optarg) {
1705131557Stjr          if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") ||
1706131557Stjr             !strcasecmp(optarg, "force"))
1707131557Stjr            color_option = 1;
1708131557Stjr          else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") ||
1709131557Stjr                  !strcasecmp(optarg, "none"))
1710131557Stjr            color_option = 0;
1711131557Stjr          else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") ||
1712131557Stjr                  !strcasecmp(optarg, "if-tty"))
1713131557Stjr            color_option = 2;
1714131557Stjr          else
1715131557Stjr            show_help = 1;
1716131557Stjr        } else
1717131557Stjr          color_option = 2;
1718131557Stjr        if(color_option == 2) {
1719131557Stjr          if(isatty(STDOUT_FILENO) && getenv("TERM") &&
1720131557Stjr	     strcmp(getenv("TERM"), "dumb"))
1721131557Stjr                  color_option = 1;
1722131557Stjr          else
1723131557Stjr            color_option = 0;
1724131557Stjr        }
1725131557Stjr	break;
1726131557Stjr
1727131557Stjr      case EXCLUDE_OPTION:
1728131557Stjr	if (!excluded_patterns)
1729131557Stjr	  excluded_patterns = new_exclude ();
1730131557Stjr	add_exclude (excluded_patterns, optarg);
1731131557Stjr	break;
1732131557Stjr
1733131557Stjr      case EXCLUDE_FROM_OPTION:
1734131557Stjr	if (!excluded_patterns)
1735131557Stjr	  excluded_patterns = new_exclude ();
1736131557Stjr        if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n')
1737131557Stjr	    != 0)
1738131557Stjr          {
1739131557Stjr            error (2, errno, "%s", optarg);
1740131557Stjr          }
1741131557Stjr        break;
1742131557Stjr
1743131557Stjr      case INCLUDE_OPTION:
1744131557Stjr	if (!included_patterns)
1745131557Stjr	  included_patterns = new_exclude ();
1746131557Stjr	add_exclude (included_patterns, optarg);
1747131557Stjr	break;
1748131557Stjr
1749131557Stjr      case LINE_BUFFERED_OPTION:
1750131557Stjr	line_buffered = 1;
1751131557Stjr	break;
1752131557Stjr
1753131557Stjr      case LABEL_OPTION:
1754131557Stjr	label = optarg;
1755131557Stjr	break;
1756131557Stjr
175753477Sobrien      case 0:
175853477Sobrien	/* long options */
175953477Sobrien	break;
1760131557Stjr
176153451Speter      default:
176253477Sobrien	usage (2);
176353451Speter	break;
1764131557Stjr
176553451Speter      }
176653451Speter
1767131557Stjr  /* POSIX.2 says that -q overrides -l, which in turn overrides the
1768131557Stjr     other output options.  */
1769131557Stjr  if (exit_on_match)
1770131557Stjr    list_files = 0;
1771131557Stjr  if (exit_on_match | list_files)
1772131557Stjr    {
1773131557Stjr      count_matches = 0;
1774131557Stjr      done_on_match = 1;
1775131557Stjr    }
1776131557Stjr  out_quiet = count_matches | done_on_match;
1777131557Stjr
177853477Sobrien  if (out_after < 0)
177953477Sobrien    out_after = default_context;
178053477Sobrien  if (out_before < 0)
178153477Sobrien    out_before = default_context;
178253477Sobrien
1783131557Stjr  if (color_option)
1784131557Stjr    {
1785131557Stjr      char *userval = getenv ("GREP_COLOR");
1786131557Stjr      if (userval != NULL && *userval != '\0')
1787131557Stjr	grep_color = userval;
1788131557Stjr    }
1789131557Stjr
179055379Sobrien  if (! matcher)
1791131557Stjr    matcher = program_name;
179255379Sobrien
179353477Sobrien  if (show_version)
179453477Sobrien    {
179555379Sobrien      printf (_("%s (GNU grep) %s\n"), matcher, VERSION);
179653477Sobrien      printf ("\n");
179753477Sobrien      printf (_("\
1798131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n"));
179953477Sobrien      printf (_("\
180053477SobrienThis is free software; see the source for copying conditions. There is NO\n\
180153477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
180253477Sobrien      printf ("\n");
180353477Sobrien      exit (0);
180453477Sobrien    }
180553477Sobrien
180653477Sobrien  if (show_help)
180753477Sobrien    usage (0);
180853477Sobrien
180953477Sobrien  if (keys)
181053477Sobrien    {
181153477Sobrien      if (keycc == 0)
1812131557Stjr	{
1813131557Stjr	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
1814131557Stjr	  out_invert ^= 1;
1815131557Stjr	  match_lines = match_words = 0;
1816131557Stjr	}
181753477Sobrien      else
181853477Sobrien	/* Strip trailing newline. */
181953477Sobrien        --keycc;
182053477Sobrien    }
182153477Sobrien  else
182253451Speter    if (optind < argc)
182353451Speter      {
182453451Speter	keys = argv[optind++];
182553477Sobrien	keycc = strlen (keys);
182653451Speter      }
182753451Speter    else
182853477Sobrien      usage (2);
182953451Speter
183055379Sobrien  if (!install_matcher (matcher) && !install_matcher ("default"))
183153477Sobrien    abort ();
183253451Speter
1833131564Stjr#ifdef MBS_SUPPORT
1834131564Stjr  if (MB_CUR_MAX != 1 && match_icase)
1835131564Stjr    {
1836131564Stjr      wchar_t wc;
1837131564Stjr      mbstate_t cur_state, prev_state;
1838131564Stjr      int i, len = strlen(keys);
1839131564Stjr
1840131564Stjr      memset(&cur_state, 0, sizeof(mbstate_t));
1841131564Stjr      for (i = 0; i <= len ;)
1842131564Stjr	{
1843131564Stjr	  size_t mbclen;
1844131564Stjr	  mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state);
1845131564Stjr	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
1846131564Stjr	    {
1847131564Stjr	      /* An invalid sequence, or a truncated multibyte character.
1848131564Stjr		 We treat it as a singlebyte character.  */
1849131564Stjr	      mbclen = 1;
1850131564Stjr	    }
1851131564Stjr	  else
1852131564Stjr	    {
1853131564Stjr	      if (iswupper((wint_t)wc))
1854131564Stjr		{
1855131564Stjr		  wc = towlower((wint_t)wc);
1856131564Stjr		  wcrtomb(keys + i, wc, &cur_state);
1857131564Stjr		}
1858131564Stjr	    }
1859131564Stjr	  i += mbclen;
1860131564Stjr	}
1861131564Stjr    }
1862131564Stjr#endif /* MBS_SUPPORT */
1863131564Stjr
186453451Speter  (*compile)(keys, keycc);
186553451Speter
186653477Sobrien  if ((argc - optind > 1 && !no_filenames) || with_filenames)
186753451Speter    out_file = 1;
186853451Speter
1869131557Stjr#ifdef SET_BINARY
187053477Sobrien  /* Output is set to binary mode because we shouldn't convert
187153477Sobrien     NL to CR-LF pairs, especially when grepping binary files.  */
187253477Sobrien  if (!isatty (1))
187353477Sobrien    SET_BINARY (1);
187453451Speter#endif
187553451Speter
1876131557Stjr  if (max_count == 0)
1877131557Stjr    exit (1);
187853451Speter
187953451Speter  if (optind < argc)
188053451Speter    {
188153477Sobrien	status = 1;
188253477Sobrien	do
188353451Speter	{
188453477Sobrien	  char *file = argv[optind];
1885131557Stjr	  if ((included_patterns || excluded_patterns)
1886131557Stjr	      && !isdir (file))
1887131557Stjr	    {
1888131557Stjr	      if (included_patterns &&
1889131557Stjr		  ! excluded_filename (included_patterns, file, 0))
1890131557Stjr		continue;
1891131557Stjr	      if (excluded_patterns &&
1892131557Stjr		  excluded_filename (excluded_patterns, file, 0))
1893131557Stjr		continue;
1894131557Stjr	    }
189553477Sobrien	  status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
189653477Sobrien			      &stats_base);
189753451Speter	}
189853477Sobrien	while ( ++optind < argc);
189953451Speter    }
190053477Sobrien  else
190153477Sobrien    status = grepfile ((char *) NULL, &stats_base);
190253451Speter
1903131557Stjr  /* We register via atexit() to test stdout.  */
190453477Sobrien  exit (errseen ? 2 : status);
190553451Speter}
1906131557Stjr/* vim:set shiftwidth=2: */
1907