Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / gnu / usr.bin / grep / grep.c
1 /* grep.c - main driver file for grep.
2    Copyright (C) 1992, 1997, 1998, 1999 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17    02111-1307, USA.  */
18
19 /* Written July 1992 by Mike Haertel.  */
20 /* Builtin decompression 1997 by Wolfram Schneider <wosch@FreeBSD.org>.  */
21
22 /* $FreeBSD: src/gnu/usr.bin/grep/grep.c,v 1.20.2.1 2000/06/13 07:17:27 ru Exp $ */
23 /* $DragonFly: src/gnu/usr.bin/grep/grep.c,v 1.2 2003/06/17 04:25:45 dillon Exp $ */
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #if defined(HAVE_MMAP)
31 # include <sys/mman.h>
32 #endif
33 #if defined(HAVE_SETRLIMIT)
34 # include <sys/time.h>
35 # include <sys/resource.h>
36 #endif
37 #include <stdio.h>
38 #include "system.h"
39 #include "getopt.h"
40 #include "getpagesize.h"
41 #include "grep.h"
42 #include "savedir.h"
43
44 #undef MAX
45 #define MAX(A,B) ((A) > (B) ? (A) : (B))
46
47 struct stats
48 {
49   struct stats *parent;
50   struct stat stat;
51 };
52
53 /* base of chain of stat buffers, used to detect directory loops */
54 static struct stats stats_base;
55
56 /* if non-zero, display usage information and exit */
57 static int show_help;
58
59 /* If non-zero, print the version on standard output and exit.  */
60 static int show_version;
61
62 /* If nonzero, use mmap if possible.  */
63 static int mmap_option;
64
65 /* If zero, output nulls after filenames.  */
66 static int filename_mask;
67
68 /* Short options.  */
69 static char const short_options[] =
70 "0123456789A:B:C::EFGHIRUVX:abcd:e:f:hiLlnqrsuvwxyZz";
71
72 /* Non-boolean long options that have no corresponding short equivalents.  */
73 enum
74 {
75   BINARY_FILES_OPTION = CHAR_MAX + 1
76 };
77
78 /* Long options equivalences. */
79 static struct option long_options[] =
80 {
81   {"after-context", required_argument, NULL, 'A'},
82   {"basic-regexp", no_argument, NULL, 'G'},
83   {"before-context", required_argument, NULL, 'B'},
84   {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},
85   {"byte-offset", no_argument, NULL, 'b'},
86   {"context", optional_argument, NULL, 'C'},
87   {"count", no_argument, NULL, 'c'},
88   {"directories", required_argument, NULL, 'd'},
89   {"extended-regexp", no_argument, NULL, 'E'},
90   {"file", required_argument, NULL, 'f'},
91   {"files-with-matches", no_argument, NULL, 'l'},
92   {"files-without-match", no_argument, NULL, 'L'},
93   {"fixed-regexp", no_argument, NULL, 'F'},
94   {"fixed-strings", no_argument, NULL, 'F'},
95   {"help", no_argument, &show_help, 1},
96   {"ignore-case", no_argument, NULL, 'i'},
97   {"line-number", no_argument, NULL, 'n'},
98   {"line-regexp", no_argument, NULL, 'x'},
99   {"mmap", no_argument, &mmap_option, 1},
100   {"no-filename", no_argument, NULL, 'h'},
101   {"no-messages", no_argument, NULL, 's'},
102 #if HAVE_LIBZ > 0
103   {"decompress", no_argument, NULL, 'Z'},
104   {"null", no_argument, &filename_mask, 0},
105 #else
106   {"null", no_argument, NULL, 'Z'},
107 #endif
108   {"null-data", no_argument, NULL, 'z'},
109   {"quiet", no_argument, NULL, 'q'},
110   {"recursive", no_argument, NULL, 'r'},
111   {"regexp", required_argument, NULL, 'e'},
112   {"invert-match", no_argument, NULL, 'v'},
113   {"silent", no_argument, NULL, 'q'},
114   {"text", no_argument, NULL, 'a'},
115   {"binary", no_argument, NULL, 'U'},
116   {"unix-byte-offsets", no_argument, NULL, 'u'},
117   {"version", no_argument, NULL, 'V'},
118   {"with-filename", no_argument, NULL, 'H'},
119   {"word-regexp", no_argument, NULL, 'w'},
120   {0, 0, 0, 0}
121 };
122
123 /* Define flags declared in grep.h. */
124 char const *matcher;
125 int match_icase;
126 int match_words;
127 int match_lines;
128 unsigned char eolbyte;
129
130 /* For error messages. */
131 static char *prog;
132 static char const *filename;
133 static int errseen;
134
135 /* How to handle directories.  */
136 static enum
137   {
138     READ_DIRECTORIES,
139     RECURSE_DIRECTORIES,
140     SKIP_DIRECTORIES
141   } directories;
142
143 static int  ck_atoi PARAMS ((char const *, int *));
144 static void usage PARAMS ((int)) __attribute__((noreturn));
145 static void error PARAMS ((const char *, int));
146 static void setmatcher PARAMS ((char const *));
147 static int  install_matcher PARAMS ((char const *));
148 static int  prepend_args PARAMS ((char const *, char *, char **));
149 static void prepend_default_options PARAMS ((char const *, int *, char ***));
150 static char *page_alloc PARAMS ((size_t, char **));
151 static int  reset PARAMS ((int, char const *, struct stats *));
152 static int  fillbuf PARAMS ((size_t, struct stats *));
153 static int  grepbuf PARAMS ((char *, char *));
154 static void prtext PARAMS ((char *, char *, int *));
155 static void prpending PARAMS ((char *));
156 static void prline PARAMS ((char *, char *, int));
157 static void print_offset_sep PARAMS ((off_t, int));
158 static void nlscan PARAMS ((char *));
159 static int  grep PARAMS ((int, char const *, struct stats *));
160 static int  grepdir PARAMS ((char const *, struct stats *));
161 static int  grepfile PARAMS ((char const *, struct stats *));
162 #if O_BINARY
163 static inline int undossify_input PARAMS ((register char *, size_t));
164 #endif
165
166 /* Functions we'll use to search. */
167 static void (*compile) PARAMS ((char *, size_t));
168 static char *(*execute) PARAMS ((char *, size_t, char **));
169
170 /* Print a message and possibly an error string.  Remember
171    that something awful happened. */
172 static void
173 error (const char *mesg, int errnum)
174 {
175   if (errnum)
176     fprintf (stderr, "%s: %s: %s\n", prog, mesg, strerror (errnum));
177   else
178     fprintf (stderr, "%s: %s\n", prog, mesg);
179   errseen = 1;
180 }
181
182 /* Like error (), but die horribly after printing. */
183 void
184 fatal (const char *mesg, int errnum)
185 {
186   error (mesg, errnum);
187   exit (2);
188 }
189
190 /* Interface to handle errors and fix library lossage. */
191 char *
192 xmalloc (size_t size)
193 {
194   char *result;
195
196   result = malloc (size);
197   if (size && !result)
198     fatal (_("memory exhausted"), 0);
199   return result;
200 }
201
202 /* Interface to handle errors and fix some library lossage. */
203 char *
204 xrealloc (char *ptr, size_t size)
205 {
206   char *result;
207
208   if (ptr)
209     result = realloc (ptr, size);
210   else
211     result = malloc (size);
212   if (size && !result)
213     fatal (_("memory exhausted"), 0);
214   return result;
215 }
216
217 /* Convert STR to a positive integer, storing the result in *OUT.
218    If STR is not a valid integer, return -1 (otherwise 0). */
219 static int
220 ck_atoi (char const *str, int *out)
221 {
222   char const *p;
223   for (p = str; *p; p++)
224     if (*p < '0' || *p > '9')
225       return -1;
226
227   *out = atoi (optarg);
228   return 0;
229 }
230
231
232 /* Hairy buffering mechanism for grep.  The intent is to keep
233    all reads aligned on a page boundary and multiples of the
234    page size. */
235
236 static char *ubuffer;           /* Unaligned base of buffer. */
237 static char *buffer;            /* Base of buffer. */
238 static size_t bufsalloc;        /* Allocated size of buffer save region. */
239 static size_t bufalloc;         /* Total buffer size. */
240 #define PREFERRED_SAVE_FACTOR 5 /* Preferred value of bufalloc / bufsalloc.  */
241 static int bufdesc;             /* File descriptor. */
242 static char *bufbeg;            /* Beginning of user-visible stuff. */
243 static char *buflim;            /* Limit of user-visible stuff. */
244 static size_t pagesize;         /* alignment of memory pages */
245 static off_t bufoffset;         /* Read offset; defined on regular files.  */
246
247 #if defined(HAVE_MMAP)
248 static int bufmapped;           /* True if buffer is memory-mapped.  */
249 static off_t initial_bufoffset; /* Initial value of bufoffset. */
250 #endif
251
252 #if HAVE_LIBZ > 0
253 #include <zlib.h>
254 static gzFile gzbufdesc;        /* zlib file descriptor. */
255 static int Zflag;               /* uncompress before searching. */
256 #endif
257
258 /* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be
259    an integer or a pointer.  Both args must be free of side effects.  */
260 #define ALIGN_TO(val, alignment) \
261   ((size_t) (val) % (alignment) == 0 \
262    ? (val) \
263    : (val) + ((alignment) - (size_t) (val) % (alignment)))
264
265 /* Return the address of a page-aligned buffer of size SIZE,
266    reallocating it from *UP.  Set *UP to the newly allocated (but
267    possibly unaligned) buffer used to build the aligned buffer.  To
268    free the buffer, free (*UP).  */
269 static char *
270 page_alloc (size_t size, char **up)
271 {
272   size_t asize = size + pagesize - 1;
273   if (size <= asize)
274     {
275       char *p = *up ? realloc (*up, asize) : malloc (asize);
276       if (p)
277         {
278           *up = p;
279           return ALIGN_TO (p, pagesize);
280         }
281     }
282   return NULL;
283 }
284
285 /* Reset the buffer for a new file, returning zero if we should skip it.
286    Initialize on the first time through. */
287 static int
288 reset (int fd, char const *file, struct stats *stats)
289 {
290   if (pagesize)
291     bufsalloc = ALIGN_TO (bufalloc / PREFERRED_SAVE_FACTOR, pagesize);
292   else
293     {
294       size_t ubufsalloc;
295       pagesize = getpagesize ();
296       if (pagesize == 0)
297         abort ();
298 #ifndef BUFSALLOC
299       ubufsalloc = MAX (8192, pagesize);
300 #else
301       ubufsalloc = BUFSALLOC;
302 #endif
303       bufsalloc = ALIGN_TO (ubufsalloc, pagesize);
304       bufalloc = PREFERRED_SAVE_FACTOR * bufsalloc;
305       /* The 1 byte of overflow is a kludge for dfaexec(), which
306          inserts a sentinel newline at the end of the buffer
307          being searched.  There's gotta be a better way... */
308       if (bufsalloc < ubufsalloc
309           || bufalloc / PREFERRED_SAVE_FACTOR != bufsalloc
310           || bufalloc + 1 < bufalloc
311           || ! (buffer = page_alloc (bufalloc + 1, &ubuffer)))
312         fatal (_("memory exhausted"), 0);
313     }
314 #if HAVE_LIBZ > 0
315   if (Zflag)
316     {
317     gzbufdesc = gzdopen(fd, "r");
318     if (gzbufdesc == NULL)
319       fatal(_("memory exhausted"), 0);
320     }
321 #endif
322
323   buflim = buffer;
324   bufdesc = fd;
325
326   if (fstat (fd, &stats->stat) != 0)
327     {
328       error ("fstat", errno);
329       return 0;
330     }
331   if (directories == SKIP_DIRECTORIES && S_ISDIR (stats->stat.st_mode))
332     return 0;
333   if (
334 #if HAVE_LIBZ > 0
335       Zflag ||
336 #endif
337       S_ISREG (stats->stat.st_mode))
338     {
339       if (file)
340         bufoffset = 0;
341       else
342         {
343           bufoffset = lseek (fd, 0, SEEK_CUR);
344           if (bufoffset < 0)
345             {
346               error ("lseek", errno);
347               return 0;
348             }
349         }
350 #ifdef HAVE_MMAP
351       initial_bufoffset = bufoffset;
352       bufmapped = mmap_option && bufoffset % pagesize == 0;
353 #endif
354     }
355   else
356     {
357 #ifdef HAVE_MMAP
358       bufmapped = 0;
359 #endif
360     }
361   return 1;
362 }
363
364 /* Read new stuff into the buffer, saving the specified
365    amount of old stuff.  When we're done, 'bufbeg' points
366    to the beginning of the buffer contents, and 'buflim'
367    points just after the end.  Return zero if there's an error.  */
368 static int
369 fillbuf (size_t save, struct stats *stats)
370 {
371   size_t fillsize = 0;
372   int cc = 1;
373   size_t readsize;
374
375   /* Offset from start of unaligned buffer to start of old stuff
376      that we want to save.  */
377   size_t saved_offset = buflim - ubuffer - save;
378
379   if (bufsalloc < save)
380     {
381       size_t aligned_save = ALIGN_TO (save, pagesize);
382       size_t maxalloc = (size_t) -1;
383       size_t newalloc;
384
385       if (S_ISREG (stats->stat.st_mode))
386         {
387           /* Calculate an upper bound on how much memory we should allocate.
388              We can't use ALIGN_TO here, since off_t might be longer than
389              size_t.  Watch out for arithmetic overflow.  */
390           off_t to_be_read = stats->stat.st_size - bufoffset;
391           size_t slop = to_be_read % pagesize;
392           off_t aligned_to_be_read = to_be_read + (slop ? pagesize - slop : 0);
393           off_t maxalloc_off = aligned_save + aligned_to_be_read;
394           if (0 <= maxalloc_off && maxalloc_off == (size_t) maxalloc_off)
395             maxalloc = maxalloc_off;
396         }
397
398       /* Grow bufsalloc until it is at least as great as `save'; but
399          if there is an overflow, just grow it to the next page boundary.  */
400       while (bufsalloc < save)
401         if (bufsalloc < bufsalloc * 2)
402           bufsalloc *= 2;
403         else
404           {
405             bufsalloc = aligned_save;
406             break;
407           }
408
409       /* Grow the buffer size to be PREFERRED_SAVE_FACTOR times
410          bufsalloc....  */
411       newalloc = PREFERRED_SAVE_FACTOR * bufsalloc;
412       if (maxalloc < newalloc)
413         {
414           /* ... except don't grow it more than a pagesize past the
415              file size, as that might cause unnecessary memory
416              exhaustion if the file is large.  */
417           newalloc = maxalloc;
418           bufsalloc = aligned_save;
419         }
420
421       /* Check that the above calculations made progress, which might
422          not occur if there is arithmetic overflow.  If there's no
423          progress, or if the new buffer size is larger than the old
424          and buffer reallocation fails, report memory exhaustion.  */
425       if (bufsalloc < save || newalloc < save
426           || (newalloc == save && newalloc != maxalloc)
427           || (bufalloc < newalloc
428               && ! (buffer
429                     = page_alloc ((bufalloc = newalloc) + 1, &ubuffer))))
430         fatal (_("memory exhausted"), 0);
431     }
432
433   bufbeg = buffer + bufsalloc - save;
434   memmove (bufbeg, ubuffer + saved_offset, save);
435   readsize = bufalloc - bufsalloc;
436
437 #if defined(HAVE_MMAP)
438   if (bufmapped)
439     {
440       size_t mmapsize = readsize;
441
442       /* Don't mmap past the end of the file; some hosts don't allow this.
443          Use `read' on the last page.  */
444       if (stats->stat.st_size - bufoffset < mmapsize)
445         {
446           mmapsize = stats->stat.st_size - bufoffset;
447           mmapsize -= mmapsize % pagesize;
448         }
449
450       if (mmapsize
451           && (mmap ((caddr_t) (buffer + bufsalloc), mmapsize,
452                     PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
453                     bufdesc, bufoffset)
454               != (caddr_t) -1))
455         {
456           /* Do not bother to use madvise with MADV_SEQUENTIAL or
457              MADV_WILLNEED on the mmapped memory.  One might think it
458              would help, but it slows us down about 30% on SunOS 4.1.  */
459           fillsize = mmapsize;
460         }
461       else
462         {
463           /* Stop using mmap on this file.  Synchronize the file
464              offset.  Do not warn about mmap failures.  On some hosts
465              (e.g. Solaris 2.5) mmap can fail merely because some
466              other process has an advisory read lock on the file.
467              There's no point alarming the user about this misfeature.  */
468           bufmapped = 0;
469           if (bufoffset != initial_bufoffset
470               && lseek (bufdesc, bufoffset, SEEK_SET) < 0)
471             {
472               error ("lseek", errno);
473               cc = 0;
474             }
475         }
476     }
477 #endif /*HAVE_MMAP*/
478
479   if (! fillsize)
480     {
481       ssize_t bytesread;
482       do
483 #if HAVE_LIBZ > 0
484         if (Zflag)
485           bytesread = gzread (gzbufdesc, buffer + bufsalloc, readsize);
486         else
487 #endif
488           bytesread = read (bufdesc, buffer + bufsalloc, readsize);
489       while (bytesread < 0 && errno == EINTR);
490       if (bytesread < 0)
491         cc = 0;
492       else
493         fillsize = bytesread;
494     }
495
496   bufoffset += fillsize;
497 #if O_BINARY
498   if (fillsize)
499     fillsize = undossify_input (buffer + bufsalloc, fillsize);
500 #endif
501   buflim = buffer + bufsalloc + fillsize;
502   return cc;
503 }
504
505 /* Flags controlling the style of output. */
506 static enum
507   {
508     BINARY_BINARY_FILES,
509     TEXT_BINARY_FILES,
510     WITHOUT_MATCH_BINARY_FILES
511   } binary_files;               /* How to handle binary files.  */
512 static int out_quiet;           /* Suppress all normal output. */
513 static int out_invert;          /* Print nonmatching stuff. */
514 static int out_file;            /* Print filenames. */
515 static int out_line;            /* Print line numbers. */
516 static int out_byte;            /* Print byte offsets. */
517 static int out_before;          /* Lines of leading context. */
518 static int out_after;           /* Lines of trailing context. */
519 static int count_matches;       /* Count matching lines.  */
520 static int list_files;          /* List matching files.  */
521 static int no_filenames;        /* Suppress file names.  */
522 static int suppress_errors;     /* Suppress diagnostics.  */
523
524 /* Internal variables to keep track of byte count, context, etc. */
525 static off_t totalcc;           /* Total character count before bufbeg. */
526 static char *lastnl;            /* Pointer after last newline counted. */
527 static char *lastout;           /* Pointer after last character output;
528                                    NULL if no character has been output
529                                    or if it's conceptually before bufbeg. */
530 static off_t totalnl;           /* Total newline count before lastnl. */
531 static int pending;             /* Pending lines of output. */
532 static int done_on_match;               /* Stop scanning file on first match */
533
534 #if O_BINARY
535 # include "dosbuf.c"
536 #endif
537
538 static void
539 nlscan (char *lim)
540 {
541   char *beg;
542   for (beg = lastnl;  (beg = memchr (beg, eolbyte, lim - beg));  beg++)
543     totalnl++;
544   lastnl = lim;
545 }
546
547 static void
548 print_offset_sep (off_t pos, int sep)
549 {
550   /* Do not rely on printf to print pos, since off_t may be longer than long,
551      and long long is not portable.  */
552
553   char buf[sizeof pos * CHAR_BIT];
554   char *p = buf + sizeof buf - 1;
555   *p = sep;
556
557   do
558     *--p = '0' + pos % 10;
559   while ((pos /= 10) != 0);
560
561   fwrite (p, 1, buf + sizeof buf - p, stdout);
562 }
563
564 static void
565 prline (char *beg, char *lim, int sep)
566 {
567   if (out_file)
568     printf ("%s%c", filename, sep & filename_mask);
569   if (out_line)
570     {
571       nlscan (beg);
572       print_offset_sep (++totalnl, sep);
573       lastnl = lim;
574     }
575   if (out_byte)
576     {
577       off_t pos = totalcc + (beg - bufbeg);
578 #if O_BINARY
579       pos = dossified_pos (pos);
580 #endif
581       print_offset_sep (pos, sep);
582     }
583   fwrite (beg, 1, lim - beg, stdout);
584   if (ferror (stdout))
585     error (_("writing output"), errno);
586   lastout = lim;
587 }
588
589 /* Print pending lines of trailing context prior to LIM. */
590 static void
591 prpending (char *lim)
592 {
593   char *nl;
594
595   if (!lastout)
596     lastout = bufbeg;
597   while (pending > 0 && lastout < lim)
598     {
599       --pending;
600       if ((nl = memchr (lastout, eolbyte, lim - lastout)) != 0)
601         ++nl;
602       else
603         nl = lim;
604       prline (lastout, nl, '-');
605     }
606 }
607
608 /* Print the lines between BEG and LIM.  Deal with context crap.
609    If NLINESP is non-null, store a count of lines between BEG and LIM. */
610 static void
611 prtext (char *beg, char *lim, int *nlinesp)
612 {
613   static int used;              /* avoid printing "--" before any output */
614   char *bp, *p, *nl;
615   char eol = eolbyte;
616   int i, n;
617
618   if (!out_quiet && pending > 0)
619     prpending (beg);
620
621   p = beg;
622
623   if (!out_quiet)
624     {
625       /* Deal with leading context crap. */
626
627       bp = lastout ? lastout : bufbeg;
628       for (i = 0; i < out_before; ++i)
629         if (p > bp)
630           do
631             --p;
632           while (p > bp && p[-1] != eol);
633
634       /* We only print the "--" separator if our output is
635          discontiguous from the last output in the file. */
636       if ((out_before || out_after) && used && p != lastout)
637         puts ("--");
638
639       while (p < beg)
640         {
641           nl = memchr (p, eol, beg - p);
642           prline (p, nl + 1, '-');
643           p = nl + 1;
644         }
645     }
646
647   if (nlinesp)
648     {
649       /* Caller wants a line count. */
650       for (n = 0; p < lim; ++n)
651         {
652           if ((nl = memchr (p, eol, lim - p)) != 0)
653             ++nl;
654           else
655             nl = lim;
656           if (!out_quiet)
657             prline (p, nl, ':');
658           p = nl;
659         }
660       *nlinesp = n;
661     }
662   else
663     if (!out_quiet)
664       prline (beg, lim, ':');
665
666   pending = out_quiet ? 0 : out_after;
667   used = 1;
668 }
669
670 /* Scan the specified portion of the buffer, matching lines (or
671    between matching lines if OUT_INVERT is true).  Return a count of
672    lines printed. */
673 static int
674 grepbuf (char *beg, char *lim)
675 {
676   int nlines, n;
677   register char *p, *b;
678   char *endp;
679   char eol = eolbyte;
680
681   nlines = 0;
682   p = beg;
683   while ((b = (*execute)(p, lim - p, &endp)) != 0)
684     {
685       /* Avoid matching the empty line at the end of the buffer. */
686       if (b == lim && ((b > beg && b[-1] == eol) || b == beg))
687         break;
688       if (!out_invert)
689         {
690           prtext (b, endp, (int *) 0);
691           nlines += 1;
692           if (done_on_match)
693             return nlines;
694         }
695       else if (p < b)
696         {
697           prtext (p, b, &n);
698           nlines += n;
699         }
700       p = endp;
701     }
702   if (out_invert && p < lim)
703     {
704       prtext (p, lim, &n);
705       nlines += n;
706     }
707   return nlines;
708 }
709
710 /* Search a given file.  Normally, return a count of lines printed;
711    but if the file is a directory and we search it recursively, then
712    return -2 if there was a match, and -1 otherwise.  */
713 static int
714 grep (int fd, char const *file, struct stats *stats)
715 {
716   int nlines, i;
717   int not_text;
718   size_t residue, save;
719   char *beg, *lim;
720   char eol = eolbyte;
721
722   if (!reset (fd, file, stats))
723     return 0;
724
725   if (file && directories == RECURSE_DIRECTORIES
726       && S_ISDIR (stats->stat.st_mode))
727     {
728       /* Close fd now, so that we don't open a lot of file descriptors
729          when we recurse deeply.  */
730 #if HAVE_LIBZ > 0
731       if (Zflag)
732         gzclose(gzbufdesc);
733       else
734 #endif
735       if (close (fd) != 0)
736         error (file, errno);
737       return grepdir (file, stats) - 2;
738     }
739
740   totalcc = 0;
741   lastout = 0;
742   totalnl = 0;
743   pending = 0;
744
745   nlines = 0;
746   residue = 0;
747   save = 0;
748
749   if (! fillbuf (save, stats))
750     {
751       if (! (is_EISDIR (errno, file) && suppress_errors))
752         error (filename, errno);
753       return 0;
754     }
755
756   not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
757                || binary_files == WITHOUT_MATCH_BINARY_FILES)
758               && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
759   if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
760     return 0;
761   done_on_match += not_text;
762   out_quiet += not_text;
763
764   for (;;)
765     {
766       lastnl = bufbeg;
767       if (lastout)
768         lastout = bufbeg;
769       if (buflim - bufbeg == save)
770         break;
771       beg = bufbeg + save - residue;
772       for (lim = buflim; lim > beg && lim[-1] != eol; --lim)
773         ;
774       residue = buflim - lim;
775       if (beg < lim)
776         {
777           nlines += grepbuf (beg, lim);
778           if (pending)
779             prpending (lim);
780           if (nlines && done_on_match && !out_invert)
781             goto finish_grep;
782         }
783       i = 0;
784       beg = lim;
785       while (i < out_before && beg > bufbeg && beg != lastout)
786         {
787           ++i;
788           do
789             --beg;
790           while (beg > bufbeg && beg[-1] != eol);
791         }
792       if (beg != lastout)
793         lastout = 0;
794       save = residue + lim - beg;
795       totalcc += buflim - bufbeg - save;
796       if (out_line)
797         nlscan (beg);
798       if (! fillbuf (save, stats))
799         {
800           if (! (is_EISDIR (errno, file) && suppress_errors))
801             error (filename, errno);
802           goto finish_grep;
803         }
804     }
805   if (residue)
806     {
807       *buflim++ = eol;
808       nlines += grepbuf (bufbeg + save - residue, buflim);
809       if (pending)
810         prpending (buflim);
811     }
812
813  finish_grep:
814   done_on_match -= not_text;
815   out_quiet -= not_text;
816   if ((not_text & ~out_quiet) && nlines != 0)
817     printf (_("Binary file %s matches\n"), filename);
818   return nlines;
819 }
820
821 static int
822 grepfile (char const *file, struct stats *stats)
823 {
824   int desc;
825   int count;
826   int status;
827
828   if (! file)
829     {
830       desc = 0;
831       filename = _("(standard input)");
832     }
833   else
834     {
835       while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR)
836         continue;
837
838       if (desc < 0)
839         {
840           int e = errno;
841             
842           if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES)
843             {
844               if (stat (file, &stats->stat) != 0)
845                 {
846                   error (file, errno);
847                   return 1;
848                 }
849
850               return grepdir (file, stats);
851             }
852               
853           if (!suppress_errors)
854             {
855               if (directories == SKIP_DIRECTORIES)
856                 switch (e)
857                   {
858 #ifdef EISDIR
859                   case EISDIR:
860                     return 1;
861 #endif
862                   case EACCES:
863                     /* When skipping directories, don't worry about
864                        directories that can't be opened.  */
865                     if (stat (file, &stats->stat) == 0
866                         && S_ISDIR (stats->stat.st_mode))
867                       return 1;
868                     break;
869                   }
870
871               error (file, e);
872             }
873
874           return 1;
875         }
876
877       filename = file;
878     }
879
880 #if O_BINARY
881   /* Set input to binary mode.  Pipes are simulated with files
882      on DOS, so this includes the case of "foo | grep bar".  */
883   if (!isatty (desc))
884     SET_BINARY (desc);
885 #endif
886
887   count = grep (desc, file, stats);
888   if (count < 0)
889     status = count + 2;
890   else
891     {
892       if (count_matches)
893         {
894           if (out_file)
895             printf ("%s%c", filename, ':' & filename_mask);
896           printf ("%d\n", count);
897         }
898
899       status = !count;
900       if (list_files == 1 - 2 * status)
901         printf ("%s%c", filename, '\n' & filename_mask);
902
903 #if HAVE_LIBZ > 0
904       if (Zflag)
905         gzclose(gzbufdesc);
906       else
907 #endif
908       if (file)
909         while (close (desc) != 0)
910           if (errno != EINTR)
911             {
912               error (file, errno);
913               break;
914             }
915     }
916
917   return status;
918 }
919
920 static int
921 grepdir (char const *dir, struct stats *stats)
922 {
923   int status = 1;
924   struct stats *ancestor;
925   char *name_space;
926
927   for (ancestor = stats;  (ancestor = ancestor->parent) != 0;  )
928     if (ancestor->stat.st_ino == stats->stat.st_ino
929         && ancestor->stat.st_dev == stats->stat.st_dev)
930       {
931         if (!suppress_errors)
932           fprintf (stderr, _("%s: warning: %s: %s\n"), prog, dir,
933                    _("recursive directory loop"));
934         return 1;
935       }
936
937   name_space = savedir (dir, (unsigned) stats->stat.st_size);
938
939   if (! name_space)
940     {
941       if (errno)
942         {
943           if (!suppress_errors)
944             error (dir, errno);
945         }
946       else
947         fatal (_("Memory exhausted"), 0);
948     }
949   else
950     {
951       size_t dirlen = strlen (dir);
952       int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir)
953                            || IS_SLASH (dir[dirlen - 1]));
954       char *file = NULL;
955       char *namep = name_space;
956       struct stats child;
957       child.parent = stats;
958       out_file += !no_filenames;
959       while (*namep)
960         {
961           size_t namelen = strlen (namep);
962           file = xrealloc (file, dirlen + 1 + namelen + 1);
963           strcpy (file, dir);
964           file[dirlen] = '/';
965           strcpy (file + dirlen + needs_slash, namep);
966           namep += namelen + 1;
967           status &= grepfile (file, &child);
968         }
969       out_file -= !no_filenames;
970       if (file)
971         free (file);
972       free (name_space);
973     }
974
975   return status;
976 }
977
978 static void
979 usage (int status)
980 {
981   if (status != 0)
982     {
983       fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"), prog);
984       fprintf (stderr, _("Try `%s --help' for more information.\n"), prog);
985     }
986   else
987     {
988       printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), prog);
989       printf (_("\
990 Search for PATTERN in each FILE or standard input.\n\
991 Example: %s -i 'hello world' menu.h main.c\n\
992 \n\
993 Regexp selection and interpretation:\n"), prog);
994       printf (_("\
995   -E, --extended-regexp     PATTERN is an extended regular expression\n\
996   -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
997   -G, --basic-regexp        PATTERN is a basic regular expression\n"));
998       printf (_("\
999   -e, --regexp=PATTERN      use PATTERN as a regular expression\n\
1000   -f, --file=FILE           obtain PATTERN from FILE\n\
1001   -i, --ignore-case         ignore case distinctions\n\
1002   -w, --word-regexp         force PATTERN to match only whole words\n\
1003   -x, --line-regexp         force PATTERN to match only whole lines\n\
1004   -z, --null-data           a data line ends in 0 byte, not newline\n"));
1005       printf (_("\
1006 \n\
1007 Miscellaneous:\n\
1008   -s, --no-messages         suppress error messages\n\
1009   -v, --invert-match        select non-matching lines\n\
1010   -V, --version             print version information and exit\n\
1011       --help                display this help and exit\n\
1012   -Z, --decompress          decompress input before searching (HAVE_LIBZ=1)\n\
1013       --mmap                use memory-mapped input if possible\n"));
1014       printf (_("\
1015 \n\
1016 Output control:\n\
1017   -b, --byte-offset         print the byte offset with output lines\n\
1018   -n, --line-number         print line number with output lines\n\
1019   -H, --with-filename       print the filename for each match\n\
1020   -h, --no-filename         suppress the prefixing filename on output\n\
1021   -q, --quiet, --silent     suppress all normal output\n\
1022       --binary-files=TYPE   assume that binary files are TYPE\n\
1023                             TYPE is 'binary', 'text', or 'without-match'.\n\
1024   -a, --text                equivalent to --binary-files=text\n\
1025   -I                        equivalent to --binary-files=without-match\n\
1026   -d, --directories=ACTION  how to handle directories\n\
1027                             ACTION is 'read', 'recurse', or 'skip'.\n\
1028   -r, --recursive           equivalent to --directories=recurse.\n\
1029   -L, --files-without-match only print FILE names containing no match\n\
1030   -l, --files-with-matches  only print FILE names containing matches\n\
1031   -c, --count               only print a count of matching lines per FILE\n\
1032       --null                print 0 byte after FILE name\n"));
1033       printf (_("\
1034 \n\
1035 Context control:\n\
1036   -B, --before-context=NUM  print NUM lines of leading context\n\
1037   -A, --after-context=NUM   print NUM lines of trailing context\n\
1038   -C, --context[=NUM]       print NUM (default 2) lines of output context\n\
1039                             unless overridden by -A or -B\n\
1040   -NUM                      same as --context=NUM\n\
1041   -U, --binary              do not strip CR characters at EOL (MSDOS)\n\
1042   -u, --unix-byte-offsets   report offsets as if CRs were not there (MSDOS)\n\
1043 \n\
1044 `egrep' means `grep -E'.  `fgrep' means `grep -F'.\n\
1045 With no FILE, or when FILE is -, read standard input.  If less than\n\
1046 two FILEs given, assume -h.  Exit status is 0 if match, 1 if no match,\n\
1047 and 2 if trouble.\n"));
1048       printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n"));
1049     }
1050   exit (status);
1051 }
1052
1053 /* Set the matcher to M, reporting any conflicts.  */
1054 static void
1055 setmatcher (char const *m)
1056 {
1057   if (matcher && strcmp (matcher, m) != 0)
1058     fatal (_("conflicting matchers specified"), 0);
1059   matcher = m;
1060 }
1061
1062 /* Go through the matchers vector and look for the specified matcher.
1063    If we find it, install it in compile and execute, and return 1.  */
1064 static int
1065 install_matcher (char const *name)
1066 {
1067   int i;
1068 #ifdef HAVE_SETRLIMIT
1069   struct rlimit rlim;
1070 #endif
1071
1072   for (i = 0; matchers[i].name; ++i)
1073     if (strcmp (name, matchers[i].name) == 0)
1074       {
1075         compile = matchers[i].compile;
1076         execute = matchers[i].execute;
1077 #if HAVE_SETRLIMIT && defined(RLIMIT_STACK)
1078         /* I think every platform needs to do this, so that regex.c
1079            doesn't oveflow the stack.  The default value of
1080            `re_max_failures' is too large for some platforms: it needs
1081            more than 3MB-large stack.
1082
1083            The test for HAVE_SETRLIMIT should go into `configure'.  */
1084         if (!getrlimit (RLIMIT_STACK, &rlim))
1085           {
1086             long newlim;
1087             extern long int re_max_failures; /* from regex.c */
1088
1089             /* Approximate the amount regex.c needs, plus some more.  */
1090             newlim = re_max_failures * 2 * 20 * sizeof (char *);
1091             if (newlim > rlim.rlim_max)
1092               {
1093                 newlim = rlim.rlim_max;
1094                 re_max_failures = newlim / (2 * 20 * sizeof (char *));
1095               }
1096             if (rlim.rlim_cur < newlim)
1097               rlim.rlim_cur = newlim;
1098
1099             setrlimit (RLIMIT_STACK, &rlim);
1100           }
1101 #endif
1102         return 1;
1103       }
1104   return 0;
1105 }
1106
1107 /* Find the white-space-separated options specified by OPTIONS, and
1108    using BUF to store copies of these options, set ARGV[0], ARGV[1],
1109    etc. to the option copies.  Return the number N of options found.
1110    Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
1111    etc.  Backslash can be used to escape whitespace (and backslashes).  */
1112 static int
1113 prepend_args (char const *options, char *buf, char **argv)
1114 {
1115   char const *o = options;
1116   char *b = buf;
1117   int n = 0;
1118
1119   for (;;)
1120     {
1121       while (ISSPACE ((unsigned char) *o))
1122         o++;
1123       if (!*o)
1124         return n;
1125       if (argv)
1126         argv[n] = b;
1127       n++;
1128
1129       do
1130         if ((*b++ = *o++) == '\\' && *o)
1131           b[-1] = *o++;
1132       while (*o && ! ISSPACE ((unsigned char) *o));
1133
1134       *b++ = '\0';
1135     }
1136 }
1137
1138 /* Prepend the whitespace-separated options in OPTIONS to the argument
1139    vector of a main program with argument count *PARGC and argument
1140    vector *PARGV.  */
1141 static void
1142 prepend_default_options (char const *options, int *pargc, char ***pargv)
1143 {
1144   if (options)
1145     {
1146       char *buf = xmalloc (strlen (options) + 1);
1147       int prepended = prepend_args (options, buf, (char **) NULL);
1148       int argc = *pargc;
1149       char * const *argv = *pargv;
1150       char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
1151       *pargc = prepended + argc;
1152       *pargv = pp;
1153       *pp++ = *argv++;
1154       pp += prepend_args (options, buf, pp);
1155       while ((*pp++ = *argv++))
1156         continue;
1157     }
1158 }
1159
1160 int
1161 main (int argc, char **argv)
1162 {
1163   char *keys;
1164   size_t keycc, oldcc, keyalloc;
1165   int with_filenames;
1166   int opt, cc, status;
1167   int default_context;
1168   unsigned digit_args_val;
1169   FILE *fp;
1170   extern char *optarg;
1171   extern int optind;
1172
1173   initialize_main (&argc, &argv);
1174   prog = argv[0];
1175   if (prog && strrchr (prog, '/'))
1176     prog = strrchr (prog, '/') + 1;
1177
1178 #if HAVE_LIBZ > 0
1179   if (prog[0] == 'z') {
1180     Zflag = 1;
1181     ++prog;
1182   }
1183 #endif
1184
1185 #if defined(__MSDOS__) || defined(_WIN32)
1186   /* DOS and MS-Windows use backslashes as directory separators, and usually
1187      have an .exe suffix.  They also have case-insensitive filesystems.  */
1188   if (prog)
1189     {
1190       char *p = prog;
1191       char *bslash = strrchr (argv[0], '\\');
1192
1193       if (bslash && bslash >= prog) /* for mixed forward/backslash case */
1194         prog = bslash + 1;
1195       else if (prog == argv[0]
1196                && argv[0][0] && argv[0][1] == ':') /* "c:progname" */
1197         prog = argv[0] + 2;
1198
1199       /* Collapse the letter-case, so `strcmp' could be used hence.  */
1200       for ( ; *p; p++)
1201         if (*p >= 'A' && *p <= 'Z')
1202           *p += 'a' - 'A';
1203
1204       /* Remove the .exe extension, if any.  */
1205       if ((p = strrchr (prog, '.')) && strcmp (p, ".exe") == 0)
1206         *p = '\0';
1207     }
1208 #endif
1209
1210   keys = NULL;
1211   keycc = 0;
1212   with_filenames = 0;
1213   eolbyte = '\n';
1214   filename_mask = ~0;
1215
1216   /* The value -1 means to use DEFAULT_CONTEXT. */
1217   out_after = out_before = -1;
1218   /* Default before/after context: chaged by -C/-NUM options */
1219   default_context = 0;
1220   /* Accumulated value of individual digits in a -NUM option */
1221   digit_args_val = 0;
1222
1223
1224 /* Internationalization. */
1225 #if HAVE_SETLOCALE
1226   setlocale (LC_ALL, "");
1227 #endif
1228 #if ENABLE_NLS
1229   bindtextdomain (PACKAGE, LOCALEDIR);
1230   textdomain (PACKAGE);
1231 #endif
1232
1233   prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
1234
1235   while ((opt = getopt_long (argc, argv, short_options, long_options, NULL))
1236          != -1)
1237     switch (opt)
1238       {
1239       case '0':
1240       case '1':
1241       case '2':
1242       case '3':
1243       case '4':
1244       case '5':
1245       case '6':
1246       case '7':
1247       case '8':
1248       case '9':
1249         digit_args_val = 10 * digit_args_val + opt - '0';
1250         default_context = digit_args_val;
1251         break;
1252       case 'A':
1253         if (optarg)
1254           {
1255             if (ck_atoi (optarg, &out_after))
1256               fatal (_("invalid context length argument"), 0);
1257           }
1258         break;
1259       case 'B':
1260         if (optarg)
1261           {
1262             if (ck_atoi (optarg, &out_before))
1263               fatal (_("invalid context length argument"), 0);
1264           }
1265         break;
1266       case 'C':
1267         /* Set output match context, but let any explicit leading or
1268            trailing amount specified with -A or -B stand. */
1269         if (optarg)
1270           {
1271             if (ck_atoi (optarg, &default_context))
1272               fatal (_("invalid context length argument"), 0);
1273           }
1274         else
1275           default_context = 2;
1276         break;
1277       case 'E':
1278         setmatcher ("egrep");
1279         break;
1280       case 'F':
1281         setmatcher ("fgrep");
1282         break;
1283       case 'G':
1284         setmatcher ("grep");
1285         break;
1286       case 'H':
1287         with_filenames = 1;
1288         break;
1289       case 'I':
1290         binary_files = WITHOUT_MATCH_BINARY_FILES;
1291         break;
1292       case 'U':
1293 #if O_BINARY
1294         dos_use_file_type = DOS_BINARY;
1295 #endif
1296         break;
1297       case 'u':
1298 #if O_BINARY
1299         dos_report_unix_offset = 1;
1300 #endif
1301         break;
1302       case 'V':
1303         show_version = 1;
1304         break;
1305       case 'X':
1306         setmatcher (optarg);
1307         break;
1308       case 'a':
1309         binary_files = TEXT_BINARY_FILES;
1310         break;
1311       case 'b':
1312         out_byte = 1;
1313         break;
1314       case 'c':
1315         out_quiet = 1;
1316         count_matches = 1;
1317         break;
1318       case 'd':
1319         if (strcmp (optarg, "read") == 0)
1320           directories = READ_DIRECTORIES;
1321         else if (strcmp (optarg, "skip") == 0)
1322           directories = SKIP_DIRECTORIES;
1323         else if (strcmp (optarg, "recurse") == 0)
1324           directories = RECURSE_DIRECTORIES;
1325         else
1326           fatal (_("unknown directories method"), 0);
1327         break;
1328       case 'e':
1329         cc = strlen (optarg);
1330         keys = xrealloc (keys, keycc + cc + 1);
1331         strcpy (&keys[keycc], optarg);
1332         keycc += cc;
1333         keys[keycc++] = '\n';
1334         break;
1335       case 'f':
1336         fp = strcmp (optarg, "-") != 0 ? fopen (optarg, "r") : stdin;
1337         if (!fp)
1338           fatal (optarg, errno);
1339         for (keyalloc = 1; keyalloc <= keycc + 1; keyalloc *= 2)
1340           ;
1341         keys = xrealloc (keys, keyalloc);
1342         oldcc = keycc;
1343         while (!feof (fp)
1344                && (cc = fread (keys + keycc, 1, keyalloc - 1 - keycc, fp)) > 0)
1345           {
1346             keycc += cc;
1347             if (keycc == keyalloc - 1)
1348               keys = xrealloc (keys, keyalloc *= 2);
1349           }
1350         if (fp != stdin)
1351           fclose(fp);
1352         /* Append final newline if file ended in non-newline. */
1353         if (oldcc != keycc && keys[keycc - 1] != '\n')
1354           keys[keycc++] = '\n';
1355         break;
1356       case 'h':
1357         no_filenames = 1;
1358         break;
1359       case 'i':
1360       case 'y':                 /* For old-timers . . . */
1361         match_icase = 1;
1362         break;
1363       case 'L':
1364         /* Like -l, except list files that don't contain matches.
1365            Inspired by the same option in Hume's gre. */
1366         out_quiet = 1;
1367         list_files = -1;
1368         done_on_match = 1;
1369         break;
1370       case 'l':
1371         out_quiet = 1;
1372         list_files = 1;
1373         done_on_match = 1;
1374         break;
1375       case 'n':
1376         out_line = 1;
1377         break;
1378       case 'q':
1379         done_on_match = 1;
1380         out_quiet = 1;
1381         break;
1382       case 'R':
1383       case 'r':
1384         directories = RECURSE_DIRECTORIES;
1385         break;
1386       case 's':
1387         suppress_errors = 1;
1388         break;
1389       case 'v':
1390         out_invert = 1;
1391         break;
1392       case 'w':
1393         match_words = 1;
1394         break;
1395       case 'x':
1396         match_lines = 1;
1397         break;
1398       case 'Z':
1399 #if HAVE_LIBZ > 0
1400         Zflag = 1;
1401 #else
1402         filename_mask = 0;
1403 #endif
1404         break;
1405       case 'z':
1406         eolbyte = '\0';
1407         break;
1408       case BINARY_FILES_OPTION:
1409         if (strcmp (optarg, "binary") == 0)
1410           binary_files = BINARY_BINARY_FILES;
1411         else if (strcmp (optarg, "text") == 0)
1412           binary_files = TEXT_BINARY_FILES;
1413         else if (strcmp (optarg, "without-match") == 0)
1414           binary_files = WITHOUT_MATCH_BINARY_FILES;
1415         else
1416           fatal (_("unknown binary-files type"), 0);
1417         break;
1418       case 0:
1419         /* long options */
1420         break;
1421       default:
1422         usage (2);
1423         break;
1424       }
1425
1426   if (out_after < 0)
1427     out_after = default_context;
1428   if (out_before < 0)
1429     out_before = default_context;
1430
1431   if (! matcher)
1432     matcher = prog;
1433
1434   if (show_version)
1435     {
1436       printf (_("%s (GNU grep) %s\n"), matcher, VERSION);
1437       printf ("\n");
1438       printf (_("\
1439 Copyright (C) 1988, 1992-1998, 1999 Free Software Foundation, Inc.\n"));
1440       printf (_("\
1441 This is free software; see the source for copying conditions. There is NO\n\
1442 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"));
1443       printf ("\n");
1444       exit (0);
1445     }
1446
1447   if (show_help)
1448     usage (0);
1449
1450   if (keys)
1451     {
1452       if (keycc == 0)
1453         /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
1454         out_invert ^= 1;
1455       else
1456         /* Strip trailing newline. */
1457         --keycc;
1458     }
1459   else
1460     if (optind < argc)
1461       {
1462         keys = argv[optind++];
1463         keycc = strlen (keys);
1464       }
1465     else
1466       usage (2);
1467
1468   if (!install_matcher (matcher) && !install_matcher ("default"))
1469     abort ();
1470
1471   (*compile)(keys, keycc);
1472
1473   if ((argc - optind > 1 && !no_filenames) || with_filenames)
1474     out_file = 1;
1475
1476 #if O_BINARY
1477   /* Output is set to binary mode because we shouldn't convert
1478      NL to CR-LF pairs, especially when grepping binary files.  */
1479   if (!isatty (1))
1480     SET_BINARY (1);
1481 #endif
1482
1483
1484   if (optind < argc)
1485     {
1486         status = 1;
1487         do
1488         {
1489           char *file = argv[optind];
1490           status &= grepfile (strcmp (file, "-") == 0 ? (char *) NULL : file,
1491                               &stats_base);
1492         }
1493         while ( ++optind < argc);
1494     }
1495   else
1496     status = grepfile ((char *) NULL, &stats_base);
1497
1498   if (fclose (stdout) == EOF)
1499     error (_("writing output"), errno);
1500
1501   exit (errseen ? 2 : status);
1502 }