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-2023, 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 84766 : makeStringInfo(void)
42 : {
43 : StringInfo res;
44 :
45 84766 : res = (StringInfo) palloc(sizeof(StringInfoData));
46 :
47 84766 : initStringInfo(res);
48 :
49 84766 : 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 9200302 : initStringInfo(StringInfo str)
60 : {
61 9200302 : int size = 1024; /* initial default buffer size */
62 :
63 9200302 : str->data = (char *) palloc(size);
64 9200302 : str->maxlen = size;
65 9200302 : resetStringInfo(str);
66 9200302 : }
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 28941582 : resetStringInfo(StringInfo str)
79 : {
80 : /* don't allow resets of read-only StringInfos */
81 : Assert(str->maxlen != 0);
82 :
83 28941582 : str->data[0] = '\0';
84 28941582 : str->len = 0;
85 28941582 : str->cursor = 0;
86 28941582 : }
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 298994856 : appendStringInfo(StringInfo str, const char *fmt,...)
98 : {
99 298994856 : int save_errno = errno;
100 :
101 : for (;;)
102 1198762 : {
103 : va_list args;
104 : int needed;
105 :
106 : /* Try to format the data. */
107 300193618 : errno = save_errno;
108 300193618 : va_start(args, fmt);
109 300193618 : needed = appendStringInfoVA(str, fmt, args);
110 300193618 : va_end(args);
111 :
112 300193618 : if (needed == 0)
113 298994856 : break; /* success */
114 :
115 : /* Increase the buffer size and try again. */
116 1198762 : enlargeStringInfo(str, needed);
117 : }
118 298994856 : }
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 300684944 : 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 300684944 : avail = str->maxlen - str->len;
152 300684944 : if (avail < 16)
153 1122718 : return 32;
154 :
155 299562226 : nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
156 :
157 299562226 : if (nprinted < (size_t) avail)
158 : {
159 : /* Success. Note nprinted does not include trailing null. */
160 299483790 : str->len += (int) nprinted;
161 299483790 : return 0;
162 : }
163 :
164 : /* Restore the trailing null so that str is unmodified. */
165 78436 : 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 78436 : 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 201348292 : appendStringInfoString(StringInfo str, const char *s)
183 : {
184 201348292 : appendBinaryStringInfo(str, s, strlen(s));
185 201348292 : }
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 517519032 : appendStringInfoChar(StringInfo str, char ch)
195 : {
196 : /* Make more room if needed */
197 517519032 : if (str->len + 1 >= str->maxlen)
198 160264 : enlargeStringInfo(str, 1);
199 :
200 : /* OK, append the character */
201 517519032 : str->data[str->len] = ch;
202 517519032 : str->len++;
203 517519032 : str->data[str->len] = '\0';
204 517519032 : }
205 :
206 : /*
207 : * appendStringInfoSpaces
208 : *
209 : * Append the specified number of spaces to a buffer.
210 : */
211 : void
212 157640 : appendStringInfoSpaces(StringInfo str, int count)
213 : {
214 157640 : if (count > 0)
215 : {
216 : /* Make more room if needed */
217 152414 : enlargeStringInfo(str, count);
218 :
219 : /* OK, append the spaces */
220 152414 : memset(&str->data[str->len], ' ', count);
221 152414 : str->len += count;
222 152414 : str->data[str->len] = '\0';
223 : }
224 157640 : }
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 217886386 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
234 : {
235 : Assert(str != NULL);
236 :
237 : /* Make more room if needed */
238 217886386 : enlargeStringInfo(str, datalen);
239 :
240 : /* OK, append the data */
241 217886386 : memcpy(str->data + str->len, data, datalen);
242 217886386 : 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 217886386 : str->data[str->len] = '\0';
250 217886386 : }
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 23308092 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
260 : {
261 : Assert(str != NULL);
262 :
263 : /* Make more room if needed */
264 23308092 : enlargeStringInfo(str, datalen);
265 :
266 : /* OK, append the data */
267 23308092 : memcpy(str->data + str->len, data, datalen);
268 23308092 : str->len += datalen;
269 23308092 : }
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 281905036 : 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 281905036 : 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 281905036 : 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 281905036 : needed += str->len + 1; /* total space required now */
326 :
327 : /* Because of the above test, we now have needed <= MaxAllocSize */
328 :
329 281905036 : if (needed <= str->maxlen)
330 279699996 : 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 2205040 : newlen = 2 * str->maxlen;
338 2432348 : while (needed > newlen)
339 227308 : 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 2205040 : if (newlen > (int) MaxAllocSize)
347 0 : newlen = (int) MaxAllocSize;
348 :
349 2205040 : str->data = (char *) repalloc(str->data, newlen);
350 :
351 2205040 : str->maxlen = newlen;
352 : }
|