xref: /netbsd-src/external/gpl2/grep/dist/src/grep.c (revision ab1d953c7189421d9e405d19b9bae6829abf2897)
1 /*	$NetBSD: grep.c,v 1.5 2022/09/09 22:14:29 wiz Exp $	*/
2 
3 /* grep.c - main driver file for grep.
4    Copyright 1992, 1997-1999, 2000 Free Software Foundation, Inc.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20 
21 /* Written July 1992 by Mike Haertel.  */
22 
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #if defined(HAVE_MMAP)
29 # include <sys/mman.h>
30 #endif
31 #if defined(HAVE_SETRLIMIT)
32 # include <sys/time.h>
33 # include <sys/resource.h>
34 #endif
35 #include <stdio.h>
36 #include "system.h"
37 #include "getopt.h"
38 #include "getpagesize.h"
39 #include "grep.h"
40 #include "savedir.h"
41 #include "xstrtol.h"
42 #include "xalloc.h"
43 #include "error.h"
44 #include "exclude.h"
45 #include "closeout.h"
46 
47 #undef MAX
48 #define MAX(A,B) ((A) > (B) ? (A) : (B))
49 
50 struct stats
51 {
52   struct stats const *parent;
53   struct stat stat;
54 };
55 
56 #include <limits.h>
57 #define MAX_OFF_T (sizeof(off_t) == sizeof(char) ? INT_MAX : \
58                    (sizeof(off_t) == sizeof(short) ? SHRT_MAX : \
59                     (sizeof(off_t) == sizeof(int) ? INT_MAX : \
60                      (sizeof(off_t) == sizeof(long) ? LONG_MAX : \
61                       (sizeof(off_t) == sizeof(long long) ? LLONG_MAX : INTMAX_MAX)))))
62 
63 /* base of chain of stat buffers, used to detect directory loops */
64 static struct stats stats_base;
65 
66 /* if non-zero, display usage information and exit */
67 static int show_help;
68 
69 /* If non-zero, print the version on standard output and exit.  */
70 static int show_version;
71 
72 /* If nonzero, suppress diagnostics for nonexistent or unreadable files.  */
73 static int suppress_errors;
74 
75 /* If nonzero, use mmap if possible.  */
76 static int mmap_option;
77 
78 /* If nonzero, use grep_color marker.  */
79 static int color_option;
80 
81 /* If nonzero, show only the part of a line matching the expression. */
82 static int only_matching;
83 
84 /* The color string used.  The user can overwrite it using the environment
85    variable GREP_COLOR.  The default is to print red.  */
86 static const char *grep_color = "01;31";
87 
88 static struct exclude *excluded_patterns;
89 static struct exclude *included_patterns;
90 /* Short options.  */
91 static char const short_options[] =
92 "0123456789A:B:C:D:EFGHIPUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz";
93 
94 /* Non-boolean long options that have no corresponding short equivalents.  */
95 enum
96 {
97   BINARY_FILES_OPTION = CHAR_MAX + 1,
98   COLOR_OPTION,
99   INCLUDE_OPTION,
100   EXCLUDE_OPTION,
101   EXCLUDE_FROM_OPTION,
102   LINE_BUFFERED_OPTION,
103   LABEL_OPTION
104 };
105 
106 /* Long options equivalences. */
107 static struct option const long_options[] =
108 {
109   {"after-context", required_argument, NULL, 'A'},
110   {"basic-regexp", no_argument, NULL, 'G'},
111   {"before-context", required_argument, NULL, 'B'},
112   {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},
113   {"byte-offset", no_argument, NULL, 'b'},
114   {"context", required_argument, NULL, 'C'},
115   {"color", optional_argument, NULL, COLOR_OPTION},
116   {"colour", optional_argument, NULL, COLOR_OPTION},
117   {"count", no_argument, NULL, 'c'},
118   {"devices", required_argument, NULL, 'D'},
119   {"directories", required_argument, NULL, 'd'},
120   {"extended-regexp", no_argument, NULL, 'E'},
121   {"exclude", required_argument, NULL, EXCLUDE_OPTION},
122   {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION},
123   {"file", required_argument, NULL, 'f'},
124   {"files-with-matches", no_argument, NULL, 'l'},
125   {"files-without-match", no_argument, NULL, 'L'},
126   {"fixed-regexp", no_argument, NULL, 'F'},
127   {"fixed-strings", no_argument, NULL, 'F'},
128   {"help", no_argument, &show_help, 1},
129   {"include", required_argument, NULL, INCLUDE_OPTION},
130   {"ignore-case", no_argument, NULL, 'i'},
131   {"label", required_argument, NULL, LABEL_OPTION},
132   {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION},
133   {"line-number", no_argument, NULL, 'n'},
134   {"line-regexp", no_argument, NULL, 'x'},
135   {"max-count", required_argument, NULL, 'm'},
136   {"mmap", no_argument, &mmap_option, 1},
137   {"no-filename", no_argument, NULL, 'h'},
138   {"no-messages", no_argument, NULL, 's'},
139   {"null", no_argument, NULL, 'Z'},
140   {"null-data", no_argument, NULL, 'z'},
141   {"only-matching", no_argument, NULL, 'o'},
142   {"perl-regexp", no_argument, NULL, 'P'},
143   {"quiet", no_argument, NULL, 'q'},
144   {"recursive", no_argument, NULL, 'r'},
145   {"recursive", no_argument, NULL, 'R'},
146   {"regexp", required_argument, NULL, 'e'},
147   {"invert-match", no_argument, NULL, 'v'},
148   {"silent", no_argument, NULL, 'q'},
149   {"text", no_argument, NULL, 'a'},
150   {"binary", no_argument, NULL, 'U'},
151   {"unix-byte-offsets", no_argument, NULL, 'u'},
152   {"version", no_argument, NULL, 'V'},
153   {"with-filename", no_argument, NULL, 'H'},
154   {"word-regexp", no_argument, NULL, 'w'},
155   {0, 0, 0, 0}
156 };
157 
158 /* Define flags declared in grep.h. */
159 int match_icase;
160 int match_words;
161 int match_lines;
162 unsigned char eolbyte;
163 
164 /* For error messages. */
165 /* The name the program was run with, stripped of any leading path. */
166 char *program_name;
167 static char const *filename;
168 static int errseen;
169 
170 /* How to handle directories.  */
171 static enum
172   {
173     READ_DIRECTORIES,
174     RECURSE_DIRECTORIES,
175     SKIP_DIRECTORIES
176   } directories = READ_DIRECTORIES;
177 
178 /* How to handle devices. */
179 static enum
180   {
181     READ_DEVICES,
182     SKIP_DEVICES
183   } devices = READ_DEVICES;
184 
185 static int grepdir PARAMS ((char const *, struct stats const *));
186 #if defined(HAVE_DOS_FILE_CONTENTS)
187 static inline int undossify_input PARAMS ((register char *, size_t));
188 #endif
189 
190 /* Functions we'll use to search. */
191 static void (*compile) PARAMS ((char const *, size_t));
192 static size_t (*execute) PARAMS ((char const *, size_t, size_t *, int));
193 
194 /* Like error, but suppress the diagnostic if requested.  */
195 static void
suppressible_error(char const * mesg,int errnum)196 suppressible_error (char const *mesg, int errnum)
197 {
198   if (! suppress_errors)
199     error (0, errnum, "%s", mesg);
200   errseen = 1;
201 }
202 
203 /* Convert STR to a positive integer, storing the result in *OUT.
204    STR must be a valid context length argument; report an error if it
205    isn't.  */
206 static void
context_length_arg(char const * str,int * out)207 context_length_arg (char const *str, int *out)
208 {
209   uintmax_t value;
210   if (! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK
211 	 && 0 <= (*out = value)
212 	 && *out == value))
213     {
214       error (2, 0, "%s: %s", str, _("invalid context length argument"));
215     }
216 }
217 
218 
219 /* Hairy buffering mechanism for grep.  The intent is to keep
220    all reads aligned on a page boundary and multiples of the
221    page size, unless a read yields a partial page.  */
222 
223 static char *buffer;		/* Base of buffer. */
224 static size_t bufalloc;		/* Allocated buffer size, counting slop. */
225 #define INITIAL_BUFSIZE 32768	/* Initial buffer size, not counting slop. */
226 static int bufdesc;		/* File descriptor. */
227 static char *bufbeg;		/* Beginning of user-visible stuff. */
228 static char *buflim;		/* Limit of user-visible stuff. */
229 static size_t pagesize;		/* alignment of memory pages */
230 static off_t bufoffset;		/* Read offset; defined on regular files.  */
231 static off_t after_last_match;	/* Pointer after last matching line that
232 				   would have been output if we were
233 				   outputting characters. */
234 
235 #if defined(HAVE_MMAP)
236 static int bufmapped;		/* True if buffer is memory-mapped.  */
237 static off_t initial_bufoffset;	/* Initial value of bufoffset. */
238 #else
239 # define bufmapped 0
240 #endif
241 
242 /* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be
243    an integer or a pointer.  Both args must be free of side effects.  */
244 #define ALIGN_TO(val, alignment) \
245   ((size_t) (val) % (alignment) == 0 \
246    ? (val) \
247    : (val) + ((alignment) - (size_t) (val) % (alignment)))
248 
249 /* Reset the buffer for a new file, returning zero if we should skip it.
250    Initialize on the first time through. */
251 static int
reset(int fd,char const * file,struct stats * stats)252 reset (int fd, char const *file, struct stats *stats)
253 {
254   if (! pagesize)
255     {
256       pagesize = getpagesize ();
257       if (pagesize == 0 || 2 * pagesize + 1 <= pagesize)
258 	abort ();
259       bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + 1;
260       buffer = xmalloc (bufalloc);
261     }
262 
263   bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);
264   bufbeg[-1] = eolbyte;
265   bufdesc = fd;
266 
267   if (fstat (fd, &stats->stat) != 0)
268     {
269       error (0, errno, "fstat");
270       return 0;
271     }
272   if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
273     return 0;
274   if (devices == SKIP_DEVICES && (S_ISCHR(stats->stat.st_mode)
275   || S_ISBLK(stats->stat.st_mode)
276 #ifdef S_ISSOCK
277   || S_ISSOCK(stats->stat.st_mode)
278 #endif
279 #ifdef S_ISFIFO
280   || S_ISFIFO(stats->stat.st_mode)
281 #endif
282   ))
283     return 0;
284   if (S_ISREG (stats->stat.st_mode))
285     {
286       if (file)
287 	bufoffset = 0;
288       else
289 	{
290 	  bufoffset = lseek (fd, 0, SEEK_CUR);
291 	  if (bufoffset < 0)
292 	    {
293 	      error (0, errno, "lseek");
294 	      return 0;
295 	    }
296 	}
297 #if defined(HAVE_MMAP)
298       initial_bufoffset = bufoffset;
299       bufmapped = mmap_option && bufoffset % pagesize == 0;
300 #endif
301     }
302   else
303     {
304 #if defined(HAVE_MMAP)
305       bufmapped = 0;
306 #endif
307     }
308   return 1;
309 }
310 
311 /* Read new stuff into the buffer, saving the specified
312    amount of old stuff.  When we're done, 'bufbeg' points
313    to the beginning of the buffer contents, and 'buflim'
314    points just after the end.  Return zero if there's an error.  */
315 static int
fillbuf(size_t save,struct stats const * stats)316 fillbuf (size_t save, struct stats const *stats)
317 {
318   size_t fillsize = 0;
319   int cc = 1;
320   char *readbuf;
321   size_t readsize;
322 
323   /* Offset from start of buffer to start of old stuff
324      that we want to save.  */
325   size_t saved_offset = buflim - save - buffer;
326 
327   if (pagesize <= buffer + bufalloc - buflim)
328     {
329       readbuf = buflim;
330       bufbeg = buflim - save;
331     }
332   else
333     {
334       size_t minsize = save + pagesize;
335       size_t newsize;
336       size_t newalloc;
337       char *newbuf;
338 
339       /* Grow newsize until it is at least as great as minsize.  */
340       for (newsize = bufalloc - pagesize - 1; newsize < minsize; newsize *= 2)
341 	if (newsize * 2 < newsize || newsize * 2 + pagesize + 1 < newsize * 2)
342 	  xalloc_die ();
343 
344       /* Try not to allocate more memory than the file size indicates,
345 	 as that might cause unnecessary memory exhaustion if the file
346 	 is large.  However, do not use the original file size as a
347 	 heuristic if we've already read past the file end, as most
348 	 likely the file is growing.  */
349       if (S_ISREG (stats->stat.st_mode))
350 	{
351 	  off_t to_be_read = stats->stat.st_size - bufoffset;
352 	  off_t maxsize_off = save + to_be_read;
353 	  if (0 <= to_be_read && to_be_read <= maxsize_off
354 	      && maxsize_off == (size_t) maxsize_off
355 	      && minsize <= (size_t) maxsize_off
356 	      && (size_t) maxsize_off < newsize)
357 	    newsize = maxsize_off;
358 	}
359 
360       /* Add enough room so that the buffer is aligned and has room
361 	 for byte sentinels fore and aft.  */
362       newalloc = newsize + pagesize + 1;
363 
364       newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
365       readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);
366       bufbeg = readbuf - save;
367       memmove (bufbeg, buffer + saved_offset, save);
368       bufbeg[-1] = eolbyte;
369       if (newbuf != buffer)
370 	{
371 	  free (buffer);
372 	  buffer = newbuf;
373 	}
374     }
375 
376   readsize = buffer + bufalloc - readbuf;
377   readsize -= readsize % pagesize;
378 
379 #if defined(HAVE_MMAP)
380   if (bufmapped)
381     {
382       size_t mmapsize = readsize;
383 
384       /* Don't mmap past the end of the file; some hosts don't allow this.
385 	 Use `read' on the last page.  */
386       if (stats->stat.st_size - bufoffset < mmapsize)
387 	{
388 	  mmapsize = stats->stat.st_size - bufoffset;
389 	  mmapsize -= mmapsize % pagesize;
390 	}
391 
392       if (mmapsize
393 	  && (mmap ((caddr_t) readbuf, mmapsize,
394 		    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
395 		    bufdesc, bufoffset)
396 	      != (caddr_t) -1))
397 	{
398 	  /* Do not bother to use madvise with MADV_SEQUENTIAL or
399 	     MADV_WILLNEED on the mmapped memory.  One might think it
400 	     would help, but it slows us down about 30% on SunOS 4.1.  */
401 	  fillsize = mmapsize;
402 	}
403       else
404 	{
405 	  /* Stop using mmap on this file.  Synchronize the file
406 	     offset.  Do not warn about mmap failures.  On some hosts
407 	     (e.g. Solaris 2.5) mmap can fail merely because some
408 	     other process has an advisory read lock on the file.
409 	     There's no point alarming the user about this misfeature.  */
410 	  bufmapped = 0;
411 	  if (bufoffset != initial_bufoffset
412 	      && lseek (bufdesc, bufoffset, SEEK_SET) < 0)
413 	    {
414 	      error (0, errno, "lseek");
415 	      cc = 0;
416 	    }
417 	}
418     }
419 #endif /*HAVE_MMAP*/
420 
421   if (! fillsize)
422     {
423       ssize_t bytesread;
424       while ((bytesread = read (bufdesc, readbuf, readsize)) < 0
425 	     && errno == EINTR)
426 	continue;
427       if (bytesread < 0)
428 	cc = 0;
429       else
430 	fillsize = bytesread;
431     }
432 
433   bufoffset += fillsize;
434 #if defined(HAVE_DOS_FILE_CONTENTS)
435   if (fillsize)
436     fillsize = undossify_input (readbuf, fillsize);
437 #endif
438   buflim = readbuf + fillsize;
439   return cc;
440 }
441 
442 /* Flags controlling the style of output. */
443 static enum
444 {
445   BINARY_BINARY_FILES,
446   TEXT_BINARY_FILES,
447   WITHOUT_MATCH_BINARY_FILES
448 } binary_files;		/* How to handle binary files.  */
449 
450 static int filename_mask;	/* If zero, output nulls after filenames.  */
451 static int out_quiet;		/* Suppress all normal output. */
452 static int out_invert;		/* Print nonmatching stuff. */
453 static int out_file;		/* Print filenames. */
454 static int out_line;		/* Print line numbers. */
455 static int out_byte;		/* Print byte offsets. */
456 static int out_before;		/* Lines of leading context. */
457 static int out_after;		/* Lines of trailing context. */
458 static int count_matches;	/* Count matching lines.  */
459 static int list_files;		/* List matching files.  */
460 static int no_filenames;	/* Suppress file names.  */
461 static off_t max_count;		/* Stop after outputting this many
462 				   lines from an input file.  */
463 static int line_buffered;       /* If nonzero, use line buffering, i.e.
464 				   fflush everyline out.  */
465 static char *label = NULL;      /* Fake filename for stdin */
466 
467 
468 /* Internal variables to keep track of byte count, context, etc. */
469 static uintmax_t totalcc;	/* Total character count before bufbeg. */
470 static char const *lastnl;	/* Pointer after last newline counted. */
471 static char const *lastout;	/* Pointer after last character output;
472 				   NULL if no character has been output
473 				   or if it's conceptually before bufbeg. */
474 static uintmax_t totalnl;	/* Total newline count before lastnl. */
475 static off_t outleft;		/* Maximum number of lines to be output.  */
476 static int pending;		/* Pending lines of output.
477 				   Always kept 0 if out_quiet is true.  */
478 static int done_on_match;	/* Stop scanning file on first match.  */
479 static int exit_on_match;	/* Exit on first match.  */
480 
481 #if defined(HAVE_DOS_FILE_CONTENTS)
482 # include "dosbuf.c"
483 #endif
484 
485 /* Add two numbers that count input bytes or lines, and report an
486    error if the addition overflows.  */
487 static uintmax_t
add_count(uintmax_t a,uintmax_t b)488 add_count (uintmax_t a, uintmax_t b)
489 {
490   uintmax_t sum = a + b;
491   if (sum < a)
492     error (2, 0, _("input is too large to count"));
493   return sum;
494 }
495 
496 static void
nlscan(char const * lim)497 nlscan (char const *lim)
498 {
499   size_t newlines = 0;
500   char const *beg;
501   for (beg = lastnl; beg != lim; beg = memchr (beg, eolbyte, lim - beg), beg++)
502     newlines++;
503   totalnl = add_count (totalnl, newlines);
504   lastnl = lim;
505 }
506 
507 /* Print a byte offset, followed by a character separator.  */
508 static void
print_offset_sep(uintmax_t pos,char sep)509 print_offset_sep (uintmax_t pos, char sep)
510 {
511   /* Do not rely on printf to print pos, since uintmax_t may be longer
512      than long, and long long is not portable.  */
513 
514   char buf[sizeof pos * CHAR_BIT];
515   char *p = buf + sizeof buf - 1;
516   *p = sep;
517 
518   do
519     *--p = '0' + pos % 10;
520   while ((pos /= 10) != 0);
521 
522   fwrite (p, 1, buf + sizeof buf - p, stdout);
523 }
524 
525 static void
prline(char const * beg,char const * lim,int sep)526 prline (char const *beg, char const *lim, int sep)
527 {
528   if (out_file)
529     printf ("%s%c", filename, sep & filename_mask);
530   if (out_line)
531     {
532       nlscan (beg);
533       totalnl = add_count (totalnl, 1);
534       print_offset_sep (totalnl, sep);
535       lastnl = lim;
536     }
537   if (out_byte)
538     {
539       uintmax_t pos = add_count (totalcc, beg - bufbeg);
540 #if defined(HAVE_DOS_FILE_CONTENTS)
541       pos = dossified_pos (pos);
542 #endif
543       print_offset_sep (pos, sep);
544     }
545   if (only_matching)
546     {
547       size_t match_size;
548       size_t match_offset;
549       while ((match_offset = (*execute) (beg, lim - beg, &match_size, 1))
550 	  != (size_t) -1)
551         {
552 	  char const *b = beg + match_offset;
553 	  if (b == lim)
554 	    break;
555 	  if (match_size == 0)
556 	    {
557 	      beg++;
558 	      continue;
559 	    }
560 	  if(color_option)
561 	    printf("\33[%sm", grep_color);
562 	  fwrite(b, sizeof (char), match_size, stdout);
563 	  if(color_option)
564 	    fputs("\33[00m", stdout);
565 	  fputs("\n", stdout);
566 	  beg = b + match_size;
567         }
568       lastout = lim;
569       if(line_buffered)
570 	fflush(stdout);
571       return;
572     }
573   if (color_option)
574     {
575       size_t match_size;
576       size_t match_offset;
577       if(match_icase)
578         {
579 	  /* Yuck, this is tricky */
580           char *buf = (char*) xmalloc (lim - beg);
581 	  char *ibeg = buf;
582 	  char *ilim = ibeg + (lim - beg);
583 	  int i;
584 	  for (i = 0; i < lim - beg; i++)
585 	    ibeg[i] = tolower (beg[i]);
586 	  while ((match_offset = (*execute) (ibeg, ilim-ibeg, &match_size, 1))
587 		 != (size_t) -1)
588 	    {
589 	      char const *b = beg + match_offset;
590 	      if (b == lim)
591 		break;
592 	      fwrite (beg, sizeof (char), match_offset, stdout);
593 	      printf ("\33[%sm", grep_color);
594 	      fwrite (b, sizeof (char), match_size, stdout);
595 	      fputs ("\33[00m", stdout);
596 	      beg = b + match_size;
597 	      ibeg = ibeg + match_offset + match_size;
598 	    }
599 	  fwrite (beg, 1, lim - beg, stdout);
600 	  free (buf);
601 	  lastout = lim;
602 	  return;
603 	}
604       while (lim-beg && (match_offset = (*execute) (beg, lim - beg, &match_size, 1))
605 	     != (size_t) -1)
606 	{
607 	  char const *b = beg + match_offset;
608 	  /* Avoid matching the empty line at the end of the buffer. */
609 	  if (b == lim)
610 	    break;
611 	  /* Avoid hanging on grep --color "" foo */
612 	  if (match_size == 0)
613 	    break;
614 	  fwrite (beg, sizeof (char), match_offset, stdout);
615 	  printf ("\33[%sm", grep_color);
616 	  fwrite (b, sizeof (char), match_size, stdout);
617 	  fputs ("\33[00m", stdout);
618 	  beg = b + match_size;
619 	}
620     }
621   fwrite (beg, 1, lim - beg, stdout);
622   if (ferror (stdout))
623     error (0, errno, _("writing output"));
624   lastout = lim;
625   if (line_buffered)
626     fflush (stdout);
627 }
628 
629 /* Print pending lines of trailing context prior to LIM. Trailing context ends
630    at the next matching line when OUTLEFT is 0.  */
631 static void
prpending(char const * lim)632 prpending (char const *lim)
633 {
634   if (!lastout)
635     lastout = bufbeg;
636   while (pending > 0 && lastout < lim)
637     {
638       char const *nl = memchr (lastout, eolbyte, lim - lastout);
639       size_t match_size;
640       --pending;
641       if (outleft
642 	  || (((*execute) (lastout, nl - lastout, &match_size, 0) == (size_t) -1)
643 	      == !out_invert))
644 	prline (lastout, nl + 1, '-');
645       else
646 	pending = 0;
647     }
648 }
649 
650 /* Print the lines between BEG and LIM.  Deal with context crap.
651    If NLINESP is non-null, store a count of lines between BEG and LIM.  */
652 static void
prtext(char const * beg,char const * lim,int * nlinesp)653 prtext (char const *beg, char const *lim, int *nlinesp)
654 {
655   static int used;		/* avoid printing "--" before any output */
656   char const *bp, *p;
657   char eol = eolbyte;
658   int i, n;
659 
660   if (!out_quiet && pending > 0)
661     prpending (beg);
662 
663   p = beg;
664 
665   if (!out_quiet)
666     {
667       /* Deal with leading context crap. */
668 
669       bp = lastout ? lastout : bufbeg;
670       for (i = 0; i < out_before; ++i)
671 	if (p > bp)
672 	  do
673 	    --p;
674 	  while (p[-1] != eol);
675 
676       /* We only print the "--" separator if our output is
677 	 discontiguous from the last output in the file. */
678       if ((out_before || out_after) && used && p != lastout)
679 	puts ("--");
680 
681       while (p < beg)
682 	{
683 	  char const *nl = memchr (p, eol, beg - p);
684 	  nl++;
685 	  prline (p, nl, '-');
686 	  p = nl;
687 	}
688     }
689 
690   if (nlinesp)
691     {
692       /* Caller wants a line count. */
693       for (n = 0; p < lim && n < outleft; n++)
694 	{
695 	  char const *nl = memchr (p, eol, lim - p);
696 	  nl++;
697 	  if (!out_quiet)
698 	    prline (p, nl, ':');
699 	  p = nl;
700 	}
701       *nlinesp = n;
702 
703       /* relying on it that this function is never called when outleft = 0.  */
704       after_last_match = bufoffset - (buflim - p);
705     }
706   else
707     if (!out_quiet)
708       prline (beg, lim, ':');
709 
710   pending = out_quiet ? 0 : out_after;
711   used = 1;
712 }
713 
714 /* Scan the specified portion of the buffer, matching lines (or
715    between matching lines if OUT_INVERT is true).  Return a count of
716    lines printed. */
717 static int
grepbuf(char const * beg,char const * lim)718 grepbuf (char const *beg, char const *lim)
719 {
720   int nlines, n;
721   register char const *p;
722   size_t match_offset;
723   size_t match_size;
724 
725   nlines = 0;
726   p = beg;
727   while ((match_offset = (*execute) (p, lim - p, &match_size, 0)) != (size_t) -1)
728     {
729       char const *b = p + match_offset;
730       char const *endp = b + match_size;
731       /* Avoid matching the empty line at the end of the buffer. */
732       if (b == lim)
733 	break;
734       if (!out_invert)
735 	{
736 	  prtext (b, endp, (int *) 0);
737 	  nlines++;
738           outleft--;
739 	  if (!outleft || done_on_match)
740 	    {
741 	      if (exit_on_match)
742 		exit (0);
743 	      after_last_match = bufoffset - (buflim - endp);
744 	      return nlines;
745 	    }
746 	}
747       else if (p < b)
748 	{
749 	  prtext (p, b, &n);
750 	  nlines += n;
751           outleft -= n;
752 	  if (!outleft)
753 	    return nlines;
754 	}
755       p = endp;
756     }
757   if (out_invert && p < lim)
758     {
759       prtext (p, lim, &n);
760       nlines += n;
761       outleft -= n;
762     }
763   return nlines;
764 }
765 
766 /* Search a given file.  Normally, return a count of lines printed;
767    but if the file is a directory and we search it recursively, then
768    return -2 if there was a match, and -1 otherwise.  */
769 static int
grep(int fd,char const * file,struct stats * stats)770 grep (int fd, char const *file, struct stats *stats)
771 {
772   int nlines, i;
773   int not_text;
774   size_t residue, save;
775   char oldc;
776   char *beg;
777   char *lim;
778   char eol = eolbyte;
779 
780   if (!reset (fd, file, stats))
781     return 0;
782 
783   if (file && directories == RECURSE_DIRECTORIES
784       && S_ISDIR (stats->stat.st_mode))
785     {
786       /* Close fd now, so that we don't open a lot of file descriptors
787 	 when we recurse deeply.  */
788       if (close (fd) != 0)
789 	error (0, errno, "%s", file);
790       return grepdir (file, stats) - 2;
791     }
792 
793   totalcc = 0;
794   lastout = 0;
795   totalnl = 0;
796   outleft = max_count;
797   after_last_match = 0;
798   pending = 0;
799 
800   nlines = 0;
801   residue = 0;
802   save = 0;
803 
804   if (! fillbuf (save, stats))
805     {
806       if (! is_EISDIR (errno, file))
807 	suppressible_error (filename, errno);
808       return 0;
809     }
810 
811   not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
812 	       || binary_files == WITHOUT_MATCH_BINARY_FILES)
813 	      && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
814   if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
815     return 0;
816   done_on_match += not_text;
817   out_quiet += not_text;
818 
819   for (;;)
820     {
821       lastnl = bufbeg;
822       if (lastout)
823 	lastout = bufbeg;
824 
825       beg = bufbeg + save;
826 
827       /* no more data to scan (eof) except for maybe a residue -> break */
828       if (beg == buflim)
829 	break;
830 
831       /* Determine new residue (the length of an incomplete line at the end of
832          the buffer, 0 means there is no incomplete last line).  */
833       oldc = beg[-1];
834       beg[-1] = eol;
835       for (lim = buflim; lim[-1] != eol; lim--)
836 	continue;
837       beg[-1] = oldc;
838       if (lim == beg)
839 	lim = beg - residue;
840       beg -= residue;
841       residue = buflim - lim;
842 
843       if (beg < lim)
844 	{
845 	  if (outleft)
846 	    nlines += grepbuf (beg, lim);
847 	  if (pending)
848 	    prpending (lim);
849 	  if((!outleft && !pending) || (nlines && done_on_match && !out_invert))
850 	    goto finish_grep;
851 	}
852 
853       /* The last OUT_BEFORE lines at the end of the buffer will be needed as
854 	 leading context if there is a matching line at the begin of the
855 	 next data. Make beg point to their begin.  */
856       i = 0;
857       beg = lim;
858       while (i < out_before && beg > bufbeg && beg != lastout)
859 	{
860 	  ++i;
861 	  do
862 	    --beg;
863 	  while (beg[-1] != eol);
864 	}
865 
866       /* detect if leading context is discontinuous from last printed line.  */
867       if (beg != lastout)
868 	lastout = 0;
869 
870       /* Handle some details and read more data to scan.  */
871       save = residue + lim - beg;
872       if (out_byte)
873 	totalcc = add_count (totalcc, buflim - bufbeg - save);
874       if (out_line)
875 	nlscan (beg);
876       if (! fillbuf (save, stats))
877 	{
878 	  if (! is_EISDIR (errno, file))
879 	    suppressible_error (filename, errno);
880 	  goto finish_grep;
881 	}
882     }
883   if (residue)
884     {
885       *buflim++ = eol;
886       if (outleft)
887 	nlines += grepbuf (bufbeg + save - residue, buflim);
888       if (pending)
889         prpending (buflim);
890     }
891 
892  finish_grep:
893   done_on_match -= not_text;
894   out_quiet -= not_text;
895   if ((not_text & ~out_quiet) && nlines != 0)
896     printf (_("Binary file %s matches\n"), filename);
897   return nlines;
898 }
899 
900 static int
grepfile(char const * file,struct stats * stats)901 grepfile (char const *file, struct stats *stats)
902 {
903   int desc;
904   int count;
905   int status;
906 
907   if (! file)
908     {
909       desc = 0;
910       filename = label ? label : _("(standard input)");
911     }
912   else
913     {
914       while ((desc = open (file, O_RDONLY | O_NONBLOCK)) < 0 && errno == EINTR)
915 	continue;
916 
917       if (desc >= 0 && (status = fcntl (desc, F_GETFL, 0)) != -1)
918 	fcntl (desc, F_SETFL,  status & ~O_NONBLOCK);
919 
920       if (desc < 0)
921 	{
922 	  int e = errno;
923 
924 	  if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
925 	    {
926 	      if (stat (file, &stats->stat) != 0)
927 		{
928 		  error (0, errno, "%s", file);
929 		  return 1;
930 		}
931 
932 	      return grepdir (file, stats);
933 	    }
934 
935 	  if (!suppress_errors)
936 	    {
937 	      if (directories == SKIP_DIRECTORIES)
938 		switch (e)
939 		  {
940 #if defined(EISDIR)
941 		  case EISDIR:
942 		    return 1;
943 #endif
944 		  case EACCES:
945 		    /* When skipping directories, don't worry about
946 		       directories that can't be opened.  */
947 		    if (isdir (file))
948 		      return 1;
949 		    break;
950 		  }
951 	    }
952 
953 	  suppressible_error (file, e);
954 	  return 1;
955 	}
956 
957       filename = file;
958     }
959 
960 #if defined(SET_BINARY)
961   /* Set input to binary mode.  Pipes are simulated with files
962      on DOS, so this includes the case of "foo | grep bar".  */
963   if (!isatty (desc))
964     SET_BINARY (desc);
965 #endif
966 
967   count = grep (desc, file, stats);
968   if (count < 0)
969     status = count + 2;
970   else
971     {
972       if (count_matches)
973 	{
974 	  if (out_file)
975 	    printf ("%s%c", filename, ':' & filename_mask);
976 	  printf ("%d\n", count);
977 	}
978 
979       status = !count;
980       if (list_files == 1 - 2 * status)
981 	printf ("%s%c", filename, '\n' & filename_mask);
982 
983       if (! file)
984 	{
985 	  off_t required_offset = outleft ? bufoffset : after_last_match;
986 	  if ((bufmapped || required_offset != bufoffset)
987 	      && lseek (desc, required_offset, SEEK_SET) < 0
988 	      && S_ISREG (stats->stat.st_mode))
989 	    error (0, errno, "%s", filename);
990 	}
991       else
992 	while (close (desc) != 0)
993 	  if (errno != EINTR)
994 	    {
995 	      error (0, errno, "%s", file);
996 	      break;
997 	    }
998     }
999 
1000   return status;
1001 }
1002 
1003 static int
grepdir(char const * dir,struct stats const * stats)1004 grepdir (char const *dir, struct stats const *stats)
1005 {
1006   int status = 1;
1007   struct stats const *ancestor;
1008   char *name_space;
1009 
1010   /* Mingw32 does not support st_ino.  No known working hosts use zero
1011      for st_ino, so assume that the Mingw32 bug applies if it's zero.  */
1012   if (stats->stat.st_ino)
1013     for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
1014       if (ancestor->stat.st_ino == stats->stat.st_ino
1015 	  && ancestor->stat.st_dev == stats->stat.st_dev)
1016 	{
1017 	  if (!suppress_errors)
1018 	    error (0, 0, _("warning: %s: %s"), dir,
1019 		   _("recursive directory loop"));
1020 	  return 1;
1021 	}
1022 
1023   name_space = savedir (dir, stats->stat.st_size, included_patterns,
1024 			excluded_patterns);
1025 
1026   if (! name_space)
1027     {
1028       if (errno)
1029 	suppressible_error (dir, errno);
1030       else
1031 	xalloc_die ();
1032     }
1033   else
1034     {
1035       size_t dirlen = strlen (dir);
1036       int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
1037 			   || IS_SLASH (dir[dirlen - 1]));
1038       char *file = NULL;
1039       char const *namep = name_space;
1040       struct stats child;
1041       child.parent = stats;
1042       out_file += !no_filenames;
1043       while (*namep)
1044 	{
1045 	  size_t namelen = strlen (namep);
1046 	  file = xrealloc (file, dirlen + 1 + namelen + 1);
1047 	  strcpy (file, dir);
1048 	  file[dirlen] = '/';
1049 	  strcpy (file + dirlen + needs_slash, namep);
1050 	  namep += namelen + 1;
1051 	  status &= grepfile (file, &child);
1052 	}
1053       out_file -= !no_filenames;
1054       if (file)
1055         free (file);
1056       free (name_space);
1057     }
1058 
1059   return status;
1060 }
1061 
1062 static void
usage(int status)1063 usage (int status)
1064 {
1065   if (status != 0)
1066     {
1067       fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
1068 	       program_name);
1069       fprintf (stderr, _("Try `%s --help' for more information.\n"),
1070 	       program_name);
1071     }
1072   else
1073     {
1074       printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name);
1075       printf (_("\
1076 Search for PATTERN in each FILE or standard input.\n\
1077 Example: %s -i 'hello world' menu.h main.c\n\
1078 \n\
1079 Regexp selection and interpretation:\n"), program_name);
1080       printf (_("\
1081   -E, --extended-regexp     PATTERN is an extended regular expression\n\
1082   -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
1083   -G, --basic-regexp        PATTERN is a basic regular expression\n"));
1084 #if HAVE_LIBPCRE
1085       printf (_("\
1086   -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
1087 #endif
1088       printf (_("\
1089   -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
1090   -f, --file=FILE           obtain PATTERN from FILE\n\
1091   -i, --ignore-case         ignore case distinctions\n\
1092   -w, --word-regexp         force PATTERN to match only whole words\n\
1093   -x, --line-regexp         force PATTERN to match only whole lines\n\
1094   -z, --null-data           a data line ends in 0 byte, not newline\n"));
1095       printf (_("\
1096 \n\
1097 Miscellaneous:\n\
1098   -s, --no-messages         suppress error messages\n\
1099   -v, --invert-match        select non-matching lines\n\
1100   -V, --version             print version information and exit\n\
1101       --help                display this help and exit\n\
1102       --mmap                use memory-mapped input if possible\n"));
1103       printf (_("\
1104 \n\
1105 Output control:\n\
1106   -m, --max-count=NUM       stop after NUM matches\n\
1107   -b, --byte-offset         print the byte offset with output lines\n\
1108   -n, --line-number         print line number with output lines\n\
1109       --line-buffered       flush output on every line\n\
1110   -H, --with-filename       print the filename for each match\n\
1111   -h, --no-filename         suppress the prefixing filename on output\n\
1112       --label=LABEL         print LABEL as filename for standard input\n\
1113   -o, --only-matching       show only the part of a line matching PATTERN\n\
1114   -q, --quiet, --silent     suppress all normal output\n\
1115       --binary-files=TYPE   assume that binary files are TYPE\n\
1116                             TYPE is 'binary', 'text', or 'without-match'\n\
1117   -a, --text                equivalent to --binary-files=text\n\
1118   -I                        equivalent to --binary-files=without-match\n\
1119   -d, --directories=ACTION  how to handle directories\n\
1120                             ACTION is 'read', 'recurse', or 'skip'\n\
1121   -D, --devices=ACTION      how to handle devices, FIFOs and sockets\n\
1122                             ACTION is 'read' or 'skip'\n\
1123   -R, -r, --recursive       equivalent to --directories=recurse\n\
1124       --include=PATTERN     files that match PATTERN will be examined\n\
1125       --exclude=PATTERN     files that match PATTERN will be skipped.\n\
1126       --exclude-from=FILE   files that match PATTERN in FILE will be skipped.\n\
1127   -L, --files-without-match only print FILE names containing no match\n\
1128   -l, --files-with-matches  only print FILE names containing matches\n\
1129   -c, --count               only print a count of matching lines per FILE\n\
1130   -Z, --null                print 0 byte after FILE name\n"));
1131       printf (_("\
1132 \n\
1133 Context control:\n\
1134   -B, --before-context=NUM  print NUM lines of leading context\n\
1135   -A, --after-context=NUM   print NUM lines of trailing context\n\
1136   -C, --context=NUM         print NUM lines of output context\n\
1137   -NUM                      same as --context=NUM\n\
1138       --color[=WHEN],\n\
1139       --colour[=WHEN]       use markers to distinguish the matching string\n\
1140                             WHEN may be `always', `never' or `auto'.\n\
1141   -U, --binary              do not strip CR characters at EOL (MSDOS)\n\
1142   -u, --unix-byte-offsets   report offsets as if CRs were not there (MSDOS)\n\
1143 \n\
1144 `egrep' means `grep -E'.  `fgrep' means `grep -F'.\n\
1145 With no FILE, or when FILE is -, read standard input.  If less than\n\
1146 two FILEs given, assume -h.  Exit status is 0 if match, 1 if no match,\n\
1147 and 2 if trouble.\n"));
1148       printf (_("\nReport bugs to <bug-grep@gnu.org>.\n"));
1149     }
1150   exit (status);
1151 }
1152 
1153 /* Set the matcher to M, reporting any conflicts.  */
1154 static void
setmatcher(char const * m)1155 setmatcher (char const *m)
1156 {
1157   if (matcher && strcmp (matcher, m) != 0)
1158     error (2, 0, _("conflicting matchers specified"));
1159   matcher = m;
1160 }
1161 
1162 /* Go through the matchers vector and look for the specified matcher.
1163    If we find it, install it in compile and execute, and return 1.  */
1164 static int
install_matcher(char const * name)1165 install_matcher (char const *name)
1166 {
1167   int i;
1168 #if defined(HAVE_SETRLIMIT)
1169   struct rlimit rlim;
1170 #endif
1171 
1172   for (i = 0; matchers[i].compile; i++)
1173     if (strcmp (name, matchers[i].name) == 0)
1174       {
1175 	compile = matchers[i].compile;
1176 	execute = matchers[i].execute;
1177 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
1178 	/* I think every platform needs to do this, so that regex.c
1179 	   doesn't oveflow the stack.  The default value of
1180 	   `re_max_failures' is too large for some platforms: it needs
1181 	   more than 3MB-large stack.
1182 
1183 	   The test for HAVE_SETRLIMIT should go into `configure'.  */
1184 	if (!getrlimit (RLIMIT_STACK, &rlim))
1185 	  {
1186 	    long newlim;
1187 	    extern long int re_max_failures; /* from regex.c */
1188 
1189 	    /* Approximate the amount regex.c needs, plus some more.  */
1190 	    newlim = re_max_failures * 2 * 20 * sizeof (char *);
1191 	    if (newlim > rlim.rlim_max)
1192 	      {
1193 		newlim = rlim.rlim_max;
1194 		re_max_failures = newlim / (2 * 20 * sizeof (char *));
1195 	      }
1196 	    if (rlim.rlim_cur < newlim)
1197 	      {
1198 		rlim.rlim_cur = newlim;
1199 		setrlimit (RLIMIT_STACK, &rlim);
1200 	      }
1201 	  }
1202 #endif
1203 	return 1;
1204       }
1205   return 0;
1206 }
1207 
1208 /* Find the white-space-separated options specified by OPTIONS, and
1209    using BUF to store copies of these options, set ARGV[0], ARGV[1],
1210    etc. to the option copies.  Return the number N of options found.
1211    Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
1212    etc.  Backslash can be used to escape whitespace (and backslashes).  */
1213 static int
prepend_args(char const * options,char * buf,char ** argv)1214 prepend_args (char const *options, char *buf, char **argv)
1215 {
1216   char const *o = options;
1217   char *b = buf;
1218   int n = 0;
1219 
1220   for (;;)
1221     {
1222       while (ISSPACE ((unsigned char) *o))
1223 	o++;
1224       if (!*o)
1225 	return n;
1226       if (argv)
1227 	argv[n] = b;
1228       n++;
1229 
1230       do
1231 	if ((*b++ = *o++) == '\\' && *o)
1232 	  b[-1] = *o++;
1233       while (*o && ! ISSPACE ((unsigned char) *o));
1234 
1235       *b++ = '\0';
1236     }
1237 }
1238 
1239 /* Prepend the whitespace-separated options in OPTIONS to the argument
1240    vector of a main program with argument count *PARGC and argument
1241    vector *PARGV.  */
1242 static void
prepend_default_options(char const * options,int * pargc,char *** pargv)1243 prepend_default_options (char const *options, int *pargc, char ***pargv)
1244 {
1245   if (options)
1246     {
1247       char *buf = xmalloc (strlen (options) + 1);
1248       int prepended = prepend_args (options, buf, (char **) NULL);
1249       int argc = *pargc;
1250       char * const *argv = *pargv;
1251       char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
1252       *pargc = prepended + argc;
1253       *pargv = pp;
1254       *pp++ = *argv++;
1255       pp += prepend_args (options, buf, pp);
1256       while ((*pp++ = *argv++))
1257 	continue;
1258     }
1259 }
1260 
1261 /* Get the next non-digit option from ARGC and ARGV.
1262    Return -1 if there are no more options.
1263    Process any digit options that were encountered on the way,
1264    and store the resulting integer into *DEFAULT_CONTEXT.  */
1265 static int
get_nondigit_option(int argc,char * const * argv,int * default_context)1266 get_nondigit_option (int argc, char *const *argv, int *default_context)
1267 {
1268   int opt;
1269   char buf[sizeof (uintmax_t) * CHAR_BIT + 4];
1270   char *p = buf;
1271 
1272   /* Set buf[0] to anything but '0', for the leading-zero test below.  */
1273   buf[0] = '\0';
1274 
1275   while (opt = getopt_long (argc, argv, short_options, long_options, NULL),
1276 	 '0' <= opt && opt <= '9')
1277     {
1278       /* Suppress trivial leading zeros, to avoid incorrect
1279 	 diagnostic on strings like 00000000000.  */
1280       p -= buf[0] == '0';
1281 
1282       *p++ = opt;
1283       if (p == buf + sizeof buf - 4)
1284 	{
1285 	  /* Too many digits.  Append "..." to make context_length_arg
1286 	     complain about "X...", where X contains the digits seen
1287 	     so far.  */
1288 	  strcpy (p, "...");
1289 	  p += 3;
1290 	  break;
1291 	}
1292     }
1293   if (p != buf)
1294     {
1295       *p = '\0';
1296       context_length_arg (buf, default_context);
1297     }
1298 
1299   return opt;
1300 }
1301 
1302 int
main(int argc,char ** argv)1303 main (int argc, char **argv)
1304 {
1305   char *keys;
1306   size_t cc, keycc, oldcc, keyalloc;
1307   int with_filenames;
1308   int opt, status;
1309   int default_context;
1310   FILE *fp;
1311   extern char *optarg;
1312   extern int optind;
1313 #ifdef __NetBSD__
1314   extern char *__progname;
1315 #endif
1316 
1317   initialize_main (&argc, &argv);
1318   program_name = argv[0];
1319   if (program_name && strrchr (program_name, '/'))
1320     program_name = strrchr (program_name, '/') + 1;
1321 
1322   if (!strcmp(program_name, "egrep"))
1323     setmatcher ("egrep");
1324   if (!strcmp(program_name, "fgrep"))
1325     setmatcher ("fgrep");
1326 
1327 #if defined(__MSDOS__) || defined(_WIN32)
1328   /* DOS and MS-Windows use backslashes as directory separators, and usually
1329      have an .exe suffix.  They also have case-insensitive filesystems.  */
1330   if (program_name)
1331     {
1332       char *p = program_name;
1333       char *bslash = strrchr (argv[0], '\\');
1334 
1335       if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
1336 	program_name = bslash + 1;
1337       else if (program_name == argv[0]
1338 	       && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
1339 	program_name = argv[0] + 2;
1340 
1341       /* Collapse the letter-case, so `strcmp' could be used hence.  */
1342       for ( ; *p; p++)
1343 	if (*p >= 'A' && *p <= 'Z')
1344 	  *p += 'a' - 'A';
1345 
1346       /* Remove the .exe extension, if any.  */
1347       if ((p = strrchr (program_name, '.')) && strcmp (p, ".exe") == 0)
1348 	*p = '\0';
1349     }
1350 #endif
1351 
1352   keys = NULL;
1353   keycc = 0;
1354   with_filenames = 0;
1355   eolbyte = '\n';
1356   filename_mask = ~0;
1357 
1358   max_count = MAX_OFF_T;
1359 
1360   /* The value -1 means to use DEFAULT_CONTEXT. */
1361   out_after = out_before = -1;
1362   /* Default before/after context: chaged by -C/-NUM options */
1363   default_context = 0;
1364   /* Changed by -o option */
1365   only_matching = 0;
1366 
1367   /* Internationalization. */
1368 #if defined(HAVE_SETLOCALE)
1369   setlocale (LC_ALL, "");
1370 #endif
1371 #if defined(ENABLE_NLS)
1372   bindtextdomain (PACKAGE, LOCALEDIR);
1373   textdomain (PACKAGE);
1374 #endif
1375 
1376   atexit (close_stdout);
1377 
1378   prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
1379 
1380   while ((opt = get_nondigit_option (argc, argv, &default_context)) != -1)
1381     switch (opt)
1382       {
1383       case 'A':
1384 	context_length_arg (optarg, &out_after);
1385 	break;
1386 
1387       case 'B':
1388 	context_length_arg (optarg, &out_before);
1389 	break;
1390 
1391       case 'C':
1392 	/* Set output match context, but let any explicit leading or
1393 	   trailing amount specified with -A or -B stand. */
1394 	context_length_arg (optarg, &default_context);
1395 	break;
1396 
1397       case 'D':
1398 	if (strcmp (optarg, "read") == 0)
1399 	  devices = READ_DEVICES;
1400 	else if (strcmp (optarg, "skip") == 0)
1401 	  devices = SKIP_DEVICES;
1402 	else
1403 	  error (2, 0, _("unknown devices method"));
1404 	break;
1405 
1406       case 'E':
1407 	setmatcher ("egrep");
1408 	break;
1409 
1410       case 'F':
1411 	setmatcher ("fgrep");
1412 	break;
1413 
1414       case 'P':
1415 	setmatcher ("perl");
1416 	break;
1417 
1418       case 'G':
1419 	setmatcher ("grep");
1420 	break;
1421 
1422       case 'H':
1423 	with_filenames = 1;
1424 	break;
1425 
1426       case 'I':
1427 	binary_files = WITHOUT_MATCH_BINARY_FILES;
1428 	break;
1429 
1430       case 'U':
1431 #if defined(HAVE_DOS_FILE_CONTENTS)
1432 	dos_use_file_type = DOS_BINARY;
1433 #endif
1434 	break;
1435 
1436       case 'u':
1437 #if defined(HAVE_DOS_FILE_CONTENTS)
1438 	dos_report_unix_offset = 1;
1439 #endif
1440 	break;
1441 
1442       case 'V':
1443 	show_version = 1;
1444 	break;
1445 
1446       case 'X':
1447 	setmatcher (optarg);
1448 	break;
1449 
1450       case 'a':
1451 	binary_files = TEXT_BINARY_FILES;
1452 	break;
1453 
1454       case 'b':
1455 	out_byte = 1;
1456 	break;
1457 
1458       case 'c':
1459 	count_matches = 1;
1460 	break;
1461 
1462       case 'd':
1463 	if (strcmp (optarg, "read") == 0)
1464 	  directories = READ_DIRECTORIES;
1465 	else if (strcmp (optarg, "skip") == 0)
1466 	  directories = SKIP_DIRECTORIES;
1467 	else if (strcmp (optarg, "recurse") == 0)
1468 	  directories = RECURSE_DIRECTORIES;
1469 	else
1470 	  error (2, 0, _("unknown directories method"));
1471 	break;
1472 
1473       case 'e':
1474 	cc = strlen (optarg);
1475 	keys = xrealloc (keys, keycc + cc + 1);
1476 	strcpy (&keys[keycc], optarg);
1477 	keycc += cc;
1478 	keys[keycc++] = '\n';
1479 	break;
1480 
1481       case 'f':
1482 	fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
1483 	if (!fp)
1484 	  error (2, errno, "%s", optarg);
1485 	for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
1486 	  ;
1487 	keys = xrealloc (keys, keyalloc);
1488 	oldcc = keycc;
1489 	while (!feof (fp)
1490 	       && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
1491 	  {
1492 	    keycc += cc;
1493 	    if (keycc == keyalloc - 1)
1494 	      keys = xrealloc (keys, keyalloc *= 2);
1495 	  }
1496 	if (fp != stdin)
1497 	  fclose(fp);
1498 	/* Append final newline if file ended in non-newline. */
1499 	if (oldcc != keycc && keys[keycc - 1] != '\n')
1500 	  keys[keycc++] = '\n';
1501 	break;
1502 
1503       case 'h':
1504 	no_filenames = 1;
1505 	break;
1506 
1507       case 'i':
1508       case 'y':			/* For old-timers . . . */
1509 	match_icase = 1;
1510 	break;
1511 
1512       case 'L':
1513 	/* Like -l, except list files that don't contain matches.
1514 	   Inspired by the same option in Hume's gre. */
1515 	list_files = -1;
1516 	break;
1517 
1518       case 'l':
1519 	list_files = 1;
1520 	break;
1521 
1522       case 'm':
1523 	{
1524 	  uintmax_t value;
1525 	  switch (xstrtoumax (optarg, 0, 10, &value, ""))
1526 	    {
1527 	    case LONGINT_OK:
1528 	      max_count = value;
1529 	      if (0 <= max_count && max_count == value)
1530 		break;
1531 	      /* Fall through.  */
1532 	    case LONGINT_OVERFLOW:
1533 	      max_count = MAX_OFF_T;
1534 	      break;
1535 
1536 	    default:
1537 	      error (2, 0, _("invalid max count"));
1538 	    }
1539 	}
1540 	break;
1541 
1542       case 'n':
1543 	out_line = 1;
1544 	break;
1545 
1546       case 'o':
1547 	only_matching = 1;
1548 	break;
1549 
1550       case 'q':
1551 	exit_on_match = 1;
1552 	close_stdout_set_status(0);
1553 	break;
1554 
1555       case 'R':
1556       case 'r':
1557 	directories = RECURSE_DIRECTORIES;
1558 	break;
1559 
1560       case 's':
1561 	suppress_errors = 1;
1562 	break;
1563 
1564       case 'v':
1565 	out_invert = 1;
1566 	break;
1567 
1568       case 'w':
1569 	match_words = 1;
1570 	break;
1571 
1572       case 'x':
1573 	match_lines = 1;
1574 	break;
1575 
1576       case 'Z':
1577 	filename_mask = 0;
1578 	break;
1579 
1580       case 'z':
1581 	eolbyte = '\0';
1582 	break;
1583 
1584       case BINARY_FILES_OPTION:
1585 	if (strcmp (optarg, "binary") == 0)
1586 	  binary_files = BINARY_BINARY_FILES;
1587 	else if (strcmp (optarg, "text") == 0)
1588 	  binary_files = TEXT_BINARY_FILES;
1589 	else if (strcmp (optarg, "without-match") == 0)
1590 	  binary_files = WITHOUT_MATCH_BINARY_FILES;
1591 	else
1592 	  error (2, 0, _("unknown binary-files type"));
1593 	break;
1594 
1595       case COLOR_OPTION:
1596         if(optarg) {
1597           if(!strcasecmp(optarg, "always") || !strcasecmp(optarg, "yes") ||
1598              !strcasecmp(optarg, "force"))
1599             color_option = 1;
1600           else if(!strcasecmp(optarg, "never") || !strcasecmp(optarg, "no") ||
1601                   !strcasecmp(optarg, "none"))
1602             color_option = 0;
1603           else if(!strcasecmp(optarg, "auto") || !strcasecmp(optarg, "tty") ||
1604                   !strcasecmp(optarg, "if-tty"))
1605             color_option = 2;
1606           else
1607             show_help = 1;
1608         } else
1609           color_option = 2;
1610         if(color_option == 2) {
1611           if(isatty(STDOUT_FILENO) && getenv("TERM") &&
1612 	     strcmp(getenv("TERM"), "dumb"))
1613                   color_option = 1;
1614           else
1615             color_option = 0;
1616         }
1617 	break;
1618 
1619       case EXCLUDE_OPTION:
1620 	if (!excluded_patterns)
1621 	  excluded_patterns = new_exclude ();
1622 	add_exclude (excluded_patterns, optarg);
1623 	break;
1624 
1625       case EXCLUDE_FROM_OPTION:
1626 	if (!excluded_patterns)
1627 	  excluded_patterns = new_exclude ();
1628         if (add_exclude_file (add_exclude, excluded_patterns, optarg, '\n')
1629 	    != 0)
1630           {
1631             error (2, errno, "%s", optarg);
1632           }
1633         break;
1634 
1635       case INCLUDE_OPTION:
1636 	if (!included_patterns)
1637 	  included_patterns = new_exclude ();
1638 	add_exclude (included_patterns, optarg);
1639 	break;
1640 
1641       case LINE_BUFFERED_OPTION:
1642 	line_buffered = 1;
1643 	break;
1644 
1645       case LABEL_OPTION:
1646 	label = optarg;
1647 	break;
1648 
1649       case 0:
1650 	/* long options */
1651 	break;
1652 
1653       default:
1654 	usage (2);
1655 	break;
1656 
1657       }
1658 
1659   /* POSIX.2 says that -q overrides -l, which in turn overrides the
1660      other output options.  */
1661   if (exit_on_match)
1662     list_files = 0;
1663   if (exit_on_match | list_files)
1664     {
1665       count_matches = 0;
1666       done_on_match = 1;
1667     }
1668   out_quiet = count_matches | done_on_match;
1669 
1670   if (out_after < 0)
1671     out_after = default_context;
1672   if (out_before < 0)
1673     out_before = default_context;
1674 
1675   if (color_option)
1676     {
1677       char *userval = getenv ("GREP_COLOR");
1678       if (userval != NULL && *userval != '\0')
1679 	grep_color = userval;
1680     }
1681 
1682   if (! matcher)
1683 #ifdef __NetBSD__
1684     matcher = __progname;
1685 #else
1686     matcher = "grep";
1687 #endif
1688 
1689   if (show_version)
1690     {
1691       printf (_("%s (GNU grep) %s\n"), matcher, VERSION);
1692       printf ("\n");
1693       printf (_("\
1694 Copyright 1988, 1992-1999, 2000, 2001 Free Software Foundation, Inc.\n"));
1695       printf (_("\
1696 This is free software; see the source for copying conditions. There is NO\n\
1697 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
1698       printf ("\n");
1699       exit (0);
1700     }
1701 
1702   if (show_help)
1703     usage (0);
1704 
1705   if (keys)
1706     {
1707       if (keycc == 0)
1708 	{
1709 	  /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
1710 	  out_invert ^= 1;
1711 	  match_lines = match_words = 0;
1712 	}
1713       else
1714 	/* Strip trailing newline. */
1715         --keycc;
1716     }
1717   else
1718     if (optind < argc)
1719       {
1720 	keys = argv[optind++];
1721 	keycc = strlen (keys);
1722       }
1723     else
1724       usage (2);
1725 
1726   if (!install_matcher (matcher) && !install_matcher ("default"))
1727     abort ();
1728 
1729   (*compile)(keys, keycc);
1730 
1731   if ((argc - optind > 1 && !no_filenames) || with_filenames)
1732     out_file = 1;
1733 
1734 #ifdef SET_BINARY
1735   /* Output is set to binary mode because we shouldn't convert
1736      NL to CR-LF pairs, especially when grepping binary files.  */
1737   if (!isatty (1))
1738     SET_BINARY (1);
1739 #endif
1740 
1741   if (max_count == 0)
1742     exit (1);
1743 
1744   if (optind < argc)
1745     {
1746 	status = 1;
1747 	do
1748 	{
1749 	  char *file = argv[optind];
1750 	  if ((included_patterns || excluded_patterns)
1751 	      && !isdir (file))
1752 	    {
1753 	      if (included_patterns &&
1754 		  ! excluded_filename (included_patterns, file, 0))
1755 		continue;
1756 	      if (excluded_patterns &&
1757 		  excluded_filename (excluded_patterns, file, 0))
1758 		continue;
1759 	    }
1760 	  status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
1761 			      &stats_base);
1762 	}
1763 	while ( ++optind < argc);
1764     }
1765   else
1766     {
1767       status = grepfile(directories == RECURSE_DIRECTORIES ? "." : (char *) NULL,
1768 			&stats_base);
1769     }
1770 
1771   /* We register via atexit() to test stdout.  */
1772   exit (errseen ? 2 : status);
1773 }
1774 /* vim:set shiftwidth=2: */
1775