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-2022, 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"
27 /* It's possible we could use a different value for this in frontend code */
28 #define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
32 #include "lib/stringinfo.h"
38 * Create an empty 'StringInfoData' & return a pointer to it.
45 res
= (StringInfo
) palloc(sizeof(StringInfoData
));
55 * Initialize a StringInfoData struct (with previously undefined contents)
56 * to describe an empty string.
59 initStringInfo(StringInfo str
)
61 int size
= 1024; /* initial default buffer size */
63 str
->data
= (char *) palloc(size
);
71 * Reset the StringInfo: the data buffer remains valid, but its
72 * previous content, if any, is cleared.
75 resetStringInfo(StringInfo str
)
85 * Format text data under the control of fmt (an sprintf-style format string)
86 * and append it to whatever is already in str. More space is allocated
87 * to str if necessary. This is sort of like a combination of sprintf and
91 appendStringInfo(StringInfo str
, const char *fmt
,...)
93 int save_errno
= errno
;
100 /* Try to format the data. */
103 needed
= appendStringInfoVA(str
, fmt
, args
);
109 /* Increase the buffer size and try again. */
110 enlargeStringInfo(str
, needed
);
117 * Attempt to format text data under the control of fmt (an sprintf-style
118 * format string) and append it to whatever is already in str. If successful
119 * return zero; if not (because there's not enough space), return an estimate
120 * of the space needed, without modifying str. Typically the caller should
121 * pass the return value to enlargeStringInfo() before trying again; see
122 * appendStringInfo for standard usage pattern.
124 * Caution: callers must be sure to preserve their entry-time errno
125 * when looping, in case the fmt contains "%m".
127 * XXX This API is ugly, but there seems no alternative given the C spec's
128 * restrictions on what can portably be done with va_list arguments: you have
129 * to redo va_start before you can rescan the argument list, and we can't do
133 appendStringInfoVA(StringInfo str
, const char *fmt
, va_list args
)
141 * If there's hardly any space, don't bother trying, just fail to make the
142 * caller enlarge the buffer first. We have to guess at how much to
143 * enlarge, since we're skipping the formatting work.
145 avail
= str
->maxlen
- str
->len
;
149 nprinted
= pvsnprintf(str
->data
+ str
->len
, (size_t) avail
, fmt
, args
);
151 if (nprinted
< (size_t) avail
)
153 /* Success. Note nprinted does not include trailing null. */
154 str
->len
+= (int) nprinted
;
158 /* Restore the trailing null so that str is unmodified. */
159 str
->data
[str
->len
] = '\0';
162 * Return pvsnprintf's estimate of the space needed. (Although this is
163 * given as a size_t, we know it will fit in int because it's not more
164 * than MaxAllocSize.)
166 return (int) nprinted
;
170 * appendStringInfoString
172 * Append a null-terminated string to str.
173 * Like appendStringInfo(str, "%s", s) but faster.
176 appendStringInfoString(StringInfo str
, const char *s
)
178 appendBinaryStringInfo(str
, s
, strlen(s
));
182 * appendStringInfoChar
184 * Append a single byte to str.
185 * Like appendStringInfo(str, "%c", ch) but much faster.
188 appendStringInfoChar(StringInfo str
, char ch
)
190 /* Make more room if needed */
191 if (str
->len
+ 1 >= str
->maxlen
)
192 enlargeStringInfo(str
, 1);
194 /* OK, append the character */
195 str
->data
[str
->len
] = ch
;
197 str
->data
[str
->len
] = '\0';
201 * appendStringInfoSpaces
203 * Append the specified number of spaces to a buffer.
206 appendStringInfoSpaces(StringInfo str
, int count
)
210 /* Make more room if needed */
211 enlargeStringInfo(str
, count
);
213 /* OK, append the spaces */
215 str
->data
[str
->len
++] = ' ';
216 str
->data
[str
->len
] = '\0';
221 * appendBinaryStringInfo
223 * Append arbitrary binary data to a StringInfo, allocating more space
224 * if necessary. Ensures that a trailing null byte is present.
227 appendBinaryStringInfo(StringInfo str
, const char *data
, int datalen
)
231 /* Make more room if needed */
232 enlargeStringInfo(str
, datalen
);
234 /* OK, append the data */
235 memcpy(str
->data
+ str
->len
, data
, datalen
);
239 * Keep a trailing null in place, even though it's probably useless for
240 * binary data. (Some callers are dealing with text but call this because
241 * their input isn't null-terminated.)
243 str
->data
[str
->len
] = '\0';
247 * appendBinaryStringInfoNT
249 * Append arbitrary binary data to a StringInfo, allocating more space
250 * if necessary. Does not ensure a trailing null-byte exists.
253 appendBinaryStringInfoNT(StringInfo str
, const char *data
, int datalen
)
257 /* Make more room if needed */
258 enlargeStringInfo(str
, datalen
);
260 /* OK, append the data */
261 memcpy(str
->data
+ str
->len
, data
, datalen
);
268 * Make sure there is enough space for 'needed' more bytes
269 * ('needed' does not include the terminating null).
271 * External callers usually need not concern themselves with this, since
272 * all stringinfo.c routines do it automatically. However, if a caller
273 * knows that a StringInfo will eventually become X bytes large, it
274 * can save some palloc overhead by enlarging the buffer before starting
275 * to store data in it.
277 * NB: In the backend, because we use repalloc() to enlarge the buffer, the
278 * string buffer will remain allocated in the same memory context that was
279 * current when initStringInfo was called, even if another context is now
280 * current. This is the desired and indeed critical behavior!
283 enlargeStringInfo(StringInfo str
, int needed
)
288 * Guard against out-of-range "needed" values. Without this, we can get
289 * an overflow or infinite loop in the following.
291 if (needed
< 0) /* should not happen */
294 elog(ERROR
, "invalid string enlargement request size: %d", needed
);
296 fprintf(stderr
, "invalid string enlargement request size: %d\n", needed
);
300 if (((Size
) needed
) >= (MaxAllocSize
- (Size
) str
->len
))
304 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED
),
305 errmsg("out of memory"),
306 errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
310 _("out of memory\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
316 needed
+= str
->len
+ 1; /* total space required now */
318 /* Because of the above test, we now have needed <= MaxAllocSize */
320 if (needed
<= str
->maxlen
)
321 return; /* got enough space already */
324 * We don't want to allocate just a little more space with each append;
325 * for efficiency, double the buffer size each time it overflows.
326 * Actually, we might need to more than double it if 'needed' is big...
328 newlen
= 2 * str
->maxlen
;
329 while (needed
> newlen
)
333 * Clamp to MaxAllocSize in case we went past it. Note we are assuming
334 * here that MaxAllocSize <= INT_MAX/2, else the above loop could
335 * overflow. We will still have newlen >= needed.
337 if (newlen
> (int) MaxAllocSize
)
338 newlen
= (int) MaxAllocSize
;
340 str
->data
= (char *) repalloc(str
->data
, newlen
);
342 str
->maxlen
= newlen
;