void StringAppendVT(const CharType *format, va_list ap, std::basic_string<CharType> &output) { CharType stack_buffer[1024]; /* first, we try to finish the task using a fixed-size buffer in the stack */ va_list ap_copy; GG_VA_COPY(ap_copy, ap); int result = vsnprintfT(stack_buffer, COUNT_OF(stack_buffer), format, ap_copy); va_end(ap_copy); if (result >= 0 && result < static_cast<int>(COUNT_OF(stack_buffer))) { /* It fits */ output.append(stack_buffer, result); return; } /* then, we have to repeatedly increase buffer size until it fits. */ int buffer_size = COUNT_OF(stack_buffer); std::basic_string<CharType> heap_buffer; for (;;) { if (result != -1) { assert(0); return; /* not expected, result should be -1 here */ } buffer_size <<= 1; /* try doubling the buffer size */ if (buffer_size > 32 * 1024 * 1024) { assert(0); return; /* too long */ } /* resize */ heap_buffer.resize(buffer_size); /* * NOTE: You can only use a va_list once. Since we're in a while loop, we * need to make a new copy each time so we don't use up the original. */ GG_VA_COPY(ap_copy, ap); result = vsnprintfT(&heap_buffer[0], buffer_size, format, ap_copy); va_end(ap_copy); if ((result >= 0) && (result < buffer_size)) { /* It fits */ output.append(&heap_buffer[0], result); return; } } }
void StringAppendFT(strT* str, const typename strT::value_type* fmt, va_list ap) { typedef typename strT::value_type charT; const int kDefaultCharCount = 1024; charT buf[kDefaultCharCount]; int ret = vsnprintfT(buf, kDefaultCharCount, kDefaultCharCount - 1, fmt, ap); if (ret >= 0) { str->append(buf, ret); return; } // data is truncated. // adjust the buffer size until it fits const int kMaxAllowedCharCount = (1 << 25); int tentative_char_count = kDefaultCharCount; while (true) { tentative_char_count <<= 1; if (tentative_char_count > kMaxAllowedCharCount) { throw StringFormatDataLengthError("memory needed exceeds the maximum value"); } std::vector<charT> dynamic_buf(tentative_char_count); // vsnprintf-like functions on Windows don't change the |ap| // while their counterparts on Linux do. // if you use VS2013 or higher, or compilers that support C99 // you alternatively can use |va_copy| to make a copy of |ap| // during each iteration. int ret = vsnprintfT(&dynamic_buf[0], tentative_char_count, tentative_char_count - 1, fmt, ap); if (ret >= 0) { str->append(&dynamic_buf[0], ret); return; } } }