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;
		}
	}
}
示例#2
0
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;
        }
    }
}