]>
git.cameronkatri.com Git - apple_cmds.git/blob - text_cmds/grep/file.c
1 /* $NetBSD: file.c,v 1.5 2011/02/16 18:35:39 joerg Exp $ */
2 /* $FreeBSD: src/usr.bin/grep/file.c,v 1.7 2011/10/11 22:27:23 gabor Exp $ */
3 /* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */
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>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: src/usr.bin/grep/file.c,v 1.7 2011/10/11 22:27:23 gabor Exp $");
36 #include <sys/param.h>
39 #include <sys/types.h>
61 #define MAXBUFSIZ (32 * 1024)
64 static gzFile gzbufdesc
;
66 static lzma_stream lstrm
= LZMA_STREAM_INIT
;
69 static BZFILE
* bzbufdesc
;
72 static unsigned char *buffer
;
73 static unsigned char *bufpos
;
77 static unsigned char *lnbuf
;
78 static size_t lnbuflen
;
81 grep_refill(struct file
*f
)
85 if (filebehave
== FILE_MMAP
)
91 if (filebehave
== FILE_GZIP
) {
92 nr
= gzread(gzbufdesc
, buffer
, MAXBUFSIZ
);
94 } else if (filebehave
== FILE_BZIP
&& bzbufdesc
!= NULL
) {
97 nr
= BZ2_bzRead(&bzerr
, bzbufdesc
, buffer
, MAXBUFSIZ
);
101 /* No problem, nr will be okay */
103 case BZ_DATA_ERROR_MAGIC
:
105 * As opposed to gzread(), which simply returns the
106 * plain file data, if it is not in the correct
107 * compressed format, BZ2_bzRead() instead aborts.
109 * So, just restart at the beginning of the file again,
110 * and use plain reads from now on.
112 BZ2_bzReadClose(&bzerr
, bzbufdesc
);
114 if (lseek(f
->fd
, 0, SEEK_SET
) == -1)
116 nr
= read(f
->fd
, buffer
, MAXBUFSIZ
);
119 /* Make sure we exit with an error */
124 } else if ((filebehave
== FILE_XZ
) || (filebehave
== FILE_LZMA
)) {
125 lzma_action action
= LZMA_RUN
;
126 uint8_t in_buf
[MAXBUFSIZ
];
129 ret
= (filebehave
== FILE_XZ
) ?
130 lzma_stream_decoder(&lstrm
, UINT64_MAX
,
132 lzma_alone_decoder(&lstrm
, UINT64_MAX
);
137 lstrm
.next_out
= buffer
;
138 lstrm
.avail_out
= MAXBUFSIZ
;
139 lstrm
.next_in
= in_buf
;
140 nr
= read(f
->fd
, in_buf
, MAXBUFSIZ
);
145 action
= LZMA_FINISH
;
148 ret
= lzma_code(&lstrm
, action
);
150 if (ret
!= LZMA_OK
&& ret
!= LZMA_STREAM_END
)
152 bufrem
= MAXBUFSIZ
- lstrm
.avail_out
;
156 nr
= read(f
->fd
, buffer
, MAXBUFSIZ
);
166 grep_lnbufgrow(size_t newlen
)
169 if (lnbuflen
< newlen
) {
170 lnbuf
= grep_realloc(lnbuf
, newlen
);
178 grep_fgetln(struct file
*f
, size_t *lenp
)
186 /* Fill the buffer, if necessary */
187 if (bufrem
== 0 && grep_refill(f
) != 0)
191 /* Return zero length to indicate EOF */
194 return (char *)(bufpos
);
200 /* Look for a newline in the remaining part of the buffer */
201 if ((p
= memchr(bufpos
, '\n', bufrem
)) != NULL
) {
202 ++p
; /* advance over newline */
204 ret
= (char *)bufpos
;
215 /* We have to copy the current buffered data to the line buffer */
216 for (len
= bufrem
, off
= 0; ; len
+= bufrem
) {
217 /* Make sure there is room for more data */
218 if (grep_lnbufgrow(len
+ LNBUFBUMP
))
220 memcpy(lnbuf
+ off
, bufpos
, len
- off
);
222 if (grep_refill(f
) != 0)
225 /* EOF: return partial line */
227 if ((p
= memchr(bufpos
, '\n', bufrem
)) == NULL
)
229 /* got it: finish up the line (like code above) */
233 if (grep_lnbufgrow(len
))
235 memcpy(lnbuf
+ off
, bufpos
, diff
);
242 return (char *)(lnbuf
);
253 * Opens a file for processing.
256 grep_open(const char *path
)
260 f
= grep_malloc(sizeof *f
);
261 memset(f
, 0, sizeof *f
);
263 /* Processing stdin implies --line-buffered. */
265 f
->fd
= STDIN_FILENO
;
266 } else if ((f
->fd
= open(path
, O_RDONLY
)) == -1)
269 if (filebehave
== FILE_MMAP
) {
272 if ((fstat(f
->fd
, &st
) == -1) || (st
.st_size
> OFF_MAX
) ||
273 (!S_ISREG(st
.st_mode
)))
274 filebehave
= FILE_STDIO
;
277 int flags
= MAP_PRIVATE
| MAP_NOCACHE
;
279 int flags
= MAP_PRIVATE
| MAP_NOCORE
| MAP_NOSYNC
;
281 #ifdef MAP_PREFAULT_READ
282 flags
|= MAP_PREFAULT_READ
;
285 buffer
= mmap(NULL
, fsiz
, PROT_READ
, flags
,
287 if (buffer
== MAP_FAILED
)
288 filebehave
= FILE_STDIO
;
292 madvise(buffer
, st
.st_size
, MADV_SEQUENTIAL
);
297 if ((buffer
== NULL
) || (buffer
== MAP_FAILED
))
298 buffer
= grep_malloc(MAXBUFSIZ
);
300 if (filebehave
== FILE_GZIP
&&
301 (gzbufdesc
= gzdopen(f
->fd
, "r")) == NULL
)
304 #ifndef WITHOUT_BZIP2
305 if (filebehave
== FILE_BZIP
&&
306 (bzbufdesc
= BZ2_bzdopen(f
->fd
, "r")) == NULL
)
310 /* Fill read buffer, also catches errors early */
311 if (bufrem
== 0 && grep_refill(f
) != 0)
314 /* Check for binary stuff, if necessary */
315 if (binbehave
!= BINFILE_TEXT
&& memchr(bufpos
, '\0', bufrem
) != NULL
)
331 grep_close(struct file
*f
)
336 /* Reset read buffer and line buffer */
337 if (filebehave
== FILE_MMAP
) {
338 munmap(buffer
, fsiz
);