Project

General

Profile

freebsd_grep.patch

htse, 11/09/2016 12:01 PM

Download (136 KB)

View differences:

usr.bin/Makefile
74 74
	getconf \
75 75
	getent \
76 76
	getopt \
77
	grep \
77 78
	gzip \
78 79
	head \
79 80
	hexdump \
usr.bin/grep/Makefile
1
.include <bsd.init.mk>
2

  
3
PROG=	grep
4

  
5
MK_LZMA_SUPPORT?="yes"
6
MK_BZIP2_SUPPORT?="yes"
7

  
8
CFLAGS+= -I${.CURDIR}
9

  
10
SRCS=	file.c grep.c queue.c util.c
11

  
12
# Extra files ported backported form some regex improvements
13
.PATH: ${.CURDIR}/regex
14
SRCS+=	fastmatch.c hashtable.c tre-compile.c tre-fastmatch.c xmalloc.c
15
CFLAGS+=-I${.CURDIR}/regex
16

  
17
CFLAGS.gcc+= --param max-inline-insns-single=500
18

  
19
LINKS=	${BINDIR}/grep ${BINDIR}/egrep \
20
	${BINDIR}/grep ${BINDIR}/fgrep \
21
	${BINDIR}/grep ${BINDIR}/zgrep \
22
	${BINDIR}/grep ${BINDIR}/zegrep \
23
	${BINDIR}/grep ${BINDIR}/zfgrep
24

  
25
MLINKS= grep.1 egrep.1 \
26
	grep.1 fgrep.1 \
27
	grep.1 zgrep.1 \
28
	grep.1 zegrep.1 \
29
	grep.1 zfgrep.1
30

  
31
LDADD=	-lz
32
DPADD= ${LIBZ}
33

  
34
.if ${MK_LZMA_SUPPORT} != "no"
35
LDADD+=	-llzma
36
DPADD+= ${LIBZMA}
37

  
38
LINKS+=	${BINDIR}/${PROG} ${BINDIR}/xzgrep \
39
	${BINDIR}/${PROG} ${BINDIR}/xzegrep \
40
	${BINDIR}/${PROG} ${BINDIR}/xzfgrep \
41
	${BINDIR}/${PROG} ${BINDIR}/lzgrep \
42
	${BINDIR}/${PROG} ${BINDIR}/lzegrep \
43
	${BINDIR}/${PROG} ${BINDIR}/lzfgrep
44

  
45
MLINKS+= grep.1 xzgrep.1 \
46
	 grep.1 xzegrep.1 \
47
	 grep.1 xzfgrep.1 \
48
	 grep.1 lzgrep.1 \
49
	 grep.1 lzegrep.1 \
50
	 grep.1 lzfgrep.1
51
.else
52
 CFLAGS+= -DWITHOUT_LZMA
53
.endif
54

  
55
.if ${MK_BZIP2_SUPPORT} != "no"
56
LDADD+=	-lbz2
57
DPADD+= ${LIBBZ2}
58

  
59
LINKS+= ${BINDIR}/grep ${BINDIR}/bzgrep \
60
	${BINDIR}/grep ${BINDIR}/bzegrep \
61
	${BINDIR}/grep ${BINDIR}/bzfgrep
62
MLINKS+= grep.1 bzgrep.1 \
63
	 grep.1 bzegrep.1 \
64
	 grep.1 bzfgrep.1
65
.else
66
 CFLAGS+= -DWITHOUT_BZIP2
67
.endif
68

  
69
# .if ${MK_GNU_GREP_COMPAT} != "no"
70
#CFLAGS+= -I${DESTDIR}/usr/include/gnu
71
#LIBADD+=	gnuregex
72
# .endif
73

  
74
.ifdef NLS
75
.include "${.CURDIR}/nls/Makefile.inc"
76
.else
77
CFLAGS+= -DWITHOUT_NLS
78
.endif
79

  
80

  
81
.include <bsd.prog.mk>
usr.bin/grep/file.c
1
/*	$NetBSD: file.c,v 1.5 2011/02/16 18:35:39 joerg Exp $	*/
2
/*	$FreeBSD: stable/11/usr.bin/grep/file.c 277463 2015-01-21 01:11:37Z delphij $	*/
3
/*	$OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $	*/
4

  
5
/*-
6
 * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
7
 * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
8
 * Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32

  
33
#include <sys/cdefs.h>
34
__FBSDID("$FreeBSD: stable/11/usr.bin/grep/file.c 277463 2015-01-21 01:11:37Z delphij $");
35

  
36
#include <sys/param.h>
37
#include <sys/mman.h>
38
#include <sys/stat.h>
39
#include <sys/types.h>
40

  
41
#include <err.h>
42
#include <errno.h>
43
#include <fcntl.h>
44
#include <stddef.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <unistd.h>
48
#include <wchar.h>
49
#include <wctype.h>
50
#include <zlib.h>
51

  
52
#ifndef WITHOUT_LZMA
53
#include <lzma.h>
54
#endif
55

  
56
#ifndef WITHOUT_BZIP2
57
#include <bzlib.h>
58
#endif
59

  
60
#include "grep.h"
61

  
62
#define	MAXBUFSIZ	(32 * 1024)
63
#define	LNBUFBUMP	80
64

  
65
static gzFile gzbufdesc;
66
#ifndef WITHOUT_LZMA
67
static lzma_stream lstrm = LZMA_STREAM_INIT;
68
static lzma_action laction;
69
static uint8_t lin_buf[MAXBUFSIZ];
70
#endif
71
#ifndef WITHOUT_BZIP2
72
static BZFILE* bzbufdesc;
73
#endif
74

  
75
static unsigned char *buffer;
76
static unsigned char *bufpos;
77
static size_t bufrem;
78
static size_t fsiz;
79

  
80
static unsigned char *lnbuf;
81
static size_t lnbuflen;
82

  
83
static inline int
84
grep_refill(struct file *f)
85
{
86
	ssize_t nr;
87

  
88
	if (filebehave == FILE_MMAP)
89
		return (0);
90

  
91
	bufpos = buffer;
92
	bufrem = 0;
93

  
94
	if (filebehave == FILE_GZIP) {
95
		nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
96
#ifndef WITHOUT_BZIP2
97
	} else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
98
		int bzerr;
99

  
100
		nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
101
		switch (bzerr) {
102
		case BZ_OK:
103
		case BZ_STREAM_END:
104
			/* No problem, nr will be okay */
