grep.c revision 256281
1193323Sed/* grep.c - main driver file for grep.
2193323Sed   Copyright 1992, 1997-1999, 2000 Free Software Foundation, Inc.
3193323Sed
4193323Sed   This program is free software; you can redistribute it and/or modify
5193323Sed   it under the terms of the GNU General Public License as published by
6193323Sed   the Free Software Foundation; either version 2, or (at your option)
7193323Sed   any later version.
8193323Sed
9193323Sed   This program is distributed in the hope that it will be useful,
10193323Sed   but WITHOUT ANY WARRANTY; without even the implied warranty of
11193323Sed   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12193323Sed   GNU General Public License for more details.
13193323Sed
14193323Sed   You should have received a copy of the GNU General Public License
15193323Sed   along with this program; if not, write to the Free Software
16193323Sed   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17193323Sed   02111-1307, USA.  */
18193323Sed
19193323Sed/* Written July 1992 by Mike Haertel.  */
20193323Sed/* Builtin decompression 1997 by Wolfram Schneider <wosch@FreeBSD.org>.  */
21193323Sed
22193323Sed/* $FreeBSD: stable/10/gnu/usr.bin/grep/grep.c 254093 2013-08-08 11:53:47Z ache $ */
23193323Sed
24193323Sed#ifdef HAVE_CONFIG_H
25193323Sed# include <config.h>
26193323Sed#endif
27193323Sed#include <sys/types.h>
28193323Sed#include <sys/stat.h>
29193323Sed#if defined(HAVE_MMAP)
30193323Sed# include <sys/mman.h>
31193323Sed#endif
32193323Sed#if defined(HAVE_SETRLIMIT)
33193323Sed# include <sys/time.h>
34193323Sed# include <sys/resource.h>
35198090Srdivacky#endif
36193323Sed#if defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H && defined HAVE_MBRTOWC
37198090Srdivacky/* We can handle multibyte string.  */
38193323Sed# define MBS_SUPPORT
39193323Sed# include <wchar.h>
40193323Sed# include <wctype.h>
41193323Sed#endif
42193323Sed#include <stdio.h>
43193323Sed#include "system.h"
44193323Sed#include "getopt.h"
45193323Sed#include "getpagesize.h"
46193323Sed#include "grep.h"
47193323Sed#include "savedir.h"
48193323Sed#include "xstrtol.h"
49193323Sed#include "xalloc.h"
50193323Sed#include "error.h"
51193323Sed#include "exclude.h"
52193323Sed#include "closeout.h"
53193323Sed
54193323Sed#undef MAX
55193323Sed#define MAX(A,B) ((A) > (B) ? (A) : (B))
56193323Sed
57193323Sedstruct stats
58207618Srdivacky{
59207618Srdivacky  struct stats const *parent;
60207618Srdivacky  struct stat stat;
61193323Sed};
62193323Sed
63193323Sed/* base of chain of stat buffers, used to detect directory loops */
64193323Sedstatic struct stats stats_base;
65193323Sed
66207618Srdivacky/* if non-zero, display usage information and exit */
67207618Srdivackystatic int show_help;
68207618Srdivacky
69193323Sed/* If non-zero, print the version on standard output and exit.  */
70193323Sedstatic int show_version;
71193323Sed
72195098Sed/* If nonzero, suppress diagnostics for nonexistent or unreadable files.  */
73193323Sedstatic int suppress_errors;
74193323Sed
75207618Srdivacky/* If nonzero, use mmap if possible.  */
76198892Srdivackystatic int mmap_option;
77198090Srdivacky
78193323Sed/* If zero, output nulls after filenames.  */
79193323Sedstatic int filename_mask;
80193323Sed
81198892Srdivacky/* If nonzero, use grep_color marker.  */
82193323Sedstatic int color_option;
83195098Sed
84195098Sed/* If nonzero, show only the part of a line matching the expression. */
85207618Srdivackystatic int only_matching;
86195098Sed
87195098Sed/* The color string used.  The user can overwrite it using the environment
88195098Sed   variable GREP_COLOR.  The default is to print red.  */
89195098Sedstatic const char *grep_color = "01;31";
90195098Sed
91195098Sedstatic struct exclude *excluded_patterns;
92195098Sedstatic struct exclude *included_patterns;
93207618Srdivacky/* Short options.  */
94195098Sedstatic char const short_options[] =
95195098Sed"0123456789A:B:C:D:EFGHIJPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz";
96195098Sed
97195098Sed/* Non-boolean long options that have no corresponding short equivalents.  */
98195098Sedenum
99195098Sed{
100207618Srdivacky  BINARY_FILES_OPTION = CHAR_MAX + 1,
101195098Sed  COLOR_OPTION,
102193323Sed  INCLUDE_OPTION,
103193323Sed  EXCLUDE_OPTION,
104202375Srdivacky  EXCLUDE_FROM_OPTION,
105207618Srdivacky  LINE_BUFFERED_OPTION,
106207618Srdivacky  LABEL_OPTION
107207618Srdivacky};
108198090Srdivacky
109202375Srdivacky/* Long options equivalences. */
110207618Srdivackystatic struct option const long_options[] =
111198090Srdivacky{
112198090Srdivacky  {"after-context", required_argument, NULL, 'A'},
113198090Srdivacky  {"basic-regexp", no_argument, NULL, 'G'},
114198090Srdivacky  {"before-context", required_argument, NULL, 'B'},
115198090Srdivacky  {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},
116202375Srdivacky  {"byte-offset", no_argument, NULL, 'b'},
117202375Srdivacky  {"context", required_argument, NULL, 'C'},
118198090Srdivacky  {"color", optional_argument, NULL, COLOR_OPTION},
119198090Srdivacky  {"colour", optional_argument, NULL, COLOR_OPTION},
120198090Srdivacky  {"count", no_argument, NULL, 'c'},
121198090Srdivacky  {"devices", required_argument, NULL, 'D'},
122202375Srdivacky  {"directories", required_argument, NULL, 'd'},
123202375Srdivacky  {"extended-regexp", no_argument, NULL, 'E'},
124198090Srdivacky  {"exclude", required_argument, NULL, EXCLUDE_OPTION},
125198090Srdivacky  {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION},
126198090Srdivacky  {"file", required_argument, NULL, 'f'},
127202375Srdivacky  {"files-with-matches", no_argument, NULL, 'l'},
128202375Srdivacky  {"files-without-match", no_argument, NULL, 'L'},
129198090Srdivacky  {"fixed-regexp", no_argument, NULL, 'F'},
130198090Srdivacky  {"fixed-strings", no_argument, NULL, 'F'},
131202375Srdivacky  {"help", no_argument, &show_help, 1},
132198090Srdivacky  {"include", required_argument, NULL, INCLUDE_OPTION},
133202375Srdivacky  {"ignore-case", no_argument, NULL, 'i'},
134202375Srdivacky  {"label", required_argument, NULL, LABEL_OPTION},
135193323Sed  {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION},
136193323Sed  {"line-number", no_argument, NULL, 'n'},
137193323Sed  {"line-regexp", no_argument, NULL, 'x'},
138193323Sed  {"max-count", required_argument, NULL, 'm'},
139193323Sed  {"mmap", no_argument, &mmap_option, 1},
140193323Sed  {"no-filename", no_argument, NULL, 'h'},
141193323Sed  {"no-messages", no_argument, NULL, 's'},
142193323Sed  {"bz2decompress", no_argument, NULL, 'J'},
143193323Sed#if HAVE_LIBZ > 0
144198892Srdivacky  {"decompress", no_argument, NULL, 'Z'},
145193323Sed  {"null", no_argument, &filename_mask, 0},
146193323Sed#else
147207618Srdivacky  {"null", no_argument, NULL, 'Z'},
148193323Sed#endif
149193323Sed  {"null-data", no_argument, NULL, 'z'},
150193323Sed  {"only-matching", no_argument, NULL, 'o'},
151193323Sed  {"perl-regexp", no_argument, NULL, 'P'},
152193323Sed  {"quiet", no_argument, NULL, 'q'},
153193323Sed  {"recursive", no_argument, NULL, 'r'},
154193323Sed  {"recursive", no_argument, NULL, 'R'},
155193323Sed  {"regexp", required_argument, NULL, 'e'},
156193323Sed  {"invert-match", no_argument, NULL, 'v'},
157193323Sed  {"silent", no_argument, NULL, 'q'},
158193323Sed  {"text", no_argument, NULL, 'a'},
159193323Sed  {"binary", no_argument, NULL, 'U'},
160193399Sed  {"unix-byte-offsets", no_argument, NULL, 'u'},
161193399Sed  {"version", no_argument, NULL, 'V'},
162193323Sed  {"with-filename", no_argument, NULL, 'H'},
163193323Sed  {"word-regexp", no_argument, NULL, 'w'},
164193323Sed  {0, 0, 0, 0}
165193323Sed};
166193323Sed
167193323Sed/* Define flags declared in grep.h. */
168207618Srdivackyint match_icase;
169193323Sedint match_words;
170203954Srdivackyint match_lines;
171193323Sedunsigned char eolbyte;
172204642Srdivacky
173203954Srdivacky/* For error messages. */
174193323Sed/* The name the program was run with, stripped of any leading path. */
175193323Sedchar *program_name;
176193323Sedstatic char const *filename;
177193323Sedstatic int errseen;
178202375Srdivacky
179193323Sed/* How to handle directories.  */
180198090Srdivackystatic enum
181193323Sed  {
182193323Sed    READ_DIRECTORIES,
183193323Sed    RECURSE_DIRECTORIES,
184193323Sed    SKIP_DIRECTORIES
185198090Srdivacky  } directories = READ_DIRECTORIES;
186198090Srdivacky
187198090Srdivacky/* How to handle devices. */
188193323Sedstatic enum
189202375Srdivacky  {
190193323Sed    READ_DEVICES,
191193323Sed    SKIP_DEVICES
192202375Srdivacky  } devices = READ_DEVICES;
193210299Sed
194210299Sedstatic int grepdir PARAMS ((char const *, struct stats const *));
195202375Srdivacky#if defined(HAVE_DOS_FILE_CONTENTS)
196210299Sedstatic inline int undossify_input PARAMS ((register char *, size_t));
197210299Sed#endif
198204642Srdivacky
199204642Srdivacky/* Functions we'll use to search. */
200193323Sedstatic void (*compile) PARAMS ((char const *, size_t));
201193323Sedstatic size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));
202204642Srdivacky
203204642Srdivacky/* Like error, but suppress the diagnostic if requested.  */
204202375Srdivackystatic void
205193323Sedsuppressible_error (char const *mesg, int errnum)
206193323Sed{
207193323Sed  if (! suppress_errors)
208204642Srdivacky    error (0, errnum, "%s", mesg);
209193323Sed  errseen = 1;
210193323Sed}
211193323Sed
212193323Sed/* Convert STR to a positive integer, storing the result in *OUT.
213193323Sed   STR must be a valid context length argument; report an error if it
214193323Sed   isn't.  */
215193323Sedstatic void
216193323Sedcontext_length_arg (char const *str, int *out)
217193323Sed{
218193323Sed  uintmax_t value;
219193323Sed  if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK
220193323Sed	 && 0 <= (*out = value)
221207618Srdivacky	 && *out == value))
222207618Srdivacky    {
223193323Sed      error (2, 0, "%s: %s\n", str, _("invalid context length argument"));
224193323Sed    }
225193323Sed}
226193323Sed
227193323Sed
228210299Sed/* Hairy buffering mechanism for grep.  The intent is to keep
229210299Sed   all reads aligned on a page boundary and multiples of the
230195098Sed   page size, unless a read yields a partial page.  */
231193323Sed
232193323Sedstatic char *buffer;		/* Base of buffer. */
233195098Sedstatic size_t bufalloc;		/* Allocated buffer size, counting slop. */
234193323Sed#define INITIAL_BUFSIZE 32768	/* Initial buffer size, not counting slop. */
235195098Sedstatic int bufdesc;		/* File descriptor. */
236193323Sedstatic char *bufbeg;		/* Beginning of user-visible stuff. */
237195098Sedstatic char *buflim;		/* Limit of user-visible stuff. */
238198892Srdivackystatic size_t pagesize;		/* alignment of memory pages */
239199989Srdivackystatic off_t bufoffset;		/* Read offset; defined on regular files.  */
240199989Srdivackystatic off_t after_last_match;	/* Pointer after last matching line that
241193323Sed				   would have been output if we were
242193323Sed				   outputting characters. */
243193323Sed
244193323Sed#if defined(HAVE_MMAP)
245193323Sedstatic int bufmapped;		/* True if buffer is memory-mapped.  */
246193323Sedstatic off_t initial_bufoffset;	/* Initial value of bufoffset. */
247193323Sed#else
248193323Sed# define bufmapped 0
249193323Sed#endif
250193323Sed
251193323Sed#include <bzlib.h>
252193323Sedstatic BZFILE* bzbufdesc;	/* libbz2 file handle. */
253193323Sedstatic int BZflag;		/* uncompress before searching. */
254193323Sed#if HAVE_LIBZ > 0
255193323Sed#include <zlib.h>
256193323Sedstatic gzFile gzbufdesc;	/* zlib file descriptor. */
257193323Sedstatic int Zflag;		/* uncompress before searching. */
258193323Sed#endif
259193323Sed
260193323Sed/* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be
261193323Sed   an integer or a pointer.  Both args must be free of side effects.  */
262193323Sed#define ALIGN_TO(val, alignment) \
263193323Sed  ((size_t) (val) % (alignment) == 0 \
264193323Sed   ? (val) \
265193323Sed   : (val) + ((alignment) - (size_t) (val) % (alignment)))
266193323Sed
267193323Sed/* Reset the buffer for a new file, returning zero if we should skip it.
268193323Sed   Initialize on the first time through. */
269193323Sedstatic int
270193323Sedreset (int fd, char const *file, struct stats *stats)
271193323Sed{
272193323Sed  if (! pagesize)
273193323Sed    {
274193399Sed      pagesize = getpagesize ();
275193399Sed      if (pagesize == 0 || 2 * pagesize + 1 <= pagesize)
276193399Sed	abort ();
277193399Sed      bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1;
278193399Sed      buffer = xmalloc (bufalloc);
279193399Sed    }
280193399Sed  if (BZflag)
281193399Sed    {
282193399Sed    bzbufdesc = BZ2_bzdopen(fd, "r");
283193399Sed    if (bzbufdesc == NULL)
284193399Sed      error(2, 0, _("memory exhausted"));
285193323Sed    }
286193323Sed#if HAVE_LIBZ > 0
287193323Sed  if (Zflag)
288193323Sed    {
289203954Srdivacky    gzbufdesc = gzdopen(fd, "r");
290203954Srdivacky    if (gzbufdesc == NULL)
291193323Sed      error(2, 0, _("memory exhausted"));
292193323Sed    }
293203954Srdivacky#endif
294203954Srdivacky
295203954Srdivacky  bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);
296203954Srdivacky  bufbeg[-1] = eolbyte;
297203954Srdivacky  bufdesc = fd;
298203954Srdivacky
299203954Srdivacky  if (fstat (fd, &stats->stat) != 0)
300203954Srdivacky    {
301193323Sed      error (0, errno, "fstat");
302193323Sed      return 0;
303202375Srdivacky    }
304202375Srdivacky  if (fd != STDIN_FILENO) {
305202375Srdivacky    if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
306202375Srdivacky      return 0;
307202375Srdivacky#ifndef DJGPP
308193323Sed    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)))
309193323Sed#else
310193323Sed    if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode) || S_ISBLK(stats->stat.st_mode)))
311193323Sed#endif
312193323Sed      return 0;
313193323Sed  }
314193323Sed  if (
315193323Sed      BZflag ||
316193323Sed#if HAVE_LIBZ > 0
317193323Sed      Zflag ||
318193323Sed#endif
319193323Sed      S_ISREG (stats->stat.st_mode))
320193323Sed    {
321193323Sed      if (file)
322193323Sed	bufoffset = 0;
323193323Sed      else
324193323Sed	{
325193323Sed	  bufoffset = lseek (fd, 0, SEEK_CUR);
326193323Sed	  if (bufoffset < 0)
327193323Sed	    {
328193323Sed	      error (0, errno, "lseek");
329193323Sed	      return 0;
330193323Sed	    }
331193323Sed	}
332193323Sed#if defined(HAVE_MMAP)
333193323Sed      initial_bufoffset = bufoffset;
334193323Sed      bufmapped = mmap_option && bufoffset % pagesize == 0;
335193323Sed#endif
336193323Sed    }
337193323Sed  else
338193323Sed    {
339193323Sed#if defined(HAVE_MMAP)
340193323Sed      bufmapped = 0;
341193323Sed#endif
342193323Sed    }
343193323Sed  return 1;
344193323Sed}
345193323Sed
346193323Sed/* Read new stuff into the buffer, saving the specified
347203954Srdivacky   amount of old stuff.  When we're done, 'bufbeg' points
348193323Sed   to the beginning of the buffer contents, and 'buflim'
349203954Srdivacky   points just after the end.  Return zero if there's an error.  */
350203954Srdivackystatic int
351203954Srdivackyfillbuf (size_t save, struct stats const *stats)
352205218Srdivacky{
353205218Srdivacky  size_t fillsize = 0;
354205218Srdivacky  int cc = 1;
355205218Srdivacky  char *readbuf;
356193323Sed  size_t readsize;
357205218Srdivacky
358193323Sed  /* Offset from start of buffer to start of old stuff
359193323Sed     that we want to save.  */
360193323Sed  size_t saved_offset = buflim - save - buffer;
361193323Sed
362205218Srdivacky  if (pagesize <= buffer + bufalloc - buflim)
363193323Sed    {
364193323Sed      readbuf = buflim;
365193323Sed      bufbeg = buflim - save;
366193323Sed    }
367193323Sed  else
368193323Sed    {
369193323Sed      size_t minsize = save + pagesize;
370193323Sed      size_t newsize;
371193323Sed      size_t newalloc;
372193323Sed      char *newbuf;
373193323Sed
374205218Srdivacky      /* Grow newsize until it is at least as great as minsize.  */
375205218Srdivacky      for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)
376210299Sed	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)
377210299Sed	  xalloc_die ();
378193323Sed
379193323Sed      /* Try not to allocate more memory than the file size indicates,
380193323Sed	 as that might cause unnecessary memory exhaustion if the file
381193323Sed	 is large.  However, do not use the original file size as a
382193323Sed	 heuristic if we've already read past the file end, as most
383210299Sed	 likely the file is growing.  */
384193323Sed      if (S_ISREG (stats->stat.st_mode))
385193323Sed	{
386193323Sed	  off_t to_be_read = stats->stat.st_size - bufoffset;
387193323Sed	  off_t maxsize_off = save + to_be_read;
388193323Sed	  if (0 <= to_be_read && to_be_read <= maxsize_off
389205218Srdivacky	      && maxsize_off == (size_t) maxsize_off
390205218Srdivacky	      && minsize <= (size_t) maxsize_off
391205218Srdivacky	      && (size_t) maxsize_off < newsize)
392193323Sed	    newsize = maxsize_off;
393193323Sed	}
394193323Sed
395193323Sed      /* Add enough room so that the buffer is aligned and has room
396193323Sed	 for byte sentinels fore and aft.  */
397193323Sed      newalloc = newsize + pagesize + 1;
398193323Sed
399193323Sed      newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
400193323Sed      readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);
401193323Sed      bufbeg = readbuf - save;
402205218Srdivacky      memmove (bufbeg, buffer + saved_offset, save);
403193323Sed      bufbeg[-1] = eolbyte;
404193323Sed      if (newbuf != buffer)
405193323Sed	{
406193323Sed	  free (buffer);
407205218Srdivacky	  buffer = newbuf;
408205218Srdivacky	}
409205218Srdivacky    }
410193323Sed
411193323Sed  readsize = buffer + bufalloc - readbuf;
412193323Sed  readsize -= readsize % pagesize;
413198090Srdivacky
414198090Srdivacky#if defined(HAVE_MMAP)
415193323Sed  if (bufmapped)
416193323Sed    {
417193323Sed      size_t mmapsize = readsize;
418193323Sed
419204642Srdivacky      /* Don't mmap past the end of the file; some hosts don't allow this.
420204792Srdivacky	 Use `read' on the last page.  */
421204642Srdivacky      if (stats->stat.st_size - bufoffset < mmapsize)
422204642Srdivacky	{
423204642Srdivacky	  mmapsize = stats->stat.st_size - bufoffset;
424204642Srdivacky	  mmapsize -= mmapsize % pagesize;
425204642Srdivacky	}
426193323Sed
427205218Srdivacky      if (mmapsize
428205218Srdivacky	  && (mmap ((caddr_t) readbuf, mmapsize,
429205218Srdivacky		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
430193323Sed		    bufdesc, bufoffset)
431193323Sed	      != (caddr_t) -1))
432193323Sed	{
433193323Sed	  /* Do not bother to use madvise with MADV_SEQUENTIAL or
434193323Sed	     MADV_WILLNEED on the mmapped memory.  One might think it
435193323Sed	     would help, but it slows us down about 30% on SunOS 4.1.  */
436193323Sed	  fillsize = mmapsize;
437193323Sed	}
438193323Sed      else
439193323Sed	{
440193323Sed	  /* Stop using mmap on this file.  Synchronize the file
441193323Sed	     offset.  Do not warn about mmap failures.  On some hosts
442193323Sed	     (e.g. Solaris 2.5) mmap can fail merely because some
443193323Sed	     other process has an advisory read lock on the file.
444193323Sed	     There's no point alarming the user about this misfeature.  */
445193323Sed	  bufmapped = 0;
446193323Sed	  if (bufoffset != initial_bufoffset
447193323Sed	      && lseek (bufdesc, bufoffset, SEEK_SET) < 0)
448193323Sed	    {
449205218Srdivacky	      error (0, errno, "lseek");
450204642Srdivacky	      cc = 0;
451204642Srdivacky	    }
452205218Srdivacky	}
453193323Sed    }
454205218Srdivacky#endif /*HAVE_MMAP*/
455193323Sed
456193323Sed  if (! fillsize)
457193323Sed    {
458204642Srdivacky      ssize_t bytesread;
459204642Srdivacky      do
460204642Srdivacky	if (BZflag && bzbufdesc)
461204642Srdivacky	  {
462204642Srdivacky	    int bzerr;
463204642Srdivacky	    bytesread = BZ2_bzRead (&bzerr, bzbufdesc, readbuf, readsize);
464204642Srdivacky
465204642Srdivacky	    switch (bzerr)
466204642Srdivacky	      {
467193323Sed	      case BZ_OK:
468193323Sed	      case BZ_STREAM_END:
469193323Sed		/* ok */
470193323Sed		break;
471193323Sed	      case BZ_DATA_ERROR_MAGIC:
472198090Srdivacky		BZ2_bzReadClose (&bzerr, bzbufdesc); bzbufdesc = NULL;
473198090Srdivacky		lseek (bufdesc, 0, SEEK_SET);
474193323Sed		bytesread = read (bufdesc, readbuf, readsize);
475193323Sed		break;
476193323Sed	      default:
477193323Sed		bytesread = 0;
478193323Sed		break;
479193323Sed	      }
480193323Sed	  }
481193323Sed	else
482193323Sed#if HAVE_LIBZ > 0
483193323Sed	if (Zflag)
484193323Sed	  bytesread = gzread (gzbufdesc, readbuf, readsize);
485193323Sed	else
486193323Sed#endif
487193323Sed	  bytesread = read (bufdesc, readbuf, readsize);
488193323Sed      while (bytesread < 0 && errno == EINTR);
489193323Sed      if (bytesread < 0)
490193323Sed	cc = 0;
491198090Srdivacky      else
492193323Sed	fillsize = bytesread;
493193323Sed    }
494193323Sed
495193323Sed  bufoffset += fillsize;
496193323Sed#if defined(HAVE_DOS_FILE_CONTENTS)
497193323Sed  if (fillsize)
498193323Sed    fillsize = undossify_input (readbuf, fillsize);
499193323Sed#endif
500193323Sed  buflim = readbuf + fillsize;
501193323Sed  return cc;
502193323Sed}
503203954Srdivacky
504203954Srdivacky/* Flags controlling the style of output. */
505210299Sedstatic enum
506203954Srdivacky{
507193323Sed  BINARY_BINARY_FILES,
508193323Sed  TEXT_BINARY_FILES,
509193323Sed  WITHOUT_MATCH_BINARY_FILES
510193323Sed} binary_files;		/* How to handle binary files.  */
511193323Sed
512193323Sedstatic int filename_mask;	/* If zero, output nulls after filenames.  */
513193323Sedstatic int out_quiet;		/* Suppress all normal output. */
514193323Sedstatic int out_invert;		/* Print nonmatching stuff. */
515193323Sedstatic int out_file;		/* Print filenames. */
516193323Sedstatic int out_line;		/* Print line numbers. */
517193323Sedstatic int out_byte;		/* Print byte offsets. */
518193323Sedstatic int out_before;		/* Lines of leading context. */
519193323Sedstatic int out_after;		/* Lines of trailing context. */
520193323Sedstatic int count_matches;	/* Count matching lines.  */
521193323Sedstatic int list_files;		/* List matching files.  */
522193323Sedstatic int no_filenames;	/* Suppress file names.  */
523193323Sedstatic off_t max_count;		/* Stop after outputting this many
524193323Sed				   lines from an input file.  */
525193323Sedstatic int line_buffered;       /* If nonzero, use line buffering, i.e.
526193323Sed				   fflush everyline out.  */
527193323Sedstatic char *label = NULL;      /* Fake filename for stdin */
528193323Sed
529206124Srdivacky
530193323Sed/* Internal variables to keep track of byte count, context, etc. */
531193323Sedstatic uintmax_t totalcc;	/* Total character count before bufbeg. */
532193323Sedstatic char const *lastnl;	/* Pointer after last newline counted. */
533207618Srdivackystatic char const *lastout;	/* Pointer after last character output;
534193323Sed				   NULL if no character has been output
535207618Srdivacky				   or if it's conceptually before bufbeg. */
536207618Srdivackystatic uintmax_t totalnl;	/* Total newline count before lastnl. */
537207618Srdivackystatic off_t outleft;		/* Maximum number of lines to be output.  */
538193323Sedstatic int pending;		/* Pending lines of output.
539193323Sed				   Always kept 0 if out_quiet is true.  */
540193323Sedstatic int done_on_match;	/* Stop scanning file on first match.  */
541193323Sedstatic int exit_on_match;	/* Exit on first match.  */
542193323Sed
543193323Sed#if defined(HAVE_DOS_FILE_CONTENTS)
544193323Sed# include "dosbuf.c"
545193323Sed#endif
546193323Sed
547193323Sed/* Add two numbers that count input bytes or lines, and report an
548193323Sed   error if the addition overflows.  */
549193323Sedstatic uintmax_t
550193323Sedadd_count (uintmax_t a, uintmax_t b)
551193323Sed{
552193323Sed  uintmax_t sum = a + b;
553193323Sed  if (sum < a)
554193323Sed    error (2, 0, _("input is too large to count"));
555193323Sed  return sum;
556193323Sed}
557193323Sed
558193323Sedstatic void
559193323Sednlscan (char const *lim)
560193323Sed{
561193323Sed  size_t newlines = 0;
562193323Sed  char const *beg;
563193323Sed  for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++)
564193323Sed    newlines++;
565193323Sed  totalnl = add_count (totalnl, newlines);
566193323Sed  lastnl = lim;
567195098Sed}
568195098Sed
569195098Sed/* Print a byte offset, followed by a character separator.  */
570198090Srdivackystatic void
571193323Sedprint_offset_sep (uintmax_t pos, char sep)
572195098Sed{
573195098Sed  /* Do not rely on printf to print pos, since uintmax_t may be longer
574193323Sed     than long, and long long is not portable.  */
575193323Sed
576193323Sed  char buf[sizeof pos * CHAR_BIT];
577193323Sed  char *p = buf + sizeof buf - 1;
578198090Srdivacky  *p = sep;
579198090Srdivacky
580195098Sed  do
581195098Sed    *--p = '0' + pos % 10;
582195098Sed  while ((pos /= 10) != 0);
583195098Sed
584195098Sed  fwrite (p, 1, buf + sizeof buf - p, stdout);
585195098Sed}
586198090Srdivacky
587195098Sedstatic void
588195098Sedprline (char const *beg, char const *lim, int sep)
589195098Sed{
590195098Sed  if (out_file)
591195098Sed    printf ("%s%c", filename, sep & filename_mask);
592198090Srdivacky  if (out_line)
593195098Sed    {
594195098Sed      nlscan (beg);
595195098Sed      totalnl = add_count (totalnl, 1);
596195098Sed      print_offset_sep (totalnl, sep);
597195098Sed      lastnl = lim;
598198090Srdivacky    }
599195098Sed  if (out_byte)
600195098Sed    {
601195098Sed      uintmax_t pos = add_count (totalcc, beg - bufbeg);
602195098Sed#if defined(HAVE_DOS_FILE_CONTENTS)
603195098Sed      pos = dossified_pos (pos);
604195098Sed#endif
605195098Sed      print_offset_sep (pos, sep);
606198892Srdivacky    }
607195098Sed  if (only_matching)
608195098Sed    {
609198892Srdivacky      size_t match_size;
610198892Srdivacky      size_t match_offset;
611199989Srdivacky      while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1))
612193323Sed	  != (size_t) -1)
613198090Srdivacky        {
614195098Sed	  char const *b = beg + match_offset;
615195098Sed	  if (b == lim)
616195098Sed	    break;
617195098Sed	  if (match_size == 0)
618195098Sed	    break;
619195098Sed	  if(color_option)
620195098Sed	    printf("\33[%sm", grep_color);
621195098Sed	  fwrite(b, sizeof (char), match_size, stdout);
622195098Sed	  if(color_option)
623198090Srdivacky	    fputs("\33[00m", stdout);
624195098Sed	  fputs("\n", stdout);
625195098Sed	  beg = b + match_size;
626195098Sed        }
627195098Sed      lastout = lim;
628195098Sed      if(line_buffered)
629195098Sed	fflush(stdout);
630193323Sed      return;
631193323Sed    }
632195098Sed  if (color_option)
633195098Sed    {
634195098Sed      size_t match_size;
635195098Sed      size_t match_offset;
636195098Sed      while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
637198892Srdivacky	     != (size_t) -1)
638195098Sed	{
639195098Sed	  char const *b = beg + match_offset;
640198892Srdivacky	  /* Avoid matching the empty line at the end of the buffer. */
641198892Srdivacky	  if (b == lim)
642199989Srdivacky	    break;
643193323Sed	  /* Avoid hanging on grep --color "" foo */
644193323Sed	  if (match_size == 0)
645193323Sed	    break;
646193323Sed	  fwrite (beg, sizeof (char), match_offset, stdout);
647193323Sed	  printf ("\33[%sm", grep_color);
648193323Sed	  fwrite (b, sizeof (char), match_size, stdout);
649193323Sed	  fputs ("\33[00m", stdout);
650193323Sed	  beg = b + match_size;
651193323Sed	}
652193323Sed      fputs ("\33[K", stdout);
653198090Srdivacky    }
654210299Sed  fwrite (beg, 1, lim - beg, stdout);
655198090Srdivacky  if (ferror (stdout))
656198090Srdivacky    error (0, errno, _("writing output"));
657198090Srdivacky  lastout = lim;
658198090Srdivacky  if (line_buffered)
659198090Srdivacky    fflush (stdout);
660198090Srdivacky}
661207618Srdivacky
662207618Srdivacky/* Print pending lines of trailing context prior to LIM. Trailing context ends
663198090Srdivacky   at the next matching line when OUTLEFT is 0.  */
664198090Srdivackystatic void
665198090Srdivackyprpending (char const *lim)
666198090Srdivacky{
667198090Srdivacky  if (!lastout)
668198090Srdivacky    lastout = bufbeg;
669198090Srdivacky  while (pending > 0 && lastout < lim)
670198090Srdivacky    {
671198090Srdivacky      char const *nl = memchr (lastout, eolbyte, lim - lastout);
672198090Srdivacky      size_t match_size;
673207618Srdivacky      --pending;
674198090Srdivacky      if (outleft
675198090Srdivacky	  || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1)
676198090Srdivacky	      == !out_invert))
677207618Srdivacky	prline (lastout, nl + 1, '-');
678198090Srdivacky      else
679198090Srdivacky	pending = 0;
680198090Srdivacky    }
681198090Srdivacky}
682207618Srdivacky
683207618Srdivacky/* Print the lines between BEG and LIM.  Deal with context crap.
684207618Srdivacky   If NLINESP is non-null, store a count of lines between BEG and LIM.  */
685207618Srdivackystatic void
686207618Srdivackyprtext (char const *beg, char const *lim, int *nlinesp)
687207618Srdivacky{
688207618Srdivacky  static int used;		/* avoid printing "--" before any output */
689207618Srdivacky  char const *bp, *p;
690207618Srdivacky  char eol = eolbyte;
691207618Srdivacky  int i, n;
692207618Srdivacky
693207618Srdivacky  if (!out_quiet && pending > 0)
694207618Srdivacky    prpending (beg);
695207618Srdivacky
696207618Srdivacky  p = beg;
697207618Srdivacky
698207618Srdivacky  if (!out_quiet)
699207618Srdivacky    {
700207618Srdivacky      /* Deal with leading context crap. */
701198090Srdivacky
702198090Srdivacky      bp = lastout ? lastout : bufbeg;
703193323Sed      for (i = 0; i < out_before; ++i)
704193323Sed	if (p > bp)
705198090Srdivacky	  do
706202375Srdivacky	    --p;
707198090Srdivacky	  while (p[-1] != eol);
708198090Srdivacky
709193323Sed      /* We only print the "--" separator if our output is
710193323Sed	 discontiguous from the last output in the file. */
711193323Sed      if ((out_before || out_after) && used && p != lastout)
712198090Srdivacky	puts ("--");
713198090Srdivacky
714198090Srdivacky      while (p < beg)
715195098Sed	{
716195098Sed	  char const *nl = memchr (p, eol, beg - p);
717193323Sed	  nl++;
718195098Sed	  prline (p, nl, '-');
719195098Sed	  p = nl;
720195098Sed	}
721195098Sed    }
722195098Sed
723198090Srdivacky  if (nlinesp)
724195098Sed    {
725195098Sed      /* Caller wants a line count. */
726198090Srdivacky      for (n = 0; p < lim && n < outleft; n++)
727198090Srdivacky	{
728195098Sed	  char const *nl = memchr (p, eol, lim - p);
729193323Sed	  nl++;
730193323Sed	  if (!out_quiet)
731193323Sed	    prline (p, nl, ':');
732193323Sed	  p = nl;
733193323Sed	}
734193323Sed      *nlinesp = n;
735193323Sed
736193323Sed      /* relying on it that this function is never called when outleft = 0.  */
737193323Sed      after_last_match = bufoffset - (buflim - p);
738193323Sed    }
739198090Srdivacky  else
740198090Srdivacky    if (!out_quiet)
741198090Srdivacky      prline (beg, lim, ':');
742193323Sed
743193323Sed  pending = out_quiet ? 0 : out_after;
744193323Sed  used = 1;
745193323Sed}
746193323Sed
747193323Sed/* Scan the specified portion of the buffer, matching lines (or
748193323Sed   between matching lines if OUT_INVERT is true).  Return a count of
749193323Sed   lines printed. */
750193323Sedstatic int
751193323Sedgrepbuf (char const *beg, char const *lim)
752193323Sed{
753193323Sed  int nlines, n;
754195098Sed  register char const *p;
755193323Sed  size_t match_offset;
756193323Sed  size_t match_size;
757193323Sed
758193323Sed  nlines = 0;
759193323Sed  p = beg;
760193323Sed  while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
761193323Sed    {
762193323Sed      char const *b = p + match_offset;
763193323Sed      char const *endp = b + match_size;
764193323Sed      /* Avoid matching the empty line at the end of the buffer. */
765193323Sed      if (b == lim)
766207618Srdivacky	break;
767193323Sed      if (!out_invert)
768207618Srdivacky	{
769193323Sed	  prtext (b, endp, (int *) 0);
770193323Sed	  nlines++;
771193323Sed          outleft--;
772193323Sed	  if (!outleft || done_on_match)
773193323Sed	    {
774195098Sed	      if (exit_on_match)
775193323Sed		exit (0);
776193323Sed	      after_last_match = bufoffset - (buflim - endp);
777193323Sed	      return nlines;
778193323Sed	    }
779193323Sed	}
780198090Srdivacky      else if (p < b)
781198090Srdivacky	{
782198090Srdivacky	  prtext (p, b, &n);
783198090Srdivacky	  nlines += n;
784193323Sed          outleft -= n;
785193323Sed	  if (!outleft)
786193323Sed	    return nlines;
787193323Sed	}
788193323Sed      p = endp;
789193323Sed    }
790193323Sed  if (out_invert && p < lim)
791207618Srdivacky    {
792193323Sed      prtext (p, lim, &n);
793193323Sed      nlines += n;
794193323Sed      outleft -= n;
795193323Sed    }
796198090Srdivacky  return nlines;
797198090Srdivacky}
798198090Srdivacky
799193323Sed/* Search a given file.  Normally, return a count of lines printed;
800193323Sed   but if the file is a directory and we search it recursively, then
801193323Sed   return -2 if there was a match, and -1 otherwise.  */
802193323Sedstatic int
803193323Sedgrep (int fd, char const *file, struct stats *stats)
804193323Sed{
805193323Sed  int nlines, i;
806193323Sed  int not_text;
807193323Sed  size_t residue, save;
808193323Sed  char oldc;
809193323Sed  char *beg;
810193323Sed  char *lim;
811193323Sed  char eol = eolbyte;
812193323Sed
813193323Sed  if (!reset (fd, file, stats))
814193323Sed    return 0;
815193323Sed
816193323Sed  if (file && directories == RECURSE_DIRECTORIES
817193323Sed      && S_ISDIR (stats->stat.st_mode))
818193323Sed    {
819207618Srdivacky      /* Close fd now, so that we don't open a lot of file descriptors
820195098Sed	 when we recurse deeply.  */
821193323Sed      if (BZflag && bzbufdesc)
822193323Sed	BZ2_bzclose(bzbufdesc);
823193323Sed      else
824193323Sed#if HAVE_LIBZ > 0
825193323Sed      if (Zflag)
826193323Sed	gzclose(gzbufdesc);
827193323Sed      else
828193323Sed#endif
829193323Sed      if (close (fd) != 0)
830193323Sed	error (0, errno, "%s", file);
831193323Sed      return grepdir (file, stats) - 2;
832193323Sed    }
833193323Sed
834193323Sed  totalcc = 0;
835193323Sed  lastout = 0;
836193323Sed  totalnl = 0;
837193323Sed  outleft = max_count;
838193323Sed  after_last_match = 0;
839193323Sed  pending = 0;
840198090Srdivacky
841198090Srdivacky  nlines = 0;
842198090Srdivacky  residue = 0;
843193323Sed  save = 0;
844193323Sed
845193323Sed  if (! fillbuf (save, stats))
846193323Sed    {
847193323Sed      if (! is_EISDIR (errno, file))
848193323Sed	suppressible_error (filename, errno);
849193323Sed      return 0;
850207618Srdivacky    }
851193323Sed
852193323Sed  not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
853193323Sed	       || binary_files == WITHOUT_MATCH_BINARY_FILES)
854193323Sed	      && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
855193323Sed  if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
856193323Sed    return 0;
857193323Sed  done_on_match += not_text;
858193323Sed  out_quiet += not_text;
859193323Sed
860193323Sed  for (;;)
861193323Sed    {
862193323Sed      lastnl = bufbeg;
863193323Sed      if (lastout)
864210299Sed	lastout = bufbeg;
865210299Sed
866210299Sed      beg = bufbeg + save;
867210299Sed
868193323Sed      /* no more data to scan (eof) except for maybe a residue -> break */
869193323Sed      if (beg == buflim)
870210299Sed	break;
871193323Sed
872193323Sed      /* Determine new residue (the length of an incomplete line at the end of
873193323Sed         the buffer, 0 means there is no incomplete last line).  */
874193323Sed      oldc = beg[-1];
875195098Sed      beg[-1] = eol;
876193323Sed      for (lim = buflim; lim[-1] != eol; lim--)
877193323Sed	continue;
878193323Sed      beg[-1] = oldc;
879205407Srdivacky      if (lim == beg)
880193323Sed	lim = beg - residue;
881210299Sed      beg -= residue;
882193323Sed      residue = buflim - lim;
883193323Sed
884193323Sed      if (beg < lim)
885193323Sed	{
886193323Sed	  if (outleft)
887193323Sed	    nlines += grepbuf (beg, lim);
888193323Sed	  if (pending)
889193323Sed	    prpending (lim);
890193323Sed	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
891193323Sed	    goto finish_grep;
892193323Sed	}
893193323Sed
894193323Sed      /* The last OUT_BEFORE lines at the end of the buffer will be needed as
895207618Srdivacky	 leading context if there is a matching line at the begin of the
896207618Srdivacky	 next data. Make beg point to their begin.  */
897193323Sed      i = 0;
898193323Sed      beg = lim;
899193323Sed      while (i < out_before && beg > bufbeg && beg != lastout)
900193323Sed	{
901193323Sed	  ++i;
902193323Sed	  do
903193323Sed	    --beg;
904193323Sed	  while (beg[-1] != eol);
905193323Sed	}
906193323Sed
907193323Sed      /* detect if leading context is discontinuous from last printed line.  */
908193323Sed      if (beg != lastout)
909193323Sed	lastout = 0;
910193323Sed
911193323Sed      /* Handle some details and read more data to scan.  */
912193323Sed      save = residue + lim - beg;
913193323Sed      if (out_byte)
914193323Sed	totalcc = add_count (totalcc, buflim - bufbeg - save);
915193323Sed      if (out_line)
916193323Sed	nlscan (beg);
917193323Sed      if (! fillbuf (save, stats))
918193323Sed	{
919193323Sed	  if (! is_EISDIR (errno, file))
920193323Sed	    suppressible_error (filename, errno);
921193323Sed	  goto finish_grep;
922193323Sed	}
923193323Sed    }
924193323Sed  if (residue)
925193323Sed    {
926193323Sed      *buflim++ = eol;
927193323Sed      if (outleft)
928193323Sed	nlines += grepbuf (bufbeg + save - residue, buflim);
929193323Sed      if (pending)
930193323Sed        prpending (buflim);
931193323Sed    }
932210299Sed
933210299Sed finish_grep:
934210299Sed  done_on_match -= not_text;
935210299Sed  out_quiet -= not_text;
936210299Sed  if ((not_text & ~out_quiet) && nlines != 0)
937210299Sed    printf (_("Binary file %s matches\n"), filename);
938193323Sed  return nlines;
939210299Sed}
940210299Sed
941210299Sedstatic int
942210299Sedgrepfile (char const *file, struct stats *stats)
943210299Sed{
944210299Sed  int desc;
945205407Srdivacky  int count;
946205407Srdivacky  int status;
947210299Sed  int flags;
948210299Sed
949210299Sed  if (! file)
950193323Sed    {
951210299Sed      desc = 0;
952210299Sed      filename = label ? label : _("(standard input)");
953193323Sed    }
954193323Sed  else
955193323Sed    {
956193323Sed      while ((desc = open (file, O_RDONLY | O_NONBLOCK)) < 0 && errno == EINTR)
957193323Sed	continue;
958207618Srdivacky
959195098Sed      if (desc < 0)
960210299Sed	{
961210299Sed	  int e = errno;
962193323Sed
963193323Sed	  if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
964193323Sed	    {
965193323Sed	      if (stat (file, &stats->stat) != 0)
966193323Sed		{
967193323Sed		  error (0, errno, "%s", file);
968193323Sed		  return 1;
969193323Sed		}
970207618Srdivacky
971193323Sed	      return grepdir (file, stats);
972207618Srdivacky	    }
973193323Sed
974205407Srdivacky	  if (!suppress_errors)
975193323Sed	    {
976210299Sed	      if (directories == SKIP_DIRECTORIES)
977193323Sed		switch (e)
978193323Sed		  {
979193323Sed#if defined(EISDIR)
980198090Srdivacky		  case EISDIR:
981198090Srdivacky		    return 1;
982205407Srdivacky#endif
983193323Sed		  case EACCES:
984193323Sed		    /* When skipping directories, don't worry about
985193323Sed		       directories that can't be opened.  */
986193323Sed		    if (isdir (file))
987193323Sed		      return 1;
988193323Sed		    break;
989193323Sed		  }
990193323Sed	    }
991193323Sed
992193323Sed	  suppressible_error (file, e);
993193323Sed	  return 1;
994193323Sed	}
995193323Sed
996193323Sed      flags = fcntl(desc, F_GETFL);
997193323Sed      flags &= ~O_NONBLOCK;
998193323Sed      fcntl(desc, F_SETFL, flags);
999193323Sed      filename = file;
1000193323Sed    }
1001193323Sed
1002193323Sed#if defined(SET_BINARY)
1003193323Sed  /* Set input to binary mode.  Pipes are simulated with files
1004193323Sed     on DOS, so this includes the case of "foo | grep bar".  */
1005193323Sed  if (!isatty (desc))
1006193323Sed    SET_BINARY (desc);
1007193323Sed#endif
1008193323Sed
1009193323Sed  count = grep (desc, file, stats);
1010193323Sed  if (count < 0)
1011193323Sed    status = count + 2;
1012193323Sed  else
1013193323Sed    {
1014193323Sed      if (count_matches)
1015193323Sed	{
1016193323Sed	  if (out_file)
1017193323Sed	    printf ("%s%c", filename, ':' & filename_mask);
1018193323Sed	  printf ("%d\n", count);
1019193323Sed	}
1020193323Sed
1021193323Sed      status = !count;
1022193323Sed      if (list_files == 1 - 2 * status)
1023193323Sed	printf ("%s%c", filename, '\n' & filename_mask);
1024193323Sed
1025193323Sed      if (BZflag && bzbufdesc)
1026193323Sed	BZ2_bzclose(bzbufdesc);
1027193323Sed      else
1028193323Sed#if HAVE_LIBZ > 0
1029193323Sed      if (Zflag)
1030193323Sed	gzclose(gzbufdesc);
1031193323Sed      else
1032193323Sed#endif
1033193323Sed      if (! file)
1034193323Sed	{
1035193323Sed	  off_t required_offset = outleft ? bufoffset : after_last_match;
1036193323Sed	  if ((bufmapped || required_offset != bufoffset)
1037193323Sed	      && lseek (desc, required_offset, SEEK_SET) < 0
1038193323Sed	      && S_ISREG (stats->stat.st_mode))
1039193323Sed	    error (0, errno, "%s", filename);
1040193323Sed	}
1041193323Sed      else
1042193323Sed	while (close (desc) != 0)
1043193323Sed	  if (errno != EINTR)
1044193323Sed	    {
1045193323Sed	      error (0, errno, "%s", file);
1046193323Sed	      break;
1047193323Sed	    }
1048193323Sed    }
1049193323Sed
1050193323Sed  return status;
1051193323Sed}
1052193323Sed
1053210299Sedstatic int
1054193323Sedgrepdir (char const *dir, struct stats const *stats)
1055193323Sed{
1056193323Sed  int status = 1;
1057193323Sed  struct stats const *ancestor;
1058193323Sed  char *name_space;
1059193323Sed
1060193323Sed  /* Mingw32 does not support st_ino.  No known working hosts use zero
1061193323Sed     for st_ino, so assume that the Mingw32 bug applies if it's zero.  */
1062193323Sed  if (stats->stat.st_ino)
1063193323Sed    for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
1064193323Sed      if (ancestor->stat.st_ino == stats->stat.st_ino
1065193323Sed	  && ancestor->stat.st_dev == stats->stat.st_dev)
1066193323Sed	{
1067193323Sed	  if (!suppress_errors)
1068193323Sed	    error (0, 0, _("warning: %s: %s"), dir,
1069193323Sed		   _("recursive directory loop"));
1070193323Sed	  return 1;
1071193323Sed	}
1072193323Sed
1073193323Sed  name_space = savedir (dir, stats->stat.st_size, included_patterns,
1074193323Sed			excluded_patterns);
1075193323Sed
1076193323Sed  if (! name_space)
1077193323Sed    {
1078193323Sed      if (errno)
1079193323Sed	suppressible_error (dir, errno);
1080193323Sed      else
1081193323Sed	xalloc_die ();
1082193323Sed    }
1083193323Sed  else
1084193323Sed    {
1085193323Sed      size_t dirlen = strlen (dir);
1086193323Sed      int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
1087193323Sed			   || IS_SLASH (dir[dirlen - 1]));
1088193323Sed      char *file = NULL;
1089193323Sed      char const *namep = name_space;
1090193323Sed      struct stats child;
1091193323Sed      child.parent = stats;
1092193323Sed      out_file += !no_filenames;
1093193323Sed      while (*namep)
1094193323Sed	{
1095193323Sed	  size_t namelen = strlen (namep);
1096193323Sed	  file = xrealloc (file, dirlen + 1 + namelen + 1);
1097193323Sed	  strcpy (file, dir);
1098193323Sed	  file[dirlen] = '/';
1099193323Sed	  strcpy (file + dirlen + needs_slash, namep);
1100193323Sed	  namep += namelen + 1;
1101193323Sed	  status &= grepfile (file, &child);
1102193323Sed	}
1103193323Sed      out_file -= !no_filenames;
1104210299Sed      if (file)
1105193323Sed        free (file);
1106193323Sed      free (name_space);
1107193323Sed    }
1108193323Sed
1109193323Sed  return status;
1110193323Sed}
1111193323Sed
1112193323Sedstatic void
1113193323Sedusage (int status)
1114193323Sed{
1115193323Sed  if (status != 0)
1116193323Sed    {
1117193323Sed      fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
1118193323Sed	       program_name);
1119207618Srdivacky      fprintf (stderr, _("Try `%s --help' for more information.\n"),
1120193323Sed	       program_name);
1121195098Sed    }
1122193323Sed  else
1123193323Sed    {
1124193323Sed      printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name);
1125193323Sed      printf (_("\
1126193323SedSearch for PATTERN in each FILE or standard input.\n\
1127193323SedExample: %s -i 'hello world' menu.h main.c\n\
1128193323Sed\n\
1129193323SedRegexp selection and interpretation:\n"), program_name);
1130193323Sed      printf (_("\
1131193323Sed  -E, --extended-regexp     PATTERN is an extended regular expression\n\
1132193323Sed  -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
1133207618Srdivacky  -G, --basic-regexp        PATTERN is a basic regular expression\n\
1134193323Sed  -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
1135193323Sed      printf (_("\
1136193323Sed  -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
1137193323Sed  -f, --file=FILE           obtain PATTERN from FILE\n\
1138193323Sed  -i, --ignore-case         ignore case distinctions\n\
1139193323Sed  -w, --word-regexp         force PATTERN to match only whole words\n\
1140202375Srdivacky  -x, --line-regexp         force PATTERN to match only whole lines\n\
1141193323Sed  -z, --null-data           a data line ends in 0 byte, not newline\n"));
1142193323Sed      printf (_("\
1143193323Sed\n\
1144201360SrdivackyMiscellaneous:\n\
1145193323Sed  -s, --no-messages         suppress error messages\n\
1146193323Sed  -v, --invert-match        select non-matching lines\n\
1147198090Srdivacky  -V, --version             print version information and exit\n\
1148193323Sed      --help                display this help and exit\n\
1149207618Srdivacky  -J, --bz2decompress       decompress bzip2'ed input before searching\n\
1150207618Srdivacky  -Z, --decompress          decompress input before searching (HAVE_LIBZ=1)\n\
1151193323Sed      --mmap                use memory-mapped input if possible\n"));
1152193323Sed      printf (_("\
1153193323Sed\n\
1154193323SedOutput control:\n\
1155193323Sed  -m, --max-count=NUM       stop after NUM matches\n\
1156193323Sed  -b, --byte-offset         print the byte offset with output lines\n\
1157193323Sed  -n, --line-number         print line number with output lines\n\
1158193323Sed      --line-buffered       flush output on every line\n\
1159193323Sed  -H, --with-filename       print the filename for each match\n\
1160193323Sed  -h, --no-filename         suppress the prefixing filename on output\n\
1161193323Sed      --label=LABEL         print LABEL as filename for standard input\n\
1162193323Sed  -o, --only-matching       show only the part of a line matching PATTERN\n\
1163204642Srdivacky  -q, --quiet, --silent     suppress all normal output\n\
1164204642Srdivacky      --binary-files=TYPE   assume that binary files are TYPE\n\
1165204642Srdivacky                            TYPE is 'binary', 'text', or 'without-match'\n\
1166204642Srdivacky  -a, --text                equivalent to --binary-files=text\n\
1167204642Srdivacky  -I                        equivalent to --binary-files=without-match\n\
1168193323Sed  -d, --directories=ACTION  how to handle directories\n\
1169193323Sed                            ACTION is 'read', 'recurse', or 'skip'\n\
1170193323Sed  -D, --devices=ACTION      how to handle devices, FIFOs and sockets\n\
1171204642Srdivacky                            ACTION is 'read' or 'skip'\n\
1172193323Sed  -R, -r, --recursive       equivalent to --directories=recurse\n\
1173204642Srdivacky      --include=PATTERN     files that match PATTERN will be examined\n\
1174204642Srdivacky      --exclude=PATTERN     files that match PATTERN will be skipped.\n\
1175204642Srdivacky      --exclude-from=FILE   files that match PATTERN in FILE will be skipped.\n\
1176204642Srdivacky  -L, --files-without-match only print FILE names containing no match\n\
1177207618Srdivacky  -l, --files-with-matches  only print FILE names containing matches\n\
1178204642Srdivacky  -c, --count               only print a count of matching lines per FILE\n\
1179204642Srdivacky      --null                print 0 byte after FILE name\n"));
1180193323Sed      printf (_("\
1181193323Sed\n\
1182193323SedContext control:\n\
1183193323Sed  -B, --before-context=NUM  print NUM lines of leading context\n\
1184193323Sed  -A, --after-context=NUM   print NUM lines of trailing context\n\
1185193323Sed  -C, --context=NUM         print NUM lines of output context\n\
1186193323Sed  -NUM                      same as --context=NUM\n\
1187193323Sed      --color[=WHEN],\n\
1188193323Sed      --colour[=WHEN]       use markers to distinguish the matching string\n\
1189193323Sed                            WHEN may be `always', `never' or `auto'.\n\
1190193323Sed  -U, --binary              do not strip CR characters at EOL (MSDOS)\n\
1191193323Sed  -u, --unix-byte-offsets   report offsets as if CRs were not there (MSDOS)\n\
1192204642Srdivacky\n\
1193204642Srdivacky`egrep' means `grep -E'.  `fgrep' means `grep -F'.\n\
1194207618SrdivackyWith no FILE, or when FILE is -, read standard input.  If less than\n\
1195193323Sedtwo FILEs given, assume -h.  Exit status is 0 if match, 1 if no match,\n\
1196193323Sedand 2 if trouble.\n"));
1197204642Srdivacky      printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n"));
1198193323Sed    }
1199204642Srdivacky  exit (status);
1200193323Sed}
1201193323Sed
1202193323Sed/* Set the matcher to M, reporting any conflicts.  */
1203193323Sedstatic void
1204193323Sedsetmatcher (char const *m)
1205193323Sed{
1206193323Sed  if (matcher && strcmp (matcher, m) != 0)
1207193323Sed    error (2, 0, _("conflicting matchers specified"));
1208202375Srdivacky  matcher = m;
1209193323Sed}
1210210299Sed
1211210299Sed/* Go through the matchers vector and look for the specified matcher.
1212193323Sed   If we find it, install it in compile and execute, and return 1.  */
1213193323Sedstatic int
1214193323Sedinstall_matcher (char const *name)
1215193323Sed{
1216193323Sed  int i;
1217193323Sed#if defined(HAVE_SETRLIMIT)
1218193323Sed  struct rlimit rlim;
1219193323Sed#endif
1220193323Sed
1221193323Sed  for (i = 0; matchers[i].compile; i++)
1222193323Sed    if (strcmp (name, matchers[i].name) == 0)
1223193323Sed      {
1224198090Srdivacky	compile = matchers[i].compile;
1225193323Sed	execute = matchers[i].execute;
1226193323Sed#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
1227207618Srdivacky	/* I think every platform needs to do this, so that regex.c
1228193323Sed	   doesn't oveflow the stack.  The default value of
1229193323Sed	   `re_max_failures' is too large for some platforms: it needs
1230207618Srdivacky	   more than 3MB-large stack.
1231193323Sed
1232193323Sed	   The test for HAVE_SETRLIMIT should go into `configure'.  */
1233193323Sed	if (!getrlimit (RLIMIT_STACK, &rlim))
1234193323Sed	  {
1235193323Sed	    long newlim;
1236193323Sed	    extern long int re_max_failures; /* from regex.c */
1237193323Sed
1238193323Sed	    /* Approximate the amount regex.c needs, plus some more.  */
1239193323Sed	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
1240193323Sed	    if (newlim > rlim.rlim_max)
1241193323Sed	      {
1242193323Sed		newlim = rlim.rlim_max;
1243193323Sed		re_max_failures = newlim / (2 * 20 * sizeof (char *));
1244193323Sed	      }
1245193323Sed	    if (rlim.rlim_cur < newlim)
1246193323Sed	      {
1247193323Sed		rlim.rlim_cur = newlim;
1248193323Sed		setrlimit (RLIMIT_STACK, &rlim);
1249193323Sed	      }
1250193323Sed	  }
1251193323Sed#endif
1252193323Sed	return 1;
1253193323Sed      }
1254193323Sed  return 0;
1255193323Sed}
1256193323Sed
1257193323Sed/* Find the white-space-separated options specified by OPTIONS, and
1258207618Srdivacky   using BUF to store copies of these options, set ARGV[0], ARGV[1],
1259193323Sed   etc. to the option copies.  Return the number N of options found.
1260193323Sed   Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
1261198090Srdivacky   etc.  Backslash can be used to escape whitespace (and backslashes).  */
1262198090Srdivackystatic int
1263198090Srdivackyprepend_args (char const *options, char *buf, char **argv)
1264198090Srdivacky{
1265198090Srdivacky  char const *o = options;
1266198090Srdivacky  char *b = buf;
1267193323Sed  int n = 0;
1268193323Sed
1269194612Sed  for (;;)
1270202375Srdivacky    {
1271194612Sed      while (ISSPACE ((unsigned char) *o))
1272210299Sed	o++;
1273194612Sed      if (!*o)
1274194612Sed	return n;
1275210299Sed      if (argv)
1276194612Sed	argv[n] = b;
1277194612Sed      n++;
1278194612Sed
1279207618Srdivacky      do
1280195098Sed	if ((*b++ = *o++) == '\\' && *o)
1281195098Sed	  b[-1] = *o++;
1282194612Sed      while (*o && ! ISSPACE ((unsigned char) *o));
1283194612Sed
1284194612Sed      *b++ = '\0';
1285194612Sed    }
1286194612Sed}
1287194612Sed
1288194612Sed/* Prepend the whitespace-separated options in OPTIONS to the argument
1289194612Sed   vector of a main program with argument count *PARGC and argument
1290194612Sed   vector *PARGV.  */
1291194612Sedstatic void
1292194612Sedprepend_default_options (char const *options, int *pargc, char ***pargv)
1293194612Sed{
1294202375Srdivacky  if (options)
1295193323Sed    {
1296193323Sed      char *buf = xmalloc (strlen (options) + 1);
1297193323Sed      int prepended = prepend_args (options, buf, (char **) NULL);
1298204642Srdivacky      int argc = *pargc;
1299204642Srdivacky      char * const *argv = *pargv;
1300207618Srdivacky      char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
1301204642Srdivacky      *pargc = prepended + argc;
1302204642Srdivacky      *pargv = pp;
1303204642Srdivacky      *pp++ = *argv++;
1304193323Sed      pp += prepend_args (options, buf, pp);
1305193323Sed      while ((*pp++ = *argv++))
1306193323Sed	continue;
1307193323Sed    }
1308193323Sed}
1309193323Sed
1310193323Sed/* Get the next non-digit option from ARGC and ARGV.
1311193399Sed   Return -1 if there are no more options.
1312193323Sed   Process any digit options that were encountered on the way,
1313193323Sed   and store the resulting integer into *DEFAULT_CONTEXT.  */
1314193323Sedstatic int
1315193323Sedget_nondigit_option (int argc, char *const *argv, int *default_context)
1316193323Sed{
1317193323Sed  int opt;
1318193323Sed  char buf[sizeof (uintmax_t) * CHAR_BIT + 4];
1319193323Sed  char *p = buf;
1320193323Sed
1321193323Sed  /* Set buf[0] to anything but '0', for the leading-zero test below.  */
1322193323Sed  buf[0] = '\0';
1323193323Sed
1324193323Sed  while (opt = getopt_long (argc, argv, short_options, long_options, NULL),
1325193323Sed	 '0' <= opt && opt <= '9')
1326193323Sed    {
1327193323Sed      /* Suppress trivial leading zeros, to avoid incorrect
1328202375Srdivacky	 diagnostic on strings like 00000000000.  */
1329193323Sed      p -= buf[0] == '0';
1330198090Srdivacky
1331198090Srdivacky      *p++ = opt;
1332198090Srdivacky      if (p == buf + sizeof buf - 4)
1333198090Srdivacky	{
1334198090Srdivacky	  /* Too many digits.  Append "..." to make context_length_arg
1335198090Srdivacky	     complain about "X...", where X contains the digits seen
1336198090Srdivacky	     so far.  */
1337198090Srdivacky	  strcpy (p, "...");
1338193323Sed	  p += 3;
1339193323Sed	  break;
1340198090Srdivacky	}
1341198090Srdivacky    }
1342198090Srdivacky  if (p != buf)
1343198090Srdivacky    {
1344198090Srdivacky      *p = '\0';
1345198090Srdivacky      context_length_arg (buf, default_context);
1346198090Srdivacky    }
1347198090Srdivacky
1348198090Srdivacky  return opt;
1349198090Srdivacky}
1350198090Srdivacky
1351198090Srdivackyint
1352198090Srdivackymain (int argc, char **argv)
1353198090Srdivacky{
1354202375Srdivacky  char *keys;
1355198090Srdivacky  size_t cc, keycc, oldcc, keyalloc;
1356198090Srdivacky  int with_filenames;
1357198090Srdivacky  int opt, status;
1358198090Srdivacky  int default_context;
1359198090Srdivacky  FILE *fp;
1360198090Srdivacky  extern char *optarg;
1361198090Srdivacky  extern int optind;
1362198090Srdivacky
1363198090Srdivacky  initialize_main (&argc, &argv);
1364198090Srdivacky  program_name = argv[0];
1365198090Srdivacky  if (program_name && strrchr (program_name, '/'))
1366198090Srdivacky    program_name = strrchr (program_name, '/') + 1;
1367198090Srdivacky
1368198090Srdivacky  if (program_name[0] == 'b' && program_name[1] == 'z') {
1369198090Srdivacky    BZflag = 1;
1370198090Srdivacky    program_name += 2;
1371198090Srdivacky  }
1372198090Srdivacky#if HAVE_LIBZ > 0
1373198090Srdivacky  else if (program_name[0] == 'z') {
1374198090Srdivacky    Zflag = 1;
1375198090Srdivacky    ++program_name;
1376198090Srdivacky  }
1377198090Srdivacky#endif
1378198090Srdivacky
1379198090Srdivacky#if defined(__MSDOS__) || defined(_WIN32)
1380198090Srdivacky  /* DOS and MS-Windows use backslashes as directory separators, and usually
1381198090Srdivacky     have an .exe suffix.  They also have case-insensitive filesystems.  */
1382198090Srdivacky  if (program_name)
1383198090Srdivacky    {
1384198090Srdivacky      char *p = program_name;
1385198090Srdivacky      char *bslash = strrchr (argv[0], '\\');
1386198090Srdivacky
1387198090Srdivacky      if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
1388198090Srdivacky	program_name = bslash + 1;
1389198090Srdivacky      else if (program_name == argv[0]
1390198090Srdivacky	       && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
1391198090Srdivacky	program_name = argv[0] + 2;
1392198090Srdivacky
1393198090Srdivacky      /* Collapse the letter-case, so `strcmp' could be used hence.  */
1394198090Srdivacky      for ( ; *p; p++)
1395198090Srdivacky	if (*p >= 'A' && *p <= 'Z')
1396198090Srdivacky	  *p += 'a' - 'A';
1397198090Srdivacky
1398198090Srdivacky      /* Remove the .exe extension, if any.  */
1399198090Srdivacky      if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
1400198090Srdivacky	*p = '\0';
1401198090Srdivacky    }
1402198090Srdivacky#endif
1403198090Srdivacky
1404198090Srdivacky  keys = NULL;
1405198090Srdivacky  keycc = 0;
1406204642Srdivacky  with_filenames = 0;
1407198090Srdivacky  eolbyte = '\n';
1408198090Srdivacky  filename_mask = ~0;
1409198090Srdivacky
1410198090Srdivacky  max_count = TYPE_MAXIMUM (off_t);
1411198090Srdivacky
1412198090Srdivacky  /* The value -1 means to use DEFAULT_CONTEXT. */
1413198090Srdivacky  out_after = out_before = -1;
1414204642Srdivacky  /* Default before/after context: chaged by -C/-NUM options */
1415198090Srdivacky  default_context = 0;
1416198090Srdivacky  /* Changed by -o option */
1417198090Srdivacky  only_matching = 0;
1418198090Srdivacky
1419198090Srdivacky  /* Internationalization. */
1420198090Srdivacky#if defined(HAVE_SETLOCALE)
1421198090Srdivacky  setlocale (LC_ALL, "");
1422198090Srdivacky#endif
1423198090Srdivacky#if defined(ENABLE_NLS)
1424198090Srdivacky  bindtextdomain (PACKAGE, LOCALEDIR);
1425198090Srdivacky  textdomain (PACKAGE);
1426198090Srdivacky#endif
1427198090Srdivacky
1428198090Srdivacky  atexit (close_stdout);
1429204642Srdivacky
1430198090Srdivacky  prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
1431198090Srdivacky
1432198090Srdivacky  while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1)
1433198090Srdivacky    switch (opt)
1434198090Srdivacky      {
1435198090Srdivacky      case 'A':
1436198090Srdivacky	context_length_arg (optarg, &out_after);
1437204642Srdivacky	break;
1438198090Srdivacky
1439198090Srdivacky      case 'B':
1440198090Srdivacky	context_length_arg (optarg, &out_before);
1441198090Srdivacky	break;
1442198090Srdivacky
1443198090Srdivacky      case 'C':
1444198090Srdivacky	/* Set output match context, but let any explicit leading or
1445198090Srdivacky	   trailing amount specified with -A or -B stand. */
1446198090Srdivacky	context_length_arg (optarg, &default_context);
1447198090Srdivacky	break;
1448198090Srdivacky
1449198090Srdivacky      case 'D':
1450198090Srdivacky	if (strcmp (optarg, "read") == 0)
1451198090Srdivacky	  devices = READ_DEVICES;
1452198090Srdivacky	else if (strcmp (optarg, "skip") == 0)
1453204642Srdivacky	  devices = SKIP_DEVICES;
1454198090Srdivacky	else
1455198090Srdivacky	  error (2, 0, _("unknown devices method"));
1456198090Srdivacky	break;
1457198090Srdivacky
1458198090Srdivacky      case 'E':
1459198090Srdivacky	setmatcher ("egrep");
1460198090Srdivacky	break;
1461204642Srdivacky
1462198090Srdivacky      case 'F':
1463198090Srdivacky	setmatcher ("fgrep");
1464198090Srdivacky	break;
1465198090Srdivacky
1466198090Srdivacky      case 'P':
1467198090Srdivacky	setmatcher ("perl");
1468198090Srdivacky	break;
1469198090Srdivacky
1470198090Srdivacky      case 'G':
1471203954Srdivacky	setmatcher ("grep");
1472198090Srdivacky	break;
1473198090Srdivacky
1474198090Srdivacky      case 'H':
1475198090Srdivacky	with_filenames = 1;
1476198090Srdivacky	break;
1477198090Srdivacky
1478198090Srdivacky      case 'I':
1479198090Srdivacky	binary_files = WITHOUT_MATCH_BINARY_FILES;
1480198090Srdivacky	break;
1481198090Srdivacky      case 'J':
1482198090Srdivacky	if (Zflag)
1483198090Srdivacky	  {
1484198090Srdivacky	    printf (_("Cannot mix -Z and -J.\n"));
1485198090Srdivacky	    usage (2);
1486198090Srdivacky	  }
1487198090Srdivacky	BZflag = 1;
1488198090Srdivacky	break;
1489198090Srdivacky
1490198090Srdivacky      case 'U':
1491198090Srdivacky#if defined(HAVE_DOS_FILE_CONTENTS)
1492198090Srdivacky	dos_use_file_type = DOS_BINARY;
1493198090Srdivacky#endif
1494198090Srdivacky	break;
1495198090Srdivacky
1496198090Srdivacky      case 'u':
1497198090Srdivacky#if defined(HAVE_DOS_FILE_CONTENTS)
1498198090Srdivacky	dos_report_unix_offset = 1;
1499198090Srdivacky#endif
1500198090Srdivacky	break;
1501198090Srdivacky
1502198090Srdivacky      case 'V':
1503198090Srdivacky	show_version = 1;
1504198090Srdivacky	break;
1505198090Srdivacky
1506198090Srdivacky      case 'X':
1507198090Srdivacky	setmatcher (optarg);
1508198090Srdivacky	break;
1509198090Srdivacky
1510198090Srdivacky      case 'a':
1511198090Srdivacky	binary_files = TEXT_BINARY_FILES;
1512198090Srdivacky	break;
1513198090Srdivacky
1514198090Srdivacky      case 'b':
1515198090Srdivacky	out_byte = 1;
1516198090Srdivacky	break;
1517203954Srdivacky
1518203954Srdivacky      case 'c':
1519198090Srdivacky	count_matches = 1;
1520198090Srdivacky	break;
1521198090Srdivacky
1522198090Srdivacky      case 'd':
1523198090Srdivacky	if (strcmp (optarg, "read") == 0)
1524198090Srdivacky	  directories = READ_DIRECTORIES;
1525198090Srdivacky	else if (strcmp (optarg, "skip") == 0)
1526198090Srdivacky	  directories = SKIP_DIRECTORIES;
1527198090Srdivacky	else if (strcmp (optarg, "recurse") == 0)
1528198090Srdivacky	  directories = RECURSE_DIRECTORIES;
1529198090Srdivacky	else
1530198090Srdivacky	  error (2, 0, _("unknown directories method"));
1531198090Srdivacky	break;
1532198090Srdivacky
1533198090Srdivacky      case 'e':
1534198090Srdivacky	cc = strlen (optarg);
1535198090Srdivacky	keys = xrealloc (keys, keycc + cc + 1);
1536198090Srdivacky	strcpy (&keys[keycc], optarg);
1537198090Srdivacky	keycc += cc;
1538198090Srdivacky	keys[keycc++] = '\n';
1539198090Srdivacky	break;
1540198090Srdivacky
1541198090Srdivacky      case 'f':
1542198090Srdivacky	fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
1543198090Srdivacky	if (!fp)
1544198090Srdivacky	  error (2, errno, "%s", optarg);
1545198090Srdivacky	for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
1546198090Srdivacky	  ;
1547198090Srdivacky	keys = xrealloc (keys, keyalloc);
1548198090Srdivacky	oldcc = keycc;
1549198090Srdivacky	while (!feof (fp)
1550198090Srdivacky	       && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
1551198090Srdivacky	  {
1552202375Srdivacky	    keycc += cc;
1553198090Srdivacky	    if (keycc == keyalloc - 1)
1554193323Sed	      keys = xrealloc (keys, keyalloc *= 2);
1555193323Sed	  }
1556193323Sed	if (fp != stdin)
1557193323Sed	  fclose(fp);
1558204642Srdivacky	/* Append final newline if file ended in non-newline. */
1559193323Sed	if (oldcc != keycc && keys[keycc - 1] != '\n')
1560193323Sed	  keys[keycc++] = '\n';
1561204642Srdivacky	break;
1562193323Sed
1563193323Sed      case 'h':
1564193323Sed	no_filenames = 1;
1565193323Sed	break;
1566198090Srdivacky
1567198090Srdivacky      case 'i':
1568198090Srdivacky      case 'y':			/* For old-timers . . . */
1569193323Sed	match_icase = 1;
1570198090Srdivacky	break;
1571198090Srdivacky
1572198090Srdivacky      case 'L':
1573198090Srdivacky	/* Like -l, except list files that don't contain matches.
1574198090Srdivacky	   Inspired by the same option in Hume's gre. */
1575198090Srdivacky	list_files = -1;
1576198090Srdivacky	break;
1577198090Srdivacky
1578198090Srdivacky      case 'l':
1579198090Srdivacky	list_files = 1;
1580198090Srdivacky	break;
1581198090Srdivacky
1582198090Srdivacky      case 'm':
1583198090Srdivacky	{
1584193323Sed	  uintmax_t value;
1585198090Srdivacky	  switch (xstrtoumax (optarg, 0, 10, &value, ""))
1586198090Srdivacky	    {
1587198090Srdivacky	    case LONGINT_OK:
1588198090Srdivacky	      max_count = value;
1589198090Srdivacky	      if (0 <= max_count && max_count == value)
1590198090Srdivacky		break;
1591193323Sed	      /* Fall through.  */
1592198090Srdivacky	    case LONGINT_OVERFLOW:
1593198090Srdivacky	      max_count = TYPE_MAXIMUM (off_t);
1594198090Srdivacky	      break;
1595198090Srdivacky
1596193323Sed	    default:
1597198090Srdivacky	      error (2, 0, _("invalid max count"));
1598198090Srdivacky	    }
1599198090Srdivacky	}
1600198090Srdivacky	break;
1601198090Srdivacky
1602198090Srdivacky      case 'n':
1603198090Srdivacky	out_line = 1;
1604198090Srdivacky	break;
1605193323Sed
1606198090Srdivacky      case 'o':
1607198090Srdivacky	only_matching = 1;
1608198090Srdivacky	break;
1609198090Srdivacky
1610198090Srdivacky      case 'q':
1611198090Srdivacky	exit_on_match = 1;
1612198090Srdivacky	close_stdout_set_status(0);
1613193323Sed	break;
1614198090Srdivacky
1615193323Sed      case 'R':
1616198090Srdivacky      case 'r':
1617198090Srdivacky	directories = RECURSE_DIRECTORIES;
1618198090Srdivacky	break;
1619198090Srdivacky
1620198090Srdivacky      case 's':
1621198090Srdivacky	suppress_errors = 1;
1622198090Srdivacky	break;
1623198090Srdivacky
1624193323Sed      case 'v':
1625198090Srdivacky	out_invert = 1;
1626202375Srdivacky	break;
1627198090Srdivacky
1628198090Srdivacky      case 'w':
1629202375Srdivacky	match_words = 1;
1630198090Srdivacky	break;
1631198090Srdivacky
1632198090Srdivacky      case 'x':
1633193323Sed	match_lines = 1;
1634198090Srdivacky	break;
1635198090Srdivacky
1636198090Srdivacky      case 'Z':
1637198090Srdivacky#if HAVE_LIBZ > 0
1638198090Srdivacky	if (BZflag)
1639198090Srdivacky	  {
1640198090Srdivacky	    printf (_("Cannot mix -J and -Z.\n"));
1641198090Srdivacky	    usage (2);
1642198090Srdivacky	  }
1643198090Srdivacky	Zflag = 1;
1644198090Srdivacky#else
1645198090Srdivacky	filename_mask = 0;
1646198090Srdivacky#endif
1647198090Srdivacky	break;
1648198090Srdivacky
1649198090Srdivacky      case 'z':
1650198090Srdivacky	eolbyte = '\0';
1651210299Sed	break;
1652210299Sed
1653210299Sed      case BINARY_FILES_OPTION:
1654210299Sed	if (strcmp (optarg, "binary") == 0)
1655210299Sed	  binary_files = BINARY_BINARY_FILES;
1656210299Sed	else if (strcmp (optarg, "text") == 0)
1657210299Sed	  binary_files = TEXT_BINARY_FILES;
1658210299Sed	else if (strcmp (optarg, "without-match") == 0)
1659210299Sed	  binary_files = WITHOUT_MATCH_BINARY_FILES;
1660210299Sed	else
1661210299Sed	  error (2, 0, _("unknown binary-files type"));
1662210299Sed	break;
1663210299Sed
1664210299Sed      case COLOR_OPTION:
1665210299Sed        if(optarg) {
1666210299Sed          if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") ||
1667210299Sed             !strcasecmp(optarg, "force"))
1668210299Sed            color_option = 1;
1669210299Sed          else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") ||
1670210299Sed                  !strcasecmp(optarg, "none"))
1671198090Srdivacky            color_option = 0;
1672202375Srdivacky          else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") ||
1673198090Srdivacky                  !strcasecmp(optarg, "if-tty"))
1674198090Srdivacky            color_option = 2;
1675198090Srdivacky          else
1676202375Srdivacky            show_help = 1;
1677204642Srdivacky        } else
1678198090Srdivacky          color_option = 2;
1679198090Srdivacky        if(color_option == 2) {
1680202375Srdivacky          if(isatty(STDOUT_FILENO) && getenv("TERM") &&
1681210299Sed	     strcmp(getenv("TERM"), "dumb"))
1682210299Sed                  color_option = 1;
1683210299Sed          else
1684202375Srdivacky            color_option = 0;
1685204642Srdivacky        }
1686198090Srdivacky	break;
1687193323Sed
1688198090Srdivacky      case EXCLUDE_OPTION:
1689198090Srdivacky	if (!excluded_patterns)
1690193323Sed	  excluded_patterns = new_exclude ();
1691198090Srdivacky	add_exclude (excluded_patterns, optarg);
1692198090Srdivacky	break;
1693198090Srdivacky
1694198090Srdivacky      case EXCLUDE_FROM_OPTION:
1695193323Sed	if (!excluded_patterns)
1696198090Srdivacky	  excluded_patterns = new_exclude ();
1697198090Srdivacky        if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n')
1698198090Srdivacky	    != 0)
1699198090Srdivacky          {
1700198090Srdivacky            error (2, errno, "%s", optarg);
1701198090Srdivacky          }
1702198090Srdivacky        break;
1703198090Srdivacky
1704193323Sed      case INCLUDE_OPTION:
1705198090Srdivacky	if (!included_patterns)
1706198090Srdivacky	  included_patterns = new_exclude ();
1707198090Srdivacky	add_exclude (included_patterns, optarg);
1708198090Srdivacky	break;
1709198090Srdivacky
1710198090Srdivacky      case LINE_BUFFERED_OPTION:
1711198090Srdivacky	line_buffered = 1;
1712198090Srdivacky	break;
1713198090Srdivacky
1714193323Sed      case LABEL_OPTION:
1715201360Srdivacky	label = optarg;
1716198090Srdivacky	break;
1717198090Srdivacky
1718198090Srdivacky      case 0:
1719198090Srdivacky	/* long options */
1720201360Srdivacky	break;
1721198090Srdivacky
1722198090Srdivacky      default:
1723198090Srdivacky	usage (2);
1724198090Srdivacky	break;
1725198090Srdivacky
1726202375Srdivacky      }
1727198090Srdivacky
1728198090Srdivacky  /* POSIX.2 says that -q overrides -l, which in turn overrides the
1729198090Srdivacky     other output options.  */
1730201360Srdivacky  if (exit_on_match)
1731198090Srdivacky    list_files = 0;
1732198090Srdivacky  if (exit_on_match | list_files)
1733198090Srdivacky    {
1734198090Srdivacky      count_matches = 0;
1735201360Srdivacky      done_on_match = 1;
1736202375Srdivacky    }
1737198090Srdivacky  out_quiet = count_matches | done_on_match;
1738198090Srdivacky
1739198090Srdivacky  if (out_after < 0)
1740193323Sed    out_after = default_context;
1741198090Srdivacky  if (out_before < 0)
1742202375Srdivacky    out_before = default_context;
1743198090Srdivacky
1744198090Srdivacky  if (color_option)
1745198090Srdivacky    {
1746198090Srdivacky      char *userval = getenv ("GREP_COLOR");
1747198090Srdivacky      if (userval != NULL && *userval != '\0')
1748198090Srdivacky	grep_color = userval;
1749198090Srdivacky    }
1750202375Srdivacky
1751198090Srdivacky  if (! matcher)
1752198090Srdivacky    matcher = program_name;
1753198090Srdivacky
1754198090Srdivacky  if (show_version)
1755198090Srdivacky    {
1756198090Srdivacky      printf (_("%s (GNU grep) %s\n"), matcher, VERSION);
1757198090Srdivacky      printf ("\n");
1758193323Sed      printf (_("\
1759198090SrdivackyCopyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n"));
1760198090Srdivacky      printf (_("\
1761198090SrdivackyThis is free software; see the source for copying conditions. There is NO\n\
1762198090Srdivackywarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
1763198090Srdivacky      printf ("\n");
1764198090Srdivacky      exit (0);
1765198090Srdivacky    }
1766198090Srdivacky
1767198090Srdivacky  if (show_help)
1768198090Srdivacky    usage (0);
1769198090Srdivacky
1770198090Srdivacky  if (keys)
1771193323Sed    {
1772198090Srdivacky      if (keycc == 0)
1773198090Srdivacky	{
1774198090Srdivacky	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
1775202375Srdivacky	  out_invert ^= 1;
1776202375Srdivacky	  match_lines = match_words = 0;
1777201360Srdivacky	}
1778198090Srdivacky      else
1779193323Sed	/* Strip trailing newline. */
1780198090Srdivacky        --keycc;
1781193323Sed    }
1782198090Srdivacky  else
1783198090Srdivacky    if (optind < argc)
1784198090Srdivacky      {
1785198090Srdivacky	keys = argv[optind++];
1786198090Srdivacky	keycc = strlen (keys);
1787198090Srdivacky      }
1788198090Srdivacky    else
1789198090Srdivacky      usage (2);
1790198090Srdivacky
1791198090Srdivacky  if (!install_matcher (matcher) && !install_matcher ("default"))
1792198090Srdivacky    abort ();
1793198090Srdivacky
1794198090Srdivacky#ifdef MBS_SUPPORT
1795198090Srdivacky  if (MB_CUR_MAX != 1 && match_icase)
1796210299Sed    {
1797210299Sed      wchar_t wc;
1798210299Sed      mbstate_t cur_state, prev_state;
1799210299Sed      int i, len = strlen(keys);
1800210299Sed
1801210299Sed      memset(&cur_state, 0, sizeof(mbstate_t));
1802210299Sed      for (i = 0; i <= len ;)
1803210299Sed	{
1804210299Sed	  size_t mbclen;
1805210299Sed	  mbclen = mbrtowc(&wc, keys + i, len - i, &cur_state);
1806210299Sed	  if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
1807210299Sed	    {
1808210299Sed	      /* An invalid sequence, or a truncated multibyte character.
1809210299Sed		 We treat it as a singlebyte character.  */
1810210299Sed	      mbclen = 1;
1811210299Sed	    }
1812210299Sed	  else
1813210299Sed	    {
1814210299Sed	      if (iswupper((wint_t)wc))
1815210299Sed		{
1816210299Sed		  wc = towlower((wint_t)wc);
1817210299Sed		  wcrtomb(keys + i, wc, &cur_state);
1818210299Sed		}
1819198090Srdivacky	    }
1820202375Srdivacky	  i += mbclen;
1821198090Srdivacky	}
1822198090Srdivacky    }
1823198090Srdivacky#endif /* MBS_SUPPORT */
1824202375Srdivacky
1825204642Srdivacky  (*compile)(keys, keycc);
1826198090Srdivacky
1827198090Srdivacky  if ((argc - optind > 1 && !no_filenames) || with_filenames)
1828202375Srdivacky    out_file = 1;
1829210299Sed
1830210299Sed#ifdef SET_BINARY
1831210299Sed  /* Output is set to binary mode because we shouldn't convert
1832202375Srdivacky     NL to CR-LF pairs, especially when grepping binary files.  */
1833204642Srdivacky  if (!isatty (1))
1834198090Srdivacky    SET_BINARY (1);
1835198090Srdivacky#endif
1836198090Srdivacky
1837193323Sed  if (max_count == 0)
1838198090Srdivacky    exit (1);
1839198090Srdivacky
1840198090Srdivacky  if (optind < argc)
1841198090Srdivacky    {
1842198090Srdivacky	status = 1;
1843198090Srdivacky	do
1844207618Srdivacky	{
1845207618Srdivacky	  char *file = argv[optind];
1846207618Srdivacky	  if ((included_patterns || excluded_patterns)
1847198090Srdivacky	      && !isdir (file))
1848198090Srdivacky	    {
1849198090Srdivacky	      if (included_patterns &&
1850198090Srdivacky		  ! excluded_filename (included_patterns, file, 0))
1851198090Srdivacky		continue;
1852198090Srdivacky	      if (excluded_patterns &&
1853198090Srdivacky		  excluded_filename (excluded_patterns, file, 0))
1854198090Srdivacky		continue;
1855198090Srdivacky	    }
1856198090Srdivacky	  status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
1857198090Srdivacky			      &stats_base);
1858198090Srdivacky	}
1859198090Srdivacky	while ( ++optind < argc);
1860198090Srdivacky    }
1861198090Srdivacky  else
1862198090Srdivacky    status = grepfile ((char *) NULL, &stats_base);
1863198090Srdivacky
1864198090Srdivacky  /* We register via atexit() to test stdout.  */
1865198090Srdivacky  exit (errseen ? 2 : status);
1866198090Srdivacky}
1867198090Srdivacky/* vim:set shiftwidth=2: */
1868198090Srdivacky