00001 /*------------------------------------------------------------------------- 00002 * 00003 * stringinfo.c 00004 * 00005 * StringInfo provides an indefinitely-extensible string data type. 00006 * It can be used to buffer either ordinary C strings (null-terminated text) 00007 * or arbitrary binary data. All storage is allocated with palloc(). 00008 * 00009 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group 00010 * Portions Copyright (c) 1994, Regents of the University of California 00011 * 00012 * src/backend/lib/stringinfo.c 00013 * 00014 *------------------------------------------------------------------------- 00015 */ 00016 #include "postgres.h" 00017 00018 #include "lib/stringinfo.h" 00019 #include "utils/memutils.h" 00020 00021 00022 /* 00023 * makeStringInfo 00024 * 00025 * Create an empty 'StringInfoData' & return a pointer to it. 00026 */ 00027 StringInfo 00028 makeStringInfo(void) 00029 { 00030 StringInfo res; 00031 00032 res = (StringInfo) palloc(sizeof(StringInfoData)); 00033 00034 initStringInfo(res); 00035 00036 return res; 00037 } 00038 00039 /* 00040 * initStringInfo 00041 * 00042 * Initialize a StringInfoData struct (with previously undefined contents) 00043 * to describe an empty string. 00044 */ 00045 void 00046 initStringInfo(StringInfo str) 00047 { 00048 int size = 1024; /* initial default buffer size */ 00049 00050 str->data = (char *) palloc(size); 00051 str->maxlen = size; 00052 resetStringInfo(str); 00053 } 00054 00055 /* 00056 * resetStringInfo 00057 * 00058 * Reset the StringInfo: the data buffer remains valid, but its 00059 * previous content, if any, is cleared. 00060 */ 00061 void 00062 resetStringInfo(StringInfo str) 00063 { 00064 str->data[0] = '\0'; 00065 str->len = 0; 00066 str->cursor = 0; 00067 } 00068 00069 /* 00070 * appendStringInfo 00071 * 00072 * Format text data under the control of fmt (an sprintf-style format string) 00073 * and append it to whatever is already in str. More space is allocated 00074 * to str if necessary. This is sort of like a combination of sprintf and 00075 * strcat. 00076 */ 00077 void 00078 appendStringInfo(StringInfo str, const char *fmt,...) 00079 { 00080 for (;;) 00081 { 00082 va_list args; 00083 bool success; 00084 00085 /* Try to format the data. */ 00086 va_start(args, fmt); 00087 success = appendStringInfoVA(str, fmt, args); 00088 va_end(args); 00089 00090 if (success) 00091 break; 00092 00093 /* Double the buffer size and try again. */ 00094 enlargeStringInfo(str, str->maxlen); 00095 } 00096 } 00097 00098 /* 00099 * appendStringInfoVA 00100 * 00101 * Attempt to format text data under the control of fmt (an sprintf-style 00102 * format string) and append it to whatever is already in str. If successful 00103 * return true; if not (because there's not enough space), return false 00104 * without modifying str. Typically the caller would enlarge str and retry 00105 * on false return --- see appendStringInfo for standard usage pattern. 00106 * 00107 * XXX This API is ugly, but there seems no alternative given the C spec's 00108 * restrictions on what can portably be done with va_list arguments: you have 00109 * to redo va_start before you can rescan the argument list, and we can't do 00110 * that from here. 00111 */ 00112 bool 00113 appendStringInfoVA(StringInfo str, const char *fmt, va_list args) 00114 { 00115 int avail, 00116 nprinted; 00117 00118 Assert(str != NULL); 00119 00120 /* 00121 * If there's hardly any space, don't bother trying, just fail to make the 00122 * caller enlarge the buffer first. 00123 */ 00124 avail = str->maxlen - str->len - 1; 00125 if (avail < 16) 00126 return false; 00127 00128 /* 00129 * Assert check here is to catch buggy vsnprintf that overruns the 00130 * specified buffer length. Solaris 7 in 64-bit mode is an example of a 00131 * platform with such a bug. 00132 */ 00133 #ifdef USE_ASSERT_CHECKING 00134 str->data[str->maxlen - 1] = '\0'; 00135 #endif 00136 00137 nprinted = vsnprintf(str->data + str->len, avail, fmt, args); 00138 00139 Assert(str->data[str->maxlen - 1] == '\0'); 00140 00141 /* 00142 * Note: some versions of vsnprintf return the number of chars actually 00143 * stored, but at least one returns -1 on failure. Be conservative about 00144 * believing whether the print worked. 00145 */ 00146 if (nprinted >= 0 && nprinted < avail - 1) 00147 { 00148 /* Success. Note nprinted does not include trailing null. */ 00149 str->len += nprinted; 00150 return true; 00151 } 00152 00153 /* Restore the trailing null so that str is unmodified. */ 00154 str->data[str->len] = '\0'; 00155 return false; 00156 } 00157 00158 /* 00159 * appendStringInfoString 00160 * 00161 * Append a null-terminated string to str. 00162 * Like appendStringInfo(str, "%s", s) but faster. 00163 */ 00164 void 00165 appendStringInfoString(StringInfo str, const char *s) 00166 { 00167 appendBinaryStringInfo(str, s, strlen(s)); 00168 } 00169 00170 /* 00171 * appendStringInfoChar 00172 * 00173 * Append a single byte to str. 00174 * Like appendStringInfo(str, "%c", ch) but much faster. 00175 */ 00176 void 00177 appendStringInfoChar(StringInfo str, char ch) 00178 { 00179 /* Make more room if needed */ 00180 if (str->len + 1 >= str->maxlen) 00181 enlargeStringInfo(str, 1); 00182 00183 /* OK, append the character */ 00184 str->data[str->len] = ch; 00185 str->len++; 00186 str->data[str->len] = '\0'; 00187 } 00188 00189 /* 00190 * appendStringInfoSpaces 00191 * 00192 * Append the specified number of spaces to a buffer. 00193 */ 00194 void 00195 appendStringInfoSpaces(StringInfo str, int count) 00196 { 00197 if (count > 0) 00198 { 00199 /* Make more room if needed */ 00200 enlargeStringInfo(str, count); 00201 00202 /* OK, append the spaces */ 00203 while (--count >= 0) 00204 str->data[str->len++] = ' '; 00205 str->data[str->len] = '\0'; 00206 } 00207 } 00208 00209 /* 00210 * appendBinaryStringInfo 00211 * 00212 * Append arbitrary binary data to a StringInfo, allocating more space 00213 * if necessary. 00214 */ 00215 void 00216 appendBinaryStringInfo(StringInfo str, const char *data, int datalen) 00217 { 00218 Assert(str != NULL); 00219 00220 /* Make more room if needed */ 00221 enlargeStringInfo(str, datalen); 00222 00223 /* OK, append the data */ 00224 memcpy(str->data + str->len, data, datalen); 00225 str->len += datalen; 00226 00227 /* 00228 * Keep a trailing null in place, even though it's probably useless for 00229 * binary data. (Some callers are dealing with text but call this because 00230 * their input isn't null-terminated.) 00231 */ 00232 str->data[str->len] = '\0'; 00233 } 00234 00235 /* 00236 * enlargeStringInfo 00237 * 00238 * Make sure there is enough space for 'needed' more bytes 00239 * ('needed' does not include the terminating null). 00240 * 00241 * External callers usually need not concern themselves with this, since 00242 * all stringinfo.c routines do it automatically. However, if a caller 00243 * knows that a StringInfo will eventually become X bytes large, it 00244 * can save some palloc overhead by enlarging the buffer before starting 00245 * to store data in it. 00246 * 00247 * NB: because we use repalloc() to enlarge the buffer, the string buffer 00248 * will remain allocated in the same memory context that was current when 00249 * initStringInfo was called, even if another context is now current. 00250 * This is the desired and indeed critical behavior! 00251 */ 00252 void 00253 enlargeStringInfo(StringInfo str, int needed) 00254 { 00255 int newlen; 00256 00257 /* 00258 * Guard against out-of-range "needed" values. Without this, we can get 00259 * an overflow or infinite loop in the following. 00260 */ 00261 if (needed < 0) /* should not happen */ 00262 elog(ERROR, "invalid string enlargement request size: %d", needed); 00263 if (((Size) needed) >= (MaxAllocSize - (Size) str->len)) 00264 ereport(ERROR, 00265 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), 00266 errmsg("out of memory"), 00267 errdetail("Cannot enlarge string buffer containing %d bytes by %d more bytes.", 00268 str->len, needed))); 00269 00270 needed += str->len + 1; /* total space required now */ 00271 00272 /* Because of the above test, we now have needed <= MaxAllocSize */ 00273 00274 if (needed <= str->maxlen) 00275 return; /* got enough space already */ 00276 00277 /* 00278 * We don't want to allocate just a little more space with each append; 00279 * for efficiency, double the buffer size each time it overflows. 00280 * Actually, we might need to more than double it if 'needed' is big... 00281 */ 00282 newlen = 2 * str->maxlen; 00283 while (needed > newlen) 00284 newlen = 2 * newlen; 00285 00286 /* 00287 * Clamp to MaxAllocSize in case we went past it. Note we are assuming 00288 * here that MaxAllocSize <= INT_MAX/2, else the above loop could 00289 * overflow. We will still have newlen >= needed. 00290 */ 00291 if (newlen > (int) MaxAllocSize) 00292 newlen = (int) MaxAllocSize; 00293 00294 str->data = (char *) repalloc(str->data, newlen); 00295 00296 str->maxlen = newlen; 00297 }