105
			break;
106
		case BZ_DATA_ERROR_MAGIC:
107
			/*
108
			 * As opposed to gzread(), which simply returns the
109
			 * plain file data, if it is not in the correct
110
			 * compressed format, BZ2_bzRead() instead aborts.
111
			 *
112
			 * So, just restart at the beginning of the file again,
113
			 * and use plain reads from now on.
114
			 */
115
			BZ2_bzReadClose(&bzerr, bzbufdesc);
116
			bzbufdesc = NULL;
117
			if (lseek(f->fd, 0, SEEK_SET) == -1)
118
				return (-1);
119
			nr = read(f->fd, buffer, MAXBUFSIZ);
120
			break;
121
		default:
122
			/* Make sure we exit with an error */
123
			nr = -1;
124
		}
125
#endif
126
#ifndef WITHOUT_LZMA
127
	} else if ((filebehave == FILE_XZ) || (filebehave == FILE_LZMA)) {
128
		lzma_ret ret;
129
		lstrm.next_out = buffer;
130

  
131
		do {
132
			if (lstrm.avail_in == 0) {
133
				lstrm.next_in = lin_buf;
134
				nr = read(f->fd, lin_buf, MAXBUFSIZ);
135

  
136
				if (nr < 0)
137
					return (-1);
138
				else if (nr == 0)
139
					laction = LZMA_FINISH;
140

  
141
				lstrm.avail_in = nr;
142
			}
143

  
144
			ret = lzma_code(&lstrm, laction);
145

  
146
			if (ret != LZMA_OK && ret != LZMA_STREAM_END)
147
				return (-1);
148

  
149
			if (lstrm.avail_out == 0 || ret == LZMA_STREAM_END) {
150
				bufrem = MAXBUFSIZ - lstrm.avail_out;
151
				lstrm.next_out = buffer;
152
				lstrm.avail_out = MAXBUFSIZ;
153
			}
154
		} while (bufrem == 0 && ret != LZMA_STREAM_END);
155

  
156
		return (0);
157
#endif	/* WITHOUT_LZMA */
158
	} else
159
		nr = read(f->fd, buffer, MAXBUFSIZ);
160

  
161
	if (nr < 0)
162
		return (-1);
163

  
164
	bufrem = nr;
165
	return (0);
166
}
167

  
168
static inline int
169
grep_lnbufgrow(size_t newlen)
170
{
171

  
172
	if (lnbuflen < newlen) {
173
		lnbuf = grep_realloc(lnbuf, newlen);
174
		lnbuflen = newlen;
175
	}
176

  
177
	return (0);
178
}
179

  
180
char *
181
grep_fgetln(struct file *f, size_t *lenp)
182
{
183
	unsigned char *p;
184
	char *ret;
185
	size_t len;
186
	size_t off;
187
	ptrdiff_t diff;
188

  
189
	/* Fill the buffer, if necessary */
190
	if (bufrem == 0 && grep_refill(f) != 0)
191
		goto error;
192

  
193
	if (bufrem == 0) {
194
		/* Return zero length to indicate EOF */
195
		*lenp = 0;
196
		return (bufpos);
197
	}
198

  
199
	/* Look for a newline in the remaining part of the buffer */
200
	if ((p = memchr(bufpos, '\n', bufrem)) != NULL) {
201
		++p; /* advance over newline */
202
		ret = bufpos;
203
		len = p - bufpos;
204
		bufrem -= len;
205
		bufpos = p;
206
		*lenp = len;
207
		return (ret);
208
	}
209

  
210
	/* We have to copy the current buffered data to the line buffer */
211
	for (len = bufrem, off = 0; ; len += bufrem) {
212
		/* Make sure there is room for more data */
213
		if (grep_lnbufgrow(len + LNBUFBUMP))
214
			goto error;
215
		memcpy(lnbuf + off, bufpos, len - off);
216
		off = len;
217
		if (grep_refill(f) != 0)
218
			goto error;
219
		if (bufrem == 0)
220
			/* EOF: return partial line */
221
			break;
222
		if ((p = memchr(bufpos, '\n', bufrem)) == NULL)
223
			continue;
224
		/* got it: finish up the line (like code above) */
225
		++p;
226
		diff = p - bufpos;
227
		len += diff;
228
		if (grep_lnbufgrow(len))
229
		    goto error;
230
		memcpy(lnbuf + off, bufpos, diff);
231
		bufrem -= diff;
232
		bufpos = p;
233
		break;
234
	}
235
	*lenp = len;
236
	return (lnbuf);
237

  
238
error:
239
	*lenp = 0;
240
	return (NULL);
241
}
242

  
243
/*
244
 * Opens a file for processing.
245
 */
