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    }
304254093Sache  if (fd != STDIN_FILENO) {
305254093Sache    if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
306254093Sache      return 0;
307131557Stjr#ifndef DJGPP
308254093Sache    if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode) || S_ISSOCK(stats->stat.st_mode) || S_ISFIFO(stats->stat.st_mode)))
309131557Stjr#else
310254093Sache    if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode)))
311131557Stjr#endif
312254093Sache      return 0;
313254093Sache  }
31453477Sobrien  if (
315103372Sobrien      BZflag ||
31653451Speter#if HAVE_LIBZ > 0
31753477Sobrien      Zflag ||
31853451Speter#endif
31955379Sobrien      S_ISREG (stats->stat.st_mode))
32055379Sobrien    {
32155379Sobrien      if (file)
32255379Sobrien	bufoffset = 0;
32355379Sobrien      else
32455379Sobrien	{
32555379Sobrien	  bufoffset = lseek (fd, 0, SEEK_CUR);
32655379Sobrien	  if (bufoffset < 0)
32755379Sobrien	    {
328131557Stjr	      error (0, errno, "lseek");
32955379Sobrien	      return 0;
33055379Sobrien	    }
33155379Sobrien	}
332131557Stjr#if defined(HAVE_MMAP)
33355379Sobrien      initial_bufoffset = bufoffset;
33455379Sobrien      bufmapped = mmap_option && bufoffset % pagesize == 0;
33555379Sobrien#endif
33655379Sobrien    }
33753451Speter  else
33853451Speter    {
339131557Stjr#if defined(HAVE_MMAP)
34055379Sobrien      bufmapped = 0;
34155379Sobrien#endif
34253451Speter    }
34353477Sobrien  return 1;
34453451Speter}
34553451Speter
34653451Speter/* Read new stuff into the buffer, saving the specified
34753451Speter   amount of old stuff.  When we're done, 'bufbeg' points
34853451Speter   to the beginning of the buffer contents, and 'buflim'
34955379Sobrien   points just after the end.  Return zero if there's an error.  */
35053451Speterstatic int
351131557Stjrfillbuf (size_t save, struct stats const *stats)
35253451Speter{
35355379Sobrien  size_t fillsize = 0;
35455379Sobrien  int cc = 1;
355131557Stjr  char *readbuf;
35655379Sobrien  size_t readsize;
35753451Speter
358131557Stjr  /* Offset from start of buffer to start of old stuff
35955379Sobrien     that we want to save.  */
360131557Stjr  size_t saved_offset = buflim - save - buffer;
36155379Sobrien
362131557Stjr  if (pagesize <= buffer + bufalloc - buflim)
36353451Speter    {
364131557Stjr      readbuf = buflim;
365131557Stjr      bufbeg = buflim - save;
366131557Stjr    }
367131557Stjr  else
368131557Stjr    {
369131557Stjr      size_t minsize = save + pagesize;
370131557Stjr      size_t newsize;
37155379Sobrien      size_t newalloc;
372131557Stjr      char *newbuf;
37353477Sobrien
374131557Stjr      /* Grow newsize until it is at least as great as minsize.  */
375131557Stjr      for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)
376131557Stjr	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)
377131557Stjr	  xalloc_die ();
378131557Stjr
379131557Stjr      /* Try not to allocate more memory than the file size indicates,
380131557Stjr	 as that might cause unnecessary memory exhaustion if the file
381131557Stjr	 is large.  However, do not use the original file size as a
382131557Stjr	 heuristic if we've already read past the file end, as most
383131557Stjr	 likely the file is growing.  */
38455379Sobrien      if (S_ISREG (stats->stat.st_mode))
38555379Sobrien	{
38655379Sobrien	  off_t to_be_read = stats->stat.st_size - bufoffset;
387131557Stjr	  off_t maxsize_off = save + to_be_read;
388131557Stjr	  if (0 <= to_be_read && to_be_read <= maxsize_off
389131557Stjr	      && maxsize_off == (size_t) maxsize_off
390131557Stjr	      && minsize <= (size_t) maxsize_off
391131557Stjr	      && (size_t) maxsize_off < newsize)
392131557Stjr	    newsize = maxsize_off;
39355379Sobrien	}
39455379Sobrien
395131557Stjr      /* Add enough room so that the buffer is aligned and has room
396131557Stjr	 for byte sentinels fore and aft.  */
397131557Stjr      newalloc = newsize + pagesize + 1;
39855379Sobrien
399131557Stjr      newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
400131557Stjr      readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);
401131557Stjr      bufbeg = readbuf - save;
402131557Stjr      memmove (bufbeg, buffer + saved_offset, save);
403131557Stjr      bufbeg[-1] = eolbyte;
404131557Stjr      if (newbuf != buffer)
40555379Sobrien	{
406131557Stjr	  free (buffer);
407131557Stjr	  buffer = newbuf;
40855379Sobrien	}
40953451Speter    }
41053451Speter
411131557Stjr  readsize = buffer + bufalloc - readbuf;
412131557Stjr  readsize -= readsize % pagesize;
41355379Sobrien
41453477Sobrien#if defined(HAVE_MMAP)
41555379Sobrien  if (bufmapped)
41653451Speter    {
41755379Sobrien      size_t mmapsize = readsize;
41855379Sobrien
41955379Sobrien      /* Don't mmap past the end of the file; some hosts don't allow this.
42055379Sobrien	 Use `read' on the last page.  */
42155379Sobrien      if (stats->stat.st_size - bufoffset < mmapsize)
42253451Speter	{
42355379Sobrien	  mmapsize = stats->stat.st_size - bufoffset;
42455379Sobrien	  mmapsize -= mmapsize % pagesize;
42553451Speter	}
42655379Sobrien
42755379Sobrien      if (mmapsize
428131557Stjr	  && (mmap ((caddr_t) readbuf, mmapsize,
42955379Sobrien		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
43055379Sobrien		    bufdesc, bufoffset)
43155379Sobrien	      != (caddr_t) -1))
43253451Speter	{
43355379Sobrien	  /* Do not bother to use madvise with MADV_SEQUENTIAL or
43455379Sobrien	     MADV_WILLNEED on the mmapped memory.  One might think it
43555379Sobrien	     would help, but it slows us down about 30% on SunOS 4.1.  */
43655379Sobrien	  fillsize = mmapsize;
43755379Sobrien	}
43855379Sobrien      else
43955379Sobrien	{
44055379Sobrien	  /* Stop using mmap on this file.  Synchronize the file
44155379Sobrien	     offset.  Do not warn about mmap failures.  On some hosts
44255379Sobrien	     (e.g. Solaris 2.5) mmap can fail merely because some
44355379Sobrien	     other process has an advisory read lock on the file.
44455379Sobrien	     There's no point alarming the user about this misfeature.  */
44553451Speter	  bufmapped = 0;
44655379Sobrien	  if (bufoffset != initial_bufoffset
44755379Sobrien	      && lseek (bufdesc, bufoffset, SEEK_SET) < 0)
44855379Sobrien	    {
449131557Stjr	      error (0, errno, "lseek");
45055379Sobrien	      cc = 0;
45155379Sobrien	    }
45253451Speter	}
45355379Sobrien    }
45455379Sobrien#endif /*HAVE_MMAP*/
45555379Sobrien
45655379Sobrien  if (! fillsize)
45755379Sobrien    {
45855379Sobrien      ssize_t bytesread;
45955379Sobrien      do
460104555Sobrien	if (BZflag && bzbufdesc)
461103372Sobrien	  {
462104555Sobrien	    int bzerr;
463131557Stjr	    bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize);
464104555Sobrien
465104555Sobrien	    switch (bzerr)
466104555Sobrien	      {
467104555Sobrien	      case BZ_OK:
468104555Sobrien	      case BZ_STREAM_END:
469104555Sobrien		/* ok */
470104555Sobrien		break;
471104555Sobrien	      case BZ_DATA_ERROR_MAGIC:
472104555Sobrien		BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL;
473104555Sobrien		lseek (bufdesc, 0, SEEK_SET);
474131557Stjr		bytesread = read (bufdesc, readbuf, readsize);
475104555Sobrien		break;
476104555Sobrien	      default:
477104555Sobrien		bytesread = 0;
478104555Sobrien		break;
479104555Sobrien	      }
480103372Sobrien	  }
481103372Sobrien	else
48253451Speter#if HAVE_LIBZ > 0
48355379Sobrien	if (Zflag)
484131557Stjr	  bytesread = gzread (gzbufdesc, readbuf, readsize);
48555379Sobrien	else
48655379Sobrien#endif
487131557Stjr	  bytesread = read (bufdesc, readbuf, readsize);
48855379Sobrien      while (bytesread < 0 && errno == EINTR);
48955379Sobrien      if (bytesread < 0)
49055379Sobrien	cc = 0;
49153477Sobrien      else
49255379Sobrien	fillsize = bytesread;
49353451Speter    }
49455379Sobrien
49555379Sobrien  bufoffset += fillsize;
496131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
49755379Sobrien  if (fillsize)
498131557Stjr    fillsize = undossify_input (readbuf, fillsize);
49953451Speter#endif
500131557Stjr  buflim = readbuf + fillsize;
50153451Speter  return cc;
50253451Speter}
50353451Speter
50453451Speter/* Flags controlling the style of output. */
50556233Srustatic enum
506131557Stjr{
507131557Stjr  BINARY_BINARY_FILES,
508131557Stjr  TEXT_BINARY_FILES,
509131557Stjr  WITHOUT_MATCH_BINARY_FILES
510131557Stjr} binary_files;		/* How to handle binary files.  */
511131557Stjr
512131557Stjrstatic int filename_mask;	/* If zero, output nulls after filenames.  */
51353451Speterstatic int out_quiet;		/* Suppress all normal output. */
51453451Speterstatic int out_invert;		/* Print nonmatching stuff. */
51553451Speterstatic int out_file;		/* Print filenames. */
51653451Speterstatic int out_line;		/* Print line numbers. */
51753451Speterstatic int out_byte;		/* Print byte offsets. */
51853451Speterstatic int out_before;		/* Lines of leading context. */
51953451Speterstatic int out_after;		/* Lines of trailing context. */
52053477Sobrienstatic int count_matches;	/* Count matching lines.  */
52153477Sobrienstatic int list_files;		/* List matching files.  */
52253477Sobrienstatic int no_filenames;	/* Suppress file names.  */
523131557Stjrstatic off_t max_count;		/* Stop after outputting this many
524131557Stjr				   lines from an input file.  */
525131557Stjrstatic int line_buffered;       /* If nonzero, use line buffering, i.e.
526131557Stjr				   fflush everyline out.  */
527131557Stjrstatic char *label = NULL;      /* Fake filename for stdin */
52853451Speter
529131557Stjr
53053451Speter/* Internal variables to keep track of byte count, context, etc. */
531131557Stjrstatic uintmax_t totalcc;	/* Total character count before bufbeg. */
532131557Stjrstatic char const *lastnl;	/* Pointer after last newline counted. */
533131557Stjrstatic char const *lastout;	/* Pointer after last character output;
53453451Speter				   NULL if no character has been output
53553451Speter				   or if it's conceptually before bufbeg. */
536131557Stjrstatic uintmax_t totalnl;	/* Total newline count before lastnl. */
537131557Stjrstatic off_t outleft;		/* Maximum number of lines to be output.  */
538131557Stjrstatic int pending;		/* Pending lines of output.
539131557Stjr				   Always kept 0 if out_quiet is true.  */
540131557Stjrstatic int done_on_match;	/* Stop scanning file on first match.  */
541131557Stjrstatic int exit_on_match;	/* Exit on first match.  */
54253451Speter
543131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
54453477Sobrien# include "dosbuf.c"
54553477Sobrien#endif
54653477Sobrien
547131557Stjr/* Add two numbers that count input bytes or lines, and report an
548131557Stjr   error if the addition overflows.  */
549131557Stjrstatic uintmax_t
550131557Stjradd_count (uintmax_t a, uintmax_t b)
551131557Stjr{
552131557Stjr  uintmax_t sum = a + b;
553131557Stjr  if (sum < a)
554131557Stjr    error (2, 0, _("input is too large to count"));
555131557Stjr  return sum;
556131557Stjr}
557131557Stjr
55853451Speterstatic void
559131557Stjrnlscan (char const *lim)
56053451Speter{
561131557Stjr  size_t newlines = 0;
562131557Stjr  char const *beg;
563131557Stjr  for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++)
564131557Stjr    newlines++;
565131557Stjr  totalnl = add_count (totalnl, newlines);
56655379Sobrien  lastnl = lim;
56753451Speter}
56853451Speter
569131557Stjr/* Print a byte offset, followed by a character separator.  */
57053451Speterstatic void
571131557Stjrprint_offset_sep (uintmax_t pos, char sep)
57253477Sobrien{
573131557Stjr  /* Do not rely on printf to print pos, since uintmax_t may be longer
574131557Stjr     than long, and long long is not portable.  */
57553477Sobrien
57653477Sobrien  char buf[sizeof pos * CHAR_BIT];
57753477Sobrien  char *p = buf + sizeof buf - 1;
57853477Sobrien  *p = sep;
57953477Sobrien
58053477Sobrien  do
58153477Sobrien    *--p = '0' + pos % 10;
58253477Sobrien  while ((pos /= 10) != 0);
58353477Sobrien
58453477Sobrien  fwrite (p, 1, buf + sizeof buf - p, stdout);
58553477Sobrien}
58653477Sobrien
58753477Sobrienstatic void
588146199Stjrprline (char const *beg, char const *lim, int sep)
58953451Speter{
59053451Speter  if (out_file)
59155379Sobrien    printf ("%s%c", filename, sep & filename_mask);
59253451Speter  if (out_line)
59353451Speter    {
59453477Sobrien      nlscan (beg);
595131557Stjr      totalnl = add_count (totalnl, 1);
596131557Stjr      print_offset_sep (totalnl, sep);
59753451Speter      lastnl = lim;
59853451Speter    }
59953451Speter  if (out_byte)
60053477Sobrien    {
601131557Stjr      uintmax_t pos = add_count (totalcc, beg - bufbeg);
602131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
60353477Sobrien      pos = dossified_pos (pos);
60453477Sobrien#endif
60553477Sobrien      print_offset_sep (pos, sep);
60653477Sobrien    }
607131557Stjr  if (only_matching)
608131557Stjr    {
609131557Stjr      size_t match_size;
610131557Stjr      size_t match_offset;
611146199Stjr      while ((match_offset = (*execute) (beg, lim - beg, &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;
636146199Stjr      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
637131557Stjr	     != (size_t) -1)
638131557Stjr	{
639131557Stjr	  char const *b = beg + match_offset;
640131557Stjr	  /* Avoid matching the empty line at the end of the buffer. */
641131557Stjr	  if (b == lim)
642131557Stjr	    break;
643131557Stjr	  /* Avoid hanging on grep --color "" foo */
644131557Stjr	  if (match_size == 0)
645131557Stjr	    break;
646131557Stjr	  fwrite (beg, sizeof (char), match_offset, stdout);
647131557Stjr	  printf ("\33[%sm", grep_color);
648131557Stjr	  fwrite (b, sizeof (char), match_size, stdout);
649131557Stjr	  fputs ("\33[00m", stdout);
650131557Stjr	  beg = b + match_size;
651131557Stjr	}
652146203Stjr      fputs ("\33[K", stdout);
653131557Stjr    }
65453477Sobrien  fwrite (beg, 1, lim - beg, stdout);
65553477Sobrien  if (ferror (stdout))
656131557Stjr    error (0, errno, _("writing output"));
65753451Speter  lastout = lim;
658131557Stjr  if (line_buffered)
659131557Stjr    fflush (stdout);
66053451Speter}
66153451Speter
662131557Stjr/* Print pending lines of trailing context prior to LIM. Trailing context ends
663131557Stjr   at the next matching line when OUTLEFT is 0.  */
66453451Speterstatic void
665146199Stjrprpending (char const *lim)
66653451Speter{
66753451Speter  if (!lastout)
66853451Speter    lastout = bufbeg;
66953451Speter  while (pending > 0 && lastout < lim)
67053451Speter    {
671131557Stjr      char const *nl = memchr (lastout, eolbyte, lim - lastout);
672131557Stjr      size_t match_size;
67353451Speter      --pending;
674131557Stjr      if (outleft
675146199Stjr	  || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1)
676131557Stjr	      == !out_invert))
677146199Stjr	prline (lastout, nl + 1, '-');
67853451Speter      else
679131557Stjr	pending = 0;
68053451Speter    }
68153451Speter}
68253451Speter
68353451Speter/* Print the lines between BEG and LIM.  Deal with context crap.
684131557Stjr   If NLINESP is non-null, store a count of lines between BEG and LIM.  */
68553451Speterstatic void
686146199Stjrprtext (char const *beg, char const *lim, int *nlinesp)
68753451Speter{
68853451Speter  static int used;		/* avoid printing "--" before any output */
689131557Stjr  char const *bp, *p;
69055379Sobrien  char eol = eolbyte;
69153451Speter  int i, n;
69253451Speter
69353451Speter  if (!out_quiet && pending > 0)
694146199Stjr    prpending (beg);
69553451Speter
69653451Speter  p = beg;
69753451Speter
69853451Speter  if (!out_quiet)
69953451Speter    {
70053451Speter      /* Deal with leading context crap. */
70153451Speter
70253451Speter      bp = lastout ? lastout : bufbeg;
70353451Speter      for (i = 0; i < out_before; ++i)
70453451Speter	if (p > bp)
70553451Speter	  do
70653451Speter	    --p;
707131557Stjr	  while (p[-1] != eol);
70853451Speter
70953451Speter      /* We only print the "--" separator if our output is
71053451Speter	 discontiguous from the last output in the file. */
71153451Speter      if ((out_before || out_after) && used && p != lastout)
71253477Sobrien	puts ("--");
71353451Speter
71453451Speter      while (p < beg)
71553451Speter	{
716131557Stjr	  char const *nl = memchr (p, eol, beg - p);
717131557Stjr	  nl++;
718146199Stjr	  prline (p, nl, '-');
719131557Stjr	  p = nl;
72053451Speter	}
72153451Speter    }
72253451Speter
72353451Speter  if (nlinesp)
72453451Speter    {
72553451Speter      /* Caller wants a line count. */
726131557Stjr      for (n = 0; p < lim && n < outleft; n++)
72753451Speter	{
728131557Stjr	  char const *nl = memchr (p, eol, lim - p);
729131557Stjr	  nl++;
73053451Speter	  if (!out_quiet)
731146199Stjr	    prline (p, nl, ':');
73253451Speter	  p = nl;
73353451Speter	}
73453451Speter      *nlinesp = n;
735131557Stjr
736131557Stjr      /* relying on it that this function is never called when outleft = 0.  */
737131557Stjr      after_last_match = bufoffset - (buflim - p);
73853451Speter    }
73953451Speter  else
74053451Speter    if (!out_quiet)
741146199Stjr      prline (beg, lim, ':');
74253451Speter
74355379Sobrien  pending = out_quiet ? 0 : out_after;
74453451Speter  used = 1;
74553451Speter}
74653451Speter
74753451Speter/* Scan the specified portion of the buffer, matching lines (or
74853451Speter   between matching lines if OUT_INVERT is true).  Return a count of
74953451Speter   lines printed. */
75053451Speterstatic int
751146199Stjrgrepbuf (char const *beg, char const *lim)
75253451Speter{
75353451Speter  int nlines, n;
754131557Stjr  register char const *p;
755131557Stjr  size_t match_offset;
756131557Stjr  size_t match_size;
75753451Speter
75853451Speter  nlines = 0;
75953451Speter  p = beg;
760146199Stjr  while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
76153451Speter    {
762131557Stjr      char const *b = p + match_offset;
763131557Stjr      char const *endp = b + match_size;
76453451Speter      /* Avoid matching the empty line at the end of the buffer. */
765131557Stjr      if (b == lim)
76653451Speter	break;
76753451Speter      if (!out_invert)
76853451Speter	{
769146199Stjr	  prtext (b, endp, (int *) 0);
770131557Stjr	  nlines++;
771131557Stjr          outleft--;
772131557Stjr	  if (!outleft || done_on_match)
773131557Stjr	    {
774131557Stjr	      if (exit_on_match)
775131557Stjr		exit (0);
776131557Stjr	      after_last_match = bufoffset - (buflim - endp);
777131557Stjr	      return nlines;
778131557Stjr	    }
77953451Speter	}
78053451Speter      else if (p < b)
78153451Speter	{
782146199Stjr	  prtext (p, b, &n);
78353451Speter	  nlines += n;
784131557Stjr          outleft -= n;
785131557Stjr	  if (!outleft)
786131557Stjr	    return nlines;
78753451Speter	}
78853451Speter      p = endp;
78953451Speter    }
79053451Speter  if (out_invert && p < lim)
79153451Speter    {
792146199Stjr      prtext (p, lim, &n);
79353451Speter      nlines += n;
794131557Stjr      outleft -= n;
79553451Speter    }
79653451Speter  return nlines;
79753451Speter}
79853451Speter
79953477Sobrien/* Search a given file.  Normally, return a count of lines printed;
80053477Sobrien   but if the file is a directory and we search it recursively, then
80153477Sobrien   return -2 if there was a match, and -1 otherwise.  */
80253451Speterstatic int
80356920Srugrep (int fd, char const *file, struct stats *stats)
80453451Speter{
80553451Speter  int nlines, i;
80653477Sobrien  int not_text;
80753451Speter  size_t residue, save;
808131557Stjr  char oldc;
809131557Stjr  char *beg;
810131557Stjr  char *lim;
81155379Sobrien  char eol = eolbyte;
81253451Speter
81353477Sobrien  if (!reset (fd, file, stats))
81453477Sobrien    return 0;
81553451Speter
81653477Sobrien  if (file && directories == RECURSE_DIRECTORIES
81753477Sobrien      && S_ISDIR (stats->stat.st_mode))
81853477Sobrien    {
81953477Sobrien      /* Close fd now, so that we don't open a lot of file descriptors
82053477Sobrien	 when we recurse deeply.  */
821104555Sobrien      if (BZflag && bzbufdesc)
822103372Sobrien	BZ2_bzclose(bzbufdesc);
823103372Sobrien      else
82453477Sobrien#if HAVE_LIBZ > 0
82553477Sobrien      if (Zflag)
82653477Sobrien	gzclose(gzbufdesc);
82753477Sobrien      else
82853477Sobrien#endif
82953477Sobrien      if (close (fd) != 0)
830131557Stjr	error (0, errno, "%s", file);
83153477Sobrien      return grepdir (file, stats) - 2;
83253477Sobrien    }
83353477Sobrien
83453451Speter  totalcc = 0;
83553451Speter  lastout = 0;
83653451Speter  totalnl = 0;
837131557Stjr  outleft = max_count;
838131557Stjr  after_last_match = 0;
83953451Speter  pending = 0;
84053451Speter
84153451Speter  nlines = 0;
84253451Speter  residue = 0;
84353451Speter  save = 0;
84453451Speter
84555379Sobrien  if (! fillbuf (save, stats))
84653451Speter    {
847131557Stjr      if (! is_EISDIR (errno, file))
848131557Stjr	suppressible_error (filename, errno);
84956233Sru      return 0;
85053477Sobrien    }
85153451Speter
85256233Sru  not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
85356233Sru	       || binary_files == WITHOUT_MATCH_BINARY_FILES)
85455379Sobrien	      && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
85556233Sru  if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
85656233Sru    return 0;
85753477Sobrien  done_on_match += not_text;
85853477Sobrien  out_quiet += not_text;
85953451Speter
86053477Sobrien  for (;;)
86153477Sobrien    {
86253451Speter      lastnl = bufbeg;
86353451Speter      if (lastout)
86453451Speter	lastout = bufbeg;
865131557Stjr
866131557Stjr      beg = bufbeg + save;
867131557Stjr
868131557Stjr      /* no more data to scan (eof) except for maybe a residue -> break */
869131557Stjr      if (beg == buflim)
87053451Speter	break;
871131557Stjr
872131557Stjr      /* Determine new residue (the length of an incomplete line at the end of
873131557Stjr         the buffer, 0 means there is no incomplete last line).  */
874131557Stjr      oldc = beg[-1];
875131557Stjr      beg[-1] = eol;
876131557Stjr      for (lim = buflim; lim[-1] != eol; lim--)
877131557Stjr	continue;
878131557Stjr      beg[-1] = oldc;
879131557Stjr      if (lim == beg)
880131557Stjr	lim = beg - residue;
881131557Stjr      beg -= residue;
88253451Speter      residue = buflim - lim;
883131557Stjr
88453451Speter      if (beg < lim)
88553451Speter	{
886131557Stjr	  if (outleft)
887146199Stjr	    nlines += grepbuf (beg, lim);
88853451Speter	  if (pending)
889146199Stjr	    prpending (lim);
890131557Stjr	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
89153477Sobrien	    goto finish_grep;
89253451Speter	}
893131557Stjr
894131557Stjr      /* The last OUT_BEFORE lines at the end of the buffer will be needed as
895131557Stjr	 leading context if there is a matching line at the begin of the
896131557Stjr	 next data. Make beg point to their begin.  */
89753451Speter      i = 0;
89853451Speter      beg = lim;
89953451Speter      while (i < out_before && beg > bufbeg && beg != lastout)
90053451Speter	{
90153451Speter	  ++i;
90253451Speter	  do
90353451Speter	    --beg;
904131557Stjr	  while (beg[-1] != eol);
90553451Speter	}
906131557Stjr
907131557Stjr      /* detect if leading context is discontinuous from last printed line.  */
90853451Speter      if (beg != lastout)
90953451Speter	lastout = 0;
910131557Stjr
911131557Stjr      /* Handle some details and read more data to scan.  */
91253451Speter      save = residue + lim - beg;
913131557Stjr      if (out_byte)
914131557Stjr	totalcc = add_count (totalcc, buflim - bufbeg - save);
91553451Speter      if (out_line)
91653477Sobrien	nlscan (beg);
91755379Sobrien      if (! fillbuf (save, stats))
91853477Sobrien	{
919131557Stjr	  if (! is_EISDIR (errno, file))
920131557Stjr	    suppressible_error (filename, errno);
92153477Sobrien	  goto finish_grep;
92253477Sobrien	}
92353451Speter    }
92453451Speter  if (residue)
92553451Speter    {
92656920Sru      *buflim++ = eol;
927131557Stjr      if (outleft)
928146199Stjr	nlines += grepbuf (bufbeg + save - residue, buflim);
92953451Speter      if (pending)
930146199Stjr        prpending (buflim);
93153451Speter    }
93253477Sobrien
93353477Sobrien finish_grep:
93453477Sobrien  done_on_match -= not_text;
93553477Sobrien  out_quiet -= not_text;
93653477Sobrien  if ((not_text & ~out_quiet) && nlines != 0)
93753477Sobrien    printf (_("Binary file %s matches\n"), filename);
93853451Speter  return nlines;
93953451Speter}
94053451Speter
94153477Sobrienstatic int
94256920Srugrepfile (char const *file, struct stats *stats)
94353477Sobrien{
94453477Sobrien  int desc;
94553477Sobrien  int count;
94653477Sobrien  int status;
947245761Sdavidxu  int flags;
94853477Sobrien
94953477Sobrien  if (! file)
95053477Sobrien    {
95153477Sobrien      desc = 0;
952131557Stjr      filename = label ? label : _("(standard input)");
95353477Sobrien    }
95453477Sobrien  else
95553477Sobrien    {
956245761Sdavidxu      while ((desc = open (file, O_RDONLY | O_NONBLOCK)) < 0 && errno == EINTR)
95755379Sobrien	continue;
95853477Sobrien
95953477Sobrien      if (desc < 0)
96053477Sobrien	{
96153477Sobrien	  int e = errno;
962131557Stjr
96353477Sobrien	  if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
96453477Sobrien	    {
96553477Sobrien	      if (stat (file, &stats->stat) != 0)
96653477Sobrien		{
967131557Stjr		  error (0, errno, "%s", file);
96853477Sobrien		  return 1;
96953477Sobrien		}
97053477Sobrien
97153477Sobrien	      return grepdir (file, stats);
97253477Sobrien	    }
973131557Stjr
97453477Sobrien	  if (!suppress_errors)
97553477Sobrien	    {
97653477Sobrien	      if (directories == SKIP_DIRECTORIES)
97753477Sobrien		switch (e)
97853477Sobrien		  {
979131557Stjr#if defined(EISDIR)
98053477Sobrien		  case EISDIR:
98153477Sobrien		    return 1;
98253451Speter#endif
98353477Sobrien		  case EACCES:
98453477Sobrien		    /* When skipping directories, don't worry about
98553477Sobrien		       directories that can't be opened.  */
986131557Stjr		    if (isdir (file))
98753477Sobrien		      return 1;
98853477Sobrien		    break;
98953477Sobrien		  }
99053477Sobrien	    }
99153477Sobrien
992131557Stjr	  suppressible_error (file, e);
99353477Sobrien	  return 1;
99453477Sobrien	}
99553477Sobrien
996245761Sdavidxu      flags = fcntl(desc, F_GETFL);
997245761Sdavidxu      flags &= ~O_NONBLOCK;
998245761Sdavidxu      fcntl(desc, F_SETFL, flags);
99953477Sobrien      filename = file;
100053477Sobrien    }
100153477Sobrien
1002131557Stjr#if defined(SET_BINARY)
100353477Sobrien  /* Set input to binary mode.  Pipes are simulated with files
100453477Sobrien     on DOS, so this includes the case of "foo | grep bar".  */
100553477Sobrien  if (!isatty (desc))
100653477Sobrien    SET_BINARY (desc);
100753477Sobrien#endif
100853477Sobrien
100953477Sobrien  count = grep (desc, file, stats);
101053477Sobrien  if (count < 0)
101153477Sobrien    status = count + 2;
101253477Sobrien  else
101353477Sobrien    {
101453477Sobrien      if (count_matches)
101553477Sobrien	{
101653477Sobrien	  if (out_file)
101755379Sobrien	    printf ("%s%c", filename, ':' & filename_mask);
101853477Sobrien	  printf ("%d\n", count);
101953477Sobrien	}
102053477Sobrien
102155379Sobrien      status = !count;
102255379Sobrien      if (list_files == 1 - 2 * status)
102355379Sobrien	printf ("%s%c", filename, '\n' & filename_mask);
102453477Sobrien
1025104555Sobrien      if (BZflag && bzbufdesc)
1026103372Sobrien	BZ2_bzclose(bzbufdesc);
1027103372Sobrien      else
102853451Speter#if HAVE_LIBZ > 0
102953477Sobrien      if (Zflag)
103053477Sobrien	gzclose(gzbufdesc);
103153477Sobrien      else
103253451Speter#endif
1033131557Stjr      if (! file)
1034131557Stjr	{
1035131557Stjr	  off_t required_offset = outleft ? bufoffset : after_last_match;
1036131557Stjr	  if ((bufmapped || required_offset != bufoffset)
1037131557Stjr	      && lseek (desc, required_offset, SEEK_SET) < 0
1038131557Stjr	      && S_ISREG (stats->stat.st_mode))
1039131557Stjr	    error (0, errno, "%s", filename);
1040131557Stjr	}
1041131557Stjr      else
104255379Sobrien	while (close (desc) != 0)
104355379Sobrien	  if (errno != EINTR)
104455379Sobrien	    {
1045131557Stjr	      error (0, errno, "%s", file);
104655379Sobrien	      break;
104755379Sobrien	    }
104853477Sobrien    }
104953451Speter
105053477Sobrien  return status;
105153477Sobrien}
105253477Sobrien
105353477Sobrienstatic int
1054131557Stjrgrepdir (char const *dir, struct stats const *stats)
105553477Sobrien{
105653477Sobrien  int status = 1;
1057131557Stjr  struct stats const *ancestor;
105853477Sobrien  char *name_space;
105953477Sobrien
1060131557Stjr  /* Mingw32 does not support st_ino.  No known working hosts use zero
1061131557Stjr     for st_ino, so assume that the Mingw32 bug applies if it's zero.  */
1062131557Stjr  if (stats->stat.st_ino)
1063131557Stjr    for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
1064131557Stjr      if (ancestor->stat.st_ino == stats->stat.st_ino
1065131557Stjr	  && ancestor->stat.st_dev == stats->stat.st_dev)
1066131557Stjr	{
1067131557Stjr	  if (!suppress_errors)
1068141847Sobrien	    error (0, 0, _("warning: %s: %s"), dir,
106953477Sobrien		   _("recursive directory loop"));
1070131557Stjr	  return 1;
1071131557Stjr	}
107253477Sobrien
1073131557Stjr  name_space = savedir (dir, stats->stat.st_size, included_patterns,
1074131557Stjr			excluded_patterns);
107553477Sobrien
107653477Sobrien  if (! name_space)
107753477Sobrien    {
107853477Sobrien      if (errno)
1079131557Stjr	suppressible_error (dir, errno);
108053477Sobrien      else
1081131557Stjr	xalloc_die ();
108253477Sobrien    }
108353477Sobrien  else
108453477Sobrien    {
108553477Sobrien      size_t dirlen = strlen (dir);
108653477Sobrien      int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
108753477Sobrien			   || IS_SLASH (dir[dirlen - 1]));
108853477Sobrien      char *file = NULL;
1089131557Stjr      char const *namep = name_space;
109053477Sobrien      struct stats child;
109153477Sobrien      child.parent = stats;
109253477Sobrien      out_file += !no_filenames;
109353477Sobrien      while (*namep)
109453477Sobrien	{
109553477Sobrien	  size_t namelen = strlen (namep);
109653477Sobrien	  file = xrealloc (file, dirlen + 1 + namelen + 1);
109753477Sobrien	  strcpy (file, dir);
109853477Sobrien	  file[dirlen] = '/';
109953477Sobrien	  strcpy (file + dirlen + needs_slash, namep);
110053477Sobrien	  namep += namelen + 1;
110153477Sobrien	  status &= grepfile (file, &child);
110253477Sobrien	}
110353477Sobrien      out_file -= !no_filenames;
110453477Sobrien      if (file)
110553477Sobrien        free (file);
110653477Sobrien      free (name_space);
110753477Sobrien    }
110853477Sobrien
110953477Sobrien  return status;
111053477Sobrien}
111153477Sobrien
111253451Speterstatic void
111356920Sruusage (int status)
111453451Speter{
111553477Sobrien  if (status != 0)
111653477Sobrien    {
1117131557Stjr      fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
1118131557Stjr	       program_name);
1119131557Stjr      fprintf (stderr, _("Try `%s --help' for more information.\n"),
1120131557Stjr	       program_name);
112153477Sobrien    }
112253477Sobrien  else
112353477Sobrien    {
1124131557Stjr      printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name);
112553477Sobrien      printf (_("\
112653477SobrienSearch for PATTERN in each FILE or standard input.\n\
112756920SruExample: %s -i 'hello world' menu.h main.c\n\
112853477Sobrien\n\
1129131557StjrRegexp selection and interpretation:\n"), program_name);
113055379Sobrien      printf (_("\
113153477Sobrien  -E, --extended-regexp     PATTERN is an extended regular expression\n\
113255379Sobrien  -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
1133131557Stjr  -G, --basic-regexp        PATTERN is a basic regular expression\n\
1134131557Stjr  -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
113555379Sobrien      printf (_("\
113653477Sobrien  -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
113753477Sobrien  -f, --file=FILE           obtain PATTERN from FILE\n\
113853477Sobrien  -i, --ignore-case         ignore case distinctions\n\
113953477Sobrien  -w, --word-regexp         force PATTERN to match only whole words\n\
114055379Sobrien  -x, --line-regexp         force PATTERN to match only whole lines\n\
114155379Sobrien  -z, --null-data           a data line ends in 0 byte, not newline\n"));
114253477Sobrien      printf (_("\
114353477Sobrien\n\
114453477SobrienMiscellaneous:\n\
114553477Sobrien  -s, --no-messages         suppress error messages\n\
114655379Sobrien  -v, --invert-match        select non-matching lines\n\
114753477Sobrien  -V, --version             print version information and exit\n\
114855379Sobrien      --help                display this help and exit\n\
1149103372Sobrien  -J, --bz2decompress       decompress bzip2'ed input before searching\n\
115053477Sobrien  -Z, --decompress          decompress input before searching (HAVE_LIBZ=1)\n\
115155379Sobrien      --mmap                use memory-mapped input if possible\n"));
115253477Sobrien      printf (_("\
115353477Sobrien\n\
115453477SobrienOutput control:\n\
1155131557Stjr  -m, --max-count=NUM       stop after NUM matches\n\
115653477Sobrien  -b, --byte-offset         print the byte offset with output lines\n\
115753477Sobrien  -n, --line-number         print line number with output lines\n\
1158131557Stjr      --line-buffered       flush output on every line\n\
115953477Sobrien  -H, --with-filename       print the filename for each match\n\
116053477Sobrien  -h, --no-filename         suppress the prefixing filename on output\n\
1161131557Stjr      --label=LABEL         print LABEL as filename for standard input\n\
1162131557Stjr  -o, --only-matching       show only the part of a line matching PATTERN\n\
116353477Sobrien  -q, --quiet, --silent     suppress all normal output\n\
116456233Sru      --binary-files=TYPE   assume that binary files are TYPE\n\
1165131557Stjr                            TYPE is 'binary', 'text', or 'without-match'\n\
116656920Sru  -a, --text                equivalent to --binary-files=text\n\
116756920Sru  -I                        equivalent to --binary-files=without-match\n\
116853477Sobrien  -d, --directories=ACTION  how to handle directories\n\
1169131557Stjr                            ACTION is 'read', 'recurse', or 'skip'\n\
1170131557Stjr  -D, --devices=ACTION      how to handle devices, FIFOs and sockets\n\
1171131557Stjr                            ACTION is 'read' or 'skip'\n\
1172131557Stjr  -R, -r, --recursive       equivalent to --directories=recurse\n\
1173131557Stjr      --include=PATTERN     files that match PATTERN will be examined\n\
1174131557Stjr      --exclude=PATTERN     files that match PATTERN will be skipped.\n\
1175131557Stjr      --exclude-from=FILE   files that match PATTERN in FILE will be skipped.\n\
117653477Sobrien  -L, --files-without-match only print FILE names containing no match\n\
117753477Sobrien  -l, --files-with-matches  only print FILE names containing matches\n\
117855379Sobrien  -c, --count               only print a count of matching lines per FILE\n\
117955379Sobrien      --null                print 0 byte after FILE name\n"));
118053477Sobrien      printf (_("\
118153477Sobrien\n\
118253477SobrienContext control:\n\
118353477Sobrien  -B, --before-context=NUM  print NUM lines of leading context\n\
118453477Sobrien  -A, --after-context=NUM   print NUM lines of trailing context\n\
1185131557Stjr  -C, --context=NUM         print NUM lines of output context\n\
118653477Sobrien  -NUM                      same as --context=NUM\n\
1187131557Stjr      --color[=WHEN],\n\
1188131557Stjr      --colour[=WHEN]       use markers to distinguish the matching string\n\
1189131557Stjr                            WHEN may be `always', `never' or `auto'.\n\
119053477Sobrien  -U, --binary              do not strip CR characters at EOL (MSDOS)\n\
119153477Sobrien  -u, --unix-byte-offsets   report offsets as if CRs were not there (MSDOS)\n\
119253477Sobrien\n\
119355379Sobrien`egrep' means `grep -E'.  `fgrep' means `grep -F'.\n\
119455379SobrienWith no FILE, or when FILE is -, read standard input.  If less than\n\
119555379Sobrientwo FILEs given, assume -h.  Exit status is 0 if match, 1 if no match,\n\
119655379Sobrienand 2 if trouble.\n"));
119753477Sobrien      printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n"));
119853477Sobrien    }
119953477Sobrien  exit (status);
120053451Speter}
120153451Speter
120255379Sobrien/* Set the matcher to M, reporting any conflicts.  */
120355379Sobrienstatic void
120456920Srusetmatcher (char const *m)
120555379Sobrien{
120655379Sobrien  if (matcher && strcmp (matcher, m) != 0)
1207131557Stjr    error (2, 0, _("conflicting matchers specified"));
120855379Sobrien  matcher = m;
120955379Sobrien}
121055379Sobrien
121153451Speter/* Go through the matchers vector and look for the specified matcher.
121253451Speter   If we find it, install it in compile and execute, and return 1.  */
121353477Sobrienstatic int
121456920Sruinstall_matcher (char const *name)
121553451Speter{
121653451Speter  int i;
1217131557Stjr#if defined(HAVE_SETRLIMIT)
121853477Sobrien  struct rlimit rlim;
121953477Sobrien#endif
122053451Speter
1221131557Stjr  for (i = 0; matchers[i].compile; i++)
122253477Sobrien    if (strcmp (name, matchers[i].name) == 0)
122353451Speter      {
122453451Speter	compile = matchers[i].compile;
122553451Speter	execute = matchers[i].execute;
1226131557Stjr#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
122753477Sobrien	/* I think every platform needs to do this, so that regex.c
122853477Sobrien	   doesn't oveflow the stack.  The default value of
122953477Sobrien	   `re_max_failures' is too large for some platforms: it needs
123053477Sobrien	   more than 3MB-large stack.
123153477Sobrien
123253477Sobrien	   The test for HAVE_SETRLIMIT should go into `configure'.  */
123353477Sobrien	if (!getrlimit (RLIMIT_STACK, &rlim))
123453477Sobrien	  {
123553477Sobrien	    long newlim;
123653477Sobrien	    extern long int re_max_failures; /* from regex.c */
123753477Sobrien
123853477Sobrien	    /* Approximate the amount regex.c needs, plus some more.  */
123953477Sobrien	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
124053477Sobrien	    if (newlim > rlim.rlim_max)
124153477Sobrien	      {
124253477Sobrien		newlim = rlim.rlim_max;
124353477Sobrien		re_max_failures = newlim / (2 * 20 * sizeof (char *));
124453477Sobrien	      }
124553477Sobrien	    if (rlim.rlim_cur < newlim)
1246131557Stjr	      {
1247131557Stjr		rlim.rlim_cur = newlim;
1248131557Stjr		setrlimit (RLIMIT_STACK, &rlim);
1249131557Stjr	      }
125053477Sobrien	  }
125153477Sobrien#endif
125253451Speter	return 1;
125353451Speter      }
125453451Speter  return 0;
125553451Speter}
125653451Speter
125753705Sobrien/* Find the white-space-separated options specified by OPTIONS, and
125853705Sobrien   using BUF to store copies of these options, set ARGV[0], ARGV[1],
125953705Sobrien   etc. to the option copies.  Return the number N of options found.
126053705Sobrien   Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
126153705Sobrien   etc.  Backslash can be used to escape whitespace (and backslashes).  */
126253705Sobrienstatic int
126356920Sruprepend_args (char const *options, char *buf, char **argv)
126453705Sobrien{
126553705Sobrien  char const *o = options;
126653705Sobrien  char *b = buf;
126753705Sobrien  int n = 0;
126853705Sobrien
126953705Sobrien  for (;;)
127053705Sobrien    {
127153705Sobrien      while (ISSPACE ((unsigned char) *o))
127253705Sobrien	o++;
127353705Sobrien      if (!*o)
127453705Sobrien	return n;
127553705Sobrien      if (argv)
127653705Sobrien	argv[n] = b;
127753705Sobrien      n++;
127853705Sobrien
127953705Sobrien      do
128053705Sobrien	if ((*b++ = *o++) == '\\' && *o)
128153705Sobrien	  b[-1] = *o++;
128253705Sobrien      while (*o && ! ISSPACE ((unsigned char) *o));
128353705Sobrien
128453705Sobrien      *b++ = '\0';
128553705Sobrien    }
128653705Sobrien}
128753705Sobrien
128853705Sobrien/* Prepend the whitespace-separated options in OPTIONS to the argument
128953705Sobrien   vector of a main program with argument count *PARGC and argument
129053705Sobrien   vector *PARGV.  */
129153705Sobrienstatic void
129256920Sruprepend_default_options (char const *options, int *pargc, char ***pargv)
129353705Sobrien{
129453705Sobrien  if (options)
129553705Sobrien    {
129653705Sobrien      char *buf = xmalloc (strlen (options) + 1);
129753705Sobrien      int prepended = prepend_args (options, buf, (char **) NULL);
129853705Sobrien      int argc = *pargc;
129953705Sobrien      char * const *argv = *pargv;
130053705Sobrien      char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
130153705Sobrien      *pargc = prepended + argc;
130253705Sobrien      *pargv = pp;
130353705Sobrien      *pp++ = *argv++;
130453705Sobrien      pp += prepend_args (options, buf, pp);
130553705Sobrien      while ((*pp++ = *argv++))
130653705Sobrien	continue;
130753705Sobrien    }
130853705Sobrien}
130953705Sobrien
1310131557Stjr/* Get the next non-digit option from ARGC and ARGV.
1311131557Stjr   Return -1 if there are no more options.
1312131557Stjr   Process any digit options that were encountered on the way,
1313131557Stjr   and store the resulting integer into *DEFAULT_CONTEXT.  */
1314131557Stjrstatic int
1315131557Stjrget_nondigit_option (int argc, char *const *argv, int *default_context)
1316131557Stjr{
1317131557Stjr  int opt;
1318131557Stjr  char buf[sizeof (uintmax_t) * CHAR_BIT + 4];
1319131557Stjr  char *p = buf;
1320131557Stjr
1321131557Stjr  /* Set buf[0] to anything but '0', for the leading-zero test below.  */
1322131557Stjr  buf[0] = '\0';
1323131557Stjr
1324131557Stjr  while (opt = getopt_long (argc, argv, short_options, long_options, NULL),
1325131557Stjr	 '0' <= opt && opt <= '9')
1326131557Stjr    {
1327131557Stjr      /* Suppress trivial leading zeros, to avoid incorrect
1328131557Stjr	 diagnostic on strings like 00000000000.  */
1329131557Stjr      p -= buf[0] == '0';
1330131557Stjr
1331131557Stjr      *p++ = opt;
1332131557Stjr      if (p == buf + sizeof buf - 4)
1333131557Stjr	{
1334131557Stjr	  /* Too many digits.  Append "..." to make context_length_arg
1335131557Stjr	     complain about "X...", where X contains the digits seen
1336131557Stjr	     so far.  */
1337131557Stjr	  strcpy (p, "...");
1338131557Stjr	  p += 3;
1339131557Stjr	  break;
1340131557Stjr	}
1341131557Stjr    }
1342131557Stjr  if (p != buf)
1343131557Stjr    {
1344131557Stjr      *p = '\0';
1345131557Stjr      context_length_arg (buf, default_context);
1346131557Stjr    }
1347131557Stjr
1348131557Stjr  return opt;
1349131557Stjr}
1350131557Stjr
135153451Speterint
135256920Srumain (int argc, char **argv)
135353451Speter{
135453451Speter  char *keys;
1355250823Spfg  size_t cc, keycc, oldcc, keyalloc;
135653477Sobrien  int with_filenames;
1357250823Spfg  int opt, status;
135856920Sru  int default_context;
135953451Speter  FILE *fp;
136053451Speter  extern char *optarg;
136153451Speter  extern int optind;
136253477Sobrien
136353477Sobrien  initialize_main (&argc, &argv);
1364131557Stjr  program_name = argv[0];
1365131557Stjr  if (program_name && strrchr (program_name, '/'))
1366131557Stjr    program_name = strrchr (program_name, '/') + 1;
136753477Sobrien
1368151534Sjkim  if (program_name[0] == 'b' && program_name[1] == 'z') {
1369151527Sjkim    BZflag = 1;
1370151527Sjkim    program_name += 2;
1371151527Sjkim  }
137253477Sobrien#if HAVE_LIBZ > 0
1373151534Sjkim  else if (program_name[0] == 'z') {
137453477Sobrien    Zflag = 1;
1375131557Stjr    ++program_name;
137653477Sobrien  }
137753451Speter#endif
137853451Speter
137953477Sobrien#if defined(__MSDOS__) || defined(_WIN32)
138053477Sobrien  /* DOS and MS-Windows use backslashes as directory separators, and usually
138153477Sobrien     have an .exe suffix.  They also have case-insensitive filesystems.  */
1382131557Stjr  if (program_name)
138353477Sobrien    {
1384131557Stjr      char *p = program_name;
138553477Sobrien      char *bslash = strrchr (argv[0], '\\');
138653477Sobrien
1387131557Stjr      if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
1388131557Stjr	program_name = bslash + 1;
1389131557Stjr      else if (program_name == argv[0]
139053477Sobrien	       && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
1391131557Stjr	program_name = argv[0] + 2;
139253477Sobrien
139353477Sobrien      /* Collapse the letter-case, so `strcmp' could be used hence.  */
139453477Sobrien      for ( ; *p; p++)
139553477Sobrien	if (*p >= 'A' && *p <= 'Z')
139653477Sobrien	  *p += 'a' - 'A';
139753477Sobrien
139853477Sobrien      /* Remove the .exe extension, if any.  */
1399131557Stjr      if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
140053477Sobrien	*p = '\0';
140153477Sobrien    }
140253451Speter#endif
140353451Speter
140453451Speter  keys = NULL;
140553451Speter  keycc = 0;
140653477Sobrien  with_filenames = 0;
140755379Sobrien  eolbyte = '\n';
140855379Sobrien  filename_mask = ~0;
140953477Sobrien
1410131557Stjr  max_count = TYPE_MAXIMUM (off_t);
1411131557Stjr
141253477Sobrien  /* The value -1 means to use DEFAULT_CONTEXT. */
141353477Sobrien  out_after = out_before = -1;
141453477Sobrien  /* Default before/after context: chaged by -C/-NUM options */
141553477Sobrien  default_context = 0;
1416131557Stjr  /* Changed by -o option */
1417131557Stjr  only_matching = 0;
141853477Sobrien
1419131557Stjr  /* Internationalization. */
1420131557Stjr#if defined(HAVE_SETLOCALE)
142153477Sobrien  setlocale (LC_ALL, "");
142253451Speter#endif
1423131557Stjr#if defined(ENABLE_NLS)
142453477Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
142553477Sobrien  textdomain (PACKAGE);
142653451Speter#endif
142753451Speter
1428131557Stjr  atexit (close_stdout);
1429131557Stjr
143053705Sobrien  prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
143153705Sobrien
1432131557Stjr  while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1)
143353451Speter    switch (opt)
143453451Speter      {
143553451Speter      case 'A':
1436131557Stjr	context_length_arg (optarg, &out_after);
143753451Speter	break;
1438131557Stjr
143953451Speter      case 'B':
1440131557Stjr	context_length_arg (optarg, &out_before);
144153451Speter	break;
1442131557Stjr
144353451Speter      case 'C':
144453477Sobrien	/* Set output match context, but let any explicit leading or
144553477Sobrien	   trailing amount specified with -A or -B stand. */
1446131557Stjr	context_length_arg (optarg, &default_context);
1447131557Stjr	break;
1448131557Stjr
1449131557Stjr      case 'D':
1450131557Stjr	if (strcmp (optarg, "read") == 0)
1451131557Stjr	  devices = READ_DEVICES;
1452131557Stjr	else if (strcmp (optarg, "skip") == 0)
1453131557Stjr	  devices = SKIP_DEVICES;
145453477Sobrien	else
1455131557Stjr	  error (2, 0, _("unknown devices method"));
145653451Speter	break;
1457131557Stjr
145853451Speter      case 'E':
145955379Sobrien	setmatcher ("egrep");
146053451Speter	break;
1461131557Stjr
146253451Speter      case 'F':
146355379Sobrien	setmatcher ("fgrep");
146453451Speter	break;
1465131557Stjr
1466131557Stjr      case 'P':
1467131557Stjr	setmatcher ("perl");
1468131557Stjr	break;
1469131557Stjr
147053451Speter      case 'G':
147155379Sobrien	setmatcher ("grep");
147253451Speter	break;
1473131557Stjr
147453477Sobrien      case 'H':
147553477Sobrien	with_filenames = 1;
147653477Sobrien	break;
1477131557Stjr
147856920Sru      case 'I':
147956920Sru	binary_files = WITHOUT_MATCH_BINARY_FILES;
148056920Sru	break;
1481103372Sobrien      case 'J':
1482104555Sobrien	if (Zflag)
1483104555Sobrien	  {
1484104555Sobrien	    printf (_("Cannot mix -Z and -J.\n"));
1485104555Sobrien	    usage (2);
1486104555Sobrien	  }
1487103372Sobrien	BZflag = 1;
1488103372Sobrien	break;
1489131557Stjr
149055379Sobrien      case 'U':
1491131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
149253477Sobrien	dos_use_file_type = DOS_BINARY;
149355379Sobrien#endif
149453477Sobrien	break;
1495131557Stjr
149653477Sobrien      case 'u':
1497131557Stjr#if defined(HAVE_DOS_FILE_CONTENTS)
149853477Sobrien	dos_report_unix_offset = 1;
149955379Sobrien#endif
150053477Sobrien	break;
1501131557Stjr
150253451Speter      case 'V':
150353477Sobrien	show_version = 1;
150453451Speter	break;
1505131557Stjr
150653451Speter      case 'X':
150755379Sobrien	setmatcher (optarg);
150853451Speter	break;
1509131557Stjr
151053451Speter      case 'a':
151156233Sru	binary_files = TEXT_BINARY_FILES;
151253451Speter	break;
1513131557Stjr
151453451Speter      case 'b':
151553451Speter	out_byte = 1;
151653451Speter	break;
1517131557Stjr
151853451Speter      case 'c':
151953451Speter	count_matches = 1;
152053451Speter	break;
1521131557Stjr
152253477Sobrien      case 'd':
152353477Sobrien	if (strcmp (optarg, "read") == 0)
152453477Sobrien	  directories = READ_DIRECTORIES;
152553477Sobrien	else if (strcmp (optarg, "skip") == 0)
152653477Sobrien	  directories = SKIP_DIRECTORIES;
152753477Sobrien	else if (strcmp (optarg, "recurse") == 0)
152853477Sobrien	  directories = RECURSE_DIRECTORIES;
152953477Sobrien	else
1530131557Stjr	  error (2, 0, _("unknown directories method"));
153153477Sobrien	break;
1532131557Stjr
153353451Speter      case 'e':
153453477Sobrien	cc = strlen (optarg);
153553477Sobrien	keys = xrealloc (keys, keycc + cc + 1);
153653477Sobrien	strcpy (&keys[keycc], optarg);
153753451Speter	keycc += cc;
153853477Sobrien	keys[keycc++] = '\n';
153953451Speter	break;
1540131557Stjr
154153451Speter      case 'f':
154253477Sobrien	fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
154353451Speter	if (!fp)
1544131557Stjr	  error (2, errno, "%s", optarg);
154553477Sobrien	for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
154653451Speter	  ;
154753477Sobrien	keys = xrealloc (keys, keyalloc);
154853451Speter	oldcc = keycc;
154953477Sobrien	while (!feof (fp)
155053477Sobrien	       && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
155153451Speter	  {
155253451Speter	    keycc += cc;
155353477Sobrien	    if (keycc == keyalloc - 1)
155453477Sobrien	      keys = xrealloc (keys, keyalloc *= 2);
155553451Speter	  }
155653451Speter	if (fp != stdin)
155753451Speter	  fclose(fp);
155853477Sobrien	/* Append final newline if file ended in non-newline. */
155953477Sobrien	if (oldcc != keycc && keys[keycc - 1] != '\n')
156053477Sobrien	  keys[keycc++] = '\n';
156153451Speter	break;
1562131557Stjr
156353451Speter      case 'h':
156453451Speter	no_filenames = 1;
156553451Speter	break;
1566131557Stjr
156753451Speter      case 'i':
156853451Speter      case 'y':			/* For old-timers . . . */
156953451Speter	match_icase = 1;
157053451Speter	break;
1571131557Stjr
157253451Speter      case 'L':
157353451Speter	/* Like -l, except list files that don't contain matches.
157453451Speter	   Inspired by the same option in Hume's gre. */
157553451Speter	list_files = -1;
157653451Speter	break;
1577131557Stjr
157853451Speter      case 'l':
157953451Speter	list_files = 1;
158053451Speter	break;
1581131557Stjr
1582131557Stjr      case 'm':
1583131557Stjr	{
1584131557Stjr	  uintmax_t value;
1585131557Stjr	  switch (xstrtoumax (optarg, 0, 10, &value, ""))
1586131557Stjr	    {
1587131557Stjr	    case LONGINT_OK:
1588131557Stjr	      max_count = value;
1589131557Stjr	      if (0 <= max_count && max_count == value)
1590131557Stjr		break;
1591131557Stjr	      /* Fall through.  */
1592131557Stjr	    case LONGINT_OVERFLOW:
1593131557Stjr	      max_count = TYPE_MAXIMUM (off_t);
1594131557Stjr	      break;
1595131557Stjr
1596131557Stjr	    default:
1597131557Stjr	      error (2, 0, _("invalid max count"));
1598131557Stjr	    }
1599131557Stjr	}
1600131557Stjr	break;
1601131557Stjr
160253451Speter      case 'n':
160353451Speter	out_line = 1;
160453451Speter	break;
1605131557Stjr
1606131557Stjr      case 'o':
1607131557Stjr	only_matching = 1;
1608131557Stjr	break;
1609131557Stjr
161053451Speter      case 'q':
1611131557Stjr	exit_on_match = 1;
1612131557Stjr	close_stdout_set_status(0);
161353451Speter	break;
1614131557Stjr
161553478Sobrien      case 'R':
161653477Sobrien      case 'r':
161753477Sobrien	directories = RECURSE_DIRECTORIES;
161853477Sobrien	break;
1619131557Stjr
162053451Speter      case 's':
162153451Speter	suppress_errors = 1;
162253451Speter	break;
1623131557Stjr
162453451Speter      case 'v':
162553451Speter	out_invert = 1;
162653451Speter	break;
1627131557Stjr
162853451Speter      case 'w':
162953451Speter	match_words = 1;
163053451Speter	break;
1631131557Stjr
163253451Speter      case 'x':
163353451Speter	match_lines = 1;
163453451Speter	break;
1635131557Stjr
163655379Sobrien      case 'Z':
163755379Sobrien#if HAVE_LIBZ > 0
1638104555Sobrien	if (BZflag)
1639104555Sobrien	  {
1640104555Sobrien	    printf (_("Cannot mix -J and -Z.\n"));
1641104555Sobrien	    usage (2);
1642104555Sobrien	  }
164355379Sobrien	Zflag = 1;
164455379Sobrien#else
164555379Sobrien	filename_mask = 0;
164655379Sobrien#endif
164755379Sobrien	break;
1648131557Stjr
164955379Sobrien      case 'z':
165055379Sobrien	eolbyte = '\0';
165155379Sobrien	break;
1652131557Stjr
165356233Sru      case BINARY_FILES_OPTION:
165456233Sru	if (strcmp (optarg, "binary") == 0)
165556233Sru	  binary_files = BINARY_BINARY_FILES;
165656233Sru	else if (strcmp (optarg, "text") == 0)
165756233Sru	  binary_files = TEXT_BINARY_FILES;
165856233Sru	else if (strcmp (optarg, "without-match") == 0)
165956233Sru	  binary_files = WITHOUT_MATCH_BINARY_FILES;
166056233Sru	else
1661131557Stjr	  error (2, 0, _("unknown binary-files type"));
166256233Sru	break;
1663131557Stjr
1664131557Stjr      case COLOR_OPTION:
1665131557Stjr        if(optarg) {
1666131557Stjr          if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") ||
1667131557Stjr             !strcasecmp(optarg, "force"))
1668131557Stjr            color_option = 1;
1669131557Stjr          else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") ||
1670131557Stjr                  !strcasecmp(optarg, "none"))
1671131557Stjr            color_option = 0;
1672131557Stjr          else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") ||
1673131557Stjr                  !strcasecmp(optarg, "if-tty"))
1674131557Stjr            color_option = 2;
1675131557Stjr          else
1676131557Stjr            show_help = 1;
1677131557Stjr        } else
1678131557Stjr          color_option = 2;
1679131557Stjr        if(color_option == 2) {
1680131557Stjr          if(isatty(STDOUT_FILENO) && getenv("TERM") &&
1681131557Stjr	     strcmp(getenv("TERM"), "dumb"))
1682131557Stjr                  color_option = 1;
1683131557Stjr          else
1684131557Stjr            color_option = 0;
1685131557Stjr        }
1686131557Stjr	break;
1687131557Stjr
1688131557Stjr      case EXCLUDE_OPTION:
1689131557Stjr	if (!excluded_patterns)
1690131557Stjr	  excluded_patterns = new_exclude ();
1691131557Stjr	add_exclude (excluded_patterns, optarg);
1692131557Stjr	break;
1693131557Stjr
1694131557Stjr      case EXCLUDE_FROM_OPTION:
1695131557Stjr	if (!excluded_patterns)
1696131557Stjr	  excluded_patterns = new_exclude ();
1697131557Stjr        if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n')
1698131557Stjr	    != 0)
1699131557Stjr          {
1700131557Stjr            error (2, errno, "%s", optarg);
1701131557Stjr          }
1702131557Stjr        break;
1703131557Stjr
1704131557Stjr      case INCLUDE_OPTION:
1705131557Stjr	if (!included_patterns)
1706131557Stjr	  included_patterns = new_exclude ();
1707131557Stjr	add_exclude (included_patterns, optarg);
1708131557Stjr	break;
1709131557Stjr
1710131557Stjr      case LINE_BUFFERED_OPTION:
1711131557Stjr	line_buffered = 1;
1712131557Stjr	break;
1713131557Stjr
1714131557Stjr      case LABEL_OPTION:
1715131557Stjr	label = optarg;
1716131557Stjr	break;
1717131557Stjr
171853477Sobrien      case 0:
171953477Sobrien	/* long options */
172053477Sobrien	break;
1721131557Stjr
172253451Speter      default:
172353477Sobrien	usage (2);
172453451Speter	break;
1725131557Stjr
172653451Speter      }
172753451Speter
1728131557Stjr  /* POSIX.2 says that -q overrides -l, which in turn overrides the
1729131557Stjr     other output options.  */
1730131557Stjr  if (exit_on_match)
1731131557Stjr    list_files = 0;
1732131557Stjr  if (exit_on_match | list_files)
1733131557Stjr    {
1734131557Stjr      count_matches = 0;
1735131557Stjr      done_on_match = 1;
1736131557Stjr    }
1737131557Stjr  out_quiet = count_matches | done_on_match;
1738131557Stjr
173953477Sobrien  if (out_after < 0)
174053477Sobrien    out_after = default_context;
174153477Sobrien  if (out_before < 0)
174253477Sobrien    out_before = default_context;
174353477Sobrien
1744131557Stjr  if (color_option)
1745131557Stjr    {
1746131557Stjr      char *userval = getenv ("GREP_COLOR");
1747131557Stjr      if (userval != NULL && *userval != '\0')
1748131557Stjr	grep_color = userval;
1749131557Stjr    }
1750131557Stjr
175155379Sobrien  if (! matcher)
1752131557Stjr    matcher = program_name;
175355379Sobrien
175453477Sobrien  if (show_version)
175553477Sobrien    {
175655379Sobrien      printf (_("%s (GNU grep) %s\n"), matcher, VERSION);
175753477Sobrien      printf ("\n");
175853477Sobrien      printf (_("\
1759131557StjrCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n"));
176053477Sobrien      printf (_("\
176153477SobrienThis is free software; see the source for copying conditions. There is NO\n\
176253477Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
176353477Sobrien      printf ("\n");
176453477Sobrien      exit (0);
176553477Sobrien    }
176653477Sobrien
176753477Sobrien  if (show_help)
176853477Sobrien    usage (0);
176953477Sobrien
177053477Sobrien  if (keys)
177153477Sobrien    {
177253477Sobrien      if (keycc == 0)
1773131557Stjr	{
1774131557Stjr	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
1775131557Stjr	  out_invert ^= 1;
1776131557Stjr	  match_lines = match_words = 0;
1777131557Stjr	}
177853477Sobrien      else
177953477Sobrien	/* Strip trailing newline. */
178053477Sobrien        --keycc;
178153477Sobrien    }
178253477Sobrien  else
178353451Speter    if (optind < argc)
178453451Speter      {
178553451Speter	keys = argv[optind++];
178653477Sobrien	keycc = strlen (keys);
178753451Speter      }
178853451Speter    else
178953477Sobrien      usage (2);
179053451Speter
179155379Sobrien  if (!install_matcher (matcher) && !install_matcher ("default"))
179253477Sobrien    abort ();
179353451Speter
1794131564Stjr#ifdef MBS_SUPPORT
1795131564Stjr  if (MB_CUR_MAX != 1 && match_icase)
1796131564Stjr    {
1797131564Stjr      wchar_t wc;
1798131564Stjr      mbstate_t cur_state, prev_state;
1799131564Stjr      int i, len = strlen(keys);
1800131564Stjr
1801131564Stjr      memset(&cur_state, 0, sizeof(mbstate_t));
1802131564Stjr      for (i = 0; i <= len ;)
1803131564Stjr	{
1804131564Stjr	  size_t mbclen;
1805131564Stjr	  mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state);
1806131564Stjr	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
1807131564Stjr	    {
1808131564Stjr	      /* An invalid sequence, or a truncated multibyte character.
1809131564Stjr		 We treat it as a singlebyte character.  */
1810131564Stjr	      mbclen = 1;
1811131564Stjr	    }
1812131564Stjr	  else
1813131564Stjr	    {
1814131564Stjr	      if (iswupper((wint_t)wc))
1815131564Stjr		{
1816131564Stjr		  wc = towlower((wint_t)wc);
1817131564Stjr		  wcrtomb(keys + i, wc, &cur_state);
1818131564Stjr		}
1819131564Stjr	    }
1820131564Stjr	  i += mbclen;
1821131564Stjr	}
1822131564Stjr    }
1823131564Stjr#endif /* MBS_SUPPORT */
1824131564Stjr
182553451Speter  (*compile)(keys, keycc);
182653451Speter
182753477Sobrien  if ((argc - optind > 1 && !no_filenames) || with_filenames)
182853451Speter    out_file = 1;
182953451Speter
1830131557Stjr#ifdef SET_BINARY
183153477Sobrien  /* Output is set to binary mode because we shouldn't convert
183253477Sobrien     NL to CR-LF pairs, especially when grepping binary files.  */
183353477Sobrien  if (!isatty (1))
183453477Sobrien    SET_BINARY (1);
183553451Speter#endif
183653451Speter
1837131557Stjr  if (max_count == 0)
1838131557Stjr    exit (1);
183953451Speter
184053451Speter  if (optind < argc)
184153451Speter    {
184253477Sobrien	status = 1;
184353477Sobrien	do
184453451Speter	{
184553477Sobrien	  char *file = argv[optind];
1846131557Stjr	  if ((included_patterns || excluded_patterns)
1847131557Stjr	      && !isdir (file))
1848131557Stjr	    {
1849131557Stjr	      if (included_patterns &&
1850131557Stjr		  ! excluded_filename (included_patterns, file, 0))
1851131557Stjr		continue;
1852131557Stjr	      if (excluded_patterns &&
1853131557Stjr		  excluded_filename (excluded_patterns, file, 0))
1854131557Stjr		continue;
1855131557Stjr	    }
185653477Sobrien	  status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
185753477Sobrien			      &stats_base);
185853451Speter	}
185953477Sobrien	while ( ++optind < argc);
186053451Speter    }
186153477Sobrien  else
186253477Sobrien    status = grepfile ((char *) NULL, &stats_base);
186353451Speter
1864131557Stjr  /* We register via atexit() to test stdout.  */
186553477Sobrien  exit (errseen ? 2 : status);
186653451Speter}
1867131557Stjr/* vim:set shiftwidth=2: */
1868