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