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