1 /*-------------------------------------------------------------------------
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 *-------------------------------------------------------------------------
21 #include "utils/memutils.h"
25 #include "postgres_fe.h"
29 #include "lib/stringinfo.h"
35 * Create an empty 'StringInfoData' & return a pointer to it.
42 res
= (StringInfo
) palloc(sizeof(StringInfoData
));
52 * Initialize a StringInfoData struct (with previously undefined contents)
53 * to describe an empty string.
56 initStringInfo(StringInfo str
)
58 int size
= 1024; /* initial default buffer size */
60 str
->data
= (char *) palloc(size
);
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
75 resetStringInfo(StringInfo str
)
77 /* don't allow resets of read-only StringInfos */
78 Assert(str
->maxlen
!= 0);
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
94 appendStringInfo(StringInfo str
, const char *fmt
,...)
96 int save_errno
= errno
;
103 /* Try to format the data. */
106 needed
= appendStringInfoVA(str
, fmt
, args
);
112 /* Increase the buffer size and try again. */
113 enlargeStringInfo(str
, needed
);
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
136 appendStringInfoVA(StringInfo str
, const char *fmt
, va_list args
)
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
;
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
;
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.
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.
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
;
200 str
->data
[str
->len
] = '\0';
204 * appendStringInfoSpaces
206 * Append the specified number of spaces to a buffer.
209 appendStringInfoSpaces(StringInfo str
, int count
)
213 /* Make more room if needed */
214 enlargeStringInfo(str
, count
);
216 /* OK, append the spaces */
217 memset(&str
->data
[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.
230 appendBinaryStringInfo(StringInfo str
, const void *data
, int datalen
)
234 /* Make more room if needed */
235 enlargeStringInfo(str
, datalen
);
237 /* OK, append the data */
238 memcpy(str
->data
+ str
->len
, data
, 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.
256 appendBinaryStringInfoNT(StringInfo str
, const void *data
, int datalen
)
260 /* Make more room if needed */
261 enlargeStringInfo(str
, datalen
);
263 /* OK, append the data */
264 memcpy(str
->data
+ str
->len
, data
, datalen
);
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!
286 enlargeStringInfo(StringInfo str
, int needed
)
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 */
300 elog(ERROR
, "invalid string enlargement request size: %d", needed
);
302 fprintf(stderr
, "invalid string enlargement request size: %d\n", needed
);
306 if (((Size
) needed
) >= (MaxAllocSize
- (Size
) str
->len
))
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.",
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
);
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
)
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
;
354 * Frees a StringInfo and its buffer (opposite of makeStringInfo()).
355 * This must only be called on palloc'd StringInfos.
358 destroyStringInfo(StringInfo str
)
360 /* don't allow destroys of read-only StringInfos */
361 Assert(str
->maxlen
!= 0);