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-2006, PostgreSQL Global Development Group
18 * Portions Copyright (c) 1994, Regents of the University of California
20 * $PostgreSQL: pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.22 2006/03/05 15:59:10 momjian Exp $
22 *-------------------------------------------------------------------------
25 #include "postgres_fe.h"
29 #include "pqexpbuffer.h"
38 * Create an empty 'PQExpBufferData' & return a pointer to it.
41 createPQExpBuffer(void)
45 res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
55 * Initialize a PQExpBufferData struct (with previously undefined contents)
56 * to describe an empty string.
59 initPQExpBuffer(PQExpBuffer str)
61 str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
62 if (str->data == NULL)
69 str->maxlen = INITIAL_EXPBUFFER_SIZE;
76 * destroyPQExpBuffer(str);
78 * free()s both the data buffer and the PQExpBufferData.
79 * This is the inverse of createPQExpBuffer().
82 destroyPQExpBuffer(PQExpBuffer str)
92 * termPQExpBuffer(str)
93 * free()s the data buffer but not the PQExpBufferData itself.
94 * This is the inverse of initPQExpBuffer().
97 termPQExpBuffer(PQExpBuffer str)
104 /* just for luck, make the buffer validly empty. */
111 * Reset a PQExpBuffer to empty
114 resetPQExpBuffer(PQExpBuffer str)
126 * Make sure there is enough space for 'needed' more bytes in the buffer
127 * ('needed' does not include the terminating null).
129 * Returns 1 if OK, 0 if failed to enlarge buffer.
132 enlargePQExpBuffer(PQExpBuffer str, size_t needed)
138 * Guard against ridiculous "needed" values, which can occur if we're fed
139 * bogus data. Without this, we can get an overflow or infinite loop in
142 if (needed >= ((size_t) INT_MAX - str->len))
145 needed += str->len + 1; /* total space required now */
147 /* Because of the above test, we now have needed <= INT_MAX */
149 if (needed <= str->maxlen)
150 return 1; /* got enough space already */
153 * We don't want to allocate just a little more space with each append;
154 * for efficiency, double the buffer size each time it overflows.
155 * Actually, we might need to more than double it if 'needed' is big...
157 newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
158 while (needed > newlen)
162 * Clamp to INT_MAX in case we went past it. Note we are assuming here
163 * that INT_MAX <= UINT_MAX/2, else the above loop could overflow. We
164 * will still have newlen >= needed.
166 if (newlen > (size_t) INT_MAX)
167 newlen = (size_t) INT_MAX;
169 newdata = (char *) realloc(str->data, newlen);
173 str->maxlen = newlen;
181 * Format text data under the control of fmt (an sprintf-like format string)
182 * and insert it into str. More space is allocated to str if necessary.
183 * This is a convenience routine that does the same thing as
184 * resetPQExpBuffer() followed by appendPQExpBuffer().
187 printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
193 resetPQExpBuffer(str);
198 * Try to format the given string into the available space; but if
199 * there's hardly any space, don't bother trying, just fall through to
200 * enlarge the buffer first.
202 if (str->maxlen > str->len + 16)
204 avail = str->maxlen - str->len - 1;
206 nprinted = vsnprintf(str->data + str->len, avail,
211 * Note: some versions of vsnprintf return the number of chars
212 * actually stored, but at least one returns -1 on failure. Be
213 * conservative about believing whether the print worked.
215 if (nprinted >= 0 && nprinted < (int) avail - 1)
217 /* Success. Note nprinted does not include trailing null. */
218 str->len += nprinted;
222 /* Double the buffer size and try again. */
223 if (!enlargePQExpBuffer(str, str->maxlen))
224 return; /* oops, out of memory */
231 * Format text data under the control of fmt (an sprintf-like format string)
232 * and append it to whatever is already in str. More space is allocated
233 * to str if necessary. This is sort of like a combination of sprintf and
237 appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
246 * Try to format the given string into the available space; but if
247 * there's hardly any space, don't bother trying, just fall through to
248 * enlarge the buffer first.
250 if (str->maxlen > str->len + 16)
252 avail = str->maxlen - str->len - 1;
254 nprinted = vsnprintf(str->data + str->len, avail,
259 * Note: some versions of vsnprintf return the number of chars
260 * actually stored, but at least one returns -1 on failure. Be
261 * conservative about believing whether the print worked.
263 if (nprinted >= 0 && nprinted < (int) avail - 1)
265 /* Success. Note nprinted does not include trailing null. */
266 str->len += nprinted;
270 /* Double the buffer size and try again. */
271 if (!enlargePQExpBuffer(str, str->maxlen))
272 return; /* oops, out of memory */
277 * appendPQExpBufferStr
278 * Append the given string to a PQExpBuffer, allocating more space
282 appendPQExpBufferStr(PQExpBuffer str, const char *data)
284 appendBinaryPQExpBuffer(str, data, strlen(data));
288 * appendPQExpBufferChar
289 * Append a single byte to str.
290 * Like appendPQExpBuffer(str, "%c", ch) but much faster.
293 appendPQExpBufferChar(PQExpBuffer str, char ch)
295 /* Make more room if needed */
296 if (!enlargePQExpBuffer(str, 1))
299 /* OK, append the character */
300 str->data[str->len] = ch;
302 str->data[str->len] = '\0';
306 * appendBinaryPQExpBuffer
308 * Append arbitrary binary data to a PQExpBuffer, allocating more space
312 appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
314 /* Make more room if needed */
315 if (!enlargePQExpBuffer(str, datalen))
318 /* OK, append the data */
319 memcpy(str->data + str->len, data, datalen);
323 * Keep a trailing null in place, even though it's probably useless for
326 str->data[str->len] = '\0';