Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/gnulib/lib/getndelim2.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters, | - | ||||||||||||
2 | with bounded memory allocation. | - | ||||||||||||
3 | - | |||||||||||||
4 | Copyright (C) 1993, 1996-1998, 2000, 2003-2004, 2006, 2008-2018 Free | - | ||||||||||||
5 | Software Foundation, Inc. | - | ||||||||||||
6 | - | |||||||||||||
7 | This program is free software: you can redistribute it and/or modify | - | ||||||||||||
8 | it under the terms of the GNU General Public License as published by | - | ||||||||||||
9 | the Free Software Foundation; either version 3 of the License, or | - | ||||||||||||
10 | (at your option) any later version. | - | ||||||||||||
11 | - | |||||||||||||
12 | This program is distributed in the hope that it will be useful, | - | ||||||||||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | ||||||||||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | ||||||||||||
15 | GNU General Public License for more details. | - | ||||||||||||
16 | - | |||||||||||||
17 | You should have received a copy of the GNU General Public License | - | ||||||||||||
18 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ | - | ||||||||||||
19 | - | |||||||||||||
20 | /* Originally written by Jan Brittenson, bson@gnu.ai.mit.edu. */ | - | ||||||||||||
21 | - | |||||||||||||
22 | #include <config.h> | - | ||||||||||||
23 | - | |||||||||||||
24 | #include "getndelim2.h" | - | ||||||||||||
25 | - | |||||||||||||
26 | #include <stdbool.h> | - | ||||||||||||
27 | #include <stddef.h> | - | ||||||||||||
28 | #include <stdlib.h> | - | ||||||||||||
29 | #include <string.h> | - | ||||||||||||
30 | - | |||||||||||||
31 | #if USE_UNLOCKED_IO | - | ||||||||||||
32 | # include "unlocked-io.h" | - | ||||||||||||
33 | #endif | - | ||||||||||||
34 | #if !HAVE_FLOCKFILE | - | ||||||||||||
35 | # undef flockfile | - | ||||||||||||
36 | # define flockfile(x) ((void) 0) | - | ||||||||||||
37 | #endif | - | ||||||||||||
38 | #if !HAVE_FUNLOCKFILE | - | ||||||||||||
39 | # undef funlockfile | - | ||||||||||||
40 | # define funlockfile(x) ((void) 0) | - | ||||||||||||
41 | #endif | - | ||||||||||||
42 | - | |||||||||||||
43 | #include <limits.h> | - | ||||||||||||
44 | #include <stdint.h> | - | ||||||||||||
45 | - | |||||||||||||
46 | #include "freadptr.h" | - | ||||||||||||
47 | #include "freadseek.h" | - | ||||||||||||
48 | #include "memchr2.h" | - | ||||||||||||
49 | - | |||||||||||||
50 | #ifndef SSIZE_MAX | - | ||||||||||||
51 | # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) | - | ||||||||||||
52 | #endif | - | ||||||||||||
53 | - | |||||||||||||
54 | /* Use this to suppress gcc's "...may be used before initialized" warnings. */ | - | ||||||||||||
55 | #if defined GCC_LINT || defined lint | - | ||||||||||||
56 | # define IF_LINT(Code) Code | - | ||||||||||||
57 | #else | - | ||||||||||||
58 | # define IF_LINT(Code) /* empty */ | - | ||||||||||||
59 | #endif | - | ||||||||||||
60 | - | |||||||||||||
61 | /* The maximum value that getndelim2 can return without suffering from | - | ||||||||||||
62 | overflow problems, either internally (because of pointer | - | ||||||||||||
63 | subtraction overflow) or due to the API (because of ssize_t). */ | - | ||||||||||||
64 | #define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX) | - | ||||||||||||
65 | - | |||||||||||||
66 | /* Try to add at least this many bytes when extending the buffer. | - | ||||||||||||
67 | MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */ | - | ||||||||||||
68 | #define MIN_CHUNK 64 | - | ||||||||||||
69 | - | |||||||||||||
70 | ssize_t | - | ||||||||||||
71 | getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax, | - | ||||||||||||
72 | int delim1, int delim2, FILE *stream) | - | ||||||||||||
73 | { | - | ||||||||||||
74 | size_t nbytes_avail; /* Allocated but unused bytes in *LINEPTR. */ | - | ||||||||||||
75 | char *read_pos; /* Where we're reading into *LINEPTR. */ | - | ||||||||||||
76 | ssize_t bytes_stored = -1; | - | ||||||||||||
77 | char *ptr = *lineptr; | - | ||||||||||||
78 | size_t size = *linesize; | - | ||||||||||||
79 | bool found_delimiter; | - | ||||||||||||
80 | - | |||||||||||||
81 | if (!ptr)
| 83 | ||||||||||||
82 | { | - | ||||||||||||
83 | size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
| 0-83 | ||||||||||||
84 | ptr = malloc (size); | - | ||||||||||||
85 | if (!ptr)
| 0-83 | ||||||||||||
86 | return -1; never executed: return -1; | 0 | ||||||||||||
87 | } executed 83 times by 1 test: end of block Executed by:
| 83 | ||||||||||||
88 | - | |||||||||||||
89 | if (size < offset)
| 0-166 | ||||||||||||
90 | goto done; never executed: goto done; | 0 | ||||||||||||
91 | - | |||||||||||||
92 | nbytes_avail = size - offset; | - | ||||||||||||
93 | read_pos = ptr + offset; | - | ||||||||||||
94 | - | |||||||||||||
95 | if (nbytes_avail == 0 && nmax <= size)
| 0-166 | ||||||||||||
96 | goto done; never executed: goto done; | 0 | ||||||||||||
97 | - | |||||||||||||
98 | /* Normalize delimiters, since memchr2 doesn't handle EOF. */ | - | ||||||||||||
99 | if (delim1 == EOF)
| 0-166 | ||||||||||||
100 | delim1 = delim2; never executed: delim1 = delim2; | 0 | ||||||||||||
101 | else if (delim2 == EOF)
| 0-166 | ||||||||||||
102 | delim2 = delim1; never executed: delim2 = delim1; | 0 | ||||||||||||
103 | - | |||||||||||||
104 | flockfile (stream); | - | ||||||||||||
105 | - | |||||||||||||
106 | found_delimiter = false; | - | ||||||||||||
107 | do | - | ||||||||||||
108 | { | - | ||||||||||||
109 | /* Here always ptr + size == read_pos + nbytes_avail. | - | ||||||||||||
110 | Also nbytes_avail > 0 || size < nmax. */ | - | ||||||||||||
111 | - | |||||||||||||
112 | int c IF_LINT (= 0); | - | ||||||||||||
113 | const char *buffer; | - | ||||||||||||
114 | size_t buffer_len; | - | ||||||||||||
115 | - | |||||||||||||
116 | buffer = freadptr (stream, &buffer_len); | - | ||||||||||||
117 | if (buffer)
| 61-110 | ||||||||||||
118 | { | - | ||||||||||||
119 | if (delim1 != EOF)
| 0-110 | ||||||||||||
120 | { | - | ||||||||||||
121 | const char *end = memchr2 (buffer, delim1, delim2, buffer_len); | - | ||||||||||||
122 | if (end)
| 5-105 | ||||||||||||
123 | { | - | ||||||||||||
124 | buffer_len = end - buffer + 1; | - | ||||||||||||
125 | found_delimiter = true; | - | ||||||||||||
126 | } executed 105 times by 1 test: end of block Executed by:
| 105 | ||||||||||||
127 | } executed 110 times by 1 test: end of block Executed by:
| 110 | ||||||||||||
128 | } executed 110 times by 1 test: end of block Executed by:
| 110 | ||||||||||||
129 | else | - | ||||||||||||
130 | { | - | ||||||||||||
131 | c = getc (stream); | - | ||||||||||||
132 | if (c == EOF)
| 0-61 | ||||||||||||
133 | { | - | ||||||||||||
134 | /* Return partial line, if any. */ | - | ||||||||||||
135 | if (read_pos == ptr)
| 5-56 | ||||||||||||
136 | goto unlock_done; executed 56 times by 1 test: goto unlock_done; Executed by:
| 56 | ||||||||||||
137 | else | - | ||||||||||||
138 | break; executed 5 times by 1 test: break; Executed by:
| 5 | ||||||||||||
139 | } | - | ||||||||||||
140 | if (c == delim1 || c == delim2)
| 0 | ||||||||||||
141 | found_delimiter = true; never executed: found_delimiter = 1 ; | 0 | ||||||||||||
142 | buffer_len = 1; | - | ||||||||||||
143 | } never executed: end of block | 0 | ||||||||||||
144 | - | |||||||||||||
145 | /* We always want at least one byte left in the buffer, since we | - | ||||||||||||
146 | always (unless we get an error while reading the first byte) | - | ||||||||||||
147 | NUL-terminate the line buffer. */ | - | ||||||||||||
148 | - | |||||||||||||
149 | if (nbytes_avail < buffer_len + 1 && size < nmax)
| 0-110 | ||||||||||||
150 | { | - | ||||||||||||
151 | /* Grow size proportionally, not linearly, to avoid O(n^2) | - | ||||||||||||
152 | running time. */ | - | ||||||||||||
153 | size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
| 0 | ||||||||||||
154 | char *newptr; | - | ||||||||||||
155 | - | |||||||||||||
156 | /* Increase newsize so that it becomes | - | ||||||||||||
157 | >= (read_pos - ptr) + buffer_len. */ | - | ||||||||||||
158 | if (newsize - (read_pos - ptr) < buffer_len + 1)
| 0 | ||||||||||||
159 | newsize = (read_pos - ptr) + buffer_len + 1; never executed: newsize = (read_pos - ptr) + buffer_len + 1; | 0 | ||||||||||||
160 | /* Respect nmax. This handles possible integer overflow. */ | - | ||||||||||||
161 | if (! (size < newsize && newsize <= nmax))
| 0 | ||||||||||||
162 | newsize = nmax; never executed: newsize = nmax; | 0 | ||||||||||||
163 | - | |||||||||||||
164 | if (GETNDELIM2_MAXIMUM < newsize - offset)
| 0 | ||||||||||||
165 | { | - | ||||||||||||
166 | size_t newsizemax = offset + GETNDELIM2_MAXIMUM + 1;
| 0 | ||||||||||||
167 | if (size == newsizemax)
| 0 | ||||||||||||
168 | goto unlock_done; never executed: goto unlock_done; | 0 | ||||||||||||
169 | newsize = newsizemax; | - | ||||||||||||
170 | } never executed: end of block | 0 | ||||||||||||
171 | - | |||||||||||||
172 | nbytes_avail = newsize - (read_pos - ptr); | - | ||||||||||||
173 | newptr = realloc (ptr, newsize); | - | ||||||||||||
174 | if (!newptr)
| 0 | ||||||||||||
175 | goto unlock_done; never executed: goto unlock_done; | 0 | ||||||||||||
176 | ptr = newptr; | - | ||||||||||||
177 | size = newsize; | - | ||||||||||||
178 | read_pos = size - nbytes_avail + ptr; | - | ||||||||||||
179 | } never executed: end of block | 0 | ||||||||||||
180 | - | |||||||||||||
181 | /* Here, if size < nmax, nbytes_avail >= buffer_len + 1. | - | ||||||||||||
182 | If size == nmax, nbytes_avail > 0. */ | - | ||||||||||||
183 | - | |||||||||||||
184 | if (1 < nbytes_avail)
| 0-110 | ||||||||||||
185 | { | - | ||||||||||||
186 | size_t copy_len = nbytes_avail - 1; | - | ||||||||||||
187 | if (buffer_len < copy_len)
| 0-110 | ||||||||||||
188 | copy_len = buffer_len; executed 110 times by 1 test: copy_len = buffer_len; Executed by:
| 110 | ||||||||||||
189 | if (buffer)
| 0-110 | ||||||||||||
190 | memcpy (read_pos, buffer, copy_len); executed 110 times by 1 test: memcpy (read_pos, buffer, copy_len); Executed by:
| 110 | ||||||||||||
191 | else | - | ||||||||||||
192 | *read_pos = c; never executed: *read_pos = c; | 0 | ||||||||||||
193 | read_pos += copy_len; | - | ||||||||||||
194 | nbytes_avail -= copy_len; | - | ||||||||||||
195 | } executed 110 times by 1 test: end of block Executed by:
| 110 | ||||||||||||
196 | - | |||||||||||||
197 | /* Here still nbytes_avail > 0. */ | - | ||||||||||||
198 | - | |||||||||||||
199 | if (buffer && freadseek (stream, buffer_len))
| 0-110 | ||||||||||||
200 | goto unlock_done; never executed: goto unlock_done; | 0 | ||||||||||||
201 | } executed 110 times by 1 test: end of block Executed by:
| 110 | ||||||||||||
202 | while (!found_delimiter);
| 5-105 | ||||||||||||
203 | - | |||||||||||||
204 | /* Done - NUL terminate and return the number of bytes read. | - | ||||||||||||
205 | At this point we know that nbytes_avail >= 1. */ | - | ||||||||||||
206 | *read_pos = '\0'; | - | ||||||||||||
207 | - | |||||||||||||
208 | bytes_stored = read_pos - (ptr + offset); | - | ||||||||||||
209 | - | |||||||||||||
210 | unlock_done: code before this statement executed 110 times by 1 test: unlock_done: Executed by:
| 110 | ||||||||||||
211 | funlockfile (stream); | - | ||||||||||||
212 | - | |||||||||||||
213 | done: code before this statement executed 166 times by 1 test: done: Executed by:
| 166 | ||||||||||||
214 | *lineptr = ptr; | - | ||||||||||||
215 | *linesize = size; | - | ||||||||||||
216 | return bytes_stored ? bytes_stored : -1; executed 166 times by 1 test: return bytes_stored ? bytes_stored : -1; Executed by:
| 166 | ||||||||||||
217 | } | - | ||||||||||||
Source code | Switch to Preprocessed file |