1 /*-------------------------------------------------------------------------
5 * PQExpBuffer provides an indefinitely-extensible string data type.
6 * It can be used to buffer either ordinary C strings (null-terminated text)
7 * or arbitrary binary data. All storage is allocated with malloc().
9 * This module is essentially the same as the backend's StringInfo data type,
10 * but it is intended for use in frontend libpq and client applications.
11 * Thus, it does not rely on palloc() nor elog(), nor psprintf.c which
12 * will exit() on error.
14 * It does rely on vsnprintf(); if configure finds that libc doesn't provide
15 * a usable vsnprintf(), then a copy of our own implementation of it will
16 * be linked into libpq.
18 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
19 * Portions Copyright (c) 1994, Regents of the University of California
21 * src/interfaces/libpq/pqexpbuffer.c
23 *-------------------------------------------------------------------------
26 #include "postgres_fe.h"
30 #include "pqexpbuffer.h"
37 /* All "broken" PQExpBuffers point to this string. */
38 static const char oom_buffer[1] = "";
41 appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
42 __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
46 * markPQExpBufferBroken
48 * Put a PQExpBuffer in "broken" state if it isn't already.
51 markPQExpBufferBroken(PQExpBuffer str)
53 if (str->data != oom_buffer)
57 * Casting away const here is a bit ugly, but it seems preferable to not
58 * marking oom_buffer const. We want to do that to encourage the compiler
59 * to put oom_buffer in read-only storage, so that anyone who tries to
60 * scribble on a broken PQExpBuffer will get a failure.
62 str->data = (char *) oom_buffer;
70 * Create an empty 'PQExpBufferData' & return a pointer to it.
73 createPQExpBuffer(void)
77 res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
87 * Initialize a PQExpBufferData struct (with previously undefined contents)
88 * to describe an empty string.
91 initPQExpBuffer(PQExpBuffer str)
93 str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
94 if (str->data == NULL)
96 str->data = (char *) oom_buffer; /* see comment above */
102 str->maxlen = INITIAL_EXPBUFFER_SIZE;
109 * destroyPQExpBuffer(str);
111 * free()s both the data buffer and the PQExpBufferData.
112 * This is the inverse of createPQExpBuffer().
115 destroyPQExpBuffer(PQExpBuffer str)
119 termPQExpBuffer(str);
125 * termPQExpBuffer(str)
126 * free()s the data buffer but not the PQExpBufferData itself.
127 * This is the inverse of initPQExpBuffer().
130 termPQExpBuffer(PQExpBuffer str)
132 if (str->data != oom_buffer)
134 /* just for luck, make the buffer validly empty. */
135 str->data = (char *) oom_buffer; /* see comment above */
142 * Reset a PQExpBuffer to empty
144 * Note: if possible, a "broken" PQExpBuffer is returned to normal.
147 resetPQExpBuffer(PQExpBuffer str)
151 if (str->data != oom_buffer)
158 /* try to reinitialize to valid state */
159 initPQExpBuffer(str);
166 * Make sure there is enough space for 'needed' more bytes in the buffer
167 * ('needed' does not include the terminating null).
169 * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
170 * the buffer is left in "broken" state.)
173 enlargePQExpBuffer(PQExpBuffer str, size_t needed)
178 if (PQExpBufferBroken(str))
179 return 0; /* already failed */
182 * Guard against ridiculous "needed" values, which can occur if we're fed
183 * bogus data. Without this, we can get an overflow or infinite loop in
186 if (needed >= ((size_t) INT_MAX - str->len))
188 markPQExpBufferBroken(str);
192 needed += str->len + 1; /* total space required now */
194 /* Because of the above test, we now have needed <= INT_MAX */
196 if (needed <= str->maxlen)
197 return 1; /* got enough space already */
200 * We don't want to allocate just a little more space with each append;
201 * for efficiency, double the buffer size each time it overflows.
202 * Actually, we might need to more than double it if 'needed' is big...
204 newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
205 while (needed > newlen)
209 * Clamp to INT_MAX in case we went past it. Note we are assuming here
210 * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We
211 * will still have newlen >= needed.
213 if (newlen > (size_t) INT_MAX)
214 newlen = (size_t) INT_MAX;
216 newdata = (char *) realloc(str->data, newlen);
220 str->maxlen = newlen;
224 markPQExpBufferBroken(str);
230 * Format text data under the control of fmt (an sprintf-like format string)
231 * and insert it into str. More space is allocated to str if necessary.
232 * This is a convenience routine that does the same thing as
233 * resetPQExpBuffer() followed by appendPQExpBuffer().
236 printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
241 resetPQExpBuffer(str);
243 if (PQExpBufferBroken(str))
244 return; /* already failed */
246 /* Loop in case we have to retry after enlarging the buffer. */
250 done = appendPQExpBufferVA(str, fmt, args);
258 * Format text data under the control of fmt (an sprintf-like format string)
259 * and append it to whatever is already in str. More space is allocated
260 * to str if necessary. This is sort of like a combination of sprintf and
264 appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
269 if (PQExpBufferBroken(str))
270 return; /* already failed */
272 /* Loop in case we have to retry after enlarging the buffer. */
276 done = appendPQExpBufferVA(str, fmt, args);
282 * appendPQExpBufferVA
283 * Shared guts of printfPQExpBuffer/appendPQExpBuffer.
284 * Attempt to format data and append it to str. Returns true if done
285 * (either successful or hard failure), false if need to retry.
288 appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
295 * Try to format the given string into the available space; but if there's
296 * hardly any space, don't bother trying, just enlarge the buffer first.
298 if (str->maxlen > str->len + 16)
301 * Note: we intentionally leave one byte unused, as a guard against
302 * old broken versions of vsnprintf.
304 avail = str->maxlen - str->len - 1;
308 nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
311 * If vsnprintf reports an error other than ENOMEM, fail.
313 if (nprinted < 0 && errno != 0 && errno != ENOMEM)
315 markPQExpBufferBroken(str);
320 * Note: some versions of vsnprintf return the number of chars
321 * actually stored, not the total space needed as C99 specifies. And
322 * at least one returns -1 on failure. Be conservative about
323 * believing whether the print worked.
325 if (nprinted >= 0 && (size_t) nprinted < avail - 1)
327 /* Success. Note nprinted does not include trailing null. */
328 str->len += nprinted;
332 if (nprinted >= 0 && (size_t) nprinted > avail)
335 * This appears to be a C99-compliant vsnprintf, so believe its
336 * estimate of the required space. (If it's wrong, the logic will
337 * still work, but we may loop multiple times.) Note that the
338 * space needed should be only nprinted+1 bytes, but we'd better
339 * allocate one more than that so that the test above will succeed
342 * In the corner case where the required space just barely
345 if (nprinted > INT_MAX - 2)
347 markPQExpBufferBroken(str);
350 needed = nprinted + 2;
355 * Buffer overrun, and we don't know how much space is needed.
356 * Estimate twice the previous buffer size, but not more than
359 if (avail >= INT_MAX / 2)
368 * We have to guess at how much to enlarge, since we're skipping the
374 /* Increase the buffer size and try again. */
375 if (!enlargePQExpBuffer(str, needed))
376 return true; /* oops, out of memory */
382 * appendPQExpBufferStr
383 * Append the given string to a PQExpBuffer, allocating more space
387 appendPQExpBufferStr(PQExpBuffer str, const char *data)
389 appendBinaryPQExpBuffer(str, data, strlen(data));
393 * appendPQExpBufferChar
394 * Append a single byte to str.
395 * Like appendPQExpBuffer(str, "%c", ch) but much faster.
398 appendPQExpBufferChar(PQExpBuffer str, char ch)
400 /* Make more room if needed */
401 if (!enlargePQExpBuffer(str, 1))
404 /* OK, append the character */
405 str->data[str->len] = ch;
407 str->data[str->len] = '\0';
411 * appendBinaryPQExpBuffer
413 * Append arbitrary binary data to a PQExpBuffer, allocating more space
417 appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
419 /* Make more room if needed */
420 if (!enlargePQExpBuffer(str, datalen))
423 /* OK, append the data */
424 memcpy(str->data + str->len, data, datalen);
428 * Keep a trailing null in place, even though it's probably useless for
431 str->data[str->len] = '\0';