File Coverage

src/match_line_reader.c
Criterion Covered Total %
statement 51 71 71.8
branch 18 30 60.0
condition n/a
subroutine n/a
pod n/a
total 69 101 68.3


line stmt bran cond sub pod time code
1             /*-
2             * Copyright (c) 2008 Tim Kientzle
3             * Copyright (c) 2010 Joerg Sonnenberger
4             * All rights reserved.
5             *
6             * Redistribution and use in source and binary forms, with or without
7             * modification, are permitted provided that the following conditions
8             * are met:
9             * 1. Redistributions of source code must retain the above copyright
10             * notice, this list of conditions and the following disclaimer
11             * in this position and unchanged.
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             *
16             * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17             * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18             * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19             * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20             * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21             * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22             * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23             * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24             * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25             * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26             */
27              
28             /*
29             * Copyright (c) 2012, cPanel, Inc.
30             * All rights reserved.
31             * http://cpanel.net/
32             *
33             * This is free software; you can redistribute it and/or modify it under the
34             * same terms as Perl itself. See the Perl manual section 'perlartistic' for
35             * further information.
36             *
37             * Modified for use in Archive::Tar::Builder.
38             */
39              
40             #include
41             #include
42             #include
43             #include
44              
45             #include "match_line_reader.h"
46              
47             #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
48             #define strdup _strdup
49             #endif
50              
51             /*
52             * Read lines from file and do something with each one. If option_null
53             * is set, lines are terminated with zero bytes; otherwise, they're
54             * terminated with newlines.
55             *
56             * This uses a self-sizing buffer to handle arbitrarily-long lines.
57             */
58             struct lafe_line_reader {
59             FILE * f;
60             char * buff;
61             char * buff_end;
62             char * line_start;
63             char * line_end;
64             char * p;
65             char * pathname;
66             size_t buff_length;
67             int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */
68             int ret;
69             };
70              
71             struct lafe_line_reader *
72 42           lafe_line_reader(const char *pathname, int nullSeparator)
73             {
74             struct lafe_line_reader *lr;
75              
76 42 50         if ((lr = calloc(1, sizeof(*lr))) == NULL) {
77 0           errno = ENOMEM;
78              
79 0           return NULL;
80             }
81              
82 42           lr->nullSeparator = nullSeparator;
83 42           lr->pathname = strdup(pathname);
84              
85 42 50         if (strcmp(pathname, "-") == 0) {
86 0           lr->f = stdin;
87             }
88             else {
89 42           lr->f = fopen(pathname, "r");
90             }
91              
92 42 100         if (lr->f == NULL) {
93 14           return NULL;
94             }
95              
96 28           lr->buff_length = 8192;
97 28           lr->line_start = lr->line_end = lr->buff_end = lr->buff = NULL;
98              
99 28           return lr;
100             }
101              
102             static void
103 98           lafe_line_reader_find_eol(struct lafe_line_reader *lr)
104             {
105              
106 98 50         lr->line_end += strcspn(lr->line_end, lr->nullSeparator ? "" : "\x0d\x0a");
107 98           *lr->line_end = '\0'; /* Noop if line_end == buff_end */
108 98           }
109              
110             int
111 98           lafe_line_reader_next(struct lafe_line_reader *lr, const char **next)
112             {
113             size_t bytes_wanted, bytes_read, new_buff_size;
114             char *line_start, *p;
115              
116             for (;;) {
117             /* If there's a line in the buffer, return it immediately. */
118 126 100         while (lr->line_end < lr->buff_end) {
119 70           line_start = lr->line_start;
120 70           lr->line_start = ++lr->line_end;
121              
122 70           lafe_line_reader_find_eol(lr);
123              
124 70 50         if (lr->nullSeparator || line_start[0] != '\0') {
    50          
125 70           *next = line_start;
126              
127 70           return 0;
128             }
129             }
130              
131             /* If we're at end-of-file, process the final data. */
132 56 100         if (lr->f == NULL) {
133 28 50         if (lr->line_start == lr->buff_end) {
134             /* No more text */
135 28           *next = NULL;
136              
137 28           return 0;
138             }
139              
140 0           line_start = lr->line_start;
141 0           lr->line_start = lr->buff_end;
142              
143 0           *next = line_start;
144              
145 0           return 0;
146             }
147              
148             /* Buffer only has part of a line. */
149 28 50         if (lr->line_start > lr->buff) {
150             /* Move a leftover fractional line to the beginning. */
151 0           memmove(lr->buff, lr->line_start,
152 0           lr->buff_end - lr->line_start
153             );
154              
155 0           lr->buff_end -= lr->line_start - lr->buff;
156 0           lr->line_end -= lr->line_start - lr->buff;
157 0           lr->line_start = lr->buff;
158             }
159             else {
160             /* Line is too big; enlarge the buffer. */
161 28           new_buff_size = lr->buff_length * 2;
162              
163 28 50         if (new_buff_size <= lr->buff_length) {
164 0           errno = ENOMEM;
165 0           *next = NULL;
166              
167 0           return -1;
168             }
169              
170 28           lr->buff_length = new_buff_size;
171              
172             /*
173             * Allocate one extra byte to allow terminating
174             * the buffer.
175             */
176 28 50         if ((p = realloc(lr->buff, new_buff_size + 1)) == NULL) {
177 0           errno = ENOMEM;
178 0           *next = NULL;
179              
180 0           return -1;
181             }
182              
183 28           lr->buff_end = p + (lr->buff_end - lr->buff);
184 28           lr->line_end = p + (lr->line_end - lr->buff);
185 28           lr->line_start = lr->buff = p;
186             }
187              
188             /* Get some more data into the buffer. */
189 28           bytes_wanted = lr->buff + lr->buff_length - lr->buff_end;
190 28           bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f);
191 28           lr->buff_end += bytes_read;
192 28           *lr->buff_end = '\0'; /* Always terminate buffer */
193              
194 28           lafe_line_reader_find_eol(lr);
195              
196 28 50         if (ferror(lr->f)) {
197 0           *next = NULL;
198              
199 0           return -1;
200             }
201              
202 28 50         if (feof(lr->f)) {
203 28 50         if (lr->f != stdin) {
204 28           fclose(lr->f);
205             }
206              
207 28           lr->f = NULL;
208             }
209 28           }
210             }
211              
212             void
213 28           lafe_line_reader_free(struct lafe_line_reader *lr)
214             {
215 28           free(lr->buff);
216 28           free(lr->pathname);
217 28           free(lr);
218 28           }