| 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 blockExecuted 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 blockExecuted by:
| 105 | ||||||||||||
| 127 | } executed 110 times by 1 test: end of blockExecuted by:
| 110 | ||||||||||||
| 128 | } executed 110 times by 1 test: end of blockExecuted 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 blockExecuted 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 blockExecuted 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 |