| 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 | |