getndelim2.c revision 1.1.1.1.2.2 1 1.1.1.1.2.2 jym /* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters,
2 1.1.1.1.2.2 jym with bounded memory allocation.
3 1.1.1.1.2.2 jym
4 1.1.1.1.2.2 jym Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003, 2004 Free Software
5 1.1.1.1.2.2 jym Foundation, Inc.
6 1.1.1.1.2.2 jym
7 1.1.1.1.2.2 jym This program is free software; you can redistribute it and/or modify
8 1.1.1.1.2.2 jym it under the terms of the GNU General Public License as published by
9 1.1.1.1.2.2 jym the Free Software Foundation; either version 2, or (at your option)
10 1.1.1.1.2.2 jym any later version.
11 1.1.1.1.2.2 jym
12 1.1.1.1.2.2 jym This program is distributed in the hope that it will be useful,
13 1.1.1.1.2.2 jym but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1.1.1.2.2 jym MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1.1.1.2.2 jym GNU General Public License for more details.
16 1.1.1.1.2.2 jym
17 1.1.1.1.2.2 jym You should have received a copy of the GNU General Public License
18 1.1.1.1.2.2 jym along with this program; if not, write to the Free Software Foundation,
19 1.1.1.1.2.2 jym Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20 1.1.1.1.2.2 jym
21 1.1.1.1.2.2 jym /* Originally written by Jan Brittenson, bson (at) gnu.ai.mit.edu. */
22 1.1.1.1.2.2 jym
23 1.1.1.1.2.2 jym #ifdef HAVE_CONFIG_H
24 1.1.1.1.2.2 jym # include <config.h>
25 1.1.1.1.2.2 jym #endif
26 1.1.1.1.2.2 jym
27 1.1.1.1.2.2 jym #include "getndelim2.h"
28 1.1.1.1.2.2 jym
29 1.1.1.1.2.2 jym #include <stdlib.h>
30 1.1.1.1.2.2 jym #include <stddef.h>
31 1.1.1.1.2.2 jym
32 1.1.1.1.2.2 jym #if USE_UNLOCKED_IO
33 1.1.1.1.2.2 jym # include "unlocked-io.h"
34 1.1.1.1.2.2 jym #endif
35 1.1.1.1.2.2 jym
36 1.1.1.1.2.2 jym #include <limits.h>
37 1.1.1.1.2.2 jym #if HAVE_INTTYPES_H
38 1.1.1.1.2.2 jym # include <inttypes.h>
39 1.1.1.1.2.2 jym #endif
40 1.1.1.1.2.2 jym #if HAVE_STDINT_H
41 1.1.1.1.2.2 jym # include <stdint.h>
42 1.1.1.1.2.2 jym #endif
43 1.1.1.1.2.2 jym #ifndef PTRDIFF_MAX
44 1.1.1.1.2.2 jym # define PTRDIFF_MAX ((ptrdiff_t) (SIZE_MAX / 2))
45 1.1.1.1.2.2 jym #endif
46 1.1.1.1.2.2 jym #ifndef SIZE_MAX
47 1.1.1.1.2.2 jym # define SIZE_MAX ((size_t) -1)
48 1.1.1.1.2.2 jym #endif
49 1.1.1.1.2.2 jym #ifndef SSIZE_MAX
50 1.1.1.1.2.2 jym # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
51 1.1.1.1.2.2 jym #endif
52 1.1.1.1.2.2 jym
53 1.1.1.1.2.2 jym /* The maximum value that getndelim2 can return without suffering from
54 1.1.1.1.2.2 jym overflow problems, either internally (because of pointer
55 1.1.1.1.2.2 jym subtraction overflow) or due to the API (because of ssize_t). */
56 1.1.1.1.2.2 jym #define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX)
57 1.1.1.1.2.2 jym
58 1.1.1.1.2.2 jym /* Try to add at least this many bytes when extending the buffer.
59 1.1.1.1.2.2 jym MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */
60 1.1.1.1.2.2 jym #define MIN_CHUNK 64
61 1.1.1.1.2.2 jym
62 1.1.1.1.2.2 jym ssize_t
63 1.1.1.1.2.2 jym getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
64 1.1.1.1.2.2 jym int delim1, int delim2, FILE *stream)
65 1.1.1.1.2.2 jym {
66 1.1.1.1.2.2 jym size_t nbytes_avail; /* Allocated but unused bytes in *LINEPTR. */
67 1.1.1.1.2.2 jym char *read_pos; /* Where we're reading into *LINEPTR. */
68 1.1.1.1.2.2 jym ssize_t bytes_stored = -1;
69 1.1.1.1.2.2 jym char *ptr = *lineptr;
70 1.1.1.1.2.2 jym size_t size = *linesize;
71 1.1.1.1.2.2 jym
72 1.1.1.1.2.2 jym if (!ptr)
73 1.1.1.1.2.2 jym {
74 1.1.1.1.2.2 jym size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
75 1.1.1.1.2.2 jym ptr = malloc (size);
76 1.1.1.1.2.2 jym if (!ptr)
77 1.1.1.1.2.2 jym return -1;
78 1.1.1.1.2.2 jym }
79 1.1.1.1.2.2 jym
80 1.1.1.1.2.2 jym if (size < offset)
81 1.1.1.1.2.2 jym goto done;
82 1.1.1.1.2.2 jym
83 1.1.1.1.2.2 jym nbytes_avail = size - offset;
84 1.1.1.1.2.2 jym read_pos = ptr + offset;
85 1.1.1.1.2.2 jym
86 1.1.1.1.2.2 jym if (nbytes_avail == 0 && nmax <= size)
87 1.1.1.1.2.2 jym goto done;
88 1.1.1.1.2.2 jym
89 1.1.1.1.2.2 jym for (;;)
90 1.1.1.1.2.2 jym {
91 1.1.1.1.2.2 jym /* Here always ptr + size == read_pos + nbytes_avail. */
92 1.1.1.1.2.2 jym
93 1.1.1.1.2.2 jym int c;
94 1.1.1.1.2.2 jym
95 1.1.1.1.2.2 jym /* We always want at least one byte left in the buffer, since we
96 1.1.1.1.2.2 jym always (unless we get an error while reading the first byte)
97 1.1.1.1.2.2 jym NUL-terminate the line buffer. */
98 1.1.1.1.2.2 jym
99 1.1.1.1.2.2 jym if (nbytes_avail < 2 && size < nmax)
100 1.1.1.1.2.2 jym {
101 1.1.1.1.2.2 jym size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
102 1.1.1.1.2.2 jym char *newptr;
103 1.1.1.1.2.2 jym
104 1.1.1.1.2.2 jym if (! (size < newsize && newsize <= nmax))
105 1.1.1.1.2.2 jym newsize = nmax;
106 1.1.1.1.2.2 jym
107 1.1.1.1.2.2 jym if (GETNDELIM2_MAXIMUM < newsize - offset)
108 1.1.1.1.2.2 jym {
109 1.1.1.1.2.2 jym size_t newsizemax = offset + GETNDELIM2_MAXIMUM + 1;
110 1.1.1.1.2.2 jym if (size == newsizemax)
111 1.1.1.1.2.2 jym goto done;
112 1.1.1.1.2.2 jym newsize = newsizemax;
113 1.1.1.1.2.2 jym }
114 1.1.1.1.2.2 jym
115 1.1.1.1.2.2 jym nbytes_avail = newsize - (read_pos - ptr);
116 1.1.1.1.2.2 jym newptr = realloc (ptr, newsize);
117 1.1.1.1.2.2 jym if (!newptr)
118 1.1.1.1.2.2 jym goto done;
119 1.1.1.1.2.2 jym ptr = newptr;
120 1.1.1.1.2.2 jym size = newsize;
121 1.1.1.1.2.2 jym read_pos = size - nbytes_avail + ptr;
122 1.1.1.1.2.2 jym }
123 1.1.1.1.2.2 jym
124 1.1.1.1.2.2 jym c = getc (stream);
125 1.1.1.1.2.2 jym if (c == EOF)
126 1.1.1.1.2.2 jym {
127 1.1.1.1.2.2 jym /* Return partial line, if any. */
128 1.1.1.1.2.2 jym if (read_pos == ptr)
129 1.1.1.1.2.2 jym goto done;
130 1.1.1.1.2.2 jym else
131 1.1.1.1.2.2 jym break;
132 1.1.1.1.2.2 jym }
133 1.1.1.1.2.2 jym
134 1.1.1.1.2.2 jym if (nbytes_avail >= 2)
135 1.1.1.1.2.2 jym {
136 1.1.1.1.2.2 jym *read_pos++ = c;
137 1.1.1.1.2.2 jym nbytes_avail--;
138 1.1.1.1.2.2 jym }
139 1.1.1.1.2.2 jym
140 1.1.1.1.2.2 jym if (c == delim1 || c == delim2)
141 1.1.1.1.2.2 jym /* Return the line. */
142 1.1.1.1.2.2 jym break;
143 1.1.1.1.2.2 jym }
144 1.1.1.1.2.2 jym
145 1.1.1.1.2.2 jym /* Done - NUL terminate and return the number of bytes read.
146 1.1.1.1.2.2 jym At this point we know that nbytes_avail >= 1. */
147 1.1.1.1.2.2 jym *read_pos = '\0';
148 1.1.1.1.2.2 jym
149 1.1.1.1.2.2 jym bytes_stored = read_pos - (ptr + offset);
150 1.1.1.1.2.2 jym
151 1.1.1.1.2.2 jym done:
152 1.1.1.1.2.2 jym *lineptr = ptr;
153 1.1.1.1.2.2 jym *linesize = size;
154 1.1.1.1.2.2 jym return bytes_stored;
155 1.1.1.1.2.2 jym }
156