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$ */
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));
201146199Stjrstatic size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));
20253477Sobrien
203131557Stjr/* Like error, but suppress the diagnostic if requested.  */
20453451Speterstatic void
205131557Stjrsuppressible_error (char const *mesg, int errnum)
20653451Speter{
207131557Stjr  if (! suppress_errors)
208131557Stjr    error (0, errnum, "%s", mesg);
20953451Speter  errseen = 1;
21053451Speter}
21153451Speter
21253477Sobrien/* Convert STR to a positive integer, storing the result in *OUT.
213131557Stjr   STR must be a valid context length argument; report an error if it
214131557Stjr   isn't.  */
215131557Stjrstatic void
216131557Stjrcontext_length_arg (char const *str, int *out)
21753477Sobrien{
218131557Stjr  uintmax_t value;
219131557Stjr  if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK
220131557Stjr	 && 0 <= (*out = value)
221131557Stjr	 && *out == value))
222131557Stjr    {
223131557Stjr      error (2, 0, "%s: %s\n", str, _("invalid context length argument"));
224131557Stjr    }
22553477Sobrien}
22653477Sobrien
22753477Sobrien
22853451Speter/* Hairy buffering mechanism for grep.  The intent is to keep
22953451Speter   all reads aligned on a page boundary and multiples of the
230131557Stjr   page size, unless a read yields a partial page.  */
23153451Speter
23253451Speterstatic char *buffer;		/* Base of buffer. */
233131557Stjrstatic size_t bufalloc;		/* Allocated buffer size, counting slop. */
234131557Stjr#define INITIAL_BUFSIZE 32768	/* Initial buffer size, not counting slop. */
23553451Speterstatic int bufdesc;		/* File descriptor. */
23653451Speterstatic char *bufbeg;		/* Beginning of user-visible stuff. */
23753451Speterstatic char *buflim;		/* Limit of user-visible stuff. */
23853477Sobrienstatic size_t pagesize;		/* alignment of memory pages */
23955379Sobrienstatic off_t bufoffset;		/* Read offset; defined on regular files.  */
240131557Stjrstatic off_t after_last_match;	/* Pointer after last matching line that
241131557Stjr				   would have been output if we were
242131557Stjr				   outputting characters. */
24353451Speter
24453477Sobrien#if defined(HAVE_MMAP)
24555379Sobrienstatic int bufmapped;		/* True if buffer is memory-mapped.  */
24653477Sobrienstatic off_t initial_bufoffset;	/* Initial value of bufoffset. */
247131557Stjr#else
248131557Stjr# define bufmapped 0
24953451Speter#endif
25053451Speter
251103372Sobrien#include <bzlib.h>
252103372Sobrienstatic BZFILE* bzbufdesc;	/* libbz2 file handle. */
253103372Sobrienstatic int BZflag;		/* uncompress before searching. */
25453451Speter#if HAVE_LIBZ > 0
25553451Speter#include <zlib.h>
25653477Sobrienstatic gzFile gzbufdesc;	/* zlib file descriptor. */
25753477Sobrienstatic int Zflag;		/* uncompress before searching. */
25853451Speter#endif
25953451Speter
26053477Sobrien/* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be
26153477Sobrien   an integer or a pointer.  Both args must be free of side effects.  */
26253477Sobrien#define ALIGN_TO(val, alignment) \
26353477Sobrien  ((size_t) (val) % (alignment) == 0 \
26453477Sobrien   ? (val) \
26553477Sobrien   : (val) + ((alignment) - (size_t) (val) % (alignment)))
26653477Sobrien
26753477Sobrien/* Reset the buffer for a new file, returning zero if we should skip it.
26853477Sobrien   Initialize on the first time through. */
26953477Sobrienstatic int
27056920Srureset (int fd, char const *file, struct stats *stats)
27153451Speter{
272131557Stjr  if (! pagesize)
27353451Speter    {
27453477Sobrien      pagesize = getpagesize ();
275131557Stjr      if (pagesize == 0 || 2 * pagesize + 1 <= pagesize)
27653477Sobrien	abort ();
277131557Stjr      bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1;
278131557Stjr      buffer = xmalloc (bufalloc);
27953451Speter    }
280103372Sobrien  if (BZflag)
281103372Sobrien    {
282103372Sobrien    bzbufdesc = BZ2_bzdopen(fd, "r");
283103372Sobrien    if (bzbufdesc == NULL)
284131557Stjr      error(2, 0, _("memory exhausted"));
285103372Sobrien    }
28653451Speter#if HAVE_LIBZ > 0
28755379Sobrien  if (Zflag)
28855379Sobrien    {
28953451Speter    gzbufdesc = gzdopen(fd, "r");
29053477Sobrien    if (gzbufdesc == NULL)
291131557Stjr      error(2, 0, _("memory exhausted"));
29255379Sobrien    }
29353451Speter#endif
29455379Sobrien
295131557Stjr  bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);
296131557Stjr  bufbeg[-1] = eolbyte;
29753477Sobrien  bufdesc = fd;
29853477Sobrien
29955379Sobrien  if (fstat (fd, &stats->stat) != 0)
30055379Sobrien    {
301131557Stjr      error (0, errno, "fstat");
30255379Sobrien      return 0;
30355379Sobrien    }
30453477Sobrien  if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
30553477Sobrien    return 0;
306131557Stjr#ifndef DJGPP
307131557Stjr  if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode)))
308131557Stjr#else
309131557Stjr  if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode)))
310131557Stjr#endif
311131557Stjr    return 0;
31253477Sobrien  if (
313103372Sobrien      BZflag ||
31453451Speter#if HAVE_LIBZ > 0
31553477Sobrien      Zflag ||
31653451Speter#endif
31755379Sobrien      S_ISREG (stats->stat.st_mode))
31855379Sobrien    {
31955379Sobrien      if (file)
32055379Sobrien	bufoffset = 0;
32155379Sobrien      else
32255379Sobrien	{
32355379Sobrien	  bufoffset = lseek (fd, 0, SEEK_CUR);
32455379Sobrien	  if (bufoffset < 0)
32555379Sobrien	    {
326131557Stjr	      error (0, errno, "lseek");
32755379Sobrien	      return 0;
32855379Sobrien	    }
32955379Sobrien	}
330131557Stjr#if defined(HAVE_MMAP)
33155379Sobrien      initial_bufoffset = bufoffset;
33255379Sobrien      bufmapped = mmap_option && bufoffset % pagesize == 0;
33355379Sobrien#endif
33455379Sobrien    }
33553451Speter  else
33653451Speter    {
337131557Stjr#if defined(HAVE_MMAP)
33855379Sobrien      bufmapped = 0;
33955379Sobrien#endif
34053451Speter    }
34153477Sobrien  return 1;
34253451Speter}
34353451Speter
34453451Speter/* Read new stuff into the buffer, saving the specified
34553451Speter   amount of old stuff.  When we're done, 'bufbeg' points
34653451Speter   to the beginning of the buffer contents, and 'buflim'
34755379Sobrien   points just after the end.  Return zero if there's an error.  */
34853451Speterstatic int
349131557Stjrfillbuf (size_t save, struct stats const *stats)
35053451Speter{
35155379Sobrien  size_t fillsize = 0;
35255379Sobrien  int cc = 1;
353131557Stjr  char *readbuf;
35455379Sobrien  size_t readsize;
35553451Speter
356131557Stjr  /* Offset from start of buffer to start of old stuff
35755379Sobrien     that we want to save.  */
358131557Stjr  size_t saved_offset = buflim - save - buffer;
35955379Sobrien
360131557Stjr  if (pagesize <= buffer + bufalloc - buflim)
36153451Speter    {
362131557Stjr      readbuf = buflim;
363131557Stjr      bufbeg = buflim - save;
364131557Stjr    }
365131557Stjr  else
366131557Stjr    {
367131557Stjr      size_t minsize = save + pagesize;
368131557Stjr      size_t newsize;
36955379Sobrien      size_t newalloc;
370131557Stjr      char *newbuf;
37153477Sobrien
372131557Stjr      /* Grow newsize until it is at least as great as minsize.  */
373131557Stjr      for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)
374131557Stjr	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)
375131557Stjr	  xalloc_die ();
376131557Stjr
377131557Stjr      /* Try not to allocate more memory than the file size indicates,
378131557Stjr	 as that might cause unnecessary memory exhaustion if the file
379131557Stjr	 is large.  However, do not use the original file size as a
380131557Stjr	 heuristic if we've already read past the file end, as most
381131557Stjr	 likely the file is growing.  */
38255379Sobrien      if (S_ISREG (stats->stat.st_mode))
38355379Sobrien	{
38455379Sobrien	  off_t to_be_read = stats->stat.st_size - bufoffset;
385131557Stjr	  off_t maxsize_off = save + to_be_read;
386131557Stjr	  if (0 <= to_be_read && to_be_read <= maxsize_off
387131557Stjr	      && maxsize_off == (size_t) maxsize_off
388131557Stjr	      && minsize <= (size_t) maxsize_off
389131557Stjr	      && (size_t) maxsize_off < newsize)
390131557Stjr	    newsize = maxsize_off;
39155379Sobrien	}
39255379Sobrien
393131557Stjr      /* Add enough room so that the buffer is aligned and has room
394131557Stjr	 for byte sentinels fore and aft.  */
395131557Stjr      newalloc = newsize + pagesize + 1;
39655379Sobrien
397131557Stjr      newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
398131557Stjr      readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);
399131557Stjr      bufbeg = readbuf - save;
400131557Stjr      memmove (bufbeg, buffer + saved_offset, save);
401131557Stjr      bufbeg[-1] = eolbyte;
402131557Stjr      if (newbuf != buffer)
40355379Sobrien	{
404131557Stjr	  free (buffer);
405131557Stjr	  buffer = newbuf;
40655379Sobrien	}
40753451Speter    }
40853451Speter
409131557Stjr  readsize = buffer + bufalloc - readbuf;
410131557Stjr  readsize -= readsize % pagesize;
41155379Sobrien
41253477Sobrien#if defined(HAVE_MMAP)
41355379Sobrien  if (bufmapped)
41453451Speter    {
41555379Sobrien      size_t mmapsize = readsize;
41655379Sobrien
41755379Sobrien      /* Don't mmap past the end of the file; some hosts don't allow this.
41855379Sobrien	 Use `read' on the last page.  */
41955379Sobrien      if (stats->stat.st_size - bufoffset < mmapsize)
42053451Speter	{
42155379Sobrien	  mmapsize = stats->stat.st_size - bufoffset;
42255379Sobrien	  mmapsize -= mmapsize % pagesize;
42353451Speter	}
42455379Sobrien
42555379Sobrien      if (mmapsize
426131557Stjr	  && (mmap ((caddr_t) readbuf, mmapsize,
42755379Sobrien		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
42855379Sobrien		    bufdesc, bufoffset)
42955379Sobrien	      != (caddr_t) -1))
43053451Speter	{
43155379Sobrien	  /* Do not bother to use madvise with MADV_SEQUENTIAL or
43255379Sobrien	     MADV_WILLNEED on the mmapped memory.  One might think it
43355379Sobrien	     would help, but it slows us down about 30% on SunOS 4.1.  */
43455379Sobrien	  fillsize = mmapsize;
43555379Sobrien	}
43655379Sobrien      else
43755379Sobrien	{
43855379Sobrien	  /* Stop using mmap on this file.  Synchronize the file
43955379Sobrien	     offset.  Do not warn about mmap failures.  On some hosts
44055379Sobrien	     (e.g. Solaris 2.5) mmap can fail merely because some
44155379Sobrien	     other process has an advisory read lock on the file.
44255379Sobrien	     There's no point alarming the user about this misfeature.  */
44353451Speter	  bufmapped = 0;
44455379Sobrien	  if (bufoffset != initial_bufoffset
44555379Sobrien	      && lseek (bufdesc, bufoffset, SEEK_SET) < 0)
44655379Sobrien	    {
447131557Stjr	      error (0, errno, "lseek");
44855379Sobrien	      cc = 0;
44955379Sobrien	    }
45053451Speter	}
45155379Sobrien    }
45255379Sobrien#endif /*HAVE_MMAP*/
45355379Sobrien
45455379Sobrien  if (! fillsize)
45555379Sobrien    {
45655379Sobrien      ssize_t bytesread;
45755379Sobrien      do
458104555Sobrien	if (BZflag && bzbufdesc)
459103372Sobrien	  {
460104555Sobrien	    int bzerr;
461131557Stjr	    bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize);
462104555Sobrien
463104555Sobrien	    switch (bzerr)
464104555Sobrien	      {
465104555Sobrien	      case BZ_OK:
466104555Sobrien	      case BZ_STREAM_END:
467104555Sobrien		/* ok */
468104555Sobrien		break;
469104555Sobrien	      case BZ_DATA_ERROR_MAGIC:
470104555Sobrien		BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL;
471104555Sobrien		lseek (bufdesc, 0, SEEK_SET);
472131557Stjr		bytesread = read (bufdesc, readbuf, readsize);
473104555Sobrien		break;
474104555Sobrien	      default:
475104555Sobrien		bytesread = 0;
476104555Sobrien		break;
477104555Sobrien	      }
478103372Sobrien	  }
479103372Sobrien	else
48053451Speter#if HAVE_LIBZ > 0
48155379Sobrien	if (Zflag)
482131557Stjr	  bytesread = gzread (gzbufdesc, readbuf, readsize);
48355379Sobrien	else
48455379Sobrien#endif
485131557Stjr	  bytesread = read (bufdesc, readbuf, readsize);
48655379Sobrien      while (bytesread < 0 && errno == EINTR);
48755379Sobrien      if (bytesread < 0)
48855379Sobrien	cc = 0;
48953477Sobrien      else
49055379Sobrien	fillsize = bytesread;
49153451Speter    }
49255379Sobrien
49355379Sobrien  bufoffset += fillsize;
494131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
49555379Sobrien  if (fillsize)
496131557Stjr    fillsize = undossify_input (readbuf, fillsize);
49753451Speter#endif
498131557Stjr  buflim = readbuf + fillsize;
49953451Speter  return cc;
50053451Speter}
50153451Speter
50253451Speter/* Flags controlling the style of output. */
50356233Srustatic enum
504131557Stjr{
505131557Stjr  BINARY_BINARY_FILES,
506131557Stjr  TEXT_BINARY_FILES,
507131557Stjr  WITHOUT_MATCH_BINARY_FILES
508131557Stjr} binary_files;		/* How to handle binary files.  */
509131557Stjr
510131557Stjrstatic int filename_mask;	/* If zero, output nulls after filenames.  */
51153451Speterstatic int out_quiet;		/* Suppress all normal output. */
51253451Speterstatic int out_invert;		/* Print nonmatching stuff. */
51353451Speterstatic int out_file;		/* Print filenames. */
51453451Speterstatic int out_line;		/* Print line numbers. */
51553451Speterstatic int out_byte;		/* Print byte offsets. */
51653451Speterstatic int out_before;		/* Lines of leading context. */
51753451Speterstatic int out_after;		/* Lines of trailing context. */
51853477Sobrienstatic int count_matches;	/* Count matching lines.  */
51953477Sobrienstatic int list_files;		/* List matching files.  */
52053477Sobrienstatic int no_filenames;	/* Suppress file names.  */
521131557Stjrstatic off_t max_count;		/* Stop after outputting this many
522131557Stjr				   lines from an input file.  */
523131557Stjrstatic int line_buffered;       /* If nonzero, use line buffering, i.e.
524131557Stjr				   fflush everyline out.  */
525131557Stjrstatic char *label = NULL;      /* Fake filename for stdin */
52653451Speter
527131557Stjr
52853451Speter/* Internal variables to keep track of byte count, context, etc. */
529131557Stjrstatic uintmax_t totalcc;	/* Total character count before bufbeg. */
530131557Stjrstatic char const *lastnl;	/* Pointer after last newline counted. */
531131557Stjrstatic char const *lastout;	/* Pointer after last character output;
53253451Speter				   NULL if no character has been output
53353451Speter				   or if it's conceptually before bufbeg. */
534131557Stjrstatic uintmax_t totalnl;	/* Total newline count before lastnl. */
535131557Stjrstatic off_t outleft;		/* Maximum number of lines to be output.  */
536131557Stjrstatic int pending;		/* Pending lines of output.
537131557Stjr				   Always kept 0 if out_quiet is true.  */
538131557Stjrstatic int done_on_match;	/* Stop scanning file on first match.  */
539131557Stjrstatic int exit_on_match;	/* Exit on first match.  */
54053451Speter
541131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
54253477Sobrien# include "dosbuf.c"
54353477Sobrien#endif
54453477Sobrien
545131557Stjr/* Add two numbers that count input bytes or lines, and report an
546131557Stjr   error if the addition overflows.  */
547131557Stjrstatic uintmax_t
548131557Stjradd_count (uintmax_t a, uintmax_t b)
549131557Stjr{
550131557Stjr  uintmax_t sum = a + b;
551131557Stjr  if (sum < a)
552131557Stjr    error (2, 0, _("input is too large to count"));
553131557Stjr  return sum;
554131557Stjr}
555131557Stjr
55653451Speterstatic void
557131557Stjrnlscan (char const *lim)
55853451Speter{
559131557Stjr  size_t newlines = 0;
560131557Stjr  char const *beg;
561131557Stjr  for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++)
562131557Stjr    newlines++;
563131557Stjr  totalnl = add_count (totalnl, newlines);
56455379Sobrien  lastnl = lim;
56553451Speter}
56653451Speter
567131557Stjr/* Print a byte offset, followed by a character separator.  */
56853451Speterstatic void
569131557Stjrprint_offset_sep (uintmax_t pos, char sep)
57053477Sobrien{
571131557Stjr  /* Do not rely on printf to print pos, since uintmax_t may be longer
572131557Stjr     than long, and long long is not portable.  */
57353477Sobrien
57453477Sobrien  char buf[sizeof pos * CHAR_BIT];
57553477Sobrien  char *p = buf + sizeof buf - 1;
57653477Sobrien  *p = sep;
57753477Sobrien
57853477Sobrien  do
57953477Sobrien    *--p = '0' + pos % 10;
58053477Sobrien  while ((pos /= 10) != 0);
58153477Sobrien
58253477Sobrien  fwrite (p, 1, buf + sizeof buf - p, stdout);
58353477Sobrien}
58453477Sobrien
58553477Sobrienstatic void
586146199Stjrprline (char const *beg, char const *lim, int sep)
58753451Speter{
58853451Speter  if (out_file)
58955379Sobrien    printf ("%s%c", filename, sep & filename_mask);
59053451Speter  if (out_line)
59153451Speter    {
59253477Sobrien      nlscan (beg);
593131557Stjr      totalnl = add_count (totalnl, 1);
594131557Stjr      print_offset_sep (totalnl, sep);
59553451Speter      lastnl = lim;
59653451Speter    }
59753451Speter  if (out_byte)
59853477Sobrien    {
599131557Stjr      uintmax_t pos = add_count (totalcc, beg - bufbeg);
600131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
60153477Sobrien      pos = dossified_pos (pos);
60253477Sobrien#endif
60353477Sobrien      print_offset_sep (pos, sep);
60453477Sobrien    }
605131557Stjr  if (only_matching)
606131557Stjr    {
607131557Stjr      size_t match_size;
608131557Stjr      size_t match_offset;
609146199Stjr      while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1))
610131557Stjr	  != (size_t) -1)
611131557Stjr        {
612131557Stjr	  char const *b = beg + match_offset;
613131557Stjr	  if (b == lim)
614131557Stjr	    break;
615131557Stjr	  if (match_size == 0)
616131557Stjr	    break;
617131557Stjr	  if(color_option)
618131557Stjr	    printf("\33[%sm", grep_color);
619131557Stjr	  fwrite(b, sizeof (char), match_size, stdout);
620131557Stjr	  if(color_option)
621131557Stjr	    fputs("\33[00m", stdout);
622131557Stjr	  fputs("\n", stdout);
623131557Stjr	  beg = b + match_size;
624131557Stjr        }
625131557Stjr      lastout = lim;
626131557Stjr      if(line_buffered)
627131557Stjr	fflush(stdout);
628131557Stjr      return;
629131557Stjr    }
630131557Stjr  if (color_option)
631131557Stjr    {
632131557Stjr      size_t match_size;
633131557Stjr      size_t match_offset;
634146199Stjr      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
635131557Stjr	     != (size_t) -1)
636131557Stjr	{
637131557Stjr	  char const *b = beg + match_offset;
638131557Stjr	  /* Avoid matching the empty line at the end of the buffer. */
639131557Stjr	  if (b == lim)
640131557Stjr	    break;
641131557Stjr	  /* Avoid hanging on grep --color "" foo */
642131557Stjr	  if (match_size == 0)
643131557Stjr	    break;
644131557Stjr	  fwrite (beg, sizeof (char), match_offset, stdout);
645131557Stjr	  printf ("\33[%sm", grep_color);
646131557Stjr	  fwrite (b, sizeof (char), match_size, stdout);
647131557Stjr	  fputs ("\33[00m", stdout);
648131557Stjr	  beg = b + match_size;
649131557Stjr	}
650146203Stjr      fputs ("\33[K", stdout);
651131557Stjr    }
65253477Sobrien  fwrite (beg, 1, lim - beg, stdout);
65353477Sobrien  if (ferror (stdout))
654131557Stjr    error (0, errno, _("writing output"));
65553451Speter  lastout = lim;
656131557Stjr  if (line_buffered)
657131557Stjr    fflush (stdout);
65853451Speter}
65953451Speter
660131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends
661131557Stjr   at the next matching line when OUTLEFT is 0.  */
66253451Speterstatic void
663146199Stjrprpending (char const *lim)
66453451Speter{
66553451Speter  if (!lastout)
66653451Speter    lastout = bufbeg;
66753451Speter  while (pending > 0 && lastout < lim)
66853451Speter    {
669131557Stjr      char const *nl = memchr (lastout, eolbyte, lim - lastout);
670131557Stjr      size_t match_size;
67153451Speter      --pending;
672131557Stjr      if (outleft
673146199Stjr	  || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1)
674131557Stjr	      == !out_invert))
675146199Stjr	prline (lastout, nl + 1, '-');
67653451Speter      else
677131557Stjr	pending = 0;
67853451Speter    }
67953451Speter}
68053451Speter
68153451Speter/* Print the lines between BEG and LIM.  Deal with context crap.
682131557Stjr   If NLINESP is non-null, store a count of lines between BEG and LIM.  */
68353451Speterstatic void
684146199Stjrprtext (char const *beg, char const *lim, int *nlinesp)
68553451Speter{
68653451Speter  static int used;		/* avoid printing "--" before any output */
687131557Stjr  char const *bp, *p;
68855379Sobrien  char eol = eolbyte;
68953451Speter  int i, n;
69053451Speter
69153451Speter  if (!out_quiet && pending > 0)
692146199Stjr    prpending (beg);
69353451Speter
69453451Speter  p = beg;
69553451Speter
69653451Speter  if (!out_quiet)
69753451Speter    {
69853451Speter      /* Deal with leading context crap. */
69953451Speter
70053451Speter      bp = lastout ? lastout : bufbeg;
70153451Speter      for (i = 0; i < out_before; ++i)
70253451Speter	if (p > bp)
70353451Speter	  do
70453451Speter	    --p;
705131557Stjr	  while (p[-1] != eol);
70653451Speter
70753451Speter      /* We only print the "--" separator if our output is
70853451Speter	 discontiguous from the last output in the file. */
70953451Speter      if ((out_before || out_after) && used && p != lastout)
71053477Sobrien	puts ("--");
71153451Speter
71253451Speter      while (p < beg)
71353451Speter	{
714131557Stjr	  char const *nl = memchr (p, eol, beg - p);
715131557Stjr	  nl++;
716146199Stjr	  prline (p, nl, '-');
717131557Stjr	  p = nl;
71853451Speter	}
71953451Speter    }
72053451Speter
72153451Speter  if (nlinesp)
72253451Speter    {
72353451Speter      /* Caller wants a line count. */
724131557Stjr      for (n = 0; p < lim && n < outleft; n++)
72553451Speter	{
726131557Stjr	  char const *nl = memchr (p, eol, lim - p);
727131557Stjr	  nl++;
72853451Speter	  if (!out_quiet)
729146199Stjr	    prline (p, nl, ':');
73053451Speter	  p = nl;
73153451Speter	}
73253451Speter      *nlinesp = n;
733131557Stjr
734131557Stjr      /* relying on it that this function is never called when outleft = 0.  */
735131557Stjr      after_last_match = bufoffset - (buflim - p);
73653451Speter    }
73753451Speter  else
73853451Speter    if (!out_quiet)
739146199Stjr      prline (beg, lim, ':');
74053451Speter
74155379Sobrien  pending = out_quiet ? 0 : out_after;
74253451Speter  used = 1;
74353451Speter}
74453451Speter
74553451Speter/* Scan the specified portion of the buffer, matching lines (or
74653451Speter   between matching lines if OUT_INVERT is true).  Return a count of
74753451Speter   lines printed. */
74853451Speterstatic int
749146199Stjrgrepbuf (char const *beg, char const *lim)
75053451Speter{
75153451Speter  int nlines, n;
752131557Stjr  register char const *p;
753131557Stjr  size_t match_offset;
754131557Stjr  size_t match_size;
75553451Speter
75653451Speter  nlines = 0;
75753451Speter  p = beg;
758146199Stjr  while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
75953451Speter    {
760131557Stjr      char const *b = p + match_offset;
761131557Stjr      char const *endp = b + match_size;
76253451Speter      /* Avoid matching the empty line at the end of the buffer. */
763131557Stjr      if (b == lim)
76453451Speter	break;
76553451Speter      if (!out_invert)
76653451Speter	{
767146199Stjr	  prtext (b, endp, (int *) 0);
768131557Stjr	  nlines++;
769131557Stjr          outleft--;
770131557Stjr	  if (!outleft || done_on_match)
771131557Stjr	    {
772131557Stjr	      if (exit_on_match)
773131557Stjr		exit (0);
774131557Stjr	      after_last_match = bufoffset - (buflim - endp);
775131557Stjr	      return nlines;
776131557Stjr	    }
77753451Speter	}
77853451Speter      else if (p < b)
77953451Speter	{
780146199Stjr	  prtext (p, b, &n);
78153451Speter	  nlines += n;
782131557Stjr          outleft -= n;
783131557Stjr	  if (!outleft)
784131557Stjr	    return nlines;
78553451Speter	}
78653451Speter      p = endp;
78753451Speter    }
78853451Speter  if (out_invert && p < lim)
78953451Speter    {
790146199Stjr      prtext (p, lim, &n);
79153451Speter      nlines += n;
792131557Stjr      outleft -= n;
79353451Speter    }
79453451Speter  return nlines;
79553451Speter}
79653451Speter
79753477Sobrien/* Search a given file.  Normally, return a count of lines printed;
79853477Sobrien   but if the file is a directory and we search it recursively, then
79953477Sobrien   return -2 if there was a match, and -1 otherwise.  */
80053451Speterstatic int
80156920Srugrep (int fd, char const *file, struct stats *stats)
80253451Speter{
80353451Speter  int nlines, i;
80453477Sobrien  int not_text;
80553451Speter  size_t residue, save;
806131557Stjr  char oldc;
807131557Stjr  char *beg;
808131557Stjr  char *lim;
80955379Sobrien  char eol = eolbyte;
81053451Speter
81153477Sobrien  if (!reset (fd, file, stats))
81253477Sobrien    return 0;
81353451Speter
81453477Sobrien  if (file && directories == RECURSE_DIRECTORIES
81553477Sobrien      && S_ISDIR (stats->stat.st_mode))
81653477Sobrien    {
81753477Sobrien      /* Close fd now, so that we don't open a lot of file descriptors
81853477Sobrien	 when we recurse deeply.  */
819104555Sobrien      if (BZflag && bzbufdesc)
820103372Sobrien	BZ2_bzclose(bzbufdesc);
821103372Sobrien      else
82253477Sobrien#if HAVE_LIBZ > 0
82353477Sobrien      if (Zflag)
82453477Sobrien	gzclose(gzbufdesc);
82553477Sobrien      else
82653477Sobrien#endif
82753477Sobrien      if (close (fd) != 0)
828131557Stjr	error (0, errno, "%s", file);
82953477Sobrien      return grepdir (file, stats) - 2;
83053477Sobrien    }
83153477Sobrien
83253451Speter  totalcc = 0;
83353451Speter  lastout = 0;
83453451Speter  totalnl = 0;
835131557Stjr  outleft = max_count;
836131557Stjr  after_last_match = 0;
83753451Speter  pending = 0;
83853451Speter
83953451Speter  nlines = 0;
84053451Speter  residue = 0;
84153451Speter  save = 0;
84253451Speter
84355379Sobrien  if (! fillbuf (save, stats))
84453451Speter    {
845131557Stjr      if (! is_EISDIR (errno, file))
846131557Stjr	suppressible_error (filename, errno);
84756233Sru      return 0;
84853477Sobrien    }
84953451Speter
85056233Sru  not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
85156233Sru	       || binary_files == WITHOUT_MATCH_BINARY_FILES)
85255379Sobrien	      && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
85356233Sru  if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
85456233Sru    return 0;
85553477Sobrien  done_on_match += not_text;
85653477Sobrien  out_quiet += not_text;
85753451Speter
85853477Sobrien  for (;;)
85953477Sobrien    {
86053451Speter      lastnl = bufbeg;
86153451Speter      if (lastout)
86253451Speter	lastout = bufbeg;
863131557Stjr
864131557Stjr      beg = bufbeg + save;
865131557Stjr
866131557Stjr      /* no more data to scan (eof) except for maybe a residue -> break */
867131557Stjr      if (beg == buflim)
86853451Speter	break;
869131557Stjr
870131557Stjr      /* Determine new residue (the length of an incomplete line at the end of
871131557Stjr         the buffer, 0 means there is no incomplete last line).  */
872131557Stjr      oldc = beg[-1];
873131557Stjr      beg[-1] = eol;
874131557Stjr      for (lim = buflim; lim[-1] != eol; lim--)
875131557Stjr	continue;
876131557Stjr      beg[-1] = oldc;
877131557Stjr      if (lim == beg)
878131557Stjr	lim = beg - residue;
879131557Stjr      beg -= residue;
88053451Speter      residue = buflim - lim;
881131557Stjr
88253451Speter      if (beg < lim)
88353451Speter	{
884131557Stjr	  if (outleft)
885146199Stjr	    nlines += grepbuf (beg, lim);
88653451Speter	  if (pending)
887146199Stjr	    prpending (lim);
888131557Stjr	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
88953477Sobrien	    goto finish_grep;
89053451Speter	}
891131557Stjr
892131557Stjr      /* The last OUT_BEFORE lines at the end of the buffer will be needed as
893131557Stjr	 leading context if there is a matching line at the begin of the
894131557Stjr	 next data. Make beg point to their begin.  */
89553451Speter      i = 0;
89653451Speter      beg = lim;
89753451Speter      while (i < out_before && beg > bufbeg && beg != lastout)
89853451Speter	{
89953451Speter	  ++i;
90053451Speter	  do
90153451Speter	    --beg;
902131557Stjr	  while (beg[-1] != eol);
90353451Speter	}
904131557Stjr
905131557Stjr      /* detect if leading context is discontinuous from last printed line.  */
90653451Speter      if (beg != lastout)
90753451Speter	lastout = 0;
908131557Stjr
909131557Stjr      /* Handle some details and read more data to scan.  */
91053451Speter      save = residue + lim - beg;
911131557Stjr      if (out_byte)
912131557Stjr	totalcc = add_count (totalcc, buflim - bufbeg - save);
91353451Speter      if (out_line)
91453477Sobrien	nlscan (beg);
91555379Sobrien      if (! fillbuf (save, stats))
91653477Sobrien	{
917131557Stjr	  if (! is_EISDIR (errno, file))
918131557Stjr	    suppressible_error (filename, errno);
91953477Sobrien	  goto finish_grep;
92053477Sobrien	}
92153451Speter    }
92253451Speter  if (residue)
92353451Speter    {
92456920Sru      *buflim++ = eol;
925131557Stjr      if (outleft)
926146199Stjr	nlines += grepbuf (bufbeg + save - residue, buflim);
92753451Speter      if (pending)
928146199Stjr        prpending (buflim);
92953451Speter    }
93053477Sobrien
93153477Sobrien finish_grep:
93253477Sobrien  done_on_match -= not_text;
93353477Sobrien  out_quiet -= not_text;
93453477Sobrien  if ((not_text & ~out_quiet) && nlines != 0)
93553477Sobrien    printf (_("Binary file %s matches\n"), filename);
93653451Speter  return nlines;
93753451Speter}
93853451Speter
93953477Sobrienstatic int
94056920Srugrepfile (char const *file, struct stats *stats)
94153477Sobrien{
94253477Sobrien  int desc;
94353477Sobrien  int count;
94453477Sobrien  int status;
94553477Sobrien
94653477Sobrien  if (! file)
94753477Sobrien    {
94853477Sobrien      desc = 0;
949131557Stjr      filename = label ? label : _("(standard input)");
95053477Sobrien    }
95153477Sobrien  else
95253477Sobrien    {
95355379Sobrien      while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR)
95455379Sobrien	continue;
95553477Sobrien
95653477Sobrien      if (desc < 0)
95753477Sobrien	{
95853477Sobrien	  int e = errno;
959131557Stjr
96053477Sobrien	  if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
96153477Sobrien	    {
96253477Sobrien	      if (stat (file, &stats->stat) != 0)
96353477Sobrien		{
964131557Stjr		  error (0, errno, "%s", file);
96553477Sobrien		  return 1;
96653477Sobrien		}
96753477Sobrien
96853477Sobrien	      return grepdir (file, stats);
96953477Sobrien	    }
970131557Stjr
97153477Sobrien	  if (!suppress_errors)
97253477Sobrien	    {
97353477Sobrien	      if (directories == SKIP_DIRECTORIES)
97453477Sobrien		switch (e)
97553477Sobrien		  {
976131557Stjr#if defined(EISDIR)
97753477Sobrien		  case EISDIR:
97853477Sobrien		    return 1;
97953451Speter#endif
98053477Sobrien		  case EACCES:
98153477Sobrien		    /* When skipping directories, don't worry about
98253477Sobrien		       directories that can't be opened.  */
983131557Stjr		    if (isdir (file))
98453477Sobrien		      return 1;
98553477Sobrien		    break;
98653477Sobrien		  }
98753477Sobrien	    }
98853477Sobrien
989131557Stjr	  suppressible_error (file, e);
99053477Sobrien	  return 1;
99153477Sobrien	}
99253477Sobrien
99353477Sobrien      filename = file;
99453477Sobrien    }
99553477Sobrien
996131557Stjr#if defined(SET_BINARY)
99753477Sobrien  /* Set input to binary mode.  Pipes are simulated with files
99853477Sobrien     on DOS, so this includes the case of "foo | grep bar".  */
99953477Sobrien  if (!isatty (desc))
100053477Sobrien    SET_BINARY (desc);
100153477Sobrien#endif
100253477Sobrien
100353477Sobrien  count = grep (desc, file, stats);
100453477Sobrien  if (count < 0)
100553477Sobrien    status = count + 2;
100653477Sobrien  else
100753477Sobrien    {
100853477Sobrien      if (count_matches)
100953477Sobrien	{
101053477Sobrien	  if (out_file)
101155379Sobrien	    printf ("%s%c", filename, ':' & filename_mask);
101253477Sobrien	  printf ("%d\n", count);
101353477Sobrien	}
101453477Sobrien
101555379Sobrien      status = !count;
101655379Sobrien      if (list_files == 1 - 2 * status)
101755379Sobrien	printf ("%s%c", filename, '\n' & filename_mask);
101853477Sobrien
1019104555Sobrien      if (BZflag && bzbufdesc)
1020103372Sobrien	BZ2_bzclose(bzbufdesc);
1021103372Sobrien      else
102253451Speter#if HAVE_LIBZ > 0
102353477Sobrien      if (Zflag)
102453477Sobrien	gzclose(gzbufdesc);
102553477Sobrien      else
102653451Speter#endif
1027131557Stjr      if (! file)
1028131557Stjr	{
1029131557Stjr	  off_t required_offset = outleft ? bufoffset : after_last_match;
1030131557Stjr	  if ((bufmapped || required_offset != bufoffset)
1031131557Stjr	      && lseek (desc, required_offset, SEEK_SET) < 0
1032131557Stjr	      && S_ISREG (stats->stat.st_mode))
1033131557Stjr	    error (0, errno, "%s", filename);
1034131557Stjr	}
1035131557Stjr      else
103655379Sobrien	while (close (desc) != 0)
103755379Sobrien	  if (errno != EINTR)
103855379Sobrien	    {
1039131557Stjr	      error (0, errno, "%s", file);
104055379Sobrien	      break;
104155379Sobrien	    }
104253477Sobrien    }
104353451Speter
104453477Sobrien  return status;
104553477Sobrien}
104653477Sobrien
104753477Sobrienstatic int
1048131557Stjrgrepdir (char const *dir, struct stats const *stats)
104953477Sobrien{
105053477Sobrien  int status = 1;
1051131557Stjr  struct stats const *ancestor;
105253477Sobrien  char *name_space;
105353477Sobrien
1054131557Stjr  /* Mingw32 does not support st_ino.  No known working hosts use zero
1055131557Stjr     for st_ino, so assume that the Mingw32 bug applies if it's zero.  */
1056131557Stjr  if (stats->stat.st_ino)
1057131557Stjr    for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
1058131557Stjr      if (ancestor->stat.st_ino == stats->stat.st_ino
1059131557Stjr	  && ancestor->stat.st_dev == stats->stat.st_dev)
1060131557Stjr	{
1061131557Stjr	  if (!suppress_errors)
1062141847Sobrien	    error (0, 0, _("warning: %s: %s"), dir,
106353477Sobrien		   _("recursive directory loop"));
1064131557Stjr	  return 1;
1065131557Stjr	}
106653477Sobrien
1067131557Stjr  name_space = savedir (dir, stats->stat.st_size, included_patterns,
1068131557Stjr			excluded_patterns);
106953477Sobrien
107053477Sobrien  if (! name_space)
107153477Sobrien    {
107253477Sobrien      if (errno)
1073131557Stjr	suppressible_error (dir, errno);
107453477Sobrien      else
1075131557Stjr	xalloc_die ();
107653477Sobrien    }
107753477Sobrien  else
107853477Sobrien    {
107953477Sobrien      size_t dirlen = strlen (dir);
108053477Sobrien      int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
108153477Sobrien			   || IS_SLASH (dir[dirlen - 1]));
108253477Sobrien      char *file = NULL;
1083131557Stjr      char const *namep = name_space;
108453477Sobrien      struct stats child;
108553477Sobrien      child.parent = stats;
108653477Sobrien      out_file += !no_filenames;
108753477Sobrien      while (*namep)
108853477Sobrien	{
108953477Sobrien	  size_t namelen = strlen (namep);
109053477Sobrien	  file = xrealloc (file, dirlen + 1 + namelen + 1);
109153477Sobrien	  strcpy (file, dir);
109253477Sobrien	  file[dirlen] = '/';
109353477Sobrien	  strcpy (file + dirlen + needs_slash, namep);
109453477Sobrien	  namep += namelen + 1;
109553477Sobrien	  status &= grepfile (file, &child);
109653477Sobrien	}
109753477Sobrien      out_file -= !no_filenames;
109853477Sobrien      if (file)
109953477Sobrien        free (file);
110053477Sobrien      free (name_space);
110153477Sobrien    }
110253477Sobrien
110353477Sobrien  return status;
110453477Sobrien}
110553477Sobrien
110653451Speterstatic void
110756920Sruusage (int status)
110853451Speter{
110953477Sobrien  if (status != 0)
111053477Sobrien    {
1111131557Stjr      fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
1112131557Stjr	       program_name);
1113131557Stjr      fprintf (stderr, _("Try `%s --help' for more information.\n"),
1114131557Stjr	       program_name);
111553477Sobrien    }
111653477Sobrien  else
111753477Sobrien    {
1118131557Stjr      printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name);
111953477Sobrien      printf (_("\
112053477SobrienSearch for PATTERN in each FILE or standard input.\n\
112156920SruExample: %s -i 'hello world' menu.h main.c\n\
112253477Sobrien\n\
1123131557StjrRegexp selection and interpretation:\n"), program_name);
112455379Sobrien      printf (_("\
112553477Sobrien  -E, --extended-regexp     PATTERN is an extended regular expression\n\
112655379Sobrien  -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
1127131557Stjr  -G, --basic-regexp        PATTERN is a basic regular expression\n\
1128131557Stjr  -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
112955379Sobrien      printf (_("\
113053477Sobrien  -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
113153477Sobrien  -f, --file=FILE           obtain PATTERN from FILE\n\
113253477Sobrien  -i, --ignore-case         ignore case distinctions\n\
113353477Sobrien  -w, --word-regexp         force PATTERN to match only whole words\n\
113455379Sobrien  -x, --line-regexp         force PATTERN to match only whole lines\n\
113555379Sobrien  -z, --null-data           a data line ends in 0 byte, not newline\n"));
113653477Sobrien      printf (_("\
113753477Sobrien\n\
113853477SobrienMiscellaneous:\n\
113953477Sobrien  -s, --no-messages         suppress error messages\n\
114055379Sobrien  -v, --invert-match        select non-matching lines\n\
114153477Sobrien  -V, --version             print version information and exit\n\
114255379Sobrien      --help                display this help and exit\n\
1143103372Sobrien  -J, --bz2decompress       decompress bzip2'ed input before searching\n\
114453477Sobrien  -Z, --decompress          decompress input before searching (HAVE_LIBZ=1)\n\
114555379Sobrien      --mmap                use memory-mapped input if possible\n"));
114653477Sobrien      printf (_("\
114753477Sobrien\n\
114853477SobrienOutput control:\n\
1149131557Stjr  -m, --max-count=NUM       stop after NUM matches\n\
115053477Sobrien  -b, --byte-offset         print the byte offset with output lines\n\
115153477Sobrien  -n, --line-number         print line number with output lines\n\
1152131557Stjr      --line-buffered       flush output on every line\n\
115353477Sobrien  -H, --with-filename       print the filename for each match\n\
115453477Sobrien  -h, --no-filename         suppress the prefixing filename on output\n\
1155131557Stjr      --label=LABEL         print LABEL as filename for standard input\n\
1156131557Stjr  -o, --only-matching       show only the part of a line matching PATTERN\n\
115753477Sobrien  -q, --quiet, --silent     suppress all normal output\n\
115856233Sru      --binary-files=TYPE   assume that binary files are TYPE\n\
1159131557Stjr                            TYPE is 'binary', 'text', or 'without-match'\n\
116056920Sru  -a, --text                equivalent to --binary-files=text\n\
116156920Sru  -I                        equivalent to --binary-files=without-match\n\
116253477Sobrien  -d, --directories=ACTION  how to handle directories\n\
1163131557Stjr                            ACTION is 'read', 'recurse', or 'skip'\n\
1164131557Stjr  -D, --devices=ACTION      how to handle devices, FIFOs and sockets\n\
1165131557Stjr                            ACTION is 'read' or 'skip'\n\
1166131557Stjr  -R, -r, --recursive       equivalent to --directories=recurse\n\
1167131557Stjr      --include=PATTERN     files that match PATTERN will be examined\n\
1168131557Stjr      --exclude=PATTERN     files that match PATTERN will be skipped.\n\
1169131557Stjr      --exclude-from=FILE   files that match PATTERN in FILE will be skipped.\n\
117053477Sobrien  -L, --files-without-match only print FILE names containing no match\n\
117153477Sobrien  -l, --files-with-matches  only print FILE names containing matches\n\
117255379Sobrien  -c, --count               only print a count of matching lines per FILE\n\
117355379Sobrien      --null                print 0 byte after FILE name\n"));
117453477Sobrien      printf (_("\
117553477Sobrien\n\
117653477SobrienContext control:\n\
117753477Sobrien  -B, --before-context=NUM  print NUM lines of leading context\n\
117853477Sobrien  -A, --after-context=NUM   print NUM lines of trailing context\n\
1179131557Stjr  -C, --context=NUM         print NUM lines of output context\n\
118053477Sobrien  -NUM                      same as --context=NUM\n\
1181131557Stjr      --color[=WHEN],\n\
1182131557Stjr      --colour[=WHEN]       use markers to distinguish the matching string\n\
1183131557Stjr                            WHEN may be `always', `never' or `auto'.\n\
118453477Sobrien  -U, --binary              do not strip CR characters at EOL (MSDOS)\n\
118553477Sobrien  -u, --unix-byte-offsets   report offsets as if CRs were not there (MSDOS)\n\
118653477Sobrien\n\
118755379Sobrien`egrep' means `grep -E'.  `fgrep' means `grep -F'.\n\
118855379SobrienWith no FILE, or when FILE is -, read standard input.  If less than\n\
118955379Sobrientwo FILEs given, assume -h.  Exit status is 0 if match, 1 if no match,\n\
119055379Sobrienand 2 if trouble.\n"));
119153477Sobrien      printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n"));
119253477Sobrien    }
119353477Sobrien  exit (status);
119453451Speter}
119553451Speter
119655379Sobrien/* Set the matcher to M, reporting any conflicts.  */
119755379Sobrienstatic void
119856920Srusetmatcher (char const *m)
119955379Sobrien{
120055379Sobrien  if (matcher && strcmp (matcher, m) != 0)
1201131557Stjr    error (2, 0, _("conflicting matchers specified"));
120255379Sobrien  matcher = m;
120355379Sobrien}
120455379Sobrien
120553451Speter/* Go through the matchers vector and look for the specified matcher.
120653451Speter   If we find it, install it in compile and execute, and return 1.  */
120753477Sobrienstatic int
120856920Sruinstall_matcher (char const *name)
120953451Speter{
121053451Speter  int i;
1211131557Stjr#if defined(HAVE_SETRLIMIT)
121253477Sobrien  struct rlimit rlim;
121353477Sobrien#endif
121453451Speter
1215131557Stjr  for (i = 0; matchers[i].compile; i++)
121653477Sobrien    if (strcmp (name, matchers[i].name) == 0)
121753451Speter      {
121853451Speter	compile = matchers[i].compile;
121953451Speter	execute = matchers[i].execute;
1220131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
122153477Sobrien	/* I think every platform needs to do this, so that regex.c
122253477Sobrien	   doesn't oveflow the stack.  The default value of
122353477Sobrien	   `re_max_failures' is too large for some platforms: it needs
122453477Sobrien	   more than 3MB-large stack.
122553477Sobrien
122653477Sobrien	   The test for HAVE_SETRLIMIT should go into `configure'.  */
122753477Sobrien	if (!getrlimit (RLIMIT_STACK, &rlim))
122853477Sobrien	  {
122953477Sobrien	    long newlim;
123053477Sobrien	    extern long int re_max_failures; /* from regex.c */
123153477Sobrien
123253477Sobrien	    /* Approximate the amount regex.c needs, plus some more.  */
123353477Sobrien	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
123453477Sobrien	    if (newlim > rlim.rlim_max)
123553477Sobrien	      {
123653477Sobrien		newlim = rlim.rlim_max;
123753477Sobrien		re_max_failures = newlim / (2 * 20 * sizeof (char *));
123853477Sobrien	      }
123953477Sobrien	    if (rlim.rlim_cur < newlim)
1240131557Stjr	      {
1241131557Stjr		rlim.rlim_cur = newlim;
1242131557Stjr		setrlimit (RLIMIT_STACK, &rlim);
1243131557Stjr	      }
124453477Sobrien	  }
124553477Sobrien#endif
124653451Speter	return 1;
124753451Speter      }
124853451Speter  return 0;
124953451Speter}
125053451Speter
125153705Sobrien/* Find the white-space-separated options specified by OPTIONS, and
125253705Sobrien   using BUF to store copies of these options, set ARGV[0], ARGV[1],
125353705Sobrien   etc. to the option copies.  Return the number N of options found.
125453705Sobrien   Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
125553705Sobrien   etc.  Backslash can be used to escape whitespace (and backslashes).  */
125653705Sobrienstatic int
125756920Sruprepend_args (char const *options, char *buf, char **argv)
125853705Sobrien{
125953705Sobrien  char const *o = options;
126053705Sobrien  char *b = buf;
126153705Sobrien  int n = 0;
126253705Sobrien
126353705Sobrien  for (;;)
126453705Sobrien    {
126553705Sobrien      while (ISSPACE ((unsigned char) *o))
126653705Sobrien	o++;
126753705Sobrien      if (!*o)
126853705Sobrien	return n;
126953705Sobrien      if (argv)
127053705Sobrien	argv[n] = b;
127153705Sobrien      n++;
127253705Sobrien
127353705Sobrien      do
127453705Sobrien	if ((*b++ = *o++) == '\\' && *o)
127553705Sobrien	  b[-1] = *o++;
127653705Sobrien      while (*o && ! ISSPACE ((unsigned char) *o));
127753705Sobrien
127853705Sobrien      *b++ = '\0';
127953705Sobrien    }
128053705Sobrien}
128153705Sobrien
128253705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument
128353705Sobrien   vector of a main program with argument count *PARGC and argument
128453705Sobrien   vector *PARGV.  */
128553705Sobrienstatic void
128656920Sruprepend_default_options (char const *options, int *pargc, char ***pargv)
128753705Sobrien{
128853705Sobrien  if (options)
128953705Sobrien    {
129053705Sobrien      char *buf = xmalloc (strlen (options) + 1);
129153705Sobrien      int prepended = prepend_args (options, buf, (char **) NULL);
129253705Sobrien      int argc = *pargc;
129353705Sobrien      char * const *argv = *pargv;
129453705Sobrien      char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
129553705Sobrien      *pargc = prepended + argc;
129653705Sobrien      *pargv = pp;
129753705Sobrien      *pp++ = *argv++;
129853705Sobrien      pp += prepend_args (options, buf, pp);
129953705Sobrien      while ((*pp++ = *argv++))
130053705Sobrien	continue;
130153705Sobrien    }
130253705Sobrien}
130353705Sobrien
1304131557Stjr/* Get the next non-digit option from ARGC and ARGV.
1305131557Stjr   Return -1 if there are no more options.
1306131557Stjr   Process any digit options that were encountered on the way,
1307131557Stjr   and store the resulting integer into *DEFAULT_CONTEXT.  */
1308131557Stjrstatic int
1309131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context)
1310131557Stjr{
1311131557Stjr  int opt;
1312131557Stjr  char buf[sizeof (uintmax_t) * CHAR_BIT + 4];
1313131557Stjr  char *p = buf;
1314131557Stjr
1315131557Stjr  /* Set buf[0] to anything but '0', for the leading-zero test below.  */
1316131557Stjr  buf[0] = '\0';
1317131557Stjr
1318131557Stjr  while (opt = getopt_long (argc, argv, short_options, long_options, NULL),
1319131557Stjr	 '0' <= opt && opt <= '9')
1320131557Stjr    {
1321131557Stjr      /* Suppress trivial leading zeros, to avoid incorrect
1322131557Stjr	 diagnostic on strings like 00000000000.  */
1323131557Stjr      p -= buf[0] == '0';
1324131557Stjr
1325131557Stjr      *p++ = opt;
1326131557Stjr      if (p == buf + sizeof buf - 4)
1327131557Stjr	{
1328131557Stjr	  /* Too many digits.  Append "..." to make context_length_arg
1329131557Stjr	     complain about "X...", where X contains the digits seen
1330131557Stjr	     so far.  */
1331131557Stjr	  strcpy (p, "...");
1332131557Stjr	  p += 3;
1333131557Stjr	  break;
1334131557Stjr	}
1335131557Stjr    }
1336131557Stjr  if (p != buf)
1337131557Stjr    {
1338131557Stjr      *p = '\0';
1339131557Stjr      context_length_arg (buf, default_context);
1340131557Stjr    }
1341131557Stjr
1342131557Stjr  return opt;
1343131557Stjr}
1344131557Stjr
134553451Speterint
134656920Srumain (int argc, char **argv)
134753451Speter{
134853451Speter  char *keys;
1349250937Spfg  size_t cc, keycc, oldcc, keyalloc;
135053477Sobrien  int with_filenames;
1351250937Spfg  int opt, status;
135256920Sru  int default_context;
135353451Speter  FILE *fp;
135453451Speter  extern char *optarg;
135553451Speter  extern int optind;
135653477Sobrien
135753477Sobrien  initialize_main (&argc, &argv);
1358131557Stjr  program_name = argv[0];
1359131557Stjr  if (program_name && strrchr (program_name, '/'))
1360131557Stjr    program_name = strrchr (program_name, '/') + 1;
136153477Sobrien
1362151534Sjkim  if (program_name[0] == 'b' && program_name[1] == 'z') {
1363151527Sjkim    BZflag = 1;
1364151527Sjkim    program_name += 2;
1365151527Sjkim  }
136653477Sobrien#if HAVE_LIBZ > 0
1367151534Sjkim  else if (program_name[0] == 'z') {
136853477Sobrien    Zflag = 1;
1369131557Stjr    ++program_name;
137053477Sobrien  }
137153451Speter#endif
137253451Speter
137353477Sobrien#if defined(__MSDOS__) || defined(_WIN32)
137453477Sobrien  /* DOS and MS-Windows use backslashes as directory separators, and usually
137553477Sobrien     have an .exe suffix.  They also have case-insensitive filesystems.  */
1376131557Stjr  if (program_name)
137753477Sobrien    {
1378131557Stjr      char *p = program_name;
137953477Sobrien      char *bslash = strrchr (argv[0], '\\');
138053477Sobrien
1381131557Stjr      if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
1382131557Stjr	program_name = bslash + 1;
1383131557Stjr      else if (program_name == argv[0]
138453477Sobrien	       && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
1385131557Stjr	program_name = argv[0] + 2;
138653477Sobrien
138753477Sobrien      /* Collapse the letter-case, so `strcmp' could be used hence.  */
138853477Sobrien      for ( ; *p; p++)
138953477Sobrien	if (*p >= 'A' && *p <= 'Z')
139053477Sobrien	  *p += 'a' - 'A';
139153477Sobrien
139253477Sobrien      /* Remove the .exe extension, if any.  */
1393131557Stjr      if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
139453477Sobrien	*p = '\0';
139553477Sobrien    }
139653451Speter#endif
139753451Speter
139853451Speter  keys = NULL;
139953451Speter  keycc = 0;
140053477Sobrien  with_filenames = 0;
140155379Sobrien  eolbyte = '\n';
140255379Sobrien  filename_mask = ~0;
140353477Sobrien
1404131557Stjr  max_count = TYPE_MAXIMUM (off_t);
1405131557Stjr
140653477Sobrien  /* The value -1 means to use DEFAULT_CONTEXT. */
140753477Sobrien  out_after = out_before = -1;
140853477Sobrien  /* Default before/after context: chaged by -C/-NUM options */
140953477Sobrien  default_context = 0;
1410131557Stjr  /* Changed by -o option */
1411131557Stjr  only_matching = 0;
141253477Sobrien
1413131557Stjr  /* Internationalization. */
1414131557Stjr#if defined(HAVE_SETLOCALE)
141553477Sobrien  setlocale (LC_ALL, "");
141653451Speter#endif
1417131557Stjr#if defined(ENABLE_NLS)
141853477Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
141953477Sobrien  textdomain (PACKAGE);
142053451Speter#endif
142153451Speter
1422131557Stjr  atexit (close_stdout);
1423131557Stjr
142453705Sobrien  prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
142553705Sobrien
1426131557Stjr  while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1)
142753451Speter    switch (opt)
142853451Speter      {
142953451Speter      case 'A':
1430131557Stjr	context_length_arg (optarg, &out_after);
143153451Speter	break;
1432131557Stjr
143353451Speter      case 'B':
1434131557Stjr	context_length_arg (optarg, &out_before);
143553451Speter	break;
1436131557Stjr
143753451Speter      case 'C':
143853477Sobrien	/* Set output match context, but let any explicit leading or
143953477Sobrien	   trailing amount specified with -A or -B stand. */
1440131557Stjr	context_length_arg (optarg, &default_context);
1441131557Stjr	break;
1442131557Stjr
1443131557Stjr      case 'D':
1444131557Stjr	if (strcmp (optarg, "read") == 0)
1445131557Stjr	  devices = READ_DEVICES;
1446131557Stjr	else if (strcmp (optarg, "skip") == 0)
1447131557Stjr	  devices = SKIP_DEVICES;
144853477Sobrien	else
1449131557Stjr	  error (2, 0, _("unknown devices method"));
145053451Speter	break;
1451131557Stjr
145253451Speter      case 'E':
145355379Sobrien	setmatcher ("egrep");
145453451Speter	break;
1455131557Stjr
145653451Speter      case 'F':
145755379Sobrien	setmatcher ("fgrep");
145853451Speter	break;
1459131557Stjr
1460131557Stjr      case 'P':
1461131557Stjr	setmatcher ("perl");
1462131557Stjr	break;
1463131557Stjr
146453451Speter      case 'G':
146555379Sobrien	setmatcher ("grep");
146653451Speter	break;
1467131557Stjr
146853477Sobrien      case 'H':
146953477Sobrien	with_filenames = 1;
147053477Sobrien	break;
1471131557Stjr
147256920Sru      case 'I':
147356920Sru	binary_files = WITHOUT_MATCH_BINARY_FILES;
147456920Sru	break;
1475103372Sobrien      case 'J':
1476104555Sobrien	if (Zflag)
1477104555Sobrien	  {
1478104555Sobrien	    printf (_("Cannot mix -Z and -J.\n"));
1479104555Sobrien	    usage (2);
1480104555Sobrien	  }
1481103372Sobrien	BZflag = 1;
1482103372Sobrien	break;
1483131557Stjr
148455379Sobrien      case 'U':
1485131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
148653477Sobrien	dos_use_file_type = DOS_BINARY;
148755379Sobrien#endif
148853477Sobrien	break;
1489131557Stjr
149053477Sobrien      case 'u':
1491131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
149253477Sobrien	dos_report_unix_offset = 1;
149355379Sobrien#endif
149453477Sobrien	break;
1495131557Stjr
149653451Speter      case 'V':
149753477Sobrien	show_version = 1;
149853451Speter	break;
1499131557Stjr
150053451Speter      case 'X':
150155379Sobrien	setmatcher (optarg);
150253451Speter	break;
1503131557Stjr
150453451Speter      case 'a':
150556233Sru	binary_files = TEXT_BINARY_FILES;
150653451Speter	break;
1507131557Stjr
150853451Speter      case 'b':
150953451Speter	out_byte = 1;
151053451Speter	break;
1511131557Stjr
151253451Speter      case 'c':
151353451Speter	count_matches = 1;
151453451Speter	break;
1515131557Stjr
151653477Sobrien      case 'd':
151753477Sobrien	if (strcmp (optarg, "read") == 0)
151853477Sobrien	  directories = READ_DIRECTORIES;
151953477Sobrien	else if (strcmp (optarg, "skip") == 0)
152053477Sobrien	  directories = SKIP_DIRECTORIES;
152153477Sobrien	else if (strcmp (optarg, "recurse") == 0)
152253477Sobrien	  directories = RECURSE_DIRECTORIES;
152353477Sobrien	else
1524131557Stjr	  error (2, 0, _("unknown directories method"));
152553477Sobrien	break;
1526131557Stjr
152753451Speter      case 'e':
152853477Sobrien	cc = strlen (optarg);
152953477Sobrien	keys = xrealloc (keys, keycc + cc + 1);
153053477Sobrien	strcpy (&keys[keycc], optarg);
153153451Speter	keycc += cc;
153253477Sobrien	keys[keycc++] = '\n';
153353451Speter	break;
1534131557Stjr
153553451Speter      case 'f':
153653477Sobrien	fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
153753451Speter	if (!fp)
1538131557Stjr	  error (2, errno, "%s", optarg);
153953477Sobrien	for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
154053451Speter	  ;
154153477Sobrien	keys = xrealloc (keys, keyalloc);
154253451Speter	oldcc = keycc;
154353477Sobrien	while (!feof (fp)
154453477Sobrien	       && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
154553451Speter	  {
154653451Speter	    keycc += cc;
154753477Sobrien	    if (keycc == keyalloc - 1)
154853477Sobrien	      keys = xrealloc (keys, keyalloc *= 2);
154953451Speter	  }
155053451Speter	if (fp != stdin)
155153451Speter	  fclose(fp);
155253477Sobrien	/* Append final newline if file ended in non-newline. */
155353477Sobrien	if (oldcc != keycc && keys[keycc - 1] != '\n')
155453477Sobrien	  keys[keycc++] = '\n';
155553451Speter	break;
1556131557Stjr
155753451Speter      case 'h':
155853451Speter	no_filenames = 1;
155953451Speter	break;
1560131557Stjr
156153451Speter      case 'i':
156253451Speter      case 'y':			/* For old-timers . . . */
156353451Speter	match_icase = 1;
156453451Speter	break;
1565131557Stjr
156653451Speter      case 'L':
156753451Speter	/* Like -l, except list files that don't contain matches.
156853451Speter	   Inspired by the same option in Hume's gre. */
156953451Speter	list_files = -1;
157053451Speter	break;
1571131557Stjr
157253451Speter      case 'l':
157353451Speter	list_files = 1;
157453451Speter	break;
1575131557Stjr
1576131557Stjr      case 'm':
1577131557Stjr	{
1578131557Stjr	  uintmax_t value;
1579131557Stjr	  switch (xstrtoumax (optarg, 0, 10, &value, ""))
1580131557Stjr	    {
1581131557Stjr	    case LONGINT_OK:
1582131557Stjr	      max_count = value;
1583131557Stjr	      if (0 <= max_count && max_count == value)
1584131557Stjr		break;
1585131557Stjr	      /* Fall through.  */
1586131557Stjr	    case LONGINT_OVERFLOW:
1587131557Stjr	      max_count = TYPE_MAXIMUM (off_t);
1588131557Stjr	      break;
1589131557Stjr
1590131557Stjr	    default:
1591131557Stjr	      error (2, 0, _("invalid max count"));
1592131557Stjr	    }
1593131557Stjr	}
1594131557Stjr	break;
1595131557Stjr
159653451Speter      case 'n':
159753451Speter	out_line = 1;
159853451Speter	break;
1599131557Stjr
1600131557Stjr      case 'o':
1601131557Stjr	only_matching = 1;
1602131557Stjr	break;
1603131557Stjr
160453451Speter      case 'q':
1605131557Stjr	exit_on_match = 1;
1606131557Stjr	close_stdout_set_status(0);
160753451Speter	break;
1608131557Stjr
160953478Sobrien      case 'R':
161053477Sobrien      case 'r':
161153477Sobrien	directories = RECURSE_DIRECTORIES;
161253477Sobrien	break;
1613131557Stjr
161453451Speter      case 's':
161553451Speter	suppress_errors = 1;
161653451Speter	break;
1617131557Stjr
161853451Speter      case 'v':
161953451Speter	out_invert = 1;
162053451Speter	break;
1621131557Stjr
162253451Speter      case 'w':
162353451Speter	match_words = 1;
162453451Speter	break;
1625131557Stjr
162653451Speter      case 'x':
162753451Speter	match_lines = 1;
162853451Speter	break;
1629131557Stjr
163055379Sobrien      case 'Z':
163155379Sobrien#if HAVE_LIBZ > 0
1632104555Sobrien	if (BZflag)
1633104555Sobrien	  {
1634104555Sobrien	    printf (_("Cannot mix -J and -Z.\n"));
1635104555Sobrien	    usage (2);
1636104555Sobrien	  }
163755379Sobrien	Zflag = 1;
163855379Sobrien#else
163955379Sobrien	filename_mask = 0;
164055379Sobrien#endif
164155379Sobrien	break;
1642131557Stjr
164355379Sobrien      case 'z':
164455379Sobrien	eolbyte = '\0';
164555379Sobrien	break;
1646131557Stjr
164756233Sru      case BINARY_FILES_OPTION:
164856233Sru	if (strcmp (optarg, "binary") == 0)
164956233Sru	  binary_files = BINARY_BINARY_FILES;
165056233Sru	else if (strcmp (optarg, "text") == 0)
165156233Sru	  binary_files = TEXT_BINARY_FILES;
165256233Sru	else if (strcmp (optarg, "without-match") == 0)
165356233Sru	  binary_files = WITHOUT_MATCH_BINARY_FILES;
165456233Sru	else
1655131557Stjr	  error (2, 0, _("unknown binary-files type"));
165656233Sru	break;
1657131557Stjr
1658131557Stjr      case COLOR_OPTION:
1659131557Stjr        if(optarg) {
1660131557Stjr          if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") ||
1661131557Stjr             !strcasecmp(optarg, "force"))
1662131557Stjr            color_option = 1;
1663131557Stjr          else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") ||
1664131557Stjr                  !strcasecmp(optarg, "none"))
1665131557Stjr            color_option = 0;
1666131557Stjr          else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") ||
1667131557Stjr                  !strcasecmp(optarg, "if-tty"))
1668131557Stjr            color_option = 2;
1669131557Stjr          else
1670131557Stjr            show_help = 1;
1671131557Stjr        } else
1672131557Stjr          color_option = 2;
1673131557Stjr        if(color_option == 2) {
1674131557Stjr          if(isatty(STDOUT_FILENO) && getenv("TERM") &&
1675131557Stjr	     strcmp(getenv("TERM"), "dumb"))
1676131557Stjr                  color_option = 1;
1677131557Stjr          else
1678131557Stjr            color_option = 0;
1679131557Stjr        }
1680131557Stjr	break;
1681131557Stjr
1682131557Stjr      case EXCLUDE_OPTION:
1683131557Stjr	if (!excluded_patterns)
1684131557Stjr	  excluded_patterns = new_exclude ();
1685131557Stjr	add_exclude (excluded_patterns, optarg);
1686131557Stjr	break;
1687131557Stjr
1688131557Stjr      case EXCLUDE_FROM_OPTION:
1689131557Stjr	if (!excluded_patterns)
1690131557Stjr	  excluded_patterns = new_exclude ();
1691131557Stjr        if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n')
1692131557Stjr	    != 0)
1693131557Stjr          {
1694131557Stjr            error (2, errno, "%s", optarg);
1695131557Stjr          }
1696131557Stjr        break;
1697131557Stjr
1698131557Stjr      case INCLUDE_OPTION:
1699131557Stjr	if (!included_patterns)
1700131557Stjr	  included_patterns = new_exclude ();
1701131557Stjr	add_exclude (included_patterns, optarg);
1702131557Stjr	break;
1703131557Stjr
1704131557Stjr      case LINE_BUFFERED_OPTION:
1705131557Stjr	line_buffered = 1;
1706131557Stjr	break;
1707131557Stjr
1708131557Stjr      case LABEL_OPTION:
1709131557Stjr	label = optarg;
1710131557Stjr	break;
1711131557Stjr
171253477Sobrien      case 0:
171353477Sobrien	/* long options */
171453477Sobrien	break;
1715131557Stjr
171653451Speter      default:
171753477Sobrien	usage (2);
171853451Speter	break;
1719131557Stjr
172053451Speter      }
172153451Speter
1722131557Stjr  /* POSIX.2 says that -q overrides -l, which in turn overrides the
1723131557Stjr     other output options.  */
1724131557Stjr  if (exit_on_match)
1725131557Stjr    list_files = 0;
1726131557Stjr  if (exit_on_match | list_files)
1727131557Stjr    {
1728131557Stjr      count_matches = 0;
1729131557Stjr      done_on_match = 1;
1730131557Stjr    }
1731131557Stjr  out_quiet = count_matches | done_on_match;
1732131557Stjr
173353477Sobrien  if (out_after < 0)
173453477Sobrien    out_after = default_context;
173553477Sobrien  if (out_before < 0)
173653477Sobrien    out_before = default_context;
173753477Sobrien
1738131557Stjr  if (color_option)
1739131557Stjr    {
1740131557Stjr      char *userval = getenv ("GREP_COLOR");
1741131557Stjr      if (userval != NULL && *userval != '\0')
1742131557Stjr	grep_color = userval;
1743131557Stjr    }
1744131557Stjr
174555379Sobrien  if (! matcher)
1746131557Stjr    matcher = program_name;
174755379Sobrien
174853477Sobrien  if (show_version)
174953477Sobrien    {
175055379Sobrien      printf (_("%s (GNU grep) %s\n"), matcher, VERSION);
175153477Sobrien      printf ("\n");
175253477Sobrien      printf (_("\
1753131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n"));
175453477Sobrien      printf (_("\
175553477SobrienThis is free software; see the source for copying conditions. There is NO\n\
175653477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
175753477Sobrien      printf ("\n");
175853477Sobrien      exit (0);
175953477Sobrien    }
176053477Sobrien
176153477Sobrien  if (show_help)
176253477Sobrien    usage (0);
176353477Sobrien
176453477Sobrien  if (keys)
176553477Sobrien    {
176653477Sobrien      if (keycc == 0)
1767131557Stjr	{
1768131557Stjr	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
1769131557Stjr	  out_invert ^= 1;
1770131557Stjr	  match_lines = match_words = 0;
1771131557Stjr	}
177253477Sobrien      else
177353477Sobrien	/* Strip trailing newline. */
177453477Sobrien        --keycc;
177553477Sobrien    }
177653477Sobrien  else
177753451Speter    if (optind < argc)
177853451Speter      {
177953451Speter	keys = argv[optind++];
178053477Sobrien	keycc = strlen (keys);
178153451Speter      }
178253451Speter    else
178353477Sobrien      usage (2);
178453451Speter
178555379Sobrien  if (!install_matcher (matcher) && !install_matcher ("default"))
178653477Sobrien    abort ();
178753451Speter
1788131564Stjr#ifdef MBS_SUPPORT
1789131564Stjr  if (MB_CUR_MAX != 1 && match_icase)
1790131564Stjr    {
1791131564Stjr      wchar_t wc;
1792131564Stjr      mbstate_t cur_state, prev_state;
1793131564Stjr      int i, len = strlen(keys);
1794131564Stjr
1795131564Stjr      memset(&cur_state, 0, sizeof(mbstate_t));
1796131564Stjr      for (i = 0; i <= len ;)
1797131564Stjr	{
1798131564Stjr	  size_t mbclen;
1799131564Stjr	  mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state);
1800131564Stjr	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
1801131564Stjr	    {
1802131564Stjr	      /* An invalid sequence, or a truncated multibyte character.
1803131564Stjr		 We treat it as a singlebyte character.  */
1804131564Stjr	      mbclen = 1;
1805131564Stjr	    }
1806131564Stjr	  else
1807131564Stjr	    {
1808131564Stjr	      if (iswupper((wint_t)wc))
1809131564Stjr		{
1810131564Stjr		  wc = towlower((wint_t)wc);
1811131564Stjr		  wcrtomb(keys + i, wc, &cur_state);
1812131564Stjr		}
1813131564Stjr	    }
1814131564Stjr	  i += mbclen;
1815131564Stjr	}
1816131564Stjr    }
1817131564Stjr#endif /* MBS_SUPPORT */
1818131564Stjr
181953451Speter  (*compile)(keys, keycc);
182053451Speter
182153477Sobrien  if ((argc - optind > 1 && !no_filenames) || with_filenames)
182253451Speter    out_file = 1;
182353451Speter
1824131557Stjr#ifdef SET_BINARY
182553477Sobrien  /* Output is set to binary mode because we shouldn't convert
182653477Sobrien     NL to CR-LF pairs, especially when grepping binary files.  */
182753477Sobrien  if (!isatty (1))
182853477Sobrien    SET_BINARY (1);
182953451Speter#endif
183053451Speter
1831131557Stjr  if (max_count == 0)
1832131557Stjr    exit (1);
183353451Speter
183453451Speter  if (optind < argc)
183553451Speter    {
183653477Sobrien	status = 1;
183753477Sobrien	do
183853451Speter	{
183953477Sobrien	  char *file = argv[optind];
1840131557Stjr	  if ((included_patterns || excluded_patterns)
1841131557Stjr	      && !isdir (file))
1842131557Stjr	    {
1843131557Stjr	      if (included_patterns &&
1844131557Stjr		  ! excluded_filename (included_patterns, file, 0))
1845131557Stjr		continue;
1846131557Stjr	      if (excluded_patterns &&
1847131557Stjr		  excluded_filename (excluded_patterns, file, 0))
1848131557Stjr		continue;
1849131557Stjr	    }
185053477Sobrien	  status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
185153477Sobrien			      &stats_base);
185253451Speter	}
185353477Sobrien	while ( ++optind < argc);
185453451Speter    }
185553477Sobrien  else
185653477Sobrien    status = grepfile ((char *) NULL, &stats_base);
185753451Speter
1858131557Stjr  /* We register via atexit() to test stdout.  */
185953477Sobrien  exit (errseen ? 2 : status);
186053451Speter}
1861131557Stjr/* vim:set shiftwidth=2: */
1862