246
struct file *
247
grep_open(const char *path)
248
{
249
	struct file *f;
250

  
251
	f = grep_malloc(sizeof *f);
252
	memset(f, 0, sizeof *f);
253
	if (path == NULL) {
254
		/* Processing stdin implies --line-buffered. */
255
		lbflag = true;
256
		f->fd = STDIN_FILENO;
257
	} else if ((f->fd = open(path, O_RDONLY)) == -1)
258
		goto error1;
259

  
260
	if (filebehave == FILE_MMAP) {
261
		struct stat st;
262

  
263
		if ((fstat(f->fd, &st) == -1) || (st.st_size > OFF_MAX) ||
264
		    (!S_ISREG(st.st_mode)))
265
			filebehave = FILE_STDIO;
266
		else {
267
			int flags = MAP_PRIVATE | MAP_NOCORE | MAP_NOSYNC;
268
#ifdef MAP_PREFAULT_READ
269
			flags |= MAP_PREFAULT_READ;
270
#endif
271
			fsiz = st.st_size;
272
			buffer = mmap(NULL, fsiz, PROT_READ, flags,
273
			     f->fd, (off_t)0);
274
			if (buffer == MAP_FAILED)
275
				filebehave = FILE_STDIO;
276
			else {
277
				bufrem = st.st_size;
278
				bufpos = buffer;
279
				madvise(buffer, st.st_size, MADV_SEQUENTIAL);
280
			}
281
		}
282
	}
283

  
284
	if ((buffer == NULL) || (buffer == MAP_FAILED))
285
		buffer = grep_malloc(MAXBUFSIZ);
286

  
287
	if (filebehave == FILE_GZIP &&
288
	    (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
289
		goto error2;
290

  
291
#ifndef WITHOUT_BZIP2
292
	if (filebehave == FILE_BZIP &&
293
	    (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
294
		goto error2;
295
#endif
296
#ifndef WITHOUT_LZMA
297
	else if ((filebehave == FILE_XZ) || (filebehave == FILE_LZMA)) {
298
		lzma_ret ret;
299

  
300
		ret = (filebehave == FILE_XZ) ?
301
			lzma_stream_decoder(&lstrm, UINT64_MAX,
302
					LZMA_CONCATENATED) :
303
			lzma_alone_decoder(&lstrm, UINT64_MAX);
304

  
305
		if (ret != LZMA_OK)
306
			goto error2;
307

  
308
		lstrm.avail_in = 0;
309
		lstrm.avail_out = MAXBUFSIZ;
310
		laction = LZMA_RUN;
311
	}
312
#endif
313

  
314
	/* Fill read buffer, also catches errors early */
315
	if (bufrem == 0 && grep_refill(f) != 0)
316
		goto error2;
317

  
318
	/* Check for binary stuff, if necessary */
319
	if (binbehave != BINFILE_TEXT && memchr(bufpos, '\0', bufrem) != NULL)
320
	f->binary = true;
321

  
322
	return (f);
323

  
324
error2:
325
	close(f->fd);
326
error1:
327
	free(f);
328
	return (NULL);
329
}
330

  
331
/*
332
 * Closes a file.
333
 */
334
void
335
grep_close(struct file *f)
336
{
337

  
338
	close(f->fd);
339

  
340
	/* Reset read buffer and line buffer */
341
	if (filebehave == FILE_MMAP) {
342
		munmap(buffer, fsiz);
343
		buffer = NULL;
344
	}
345
	bufpos = buffer;
346
	bufrem = 0;
347

  
348
	free(lnbuf);
349
	lnbuf = NULL;
350
	lnbuflen = 0;
351
}
usr.bin/grep/grep.1
1
.\"	$NetBSD: grep.1,v 1.2 2011/02/16 01:31:33 joerg Exp $
2
.\"	$FreeBSD: stable/11/usr.bin/grep/grep.1 261634 2014-02-08 13:37:02Z joel $
3
.\"	$OpenBSD: grep.1,v 1.38 2010/04/05 06:30:59 jmc Exp $
4
.\" Copyright (c) 1980, 1990, 1993
5
.\"	The Regents of the University of California.  All rights reserved.
6
.\"
7
.\" Redistribution and use in source and binary forms, with or without
8
.\" modification, are permitted provided that the following conditions
9
.\" are met:
10
.\" 1. Redistributions of source code must retain the above copyright
11
.\"    notice, this list of conditions and the following disclaimer.
12
.\" 2. Redistributions in binary form must reproduce the above copyright
13
.\"    notice, this list of conditions and the following disclaimer in the
14
.\"    documentation and/or other materials provided with the distribution.
15
.\" 3. Neither the name of the University nor the names of its contributors
16
.\"    may be used to endorse or promote products derived from this software
17
.\"    without specific prior written permission.
18
.\"
19
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
.\" SUCH DAMAGE.
30
.\"
31
.\"	@(#)grep.1	8.3 (Berkeley) 4/18/94
32
.\"
33
.Dd July 28, 2010
34
.Dt GREP 1
35
.Os
36
.Sh NAME
37
.Nm grep , egrep , fgrep ,
38
.Nm zgrep , zegrep , zfgrep
39
.Nd file pattern searcher
40
.Sh SYNOPSIS
41
.Nm grep
42
.Bk -words
43
.Op Fl abcdDEFGHhIiJLlmnOopqRSsUVvwxZ
44
.Op Fl A Ar num
45
.Op Fl B Ar num
46
.Op Fl C Ns Op Ar num
47
.Op Fl e Ar pattern
48
.Op Fl f Ar file
49
.Op Fl Fl binary-files Ns = Ns Ar value
50
.Op Fl Fl color Ns Op = Ns Ar when
51
.Op Fl Fl colour Ns Op = Ns Ar when
52
.Op Fl Fl context Ns Op = Ns Ar num
53
.Op Fl Fl label
54
.Op Fl Fl line-buffered
55
.Op Fl Fl null
56
.Op Ar pattern
57
.Op Ar
58
.Ek
59
.Sh DESCRIPTION
60
The
61
.Nm grep
62
utility searches any given input files,
63
selecting lines that match one or more patterns.
64
By default, a pattern matches an input line if the regular expression
65
(RE) in the pattern matches the input line
66
without its trailing newline.
67
An empty expression matches every line.
68
Each input line that matches at least one of the patterns is written
69
to the standard output.
70
.Pp
71
.Nm grep
72
is used for simple patterns and
73
basic regular expressions
74
.Pq BREs ;
75
.Nm egrep
76
can handle extended regular expressions
77
.Pq EREs .
78
See
79
.Xr re_format 7
80
for more information on regular expressions.
81
.Nm fgrep
82
is quicker than both
83
.Nm grep
84
and
85
.Nm egrep ,
86
but can only handle fixed patterns
87
(i.e. it does not interpret regular expressions).
88
Patterns may consist of one or more lines,
89
allowing any of the pattern lines to match a portion of the input.
90
.Pp
91
.Nm zgrep ,
92
.Nm zegrep ,
93
and
94
.Nm zfgrep
95
act like
96
.Nm grep ,
97
.Nm egrep ,
98
and
99
.Nm fgrep ,
100
respectively, but accept input files compressed with the
101
.Xr compress 1
102
or
103
.Xr gzip 1
104
compression utilities.
105
.Pp
106
The following options are available:
107
.Bl -tag -width indent
108
.It Fl A Ar num , Fl Fl after-context Ns = Ns Ar num
109
Print
110
.Ar num
111
lines of trailing context after each match.
112
See also the
113
.Fl B
114
and
115
.Fl C
116
options.
117
.It Fl a , Fl Fl text
118
Treat all files as ASCII text.
119
Normally
120
.Nm
121
will simply print
122
.Dq Binary file ... matches
123
if files contain binary characters.
124
Use of this option forces
125
.Nm
126
to output lines matching the specified pattern.
127
.It Fl B Ar num , Fl Fl before-context Ns = Ns Ar num
128
Print
129
.Ar num
130
lines of leading context before each match.
131
See also the
132
.Fl A
133
and
134
.Fl C
135
options.
136
.It Fl b , Fl Fl byte-offset
137
The offset in bytes of a matched pattern is
138
displayed in front of the respective matched line.
139
.It Fl C Ns Op Ar num , Fl Fl context Ns = Ns Ar num
140
Print
141
.Ar num
142
lines of leading and trailing context surrounding each match.
143
The default is 2 and is equivalent to
144
.Fl A
145
.Ar 2
146
.Fl B
147
.Ar 2 .
148
Note:
149
no whitespace may be given between the option and its argument.
150
.It Fl c , Fl Fl count
151
Only a count of selected lines is written to standard output.
152
.It Fl Fl colour Ns = Ns Op Ar when , Fl Fl color Ns = Ns Op Ar when
153
Mark up the matching text with the expression stored in
154
.Ev GREP_COLOR
155
environment variable.
156
The possible values of when can be `never', `always' or `auto'.
157
.It Fl D Ar action , Fl Fl devices Ns = Ns Ar action
158
Specify the demanded action for devices, FIFOs and sockets.
159
The default action is `read', which means, that they are read
160
as if they were normal files.
161
If the action is set to `skip', devices will be silently skipped.
162
.It Fl d Ar action , Fl Fl directories Ns = Ns Ar action
163
Specify the demanded action for directories.
164
It is `read' by default, which means that the directories
165
are read in the same manner as normal files.
166
Other possible values are `skip' to silently ignore the
167
directories, and `recurse' to read them recursively, which
168
has the same effect as the
169
.Fl R
170
and
171
.Fl r
172
option.
173
.It Fl E , Fl Fl extended-regexp
174
Interpret
175
.Ar pattern
176
as an extended regular expression
177
(i.e. force
178
.Nm grep
179
to behave as
180
.Nm egrep ) .
181
.It Fl e Ar pattern , Fl Fl regexp Ns = Ns Ar pattern
182
Specify a pattern used during the search of the input:
183
an input line is selected if it matches any of the specified patterns.
184
This option is most useful when multiple
185
.Fl e
186
options are used to specify multiple patterns,
187
or when a pattern begins with a dash
188
.Pq Sq - .
189
.It Fl Fl exclude
190
If specified, it excludes files matching the given
191
filename pattern from the search.
192
Note that
193
.Fl Fl exclude
194
patterns take priority over
195
.Fl Fl include
196
patterns, and if no
197
.Fl Fl include
198
pattern is specified, all files are searched that are
199
not excluded.
200
Patterns are matched to the full path specified,
201
not only to the filename component.
202
.It Fl Fl exclude-dir
203
If
204
.Fl R
205
is specified, it excludes directories matching the
206
given filename pattern from the search.
207
Note that
208
.Fl Fl exclude-dir
209
patterns take priority over
210
.Fl Fl include-dir
211
patterns, and if no
212
.Fl Fl include-dir
213
pattern is specified, all directories are searched that are
214
not excluded.
215
.It Fl F , Fl Fl fixed-strings
216
Interpret
217
.Ar pattern
218
as a set of fixed strings
219
(i.e. force
220
.Nm grep
221
to behave as
222
.Nm fgrep ) .
223
.It Fl f Ar file , Fl Fl file Ns = Ns Ar file
224
Read one or more newline separated patterns from
225
.Ar file .
226
Empty pattern lines match every input line.
227
Newlines are not considered part of a pattern.
228
If
229
.Ar file
230
is empty, nothing is matched.
231
.It Fl G , Fl Fl basic-regexp
232
Interpret
233
.Ar pattern
234
as a basic regular expression
235
(i.e. force
236
.Nm grep
237
to behave as traditional
238
.Nm grep ) .
239
.It Fl H
240
Always print filename headers with output lines.
241
.It Fl h , Fl Fl no-filename
242
Never print filename headers
243
.Pq i.e. filenames
244
with output lines.
245
.It Fl Fl help
246
Print a brief help message.
247
.It Fl I
248
Ignore binary files.
249
This option is equivalent to
250
.Fl Fl binary-file Ns = Ns Ar without-match
251
option.
252
.It Fl i , Fl Fl ignore-case
253
Perform case insensitive matching.
254
By default,
255
.Nm grep
256
is case sensitive.
257
.It Fl Fl include
258
If specified, only files matching the
259
given filename pattern are searched.
260
Note that
261
.Fl Fl exclude
262
patterns take priority over
263
.Fl Fl include
264
patterns.
265
Patterns are matched to the full path specified,
266
not only to the filename component.
267
.It Fl Fl include-dir
268
If
269
.Fl R
270
is specified, only directories matching the
271
given filename pattern are searched.
272
Note that
273
.Fl Fl exclude-dir
274
patterns take priority over
275
.Fl Fl include-dir
276
patterns.
277
.It Fl J, Fl Fl bz2decompress
278
Decompress the
279
.Xr bzip2 1
280
compressed file before looking for the text.
281
.It Fl L , Fl Fl files-without-match
282
Only the names of files not containing selected lines are written to
283
standard output.
284
Pathnames are listed once per file searched.
285
If the standard input is searched, the string
286
.Dq (standard input)
287
is written.
288
.It Fl l , Fl Fl files-with-matches
289
Only the names of files containing selected lines are written to
290
standard output.
291
.Nm grep
292
will only search a file until a match has been found,
293
making searches potentially less expensive.
294
Pathnames are listed once per file searched.
295
If the standard input is searched, the string
296
.Dq (standard input)
297
is written.
298
.It Fl Fl mmap
299
Use
300
.Xr mmap 2
301
instead of
302
.Xr read 2
303
to read input, which can result in better performance under some
304
circumstances but can cause undefined behaviour.
305
.It Fl m Ar num, Fl Fl max-count Ns = Ns Ar num
306
Stop reading the file after
307
.Ar num
308
matches.
309
.It Fl n , Fl Fl line-number
310
Each output line is preceded by its relative line number in the file,
311
starting at line 1.
312
The line number counter is reset for each file processed.
313
This option is ignored if
314
.Fl c ,
315
.Fl L ,
316
.Fl l ,
317
or
318
.Fl q
319
is
320
specified.
321
.It Fl Fl null
322
Prints a zero-byte after the file name.
323
.It Fl O
324
If
325
.Fl R
326
is specified, follow symbolic links only if they were explicitly listed
327
on the command line.
328
The default is not to follow symbolic links.
329
.It Fl o, Fl Fl only-matching
330
Prints only the matching part of the lines.
331
.It Fl p
332
If
333
.Fl R
334
is specified, no symbolic links are followed.
335
This is the default.
336
.It Fl q , Fl Fl quiet , Fl Fl silent
337
Quiet mode:
338
suppress normal output.
339
.Nm grep
340
will only search a file until a match has been found,
341
making searches potentially less expensive.
342
.It Fl R , Fl r , Fl Fl recursive
343
Recursively search subdirectories listed.
344
.It Fl S
345
If
346
.Fl R
347
is specified, all symbolic links are followed.
348
The default is not to follow symbolic links.
349
.It Fl s , Fl Fl no-messages
350
Silent mode.
351
Nonexistent and unreadable files are ignored
352
(i.e. their error messages are suppressed).
353
.It Fl U , Fl Fl binary
354
Search binary files, but do not attempt to print them.
355
.It Fl V , Fl Fl version
356
Display version information and exit.
357
.It Fl v , Fl Fl invert-match
358
Selected lines are those
359
.Em not
360
matching any of the specified patterns.
361
.It Fl w , Fl Fl word-regexp
362
The expression is searched for as a word (as if surrounded by
363
.Sq [[:<:]]
364
and
365
.Sq [[:>:]] ;
366
see
367
.Xr re_format 7 ) .
368
.It Fl x , Fl Fl line-regexp
369
Only input lines selected against an entire fixed string or regular
370
expression are considered to be matching lines.
371
.It Fl y
372
Equivalent to
373
.Fl i .
374
Obsoleted.
375
.It Fl Z , Fl z , Fl Fl decompress
376
Force
377
.Nm grep
378
to behave as
379
.Nm zgrep .
380
.It Fl Fl binary-files Ns = Ns Ar value
381
Controls searching and printing of binary files.
382
Options are
383
.Ar binary ,
384
the default: search binary files but do not print them;
385
.Ar without-match :
386
do not search binary files;
387
and
388
.Ar text :
389
treat all files as text.
390
.Sm off
391
.It Fl Fl context Op = Ar num
392
.Sm on
393
Print
394
.Ar num
395
lines of leading and trailing context.
396
The default is 2.
397
.It Fl Fl line-buffered
398
Force output to be line buffered.
399
By default, output is line buffered when standard output is a terminal
400
and block buffered otherwise.
401
.El
402
.Pp
403
If no file arguments are specified, the standard input is used.
404
.Sh EXIT STATUS
405
The
406
.Nm grep
407
utility exits with one of the following values:
408
.Pp
409
.Bl -tag -width flag -compact
410
.It Li 0
411
One or more lines were selected.
412
.It Li 1
413
No lines were selected.
414
.It Li \*(Gt1
415
An error occurred.
416
.El
417
.Sh EXAMPLES
418
To find all occurrences of the word
419
.Sq patricia
420
in a file:
421
.Pp
422
.Dl $ grep 'patricia' myfile
423
.Pp
424
To find all occurrences of the pattern
425
.Ql .Pp
426
at the beginning of a line:
427
.Pp
428
.Dl $ grep '^\e.Pp' myfile
429
.Pp
430
The apostrophes ensure the entire expression is evaluated by
431
.Nm grep
432
instead of by the user's shell.
433
The caret
434
.Ql ^
435
matches the null string at the beginning of a line,
436
and the
437
.Ql \e
438
escapes the
439
.Ql \&. ,
440
which would otherwise match any character.
441
.Pp
442
To find all lines in a file which do not contain the words
443
.Sq foo
444
or
445
.Sq bar :
446
.Pp
447
.Dl $ grep -v -e 'foo' -e 'bar' myfile
448
.Pp
449
A simple example of an extended regular expression:
450
.Pp
451
.Dl $ egrep '19|20|25' calendar
452
.Pp
453
Peruses the file
454
.Sq calendar
455
looking for either 19, 20, or 25.
456
.Sh SEE ALSO
457
.Xr ed 1 ,
458
.Xr ex 1 ,
459
.Xr gzip 1 ,
460
.Xr sed 1 ,
461
.Xr re_format 7
462
.Sh STANDARDS
463
The
464
.Nm
465
utility is compliant with the
466
.St -p1003.1-2008
467
specification.
468
.Pp
469
The flags
470
.Op Fl AaBbCDdGHhIJLmoPRSUVwZ
471
are extensions to that specification, and the behaviour of the
472
.Fl f
473
flag when used with an empty pattern file is left undefined.
474
.Pp
475
All long options are provided for compatibility with
476
GNU versions of this utility.
477
.Pp
478
Historic versions of the
479
.Nm grep
480
utility also supported the flags
481
.Op Fl ruy .
482
This implementation supports those options;
483
however, their use is strongly discouraged.
484
.Sh HISTORY
485
The
486
.Nm grep
487
command first appeared in
488
.At v6 .
usr.bin/grep/grep.c
1
/*	$NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $	*/
2
/* 	$FreeBSD: stable/11/usr.bin/grep/grep.c 280307 2015-03-21 00:21:30Z pfg $	*/
3
/*	$OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $	*/
4

  
5
/*-
6
 * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
7
 * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31

  
32
#include <sys/cdefs.h>
33
__FBSDID("$FreeBSD: stable/11/usr.bin/grep/grep.c 280307 2015-03-21 00:21:30Z pfg $");
34

  
35
#include <sys/stat.h>
36
#include <sys/types.h>
37

  
38
#include <ctype.h>
39
#include <err.h>
40
#include <errno.h>
41
#include <fcntl.h>
42
#include <getopt.h>
43
#include <limits.h>
44
#include <libgen.h>
45
#include <locale.h>
46
#include <stdbool.h>
47
#define _WITH_GETLINE
48
#include <stdio.h>
49
#include <stdlib.h>
50
#include <string.h>
51
#include <unistd.h>
52

  
53
#include "fastmatch.h"
54
#include "grep.h"
55

  
56
#ifndef WITHOUT_NLS
57
#include <nl_types.h>
58
nl_catd	 catalog;
59
#endif
60

  
61
/*
62
 * Default messags to use when NLS is disabled or no catalogue
63
 * is found.
64
 */
65
const char	*errstr[] = {
66
	"",
67
/* 1*/	"(standard input)",
68
/* 2*/	"cannot read bzip2 compressed file",
69
/* 3*/	"unknown %s option",
70
/* 4*/	"usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n",
71
/* 5*/	"\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
72
/* 6*/	"\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
73
/* 7*/	"\t[--null] [pattern] [file ...]\n",
74
/* 8*/	"Binary file %s matches\n",
75
/* 9*/	"%s (BSD grep) %s\n",
76
};
77

  
78
/* Flags passed to regcomp() and regexec() */
79
int		 cflags = REG_NOSUB;
80
int		 eflags = REG_STARTEND;
81

  
82
/* Shortcut for matching all cases like empty regex */
83
bool		 matchall;
84

  
85
/* Searching patterns */
86
unsigned int	 patterns;
87
static unsigned int pattern_sz;
88
struct pat	*pattern;
89
regex_t		*r_pattern;
90
fastmatch_t	*fg_pattern;
91

  
92
/* Filename exclusion/inclusion patterns */
93
unsigned int	fpatterns, dpatterns;
94
static unsigned int fpattern_sz, dpattern_sz;
95
struct epat	*dpattern, *fpattern;
96

  
97
/* For regex errors  */
98
char	 re_error[RE_ERROR_BUF + 1];
99

  
100
/* Command-line flags */
101
unsigned long long Aflag;	/* -A x: print x lines trailing each match */
102
unsigned long long Bflag;	/* -B x: print x lines leading each match */
103
bool	 Hflag;		/* -H: always print file name */
104
bool	 Lflag;		/* -L: only show names of files with no matches */
105
bool	 bflag;		/* -b: show block numbers for each match */
106
bool	 cflag;		/* -c: only show a count of matching lines */
107
bool	 hflag;		/* -h: don't print filename headers */
108
bool	 iflag;		/* -i: ignore case */
109
bool	 lflag;		/* -l: only show names of files with matches */
110
bool	 mflag;		/* -m x: stop reading the files after x matches */
111
long long mcount;	/* count for -m */
112
long long mlimit;	/* requested value for -m */
113
bool	 nflag;		/* -n: show line numbers in front of matching lines */
114
bool	 oflag;		/* -o: print only matching part */
115
bool	 qflag;		/* -q: quiet mode (don't output anything) */
116
bool	 sflag;		/* -s: silent mode (ignore errors) */
117
bool	 vflag;		/* -v: only show non-matching lines */
118
bool	 wflag;		/* -w: pattern must start and end on word boundaries */
119
bool	 xflag;		/* -x: pattern must match entire line */
120
bool	 lbflag;	/* --line-buffered */
121
bool	 nullflag;	/* --null */
122
char	*label;		/* --label */
123
const char *color;	/* --color */
124
int	 grepbehave = GREP_BASIC;	/* -EFGP: type of the regex */
125
int	 binbehave = BINFILE_BIN;	/* -aIU: handling of binary files */
126
int	 filebehave = FILE_STDIO;	/* -JZ: normal, gzip or bzip2 file */
127
int	 devbehave = DEV_READ;		/* -D: handling of devices */
128
int	 dirbehave = DIR_READ;		/* -dRr: handling of directories */
129
int	 linkbehave = LINK_READ;	/* -OpS: handling of symlinks */
130

  
131
bool	 dexclude, dinclude;	/* --exclude-dir and --include-dir */
132
bool	 fexclude, finclude;	/* --exclude and --include */
133

  
134
enum {
135
	BIN_OPT = CHAR_MAX + 1,
136
	COLOR_OPT,
137
	HELP_OPT,
138
	MMAP_OPT,
139
	LINEBUF_OPT,
140
	LABEL_OPT,
141
	NULL_OPT,
142
	R_EXCLUDE_OPT,
143
	R_INCLUDE_OPT,
144
	R_DEXCLUDE_OPT,
145
	R_DINCLUDE_OPT
146
};
147

  
148
static inline const char	*init_color(const char *);
149

  
150
/* Housekeeping */
151
bool	 first = true;	/* flag whether we are processing the first match */
152
bool	 prev;		/* flag whether or not the previous line matched */
153
int	 tail;		/* lines left to print */
154
bool	 file_err;	/* file reading error */
155

  
156
/*
157
 * Prints usage information and returns 2.
158
 */
159
static void
160
usage(void)
161
{
162
	fprintf(stderr, getstr(4), getprogname());
163
	fprintf(stderr, "%s", getstr(5));
164
	fprintf(stderr, "%s", getstr(6));
165
	fprintf(stderr, "%s", getstr(7));
166
	exit(2);
167
}
168

  
169
static const char	*optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy";
170

  
171
static const struct option long_options[] =
172
{
173
	{"binary-files",	required_argument,	NULL, BIN_OPT},
174
	{"help",		no_argument,		NULL, HELP_OPT},
175
	{"mmap",		no_argument,		NULL, MMAP_OPT},
176
	{"line-buffered",	no_argument,		NULL, LINEBUF_OPT},
177
	{"label",		required_argument,	NULL, LABEL_OPT},
178
	{"null",		no_argument,		NULL, NULL_OPT},
179
	{"color",		optional_argument,	NULL, COLOR_OPT},
180
	{"colour",		optional_argument,	NULL, COLOR_OPT},
181
	{"exclude",		required_argument,	NULL, R_EXCLUDE_OPT},
182
	{"include",		required_argument,	NULL, R_INCLUDE_OPT},
183
	{"exclude-dir",		required_argument,	NULL, R_DEXCLUDE_OPT},
184
	{"include-dir",		required_argument,	NULL, R_DINCLUDE_OPT},
185
	{"after-context",	required_argument,	NULL, 'A'},
186
	{"text",		no_argument,		NULL, 'a'},
187
	{"before-context",	required_argument,	NULL, 'B'},
188
	{"byte-offset",		no_argument,		NULL, 'b'},
189
	{"context",		optional_argument,	NULL, 'C'},
190
	{"count",		no_argument,		NULL, 'c'},
191
	{"devices",		required_argument,	NULL, 'D'},
192
        {"directories",		required_argument,	NULL, 'd'},
193
	{"extended-regexp",	no_argument,		NULL, 'E'},
194
	{"regexp",		required_argument,	NULL, 'e'},
195
	{"fixed-strings",	no_argument,		NULL, 'F'},
196
	{"file",		required_argument,	NULL, 'f'},
197
	{"basic-regexp",	no_argument,		NULL, 'G'},
198
	{"no-filename",		no_argument,		NULL, 'h'},
199
	{"with-filename",	no_argument,		NULL, 'H'},
200
	{"ignore-case",		no_argument,		NULL, 'i'},
201
	{"bz2decompress",	no_argument,		NULL, 'J'},
202
	{"files-with-matches",	no_argument,		NULL, 'l'},
203
	{"files-without-match", no_argument,            NULL, 'L'},
204
	{"max-count",		required_argument,	NULL, 'm'},
205
	{"lzma",		no_argument,		NULL, 'M'},
206
	{"line-number",		no_argument,		NULL, 'n'},
207
	{"only-matching",	no_argument,		NULL, 'o'},
208
	{"quiet",		no_argument,		NULL, 'q'},
209
	{"silent",		no_argument,		NULL, 'q'},
210
	{"recursive",		no_argument,		NULL, 'r'},
211
	{"no-messages",		no_argument,		NULL, 's'},
212
	{"binary",		no_argument,		NULL, 'U'},
213
	{"unix-byte-offsets",	no_argument,		NULL, 'u'},
214
	{"invert-match",	no_argument,		NULL, 'v'},
215
	{"version",		no_argument,		NULL, 'V'},
216
	{"word-regexp",		no_argument,		NULL, 'w'},
217
	{"line-regexp",		no_argument,		NULL, 'x'},
218
	{"xz",			no_argument,		NULL, 'X'},
219
	{"decompress",          no_argument,            NULL, 'Z'},
220
	{NULL,			no_argument,		NULL, 0}
221
};
222

  
223
/*
224
 * Adds a searching pattern to the internal array.
225
 */
226
static void
227
add_pattern(char *pat, size_t len)
228
{
229

  
230
	/* Do not add further pattern is we already match everything */
231
	if (matchall)
232
	  return;
233

  
234
	/* Check if we can do a shortcut */
235
	if (len == 0) {
236
		matchall = true;
237
		for (unsigned int i = 0; i < patterns; i++) {
238
			free(pattern[i].pat);
239
		}
240
		pattern = grep_realloc(pattern, sizeof(struct pat));
241
		pattern[0].pat = NULL;
242
		pattern[0].len = 0;
243
		patterns = 1;
244
		return;
245
	}
246
	/* Increase size if necessary */
247
	if (patterns == pattern_sz) {
248
		pattern_sz *= 2;
249
		pattern = grep_realloc(pattern, ++pattern_sz *
250
		    sizeof(struct pat));
251
	}
252
	if (len > 0 && pat[len - 1] == '\n')
253
		--len;
254
	/* pat may not be NUL-terminated */
255
	pattern[patterns].pat = grep_malloc(len + 1);
256
	memcpy(pattern[patterns].pat, pat, len);
257
	pattern[patterns].len = len;
258
	pattern[patterns].pat[len] = '\0';
259
	++patterns;
260
}
261

  
262
/*
263
 * Adds a file include/exclude pattern to the internal array.
264
 */
265
static void
266
add_fpattern(const char *pat, int mode)
267
{
268

  
269
	/* Increase size if necessary */
270
	if (fpatterns == fpattern_sz) {
271
		fpattern_sz *= 2;
272
		fpattern = grep_realloc(fpattern, ++fpattern_sz *
273
		    sizeof(struct epat));
274
	}
275
	fpattern[fpatterns].pat = grep_strdup(pat);
276
	fpattern[fpatterns].mode = mode;
277
	++fpatterns;
278
}
279

  
280
/*
281
 * Adds a directory include/exclude pattern to the internal array.
282
 */
283
static void
284
add_dpattern(const char *pat, int mode)
285
{
286

  
287
	/* Increase size if necessary */
288
	if (dpatterns == dpattern_sz) {
289
		dpattern_sz *= 2;
290
		dpattern = grep_realloc(dpattern, ++dpattern_sz *
291
		    sizeof(struct epat));
292
	}
293
	dpattern[dpatterns].pat = grep_strdup(pat);
294
	dpattern[dpatterns].mode = mode;
295
	++dpatterns;
296
}
297

  
298
/*
299
 * Reads searching patterns from a file and adds them with add_pattern().
300
 */
301
static void
302
read_patterns(const char *fn)
303
{
304
	struct stat st;
305
	FILE *f;
306
	char *line;
307
	size_t len;
308
	ssize_t rlen;
309

  
310
	if ((f = fopen(fn, "r")) == NULL)
311
		err(2, "%s", fn);
312
	if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
313
		fclose(f);
314
		return;
315
	}
316
	len = 0;
317
	line = NULL;
318
	while ((rlen = getline(&line, &len, f)) != -1)
319
		add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
320
	free(line);
321
	if (ferror(f))
322
		err(2, "%s", fn);
323
	fclose(f);
324
}
325

  
326
static inline const char *
327
init_color(const char *d)
328
{
329
	char *c;
330

  
331
	c = getenv("GREP_COLOR");
332
	return (c != NULL && c[0] != '\0' ? c : d);
333
}
334

  
335
int
336
main(int argc, char *argv[])
337
{
338
	char **aargv, **eargv, *eopts;
339
	char *ep;
340
	const char *pn;
341
	unsigned long long l;
342
	unsigned int aargc, eargc, i;
343
	int c, lastc, needpattern, newarg, prevoptind;
344

  
345
	setlocale(LC_ALL, "");
346

  
347
#ifndef WITHOUT_NLS
348
	catalog = catopen("grep", NL_CAT_LOCALE);
349
#endif
350

  
351
	/* Check what is the program name of the binary.  In this
352
	   way we can have all the funcionalities in one binary
353
	   without the need of scripting and using ugly hacks. */
354
	pn = getprogname();
355
	if (pn[0] == 'b' && pn[1] == 'z') {
356
		filebehave = FILE_BZIP;
357
		pn += 2;
358
	} else if (pn[0] == 'x' && pn[1] == 'z') {
359
		filebehave = FILE_XZ;
360
		pn += 2;
361
	} else if (pn[0] == 'l' && pn[1] == 'z') {
362
		filebehave = FILE_LZMA;
363
		pn += 2;
364
	} else if (pn[0] == 'z') {
365
		filebehave = FILE_GZIP;
366
		pn += 1;
367
	}
368
	switch (pn[0]) {
369
	case 'e':
370
		grepbehave = GREP_EXTENDED;
371
		break;
372
	case 'f':
373
		grepbehave = GREP_FIXED;
374
		break;
375
	}
376

  
377
	lastc = '\0';
378
	newarg = 1;
379
	prevoptind = 1;
380
	needpattern = 1;
381

  
382
	eopts = getenv("GREP_OPTIONS");
383

  
384
	/* support for extra arguments in GREP_OPTIONS */
385
	eargc = 0;
386
	if (eopts != NULL && eopts[0] != '\0') {
387
		char *str;
388

  
389
		/* make an estimation of how many extra arguments we have */
390
		for (unsigned int j = 0; j < strlen(eopts); j++)
391
			if (eopts[j] == ' ')
392
				eargc++;
393

  
394
		eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
395

  
396
		eargc = 0;
397
		/* parse extra arguments */
398
		while ((str = strsep(&eopts, " ")) != NULL)
399
			if (str[0] != '\0')
400
				eargv[eargc++] = grep_strdup(str);
401

  
402
		aargv = (char **)grep_calloc(eargc + argc + 1,
403
		    sizeof(char *));
404

  
405
		aargv[0] = argv[0];
406
		for (i = 0; i < eargc; i++)
407
			aargv[i + 1] = eargv[i];
408
		for (int j = 1; j < argc; j++, i++)
409
			aargv[i + 1] = argv[j];
410

  
411
		aargc = eargc + argc;
412
	} else {
413
		aargv = argv;
414
		aargc = argc;
415
	}
416

  
417
	while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
418
	    -1)) {
419
		switch (c) {
420
		case '0': case '1': case '2': case '3': case '4':
421
		case '5': case '6': case '7': case '8': case '9':
422
			if (newarg || !isdigit(lastc))
423
				Aflag = 0;
424
			else if (Aflag > LLONG_MAX / 10) {
425
				errno = ERANGE;
426
				err(2, NULL);
427
			}
428
			Aflag = Bflag = (Aflag * 10) + (c - '0');
429
			break;
430
		case 'C':
431
			if (optarg == NULL) {
432
				Aflag = Bflag = 2;
433
				break;
434
			}
435
			/* FALLTHROUGH */
436
		case 'A':
437
			/* FALLTHROUGH */
438
		case 'B':
439
			errno = 0;
440
			l = strtoull(optarg, &ep, 10);
441
			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
442
			    ((errno == EINVAL) && (l == 0)))
443
				err(2, NULL);
444
			else if (ep[0] != '\0') {
445
				errno = EINVAL;
446
				err(2, NULL);
447
			}
448
			if (c == 'A')
449
				Aflag = l;
450
			else if (c == 'B')
451
				Bflag = l;
452
			else
453
				Aflag = Bflag = l;
454
			break;
455
		case 'a':
456
			binbehave = BINFILE_TEXT;
457
			break;
458
		case 'b':
459
			bflag = true;
460
			break;
461
		case 'c':
462
			cflag = true;
463
			break;
464
		case 'D':
465
			if (strcasecmp(optarg, "skip") == 0)
466
				devbehave = DEV_SKIP;
467
			else if (strcasecmp(optarg, "read") == 0)
468
				devbehave = DEV_READ;
469
			else
470
				errx(2, getstr(3), "--devices");
471
			break;
472
		case 'd':
473
			if (strcasecmp("recurse", optarg) == 0) {
474
				Hflag = true;
475
				dirbehave = DIR_RECURSE;
476
			} else if (strcasecmp("skip", optarg) == 0)
477
				dirbehave = DIR_SKIP;
... This diff was truncated because it exceeds the maximum size that can be displayed.