Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / lib / stringinfo.c
blob80a795c1a7a8de9d61c20c30e6de8942f5cc443d
1 /*-------------------------------------------------------------------------
3 * stringinfo.c
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-2008, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL$
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include "lib/stringinfo.h"
19 #include "utils/memutils.h"
23 * makeStringInfo
25 * Create an empty 'StringInfoData' & return a pointer to it.
27 StringInfo
28 makeStringInfo(void)
30 StringInfo res;
32 res = (StringInfo) palloc(sizeof(StringInfoData));
34 initStringInfo(res);
36 return res;
40 * initStringInfo
42 * Initialize a StringInfoData struct (with previously undefined contents)
43 * to describe an empty string.
45 void
46 initStringInfo(StringInfo str)
48 int size = 1024; /* initial default buffer size */
50 str->data = (char *) palloc(size);
51 str->maxlen = size;
52 resetStringInfo(str);
56 * resetStringInfo
58 * Reset the StringInfo: the data buffer remains valid, but its
59 * previous content, if any, is cleared.
61 void
62 resetStringInfo(StringInfo str)
64 str->data[0] = '\0';
65 str->len = 0;
66 str->cursor = 0;
70 * appendStringInfo
72 * Format text data under the control of fmt (an sprintf-style format string)
73 * and append it to whatever is already in str. More space is allocated
74 * to str if necessary. This is sort of like a combination of sprintf and
75 * strcat.
77 void
78 appendStringInfo(StringInfo str, const char *fmt,...)
80 for (;;)
82 va_list args;
83 bool success;
85 /* Try to format the data. */
86 va_start(args, fmt);
87 success = appendStringInfoVA(str, fmt, args);
88 va_end(args);
90 if (success)
91 break;
93 /* Double the buffer size and try again. */
94 enlargeStringInfo(str, str->maxlen);
99 * appendStringInfoVA
101 * Attempt to format text data under the control of fmt (an sprintf-style
102 * format string) and append it to whatever is already in str. If successful
103 * return true; if not (because there's not enough space), return false
104 * without modifying str. Typically the caller would enlarge str and retry
105 * on false return --- see appendStringInfo for standard usage pattern.
107 * XXX This API is ugly, but there seems no alternative given the C spec's
108 * restrictions on what can portably be done with va_list arguments: you have
109 * to redo va_start before you can rescan the argument list, and we can't do
110 * that from here.
112 bool
113 appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
115 int avail,
116 nprinted;
118 Assert(str != NULL);
121 * If there's hardly any space, don't bother trying, just fail to make the
122 * caller enlarge the buffer first.
124 avail = str->maxlen - str->len - 1;
125 if (avail < 16)
126 return false;
129 * Assert check here is to catch buggy vsnprintf that overruns the
130 * specified buffer length. Solaris 7 in 64-bit mode is an example of a
131 * platform with such a bug.
133 #ifdef USE_ASSERT_CHECKING
134 str->data[str->maxlen - 1] = '\0';
135 #endif
137 nprinted = vsnprintf(str->data + str->len, avail, fmt, args);
139 Assert(str->data[str->maxlen - 1] == '\0');
142 * Note: some versions of vsnprintf return the number of chars actually
143 * stored, but at least one returns -1 on failure. Be conservative about
144 * believing whether the print worked.
146 if (nprinted >= 0 && nprinted < avail - 1)
148 /* Success. Note nprinted does not include trailing null. */
149 str->len += nprinted;
150 return true;
153 /* Restore the trailing null so that str is unmodified. */
154 str->data[str->len] = '\0';
155 return false;
159 * appendStringInfoString
161 * Append a null-terminated string to str.
162 * Like appendStringInfo(str, "%s", s) but faster.
164 void
165 appendStringInfoString(StringInfo str, const char *s)
167 appendBinaryStringInfo(str, s, strlen(s));
171 * appendStringInfoChar
173 * Append a single byte to str.
174 * Like appendStringInfo(str, "%c", ch) but much faster.
176 void
177 appendStringInfoChar(StringInfo str, char ch)
179 /* Make more room if needed */
180 if (str->len + 1 >= str->maxlen)
181 enlargeStringInfo(str, 1);
183 /* OK, append the character */
184 str->data[str->len] = ch;
185 str->len++;
186 str->data[str->len] = '\0';
190 * appendBinaryStringInfo
192 * Append arbitrary binary data to a StringInfo, allocating more space
193 * if necessary.
195 void
196 appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
198 Assert(str != NULL);
200 /* Make more room if needed */
201 enlargeStringInfo(str, datalen);
203 /* OK, append the data */
204 memcpy(str->data + str->len, data, datalen);
205 str->len += datalen;
208 * Keep a trailing null in place, even though it's probably useless for
209 * binary data...
211 str->data[str->len] = '\0';
215 * enlargeStringInfo
217 * Make sure there is enough space for 'needed' more bytes
218 * ('needed' does not include the terminating null).
220 * External callers usually need not concern themselves with this, since
221 * all stringinfo.c routines do it automatically. However, if a caller
222 * knows that a StringInfo will eventually become X bytes large, it
223 * can save some palloc overhead by enlarging the buffer before starting
224 * to store data in it.
226 * NB: because we use repalloc() to enlarge the buffer, the string buffer
227 * will remain allocated in the same memory context that was current when
228 * initStringInfo was called, even if another context is now current.
229 * This is the desired and indeed critical behavior!
231 void
232 enlargeStringInfo(StringInfo str, int needed)
234 int newlen;
237 * Guard against out-of-range "needed" values. Without this, we can get
238 * an overflow or infinite loop in the following.
240 if (needed < 0) /* should not happen */
241 elog(ERROR, "invalid string enlargement request size: %d", needed);
242 if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
243 ereport(ERROR,
244 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
245 errmsg("out of memory"),
246 errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
247 str->len, needed)));
249 needed += str->len + 1; /* total space required now */
251 /* Because of the above test, we now have needed <= MaxAllocSize */
253 if (needed <= str->maxlen)
254 return; /* got enough space already */
257 * We don't want to allocate just a little more space with each append;
258 * for efficiency, double the buffer size each time it overflows.
259 * Actually, we might need to more than double it if 'needed' is big...
261 newlen = 2 * str->maxlen;
262 while (needed > newlen)
263 newlen = 2 * newlen;
266 * Clamp to MaxAllocSize in case we went past it. Note we are assuming
267 * here that MaxAllocSize <= INT_MAX/2, else the above loop could
268 * overflow. We will still have newlen >= needed.
270 if (newlen > (int) MaxAllocSize)
271 newlen = (int) MaxAllocSize;
273 str->data = (char *) repalloc(str->data, newlen);
275 str->maxlen = newlen;