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().
13 * It does rely on vsnprintf(); if configure finds that libc doesn't provide
14 * a usable vsnprintf(), then a copy of our own implementation of it will
15 * be linked into libpq.
17 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
18 * Portions Copyright (c) 1994, Regents of the University of California
20 * src/interfaces/libpq/pqexpbuffer.c
22 *-------------------------------------------------------------------------
25 #include "postgres_fe.h"
29 #include "pqexpbuffer.h"
36 /* All "broken" PQExpBuffers point to this string. */
37 static const char oom_buffer[1] = "";
41 * markPQExpBufferBroken
43 * Put a PQExpBuffer in "broken" state if it isn't already.
46 markPQExpBufferBroken(PQExpBuffer str)
48 if (str->data != oom_buffer)
52 * Casting away const here is a bit ugly, but it seems preferable to not
53 * marking oom_buffer const. We want to do that to encourage the compiler
54 * to put oom_buffer in read-only storage, so that anyone who tries to
55 * scribble on a broken PQExpBuffer will get a failure.
57 str->data = (char *) oom_buffer;
65 * Create an empty 'PQExpBufferData' & return a pointer to it.
68 createPQExpBuffer(void)
72 res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
82 * Initialize a PQExpBufferData struct (with previously undefined contents)
83 * to describe an empty string.
86 initPQExpBuffer(PQExpBuffer str)
88 str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
89 if (str->data == NULL)
91 str->data = (char *) oom_buffer; /* see comment above */
97 str->maxlen = INITIAL_EXPBUFFER_SIZE;
104 * destroyPQExpBuffer(str);
106 * free()s both the data buffer and the PQExpBufferData.
107 * This is the inverse of createPQExpBuffer().
110 destroyPQExpBuffer(PQExpBuffer str)
114 termPQExpBuffer(str);
120 * termPQExpBuffer(str)
121 * free()s the data buffer but not the PQExpBufferData itself.
122 * This is the inverse of initPQExpBuffer().
125 termPQExpBuffer(PQExpBuffer str)
127 if (str->data != oom_buffer)
129 /* just for luck, make the buffer validly empty. */
130 str->data = (char *) oom_buffer; /* see comment above */
137 * Reset a PQExpBuffer to empty
139 * Note: if possible, a "broken" PQExpBuffer is returned to normal.
142 resetPQExpBuffer(PQExpBuffer str)
146 if (str->data != oom_buffer)
153 /* try to reinitialize to valid state */
154 initPQExpBuffer(str);
161 * Make sure there is enough space for 'needed' more bytes in the buffer
162 * ('needed' does not include the terminating null).
164 * Returns 1 if OK, 0 if failed to enlarge buffer. (In the latter case
165 * the buffer is left in "broken" state.)
168 enlargePQExpBuffer(PQExpBuffer str, size_t needed)
173 if (PQExpBufferBroken(str))
174 return 0; /* already failed */
177 * Guard against ridiculous "needed" values, which can occur if we're fed
178 * bogus data. Without this, we can get an overflow or infinite loop in
181 if (needed >= ((size_t) INT_MAX - str->len))
183 markPQExpBufferBroken(str);
187 needed += str->len + 1; /* total space required now */
189 /* Because of the above test, we now have needed <= INT_MAX */
191 if (needed <= str->maxlen)
192 return 1; /* got enough space already */
195 * We don't want to allocate just a little more space with each append;
196 * for efficiency, double the buffer size each time it overflows.
197 * Actually, we might need to more than double it if 'needed' is big...
199 newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
200 while (needed > newlen)
204 * Clamp to INT_MAX in case we went past it. Note we are assuming here
205 * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We
206 * will still have newlen >= needed.
208 if (newlen > (size_t) INT_MAX)
209 newlen = (size_t) INT_MAX;
211 newdata = (char *) realloc(str->data, newlen);
215 str->maxlen = newlen;
219 markPQExpBufferBroken(str);
225 * Format text data under the control of fmt (an sprintf-like format string)
226 * and insert it into str. More space is allocated to str if necessary.
227 * This is a convenience routine that does the same thing as
228 * resetPQExpBuffer() followed by appendPQExpBuffer().
231 printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
237 resetPQExpBuffer(str);
239 if (PQExpBufferBroken(str))
240 return; /* already failed */
245 * Try to format the given string into the available space; but if
246 * there's hardly any space, don't bother trying, just fall through to
247 * enlarge the buffer first.
249 if (str->maxlen > str->len + 16)
251 avail = str->maxlen - str->len - 1;
253 nprinted = vsnprintf(str->data + str->len, avail,
258 * Note: some versions of vsnprintf return the number of chars
259 * actually stored, but at least one returns -1 on failure. Be
260 * conservative about believing whether the print worked.
262 if (nprinted >= 0 && nprinted < (int) avail - 1)
264 /* Success. Note nprinted does not include trailing null. */
265 str->len += nprinted;
269 /* Double the buffer size and try again. */
270 if (!enlargePQExpBuffer(str, str->maxlen))
271 return; /* oops, out of memory */
278 * Format text data under the control of fmt (an sprintf-like format string)
279 * and append it to whatever is already in str. More space is allocated
280 * to str if necessary. This is sort of like a combination of sprintf and
284 appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
290 if (PQExpBufferBroken(str))
291 return; /* already failed */
296 * Try to format the given string into the available space; but if
297 * there's hardly any space, don't bother trying, just fall through to
298 * enlarge the buffer first.
300 if (str->maxlen > str->len + 16)
302 avail = str->maxlen - str->len - 1;
304 nprinted = vsnprintf(str->data + str->len, avail,
309 * Note: some versions of vsnprintf return the number of chars
310 * actually stored, but at least one returns -1 on failure. Be
311 * conservative about believing whether the print worked.
313 if (nprinted >= 0 && nprinted < (int) avail - 1)
315 /* Success. Note nprinted does not include trailing null. */
316 str->len += nprinted;
320 /* Double the buffer size and try again. */
321 if (!enlargePQExpBuffer(str, str->maxlen))
322 return; /* oops, out of memory */
327 * appendPQExpBufferStr
328 * Append the given string to a PQExpBuffer, allocating more space
332 appendPQExpBufferStr(PQExpBuffer str, const char *data)
334 appendBinaryPQExpBuffer(str, data, strlen(data));
338 * appendPQExpBufferChar
339 * Append a single byte to str.
340 * Like appendPQExpBuffer(str, "%c", ch) but much faster.
343 appendPQExpBufferChar(PQExpBuffer str, char ch)
345 /* Make more room if needed */
346 if (!enlargePQExpBuffer(str, 1))
349 /* OK, append the character */
350 str->data[str->len] = ch;
352 str->data[str->len] = '\0';
356 * appendBinaryPQExpBuffer
358 * Append arbitrary binary data to a PQExpBuffer, allocating more space
362 appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
364 /* Make more room if needed */
365 if (!enlargePQExpBuffer(str, datalen))
368 /* OK, append the data */
369 memcpy(str->data + str->len, data, datalen);
373 * Keep a trailing null in place, even though it's probably useless for
376 str->data[str->len] = '\0';