jsonpath scanner: reentrant scanner
[pgsql.git] / src / common / stringinfo.c
blob6192e65477ec68c6f3b1fdfae9df0bc5d61d30f2
1 /*-------------------------------------------------------------------------
3 * stringinfo.c
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).
10 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
13 * src/common/stringinfo.c
15 *-------------------------------------------------------------------------
18 #ifndef FRONTEND
20 #include "postgres.h"
21 #include "utils/memutils.h"
23 #else
25 #include "postgres_fe.h"
27 #endif
29 #include "lib/stringinfo.h"
33 * makeStringInfo
35 * Create an empty 'StringInfoData' & return a pointer to it.
37 StringInfo
38 makeStringInfo(void)
40 StringInfo res;
42 res = (StringInfo) palloc(sizeof(StringInfoData));
44 initStringInfo(res);
46 return res;
50 * initStringInfo
52 * Initialize a StringInfoData struct (with previously undefined contents)
53 * to describe an empty string.
55 void
56 initStringInfo(StringInfo str)
58 int size = 1024; /* initial default buffer size */
60 str->data = (char *) palloc(size);
61 str->maxlen = size;
62 resetStringInfo(str);
66 * resetStringInfo
68 * Reset the StringInfo: the data buffer remains valid, but its
69 * previous content, if any, is cleared.
71 * Read-only StringInfos as initialized by initReadOnlyStringInfo cannot be
72 * reset.
74 void
75 resetStringInfo(StringInfo str)
77 /* don't allow resets of read-only StringInfos */
78 Assert(str->maxlen != 0);
80 str->data[0] = '\0';
81 str->len = 0;
82 str->cursor = 0;
86 * appendStringInfo
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.
93 void
94 appendStringInfo(StringInfo str, const char *fmt,...)
96 int save_errno = errno;
98 for (;;)
100 va_list args;
101 int needed;
103 /* Try to format the data. */
104 errno = save_errno;
105 va_start(args, fmt);
106 needed = appendStringInfoVA(str, fmt, args);
107 va_end(args);
109 if (needed == 0)
110 break; /* success */
112 /* Increase the buffer size and try again. */
113 enlargeStringInfo(str, needed);
118 * appendStringInfoVA
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.
127 * Caution: callers must be sure to preserve their entry-time errno
128 * when looping, in case the fmt contains "%m".
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.
136 appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
138 int avail;
139 size_t nprinted;
141 Assert(str != NULL);
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.
148 avail = str->maxlen - str->len;
149 if (avail < 16)
150 return 32;
152 nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
154 if (nprinted < (size_t) avail)
156 /* Success. Note nprinted does not include trailing null. */
157 str->len += (int) nprinted;
158 return 0;
161 /* Restore the trailing null so that str is unmodified. */
162 str->data[str->len] = '\0';
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.)
169 return (int) nprinted;
173 * appendStringInfoString
175 * Append a null-terminated string to str.
176 * Like appendStringInfo(str, "%s", s) but faster.
178 void
179 appendStringInfoString(StringInfo str, const char *s)
181 appendBinaryStringInfo(str, s, strlen(s));
185 * appendStringInfoChar
187 * Append a single byte to str.
188 * Like appendStringInfo(str, "%c", ch) but much faster.
190 void
191 appendStringInfoChar(StringInfo str, char ch)
193 /* Make more room if needed */
194 if (str->len + 1 >= str->maxlen)
195 enlargeStringInfo(str, 1);
197 /* OK, append the character */
198 str->data[str->len] = ch;
199 str->len++;
200 str->data[str->len] = '\0';
204 * appendStringInfoSpaces
206 * Append the specified number of spaces to a buffer.
208 void
209 appendStringInfoSpaces(StringInfo str, int count)
211 if (count > 0)
213 /* Make more room if needed */
214 enlargeStringInfo(str, count);
216 /* OK, append the spaces */
217 memset(&str->data[str->len], ' ', count);
218 str->len += count;
219 str->data[str->len] = '\0';
224 * appendBinaryStringInfo
226 * Append arbitrary binary data to a StringInfo, allocating more space
227 * if necessary. Ensures that a trailing null byte is present.
229 void
230 appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
232 Assert(str != NULL);
234 /* Make more room if needed */
235 enlargeStringInfo(str, datalen);
237 /* OK, append the data */
238 memcpy(str->data + str->len, data, datalen);
239 str->len += datalen;
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.)
246 str->data[str->len] = '\0';
250 * appendBinaryStringInfoNT
252 * Append arbitrary binary data to a StringInfo, allocating more space
253 * if necessary. Does not ensure a trailing null-byte exists.
255 void
256 appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
258 Assert(str != NULL);
260 /* Make more room if needed */
261 enlargeStringInfo(str, datalen);
263 /* OK, append the data */
264 memcpy(str->data + str->len, data, datalen);
265 str->len += datalen;
269 * enlargeStringInfo
271 * Make sure there is enough space for 'needed' more bytes
272 * ('needed' does not include the terminating null).
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.
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!
285 void
286 enlargeStringInfo(StringInfo str, int needed)
288 int newlen;
290 /* validate this is not a read-only StringInfo */
291 Assert(str->maxlen != 0);
294 * Guard against out-of-range "needed" values. Without this, we can get
295 * an overflow or infinite loop in the following.
297 if (needed < 0) /* should not happen */
299 #ifndef FRONTEND
300 elog(ERROR, "invalid string enlargement request size: %d", needed);
301 #else
302 fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
303 exit(EXIT_FAILURE);
304 #endif
306 if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
308 #ifndef FRONTEND
309 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 fprintf(stderr,
316 _("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 exit(EXIT_FAILURE);
319 #endif
322 needed += str->len + 1; /* total space required now */
324 /* Because of the above test, we now have needed <= MaxAllocSize */
326 if (needed <= str->maxlen)
327 return; /* got enough space already */
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...
334 newlen = 2 * str->maxlen;
335 while (needed > newlen)
336 newlen = 2 * newlen;
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.
343 if (newlen > (int) MaxAllocSize)
344 newlen = (int) MaxAllocSize;
346 str->data = (char *) repalloc(str->data, newlen);
348 str->maxlen = newlen;
352 * destroyStringInfo
354 * Frees a StringInfo and its buffer (opposite of makeStringInfo()).
355 * This must only be called on palloc'd StringInfos.
357 void
358 destroyStringInfo(StringInfo str)
360 /* don't allow destroys of read-only StringInfos */
361 Assert(str->maxlen != 0);
363 pfree(str->data);
364 pfree(str);