Line data Source code
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, 1997, 1998, 2000, 2003, 2004, 2006 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 <http://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 <stdlib.h>
27 : #include <stddef.h>
28 :
29 : #if USE_UNLOCKED_IO
30 : # include "unlocked-io.h"
31 : #endif
32 :
33 : #include <limits.h>
34 : #include <stdint.h>
35 :
36 : #ifndef SSIZE_MAX
37 : # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
38 : #endif
39 :
40 : /* The maximum value that getndelim2 can return without suffering from
41 : overflow problems, either internally (because of pointer
42 : subtraction overflow) or due to the API (because of ssize_t). */
43 : #define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX)
44 :
45 : /* Try to add at least this many bytes when extending the buffer.
46 : MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */
47 : #define MIN_CHUNK 64
48 :
49 : ssize_t
50 15 : getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
51 : int delim1, int delim2, FILE *stream)
52 : {
53 : size_t nbytes_avail; /* Allocated but unused bytes in *LINEPTR. */
54 : char *read_pos; /* Where we're reading into *LINEPTR. */
55 15 : ssize_t bytes_stored = -1;
56 15 : char *ptr = *lineptr;
57 15 : size_t size = *linesize;
58 :
59 15 : if (!ptr)
60 : {
61 7 : size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
62 7 : ptr = malloc (size);
63 7 : if (!ptr)
64 0 : return -1;
65 : }
66 :
67 15 : if (size < offset)
68 0 : goto done;
69 :
70 15 : nbytes_avail = size - offset;
71 15 : read_pos = ptr + offset;
72 :
73 15 : if (nbytes_avail == 0 && nmax <= size)
74 0 : goto done;
75 :
76 : for (;;)
77 3 : {
78 : /* Here always ptr + size == read_pos + nbytes_avail. */
79 :
80 : int c;
81 :
82 : /* We always want at least one byte left in the buffer, since we
83 : always (unless we get an error while reading the first byte)
84 : NUL-terminate the line buffer. */
85 :
86 18 : if (nbytes_avail < 2 && size < nmax)
87 : {
88 0 : size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
89 : char *newptr;
90 :
91 0 : if (! (size < newsize && newsize <= nmax))
92 0 : newsize = nmax;
93 :
94 0 : if (GETNDELIM2_MAXIMUM < newsize - offset)
95 : {
96 0 : size_t newsizemax = offset + GETNDELIM2_MAXIMUM + 1;
97 0 : if (size == newsizemax)
98 0 : goto done;
99 0 : newsize = newsizemax;
100 : }
101 :
102 0 : nbytes_avail = newsize - (read_pos - ptr);
103 0 : newptr = realloc (ptr, newsize);
104 0 : if (!newptr)
105 0 : goto done;
106 0 : ptr = newptr;
107 0 : size = newsize;
108 0 : read_pos = size - nbytes_avail + ptr;
109 : }
110 :
111 18 : c = getc (stream);
112 18 : if (c == EOF)
113 : {
114 : /* Return partial line, if any. */
115 3 : if (read_pos == ptr)
116 2 : goto done;
117 : else
118 1 : break;
119 : }
120 :
121 15 : if (nbytes_avail >= 2)
122 : {
123 15 : *read_pos++ = c;
124 15 : nbytes_avail--;
125 : }
126 :
127 15 : if (c == delim1 || c == delim2)
128 : /* Return the line. */
129 : break;
130 : }
131 :
132 : /* Done - NUL terminate and return the number of bytes read.
133 : At this point we know that nbytes_avail >= 1. */
134 13 : *read_pos = '\0';
135 :
136 13 : bytes_stored = read_pos - (ptr + offset);
137 :
138 15 : done:
139 15 : *lineptr = ptr;
140 15 : *linesize = size;
141 15 : return bytes_stored;
142 : }
|