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-2001, PostgreSQL Global Development Group
18 * Portions Copyright (c) 1994, Regents of the University of California
20 * $Header: /cvsroot/pgsql/src/interfaces/libpq/pqexpbuffer.c,v 1.8 2001/01/24 19:43:31 momjian Exp $
22 *-------------------------------------------------------------------------
26 #include "pqexpbuffer.h"
37 * Create an empty 'PQExpBufferData' & return a pointer to it.
40 createPQExpBuffer(void)
44 res = (PQExpBuffer) malloc(sizeof(PQExpBufferData));
54 * Initialize a PQExpBufferData struct (with previously undefined contents)
55 * to describe an empty string.
58 initPQExpBuffer(PQExpBuffer str)
60 str->data = (char *) malloc(INITIAL_EXPBUFFER_SIZE);
61 if (str->data == NULL)
68 str->maxlen = INITIAL_EXPBUFFER_SIZE;
74 /*------------------------
75 * destroyPQExpBuffer(str);
76 * free()s both the data buffer and the PQExpBufferData.
77 * This is the inverse of createPQExpBuffer().
80 destroyPQExpBuffer(PQExpBuffer str)
89 /*------------------------
90 * termPQExpBuffer(str)
91 * free()s the data buffer but not the PQExpBufferData itself.
92 * This is the inverse of initPQExpBuffer().
95 termPQExpBuffer(PQExpBuffer str)
102 /* just for luck, make the buffer validly empty. */
107 /*------------------------
109 * Reset a PQExpBuffer to empty
112 resetPQExpBuffer(PQExpBuffer str)
122 /*------------------------
124 * Make sure there is enough space for 'needed' more bytes in the buffer
125 * ('needed' does not include the terminating null).
127 * Returns 1 if OK, 0 if failed to enlarge buffer.
130 enlargePQExpBuffer(PQExpBuffer str, size_t needed)
135 needed += str->len + 1; /* total space required now */
136 if (needed <= str->maxlen)
137 return 1; /* got enough space already */
140 * We don't want to allocate just a little more space with each
141 * append; for efficiency, double the buffer size each time it
142 * overflows. Actually, we might need to more than double it if
145 newlen = (str->maxlen > 0) ? (2 * str->maxlen) : 64;
146 while (needed > newlen)
149 newdata = (char *) realloc(str->data, newlen);
153 str->maxlen = newlen;
159 /*------------------------
161 * Format text data under the control of fmt (an sprintf-like format string)
162 * and insert it into str. More space is allocated to str if necessary.
163 * This is a convenience routine that does the same thing as
164 * resetPQExpBuffer() followed by appendPQExpBuffer().
167 printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
173 resetPQExpBuffer(str);
178 * Try to format the given string into the available space;
179 * but if there's hardly any space, don't bother trying,
180 * just fall through to enlarge the buffer first.
183 if (str->maxlen > str->len + 16)
185 avail = str->maxlen - str->len - 1;
187 nprinted = vsnprintf(str->data + str->len, avail,
192 * Note: some versions of vsnprintf return the number of chars
193 * actually stored, but at least one returns -1 on failure. Be
194 * conservative about believing whether the print worked.
196 if (nprinted >= 0 && nprinted < avail - 1)
198 /* Success. Note nprinted does not include trailing null. */
199 str->len += nprinted;
203 /* Double the buffer size and try again. */
204 if (!enlargePQExpBuffer(str, str->maxlen))
205 return; /* oops, out of memory */
209 /*------------------------
212 * Format text data under the control of fmt (an sprintf-like format string)
213 * and append it to whatever is already in str. More space is allocated
214 * to str if necessary. This is sort of like a combination of sprintf and
218 appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
227 * Try to format the given string into the available space;
228 * but if there's hardly any space, don't bother trying,
229 * just fall through to enlarge the buffer first.
232 if (str->maxlen > str->len + 16)
234 avail = str->maxlen - str->len - 1;
236 nprinted = vsnprintf(str->data + str->len, avail,
241 * Note: some versions of vsnprintf return the number of chars
242 * actually stored, but at least one returns -1 on failure. Be
243 * conservative about believing whether the print worked.
245 if (nprinted >= 0 && nprinted < avail - 1)
247 /* Success. Note nprinted does not include trailing null. */
248 str->len += nprinted;
252 /* Double the buffer size and try again. */
253 if (!enlargePQExpBuffer(str, str->maxlen))
254 return; /* oops, out of memory */
258 /*------------------------
259 * appendPQExpBufferStr
260 * Append the given string to a PQExpBuffer, allocating more space
264 appendPQExpBufferStr(PQExpBuffer str, const char *data)
266 appendBinaryPQExpBuffer(str, data, strlen(data));
269 /*------------------------
270 * appendPQExpBufferChar
271 * Append a single byte to str.
272 * Like appendPQExpBuffer(str, "%c", ch) but much faster.
275 appendPQExpBufferChar(PQExpBuffer str, char ch)
277 /* Make more room if needed */
278 if (!enlargePQExpBuffer(str, 1))
281 /* OK, append the character */
282 str->data[str->len] = ch;
284 str->data[str->len] = '\0';
288 * appendBinaryPQExpBuffer
290 * Append arbitrary binary data to a PQExpBuffer, allocating more space
294 appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
296 /* Make more room if needed */
297 if (!enlargePQExpBuffer(str, datalen))
300 /* OK, append the data */
301 memcpy(str->data + str->len, data, datalen);
305 * Keep a trailing null in place, even though it's probably useless
308 str->data[str->len] = '\0';