Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * stringinfo.c
4 : *
5 : * StringInfo provides an extensible string data type (currently limited to a
6 : * length of 1GB). It can be used to buffer either ordinary C strings
7 : * (null-terminated text) or arbitrary binary data. All storage is allocated
8 : * with palloc() (falling back to malloc in frontend code).
9 : *
10 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
11 : * Portions Copyright (c) 1994, Regents of the University of California
12 : *
13 : * src/common/stringinfo.c
14 : *
15 : *-------------------------------------------------------------------------
16 : */
17 :
18 : #ifndef FRONTEND
19 :
20 : #include "postgres.h"
21 : #include "utils/memutils.h"
22 :
23 : #else
24 :
25 : #include "postgres_fe.h"
26 :
27 : /* It's possible we could use a different value for this in frontend code */
28 : #define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
29 :
30 : #endif
31 :
32 : #include "lib/stringinfo.h"
33 :
34 :
35 : /*
36 : * makeStringInfo
37 : *
38 : * Create an empty 'StringInfoData' & return a pointer to it.
39 : */
40 : StringInfo
41 97400 : makeStringInfo(void)
42 : {
43 : StringInfo res;
44 :
45 97400 : res = (StringInfo) palloc(sizeof(StringInfoData));
46 :
47 97400 : initStringInfo(res);
48 :
49 97400 : return res;
50 : }
51 :
52 : /*
53 : * initStringInfo
54 : *
55 : * Initialize a StringInfoData struct (with previously undefined contents)
56 : * to describe an empty string.
57 : */
58 : void
59 9801882 : initStringInfo(StringInfo str)
60 : {
61 9801882 : int size = 1024; /* initial default buffer size */
62 :
63 9801882 : str->data = (char *) palloc(size);
64 9801882 : str->maxlen = size;
65 9801882 : resetStringInfo(str);
66 9801882 : }
67 :
68 : /*
69 : * resetStringInfo
70 : *
71 : * Reset the StringInfo: the data buffer remains valid, but its
72 : * previous content, if any, is cleared.
73 : *
74 : * Read-only StringInfos as initialized by initReadOnlyStringInfo cannot be
75 : * reset.
76 : */
77 : void
78 31729858 : resetStringInfo(StringInfo str)
79 : {
80 : /* don't allow resets of read-only StringInfos */
81 : Assert(str->maxlen != 0);
82 :
83 31729858 : str->data[0] = '\0';
84 31729858 : str->len = 0;
85 31729858 : str->cursor = 0;
86 31729858 : }
87 :
88 : /*
89 : * appendStringInfo
90 : *
91 : * Format text data under the control of fmt (an sprintf-style format string)
92 : * and append it to whatever is already in str. More space is allocated
93 : * to str if necessary. This is sort of like a combination of sprintf and
94 : * strcat.
95 : */
96 : void
97 335991420 : appendStringInfo(StringInfo str, const char *fmt,...)
98 : {
99 335991420 : int save_errno = errno;
100 :
101 : for (;;)
102 1337716 : {
103 : va_list args;
104 : int needed;
105 :
106 : /* Try to format the data. */
107 337329136 : errno = save_errno;
108 337329136 : va_start(args, fmt);
109 337329136 : needed = appendStringInfoVA(str, fmt, args);
110 337329136 : va_end(args);
111 :
112 337329136 : if (needed == 0)
113 335991420 : break; /* success */
114 :
115 : /* Increase the buffer size and try again. */
116 1337716 : enlargeStringInfo(str, needed);
117 : }
118 335991420 : }
119 :
120 : /*
121 : * appendStringInfoVA
122 : *
123 : * Attempt to format text data under the control of fmt (an sprintf-style
124 : * format string) and append it to whatever is already in str. If successful
125 : * return zero; if not (because there's not enough space), return an estimate
126 : * of the space needed, without modifying str. Typically the caller should
127 : * pass the return value to enlargeStringInfo() before trying again; see
128 : * appendStringInfo for standard usage pattern.
129 : *
130 : * Caution: callers must be sure to preserve their entry-time errno
131 : * when looping, in case the fmt contains "%m".
132 : *
133 : * XXX This API is ugly, but there seems no alternative given the C spec's
134 : * restrictions on what can portably be done with va_list arguments: you have
135 : * to redo va_start before you can rescan the argument list, and we can't do
136 : * that from here.
137 : */
138 : int
139 337865672 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
140 : {
141 : int avail;
142 : size_t nprinted;
143 :
144 : Assert(str != NULL);
145 :
146 : /*
147 : * If there's hardly any space, don't bother trying, just fail to make the
148 : * caller enlarge the buffer first. We have to guess at how much to
149 : * enlarge, since we're skipping the formatting work.
150 : */
151 337865672 : avail = str->maxlen - str->len;
152 337865672 : if (avail < 16)
153 1251318 : return 32;
154 :
155 336614354 : nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
156 :
157 336614354 : if (nprinted < (size_t) avail)
158 : {
159 : /* Success. Note nprinted does not include trailing null. */
160 336525202 : str->len += (int) nprinted;
161 336525202 : return 0;
162 : }
163 :
164 : /* Restore the trailing null so that str is unmodified. */
165 89152 : str->data[str->len] = '\0';
166 :
167 : /*
168 : * Return pvsnprintf's estimate of the space needed. (Although this is
169 : * given as a size_t, we know it will fit in int because it's not more
170 : * than MaxAllocSize.)
171 : */
172 89152 : return (int) nprinted;
173 : }
174 :
175 : /*
176 : * appendStringInfoString
177 : *
178 : * Append a null-terminated string to str.
179 : * Like appendStringInfo(str, "%s", s) but faster.
180 : */
181 : void
182 225673380 : appendStringInfoString(StringInfo str, const char *s)
183 : {
184 225673380 : appendBinaryStringInfo(str, s, strlen(s));
185 225673380 : }
186 :
187 : /*
188 : * appendStringInfoChar
189 : *
190 : * Append a single byte to str.
191 : * Like appendStringInfo(str, "%c", ch) but much faster.
192 : */
193 : void
194 574090304 : appendStringInfoChar(StringInfo str, char ch)
195 : {
196 : /* Make more room if needed */
197 574090304 : if (str->len + 1 >= str->maxlen)
198 182440 : enlargeStringInfo(str, 1);
199 :
200 : /* OK, append the character */
201 574090304 : str->data[str->len] = ch;
202 574090304 : str->len++;
203 574090304 : str->data[str->len] = '\0';
204 574090304 : }
205 :
206 : /*
207 : * appendStringInfoSpaces
208 : *
209 : * Append the specified number of spaces to a buffer.
210 : */
211 : void
212 172282 : appendStringInfoSpaces(StringInfo str, int count)
213 : {
214 172282 : if (count > 0)
215 : {
216 : /* Make more room if needed */
217 166938 : enlargeStringInfo(str, count);
218 :
219 : /* OK, append the spaces */
220 166938 : memset(&str->data[str->len], ' ', count);
221 166938 : str->len += count;
222 166938 : str->data[str->len] = '\0';
223 : }
224 172282 : }
225 :
226 : /*
227 : * appendBinaryStringInfo
228 : *
229 : * Append arbitrary binary data to a StringInfo, allocating more space
230 : * if necessary. Ensures that a trailing null byte is present.
231 : */
232 : void
233 243216890 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
234 : {
235 : Assert(str != NULL);
236 :
237 : /* Make more room if needed */
238 243216890 : enlargeStringInfo(str, datalen);
239 :
240 : /* OK, append the data */
241 243216890 : memcpy(str->data + str->len, data, datalen);
242 243216890 : str->len += datalen;
243 :
244 : /*
245 : * Keep a trailing null in place, even though it's probably useless for
246 : * binary data. (Some callers are dealing with text but call this because
247 : * their input isn't null-terminated.)
248 : */
249 243216890 : str->data[str->len] = '\0';
250 243216890 : }
251 :
252 : /*
253 : * appendBinaryStringInfoNT
254 : *
255 : * Append arbitrary binary data to a StringInfo, allocating more space
256 : * if necessary. Does not ensure a trailing null-byte exists.
257 : */
258 : void
259 27199094 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
260 : {
261 : Assert(str != NULL);
262 :
263 : /* Make more room if needed */
264 27199094 : enlargeStringInfo(str, datalen);
265 :
266 : /* OK, append the data */
267 27199094 : memcpy(str->data + str->len, data, datalen);
268 27199094 : str->len += datalen;
269 27199094 : }
270 :
271 : /*
272 : * enlargeStringInfo
273 : *
274 : * Make sure there is enough space for 'needed' more bytes
275 : * ('needed' does not include the terminating null).
276 : *
277 : * External callers usually need not concern themselves with this, since
278 : * all stringinfo.c routines do it automatically. However, if a caller
279 : * knows that a StringInfo will eventually become X bytes large, it
280 : * can save some palloc overhead by enlarging the buffer before starting
281 : * to store data in it.
282 : *
283 : * NB: In the backend, because we use repalloc() to enlarge the buffer, the
284 : * string buffer will remain allocated in the same memory context that was
285 : * current when initStringInfo was called, even if another context is now
286 : * current. This is the desired and indeed critical behavior!
287 : */
288 : void
289 316547634 : enlargeStringInfo(StringInfo str, int needed)
290 : {
291 : int newlen;
292 :
293 : /* validate this is not a read-only StringInfo */
294 : Assert(str->maxlen != 0);
295 :
296 : /*
297 : * Guard against out-of-range "needed" values. Without this, we can get
298 : * an overflow or infinite loop in the following.
299 : */
300 316547634 : if (needed < 0) /* should not happen */
301 : {
302 : #ifndef FRONTEND
303 0 : elog(ERROR, "invalid string enlargement request size: %d", needed);
304 : #else
305 0 : fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
306 0 : exit(EXIT_FAILURE);
307 : #endif
308 : }
309 316547634 : if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
310 : {
311 : #ifndef FRONTEND
312 0 : ereport(ERROR,
313 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
314 : errmsg("out of memory"),
315 : errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
316 : str->len, needed)));
317 : #else
318 0 : fprintf(stderr,
319 0 : _("out of memory\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
320 : str->len, needed);
321 0 : exit(EXIT_FAILURE);
322 : #endif
323 : }
324 :
325 316547634 : needed += str->len + 1; /* total space required now */
326 :
327 : /* Because of the above test, we now have needed <= MaxAllocSize */
328 :
329 316547634 : if (needed <= str->maxlen)
330 314074356 : return; /* got enough space already */
331 :
332 : /*
333 : * We don't want to allocate just a little more space with each append;
334 : * for efficiency, double the buffer size each time it overflows.
335 : * Actually, we might need to more than double it if 'needed' is big...
336 : */
337 2473278 : newlen = 2 * str->maxlen;
338 2704246 : while (needed > newlen)
339 230968 : newlen = 2 * newlen;
340 :
341 : /*
342 : * Clamp to MaxAllocSize in case we went past it. Note we are assuming
343 : * here that MaxAllocSize <= INT_MAX/2, else the above loop could
344 : * overflow. We will still have newlen >= needed.
345 : */
346 2473278 : if (newlen > (int) MaxAllocSize)
347 0 : newlen = (int) MaxAllocSize;
348 :
349 2473278 : str->data = (char *) repalloc(str->data, newlen);
350 :
351 2473278 : str->maxlen = newlen;
352 : }
353 :
354 : /*
355 : * destroyStringInfo
356 : *
357 : * Frees a StringInfo and its buffer (opposite of makeStringInfo()).
358 : * This must only be called on palloc'd StringInfos.
359 : */
360 : void
361 7102 : destroyStringInfo(StringInfo str)
362 : {
363 : /* don't allow destroys of read-only StringInfos */
364 : Assert(str->maxlen != 0);
365 :
366 7102 : pfree(str->data);
367 7102 : pfree(str);
368 7102 : }
|