PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
stringinfo.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * stringinfo.c
4  *
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() and
8  * friends.
9  *
10  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
11  * Portions Copyright (c) 1994, Regents of the University of California
12  *
13  * src/backend/lib/stringinfo.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18 
19 #include "lib/stringinfo.h"
20 #include "utils/memutils.h"
21 
22 
23 /*
24  * makeStringInfo
25  *
26  * Create an empty 'StringInfoData' & return a pointer to it.
27  */
30 {
31  StringInfo res;
32 
33  res = (StringInfo) palloc(sizeof(StringInfoData));
34 
35  initStringInfo(res);
36 
37  return res;
38 }
39 
40 /*
41  * makeLongStringInfo
42  *
43  * Same as makeStringInfo, for larger strings.
44  */
47 {
48  StringInfo res;
49 
50  res = (StringInfo) palloc(sizeof(StringInfoData));
51 
52  initLongStringInfo(res);
53 
54  return res;
55 }
56 
57 
58 /*
59  * initStringInfo
60  *
61  * Initialize a StringInfoData struct (with previously undefined contents)
62  * to describe an empty string; don't enable long strings yet.
63  */
64 void
66 {
67  int size = 1024; /* initial default buffer size */
68 
69  str->data = (char *) palloc(size);
70  str->maxlen = size;
71  str->long_ok = false;
72  resetStringInfo(str);
73 }
74 
75 /*
76  * initLongStringInfo
77  *
78  * Same as initStringInfo, plus enable long strings.
79  */
80 void
82 {
83  initStringInfo(str);
84  str->long_ok = true;
85 }
86 
87 /*
88  * resetStringInfo
89  *
90  * Reset the StringInfo: the data buffer remains valid, but its
91  * previous content, if any, is cleared.
92  */
93 void
95 {
96  str->data[0] = '\0';
97  str->len = 0;
98  str->cursor = 0;
99 }
100 
101 /*
102  * appendStringInfo
103  *
104  * Format text data under the control of fmt (an sprintf-style format string)
105  * and append it to whatever is already in str. More space is allocated
106  * to str if necessary. This is sort of like a combination of sprintf and
107  * strcat.
108  */
109 void
110 appendStringInfo(StringInfo str, const char *fmt,...)
111 {
112  for (;;)
113  {
114  va_list args;
115  int needed;
116 
117  /* Try to format the data. */
118  va_start(args, fmt);
119  needed = appendStringInfoVA(str, fmt, args);
120  va_end(args);
121 
122  if (needed == 0)
123  break; /* success */
124 
125  /* Increase the buffer size and try again. */
126  enlargeStringInfo(str, needed);
127  }
128 }
129 
130 /*
131  * appendStringInfoVA
132  *
133  * Attempt to format text data under the control of fmt (an sprintf-style
134  * format string) and append it to whatever is already in str. If successful
135  * return zero; if not (because there's not enough space), return an estimate
136  * of the space needed, without modifying str. Typically the caller should
137  * pass the return value to enlargeStringInfo() before trying again; see
138  * appendStringInfo for standard usage pattern.
139  *
140  * XXX This API is ugly, but there seems no alternative given the C spec's
141  * restrictions on what can portably be done with va_list arguments: you have
142  * to redo va_start before you can rescan the argument list, and we can't do
143  * that from here.
144  */
145 int
146 appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
147 {
148  int avail;
149  size_t nprinted;
150 
151  Assert(str != NULL);
152 
153  /*
154  * If there's hardly any space, don't bother trying, just fail to make the
155  * caller enlarge the buffer first. We have to guess at how much to
156  * enlarge, since we're skipping the formatting work.
157  */
158  avail = str->maxlen - str->len;
159  if (avail < 16)
160  return 32;
161 
162  nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
163 
164  if (nprinted < (size_t) avail)
165  {
166  /* Success. Note nprinted does not include trailing null. */
167  str->len += (int) nprinted;
168  return 0;
169  }
170 
171  /* Restore the trailing null so that str is unmodified. */
172  str->data[str->len] = '\0';
173 
174  /*
175  * Return pvsnprintf's estimate of the space needed. (Although this is
176  * given as a size_t, we know it will fit in int because it's not more
177  * than either MaxAllocSize or half an int's width.)
178  */
179  return (int) nprinted;
180 }
181 
182 /*
183  * appendStringInfoString
184  *
185  * Append a null-terminated string to str.
186  * Like appendStringInfo(str, "%s", s) but faster.
187  */
188 void
190 {
191  appendBinaryStringInfo(str, s, strlen(s));
192 }
193 
194 /*
195  * appendStringInfoChar
196  *
197  * Append a single byte to str.
198  * Like appendStringInfo(str, "%c", ch) but much faster.
199  */
200 void
202 {
203  /* Make more room if needed */
204  if (str->len + 1 >= str->maxlen)
205  enlargeStringInfo(str, 1);
206 
207  /* OK, append the character */
208  str->data[str->len] = ch;
209  str->len++;
210  str->data[str->len] = '\0';
211 }
212 
213 /*
214  * appendStringInfoSpaces
215  *
216  * Append the specified number of spaces to a buffer.
217  */
218 void
220 {
221  if (count > 0)
222  {
223  /* Make more room if needed */
224  enlargeStringInfo(str, count);
225 
226  /* OK, append the spaces */
227  while (--count >= 0)
228  str->data[str->len++] = ' ';
229  str->data[str->len] = '\0';
230  }
231 }
232 
233 /*
234  * appendBinaryStringInfo
235  *
236  * Append arbitrary binary data to a StringInfo, allocating more space
237  * if necessary.
238  */
239 void
240 appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
241 {
242  Assert(str != NULL);
243 
244  /* Make more room if needed */
245  enlargeStringInfo(str, datalen);
246 
247  /* OK, append the data */
248  memcpy(str->data + str->len, data, datalen);
249  str->len += datalen;
250 
251  /*
252  * Keep a trailing null in place, even though it's probably useless for
253  * binary data. (Some callers are dealing with text but call this because
254  * their input isn't null-terminated.)
255  */
256  str->data[str->len] = '\0';
257 }
258 
259 /*
260  * enlargeStringInfo
261  *
262  * Make sure there is enough space for 'needed' more bytes
263  * ('needed' does not include the terminating null).
264  *
265  * External callers usually need not concern themselves with this, since
266  * all stringinfo.c routines do it automatically. However, if a caller
267  * knows that a StringInfo will eventually become X bytes large, it
268  * can save some palloc overhead by enlarging the buffer before starting
269  * to store data in it.
270  *
271  * NB: because we use repalloc() to enlarge the buffer, the string buffer
272  * will remain allocated in the same memory context that was current when
273  * initStringInfo was called, even if another context is now current.
274  * This is the desired and indeed critical behavior!
275  */
276 void
278 {
279  Size newlen;
280  Size limit;
281 
282  /*
283  * Determine the upper size limit. Because of overflow concerns outside
284  * of this module, we limit ourselves to 4-byte signed integer range,
285  * even for "long_ok" strings.
286  */
287  limit = str->long_ok ?
288  (((Size) 1) << (sizeof(int32) * 8 - 1)) - 1 :
289  MaxAllocSize;
290 
291  /*
292  * Guard against out-of-range "needed" values. Without this, we can get
293  * an overflow or infinite loop in the following.
294  */
295  if (needed < 0) /* should not happen */
296  elog(ERROR, "invalid string enlargement request size: %d", needed);
297  if (((Size) needed) >= (limit - (Size) str->len))
298  ereport(ERROR,
299  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
300  errmsg("out of memory"),
301  errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
302  str->len, needed)));
303 
304  needed += str->len + 1; /* total space required now */
305 
306  /* Because of the above test, we now have needed <= limit */
307 
308  if (needed <= str->maxlen)
309  return; /* got enough space already */
310 
311  /*
312  * We don't want to allocate just a little more space with each append;
313  * for efficiency, double the buffer size each time it overflows.
314  * Actually, we might need to more than double it if 'needed' is big...
315  */
316  newlen = 2 * (Size) str->maxlen;
317  while ((Size) needed > newlen)
318  newlen = 2 * newlen;
319 
320  /*
321  * Clamp to the limit in case we went past it. (We used to depend on
322  * limit <= INT32_MAX/2, to avoid overflow in the loop above; we no longer
323  * depend on that, but if "needed" and str->maxlen ever become wider, we
324  * will need similar caution here.) We will still have newlen >= needed.
325  */
326  if (newlen > limit)
327  newlen = limit;
328 
329  str->data = (char *) repalloc_huge(str->data, newlen);
330 
331  str->maxlen = newlen;
332 }
void initLongStringInfo(StringInfo str)
Definition: stringinfo.c:81
StringInfo makeStringInfo(void)
Definition: stringinfo.c:29
StringInfoData * StringInfo
Definition: stringinfo.h:46
int errcode(int sqlerrcode)
Definition: elog.c:575
signed int int32
Definition: c.h:256
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
Definition: psprintf.c:104
#define ERROR
Definition: elog.h:43
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
int errdetail(const char *fmt,...)
Definition: elog.c:873
void enlargeStringInfo(StringInfo str, int needed)
Definition: stringinfo.c:277
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:94
#define ereport(elevel, rest)
Definition: elog.h:122
#define MaxAllocSize
Definition: memutils.h:40
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
void appendStringInfoSpaces(StringInfo str, int count)
Definition: stringinfo.c:219
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
size_t Size
Definition: c.h:356
void * repalloc_huge(void *pointer, Size size)
Definition: mcxt.c:1031
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
int appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
Definition: stringinfo.c:146
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:240
StringInfo makeLongStringInfo(void)
Definition: stringinfo.c:46