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