1 /*-------------------------------------------------------------------------
5 * StringInfo 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 palloc().
9 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/backend/lib/stringinfo.c,v 1.43 2006/03/05 15:58:27 momjian Exp $
14 *-------------------------------------------------------------------------
18 #include "lib/stringinfo.h"
19 #include "utils/memutils.h"
25 * Create an empty 'StringInfoData' & return a pointer to it.
32 res = (StringInfo) palloc(sizeof(StringInfoData));
42 * Initialize a StringInfoData struct (with previously undefined contents)
43 * to describe an empty string.
46 initStringInfo(StringInfo str)
48 int size = 256; /* initial default buffer size */
50 str->data = (char *) palloc(size);
60 * Format text data under the control of fmt (an sprintf-style format string)
61 * and append it to whatever is already in str. More space is allocated
62 * to str if necessary. This is sort of like a combination of sprintf and
66 appendStringInfo(StringInfo str, const char *fmt,...)
73 /* Try to format the data. */
75 success = appendStringInfoVA(str, fmt, args);
81 /* Double the buffer size and try again. */
82 enlargeStringInfo(str, str->maxlen);
89 * Attempt to format text data under the control of fmt (an sprintf-style
90 * format string) and append it to whatever is already in str. If successful
91 * return true; if not (because there's not enough space), return false
92 * without modifying str. Typically the caller would enlarge str and retry
93 * on false return --- see appendStringInfo for standard usage pattern.
95 * XXX This API is ugly, but there seems no alternative given the C spec's
96 * restrictions on what can portably be done with va_list arguments: you have
97 * to redo va_start before you can rescan the argument list, and we can't do
101 appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
109 * If there's hardly any space, don't bother trying, just fail to make the
110 * caller enlarge the buffer first.
112 avail = str->maxlen - str->len - 1;
117 * Assert check here is to catch buggy vsnprintf that overruns the
118 * specified buffer length. Solaris 7 in 64-bit mode is an example of a
119 * platform with such a bug.
121 #ifdef USE_ASSERT_CHECKING
122 str->data[str->maxlen - 1] = '\0';
125 nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
127 Assert(str->data[str->maxlen - 1] == '\0');
130 * Note: some versions of vsnprintf return the number of chars actually
131 * stored, but at least one returns -1 on failure. Be conservative about
132 * believing whether the print worked.
134 if (nprinted >= 0 && nprinted < avail - 1)
136 /* Success. Note nprinted does not include trailing null. */
137 str->len += nprinted;
141 /* Restore the trailing null so that str is unmodified. */
142 str->data[str->len] = '\0';
147 * appendStringInfoString
149 * Append a null-terminated string to str.
150 * Like appendStringInfo(str, "%s", s) but faster.
153 appendStringInfoString(StringInfo str, const char *s)
155 appendBinaryStringInfo(str, s, strlen(s));
159 * appendStringInfoChar
161 * Append a single byte to str.
162 * Like appendStringInfo(str, "%c", ch) but much faster.
165 appendStringInfoChar(StringInfo str, char ch)
167 /* Make more room if needed */
168 if (str->len + 1 >= str->maxlen)
169 enlargeStringInfo(str, 1);
171 /* OK, append the character */
172 str->data[str->len] = ch;
174 str->data[str->len] = '\0';
178 * appendBinaryStringInfo
180 * Append arbitrary binary data to a StringInfo, allocating more space
184 appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
188 /* Make more room if needed */
189 enlargeStringInfo(str, datalen);
191 /* OK, append the data */
192 memcpy(str->data + str->len, data, datalen);
196 * Keep a trailing null in place, even though it's probably useless for
199 str->data[str->len] = '\0';
205 * Make sure there is enough space for 'needed' more bytes
206 * ('needed' does not include the terminating null).
208 * External callers usually need not concern themselves with this, since
209 * all stringinfo.c routines do it automatically. However, if a caller
210 * knows that a StringInfo will eventually become X bytes large, it
211 * can save some palloc overhead by enlarging the buffer before starting
212 * to store data in it.
214 * NB: because we use repalloc() to enlarge the buffer, the string buffer
215 * will remain allocated in the same memory context that was current when
216 * initStringInfo was called, even if another context is now current.
217 * This is the desired and indeed critical behavior!
220 enlargeStringInfo(StringInfo str, int needed)
225 * Guard against ridiculous "needed" values, which can occur if we're fed
226 * bogus data. Without this, we can get an overflow or infinite loop in
230 ((Size) needed) >= (MaxAllocSize - (Size) str->len))
231 elog(ERROR, "invalid string enlargement request size %d",
234 needed += str->len + 1; /* total space required now */
236 /* Because of the above test, we now have needed <= MaxAllocSize */
238 if (needed <= str->maxlen)
239 return; /* got enough space already */
242 * We don't want to allocate just a little more space with each append;
243 * for efficiency, double the buffer size each time it overflows.
244 * Actually, we might need to more than double it if 'needed' is big...
246 newlen = 2 * str->maxlen;
247 while (needed > newlen)
251 * Clamp to MaxAllocSize in case we went past it. Note we are assuming
252 * here that MaxAllocSize <= INT_MAX/2, else the above loop could
253 * overflow. We will still have newlen >= needed.
255 if (newlen > (int) MaxAllocSize)
256 newlen = (int) MaxAllocSize;
258 str->data = (char *) repalloc(str->data, newlen);
260 str->maxlen = newlen;