Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * stringinfo.c
4 : *
5 : * StringInfo provides an extensible string data type (currently limited to a
6 : * length of 1GB). It can be used to buffer either ordinary C strings
7 : * (null-terminated text) or arbitrary binary data. All storage is allocated
8 : * with palloc() (falling back to malloc in frontend code).
9 : *
10 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
11 : * Portions Copyright (c) 1994, Regents of the University of California
12 : *
13 : * src/common/stringinfo.c
14 : *
15 : *-------------------------------------------------------------------------
16 : */
17 :
18 : #ifndef FRONTEND
19 :
20 : #include "postgres.h"
21 : #include "utils/memutils.h"
22 :
23 : #else
24 :
25 : #include "postgres_fe.h"
26 :
27 : /* It's possible we could use a different value for this in frontend code */
28 : #define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
29 :
30 : #endif
31 :
32 : #include "lib/stringinfo.h"
33 :
34 :
35 : /*
36 : * makeStringInfo
37 : *
38 : * Create an empty 'StringInfoData' & return a pointer to it.
39 : */
40 : StringInfo
8750 tgl 41 CBC 43774 : makeStringInfo(void)
42 : {
43 : StringInfo res;
44 :
9345 bruce 45 43774 : res = (StringInfo) palloc(sizeof(StringInfoData));
46 :
8750 tgl 47 43774 : initStringInfo(res);
48 :
8986 bruce 49 43774 : return res;
50 : }
51 :
52 : /*
53 : * initStringInfo
54 : *
55 : * Initialize a StringInfoData struct (with previously undefined contents)
56 : * to describe an empty string.
57 : */
58 : void
8750 tgl 59 3461519 : initStringInfo(StringInfo str)
60 : {
5624 bruce 61 3461519 : int size = 1024; /* initial default buffer size */
62 :
8622 tgl 63 3461519 : str->data = (char *) palloc(size);
8750 64 3461519 : str->maxlen = size;
5881 neilc 65 3461519 : resetStringInfo(str);
66 3461519 : }
67 :
68 : /*
69 : * resetStringInfo
70 : *
71 : * Reset the StringInfo: the data buffer remains valid, but its
72 : * previous content, if any, is cleared.
73 : */
74 : void
75 19262388 : resetStringInfo(StringInfo str)
76 : {
8750 tgl 77 19262388 : str->data[0] = '\0';
5881 neilc 78 19262388 : str->len = 0;
7295 tgl 79 19262388 : str->cursor = 0;
8750 80 19262388 : }
81 :
82 : /*
83 : * appendStringInfo
84 : *
85 : * Format text data under the control of fmt (an sprintf-style format string)
86 : * and append it to whatever is already in str. More space is allocated
87 : * to str if necessary. This is sort of like a combination of sprintf and
88 : * strcat.
89 : */
90 : void
7188 bruce 91 56644065 : appendStringInfo(StringInfo str, const char *fmt,...)
92 : {
1656 tgl 93 56644065 : int save_errno = errno;
94 :
95 : for (;;)
7290 96 119076 : {
97 : va_list args;
98 : int needed;
99 :
100 : /* Try to format the data. */
1656 101 56763141 : errno = save_errno;
7290 102 56763141 : va_start(args, fmt);
3454 103 56763141 : needed = appendStringInfoVA(str, fmt, args);
7290 104 56763141 : va_end(args);
105 :
3454 106 56763141 : if (needed == 0)
107 56644065 : break; /* success */
108 :
109 : /* Increase the buffer size and try again. */
110 119076 : enlargeStringInfo(str, needed);
111 : }
7290 112 56644065 : }
113 :
114 : /*
115 : * appendStringInfoVA
116 : *
117 : * Attempt to format text data under the control of fmt (an sprintf-style
118 : * format string) and append it to whatever is already in str. If successful
119 : * return zero; if not (because there's not enough space), return an estimate
120 : * of the space needed, without modifying str. Typically the caller should
121 : * pass the return value to enlargeStringInfo() before trying again; see
122 : * appendStringInfo for standard usage pattern.
123 : *
124 : * Caution: callers must be sure to preserve their entry-time errno
125 : * when looping, in case the fmt contains "%m".
126 : *
127 : * XXX This API is ugly, but there seems no alternative given the C spec's
128 : * restrictions on what can portably be done with va_list arguments: you have
129 : * to redo va_start before you can rescan the argument list, and we can't do
130 : * that from here.
131 : */
132 : int
133 57000105 : appendStringInfoVA(StringInfo str, const char *fmt, va_list args)
134 : {
135 : int avail;
136 : size_t nprinted;
137 :
8750 138 57000105 : Assert(str != NULL);
139 :
140 : /*
141 : * If there's hardly any space, don't bother trying, just fail to make the
142 : * caller enlarge the buffer first. We have to guess at how much to
143 : * enlarge, since we're skipping the formatting work.
144 : */
3454 145 57000105 : avail = str->maxlen - str->len;
7290 146 57000105 : if (avail < 16)
3454 147 115916 : return 32;
148 :
149 56884189 : nprinted = pvsnprintf(str->data + str->len, (size_t) avail, fmt, args);
150 :
151 56884189 : if (nprinted < (size_t) avail)
152 : {
153 : /* Success. Note nprinted does not include trailing null. */
154 56879901 : str->len += (int) nprinted;
155 56879901 : return 0;
156 : }
157 :
158 : /* Restore the trailing null so that str is unmodified. */
7290 159 4288 : str->data[str->len] = '\0';
160 :
161 : /*
162 : * Return pvsnprintf's estimate of the space needed. (Although this is
163 : * given as a size_t, we know it will fit in int because it's not more
164 : * than MaxAllocSize.)
165 : */
3454 166 4288 : return (int) nprinted;
167 : }
168 :
169 : /*
170 : * appendStringInfoString
171 : *
172 : * Append a null-terminated string to str.
173 : * Like appendStringInfo(str, "%s", s) but faster.
174 : */
175 : void
7290 176 24299141 : appendStringInfoString(StringInfo str, const char *s)
177 : {
178 24299141 : appendBinaryStringInfo(str, s, strlen(s));
8750 179 24299141 : }
180 :
181 : /*
182 : * appendStringInfoChar
183 : *
184 : * Append a single byte to str.
185 : * Like appendStringInfo(str, "%c", ch) but much faster.
186 : */
187 : void
188 185273738 : appendStringInfoChar(StringInfo str, char ch)
189 : {
190 : /* Make more room if needed */
8560 191 185273738 : if (str->len + 1 >= str->maxlen)
192 62511 : enlargeStringInfo(str, 1);
193 :
194 : /* OK, append the character */
8750 195 185273738 : str->data[str->len] = ch;
196 185273738 : str->len++;
197 185273738 : str->data[str->len] = '\0';
198 185273738 : }
199 :
200 : /*
201 : * appendStringInfoSpaces
202 : *
203 : * Append the specified number of spaces to a buffer.
204 : */
205 : void
5007 206 75400 : appendStringInfoSpaces(StringInfo str, int count)
207 : {
208 75400 : if (count > 0)
209 : {
210 : /* Make more room if needed */
211 72814 : enlargeStringInfo(str, count);
212 :
213 : /* OK, append the spaces */
79 drowley 214 GNC 72814 : memset(&str->data[str->len], ' ', count);
215 72814 : str->len += count;
5007 tgl 216 CBC 72814 : str->data[str->len] = '\0';
217 : }
218 75400 : }
219 :
220 : /*
221 : * appendBinaryStringInfo
222 : *
223 : * Append arbitrary binary data to a StringInfo, allocating more space
224 : * if necessary. Ensures that a trailing null byte is present.
225 : */
226 : void
100 peter 227 GNC 32449729 : appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
228 : {
8750 tgl 229 CBC 32449729 : Assert(str != NULL);
230 :
231 : /* Make more room if needed */
232 32449729 : enlargeStringInfo(str, datalen);
233 :
234 : /* OK, append the data */
235 32449729 : memcpy(str->data + str->len, data, datalen);
236 32449729 : str->len += datalen;
237 :
238 : /*
239 : * Keep a trailing null in place, even though it's probably useless for
240 : * binary data. (Some callers are dealing with text but call this because
241 : * their input isn't null-terminated.)
242 : */
243 32449729 : str->data[str->len] = '\0';
9770 scrappy 244 32449729 : }
245 :
246 : /*
247 : * appendBinaryStringInfoNT
248 : *
249 : * Append arbitrary binary data to a StringInfo, allocating more space
250 : * if necessary. Does not ensure a trailing null-byte exists.
251 : */
252 : void
100 peter 253 GNC 13934242 : appendBinaryStringInfoNT(StringInfo str, const void *data, int datalen)
254 : {
2006 andres 255 CBC 13934242 : Assert(str != NULL);
256 :
257 : /* Make more room if needed */
258 13934242 : enlargeStringInfo(str, datalen);
259 :
260 : /* OK, append the data */
261 13934242 : memcpy(str->data + str->len, data, datalen);
262 13934242 : str->len += datalen;
263 13934242 : }
264 :
265 : /*
266 : * enlargeStringInfo
267 : *
268 : * Make sure there is enough space for 'needed' more bytes
269 : * ('needed' does not include the terminating null).
270 : *
271 : * External callers usually need not concern themselves with this, since
272 : * all stringinfo.c routines do it automatically. However, if a caller
273 : * knows that a StringInfo will eventually become X bytes large, it
274 : * can save some palloc overhead by enlarging the buffer before starting
275 : * to store data in it.
276 : *
277 : * NB: In the backend, because we use repalloc() to enlarge the buffer, the
278 : * string buffer will remain allocated in the same memory context that was
279 : * current when initStringInfo was called, even if another context is now
280 : * current. This is the desired and indeed critical behavior!
281 : */
282 : void
7295 tgl 283 69832025 : enlargeStringInfo(StringInfo str, int needed)
284 : {
285 : int newlen;
286 :
287 : /*
288 : * Guard against out-of-range "needed" values. Without this, we can get
289 : * an overflow or infinite loop in the following.
290 : */
5795 291 69832025 : if (needed < 0) /* should not happen */
292 : {
293 : #ifndef FRONTEND
5795 tgl 294 UBC 0 : elog(ERROR, "invalid string enlargement request size: %d", needed);
295 : #else
1251 andres 296 0 : fprintf(stderr, "invalid string enlargement request size: %d\n", needed);
297 0 : exit(EXIT_FAILURE);
298 : #endif
299 : }
2160 alvherre 300 CBC 69832025 : if (((Size) needed) >= (MaxAllocSize - (Size) str->len))
301 : {
302 : #ifndef FRONTEND
5795 tgl 303 UBC 0 : ereport(ERROR,
304 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
305 : errmsg("out of memory"),
306 : errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.",
307 : str->len, needed)));
308 : #else
1251 andres 309 0 : fprintf(stderr,
310 0 : _("out of memory\n\nCannot enlarge string buffer containing %d bytes by %d more bytes.\n"),
311 : str->len, needed);
312 0 : exit(EXIT_FAILURE);
313 : #endif
314 : }
315 :
7295 tgl 316 CBC 69832025 : needed += str->len + 1; /* total space required now */
317 :
318 : /* Because of the above test, we now have needed <= MaxAllocSize */
319 :
320 69832025 : if (needed <= str->maxlen)
321 69562121 : return; /* got enough space already */
322 :
323 : /*
324 : * We don't want to allocate just a little more space with each append;
325 : * for efficiency, double the buffer size each time it overflows.
326 : * Actually, we might need to more than double it if 'needed' is big...
327 : */
2160 alvherre 328 269904 : newlen = 2 * str->maxlen;
329 382143 : while (needed > newlen)
7295 tgl 330 112239 : newlen = 2 * newlen;
331 :
332 : /*
333 : * Clamp to MaxAllocSize in case we went past it. Note we are assuming
334 : * here that MaxAllocSize <= INT_MAX/2, else the above loop could
335 : * overflow. We will still have newlen >= needed.
336 : */
2160 alvherre 337 269904 : if (newlen > (int) MaxAllocSize)
2160 alvherre 338 UBC 0 : newlen = (int) MaxAllocSize;
339 :
2160 alvherre 340 CBC 269904 : str->data = (char *) repalloc(str->data, newlen);
341 :
7295 tgl 342 269904 : str->maxlen = newlen;
343 : }
|