Mercurial > dovecot > original-hg > dovecot-1.2
changeset 5866:092b9d3b7f97 HEAD
Implement str_vprintfa() by making vsnprintf() write directly to the string.
This also avoids excessive memory usage with strings allocated from data
stack.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 02 Jul 2007 23:24:34 +0300 |
parents | 22b300677807 |
children | 1b70ae186611 |
files | src/lib/str.c |
diffstat | 1 files changed, 28 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/str.c Mon Jul 02 23:11:46 2007 +0300 +++ b/src/lib/str.c Mon Jul 02 23:24:34 2007 +0300 @@ -102,15 +102,36 @@ void str_vprintfa(string_t *str, const char *fmt, va_list args) { - const char *tmp; - unsigned int size; +#define SNPRINTF_INITIAL_EXTRA_SIZE 256 + va_list args2; + char *tmp; + unsigned int init_size; + size_t pos = str->used; + int ret, ret2; + + VA_COPY(args2, args); + + /* the format string is modified only if %m exists in it. it happens + only in error conditions, so don't try to t_push() here since it'll + just slow down the normal code path. */ + fmt = printf_format_fix_get_len(fmt, &init_size); + init_size += SNPRINTF_INITIAL_EXTRA_SIZE; - tmp = t_noalloc_strdup_vprintf(fmt, args, &size); - if (buffer_get_pool(str)->datastack_pool) { - /* appending to buffer may allocate more data from data stack */ - t_buffer_alloc(size); + /* @UNSAFE */ + tmp = buffer_get_space_unsafe(str, pos, init_size); + ret = vsnprintf(tmp, init_size, fmt, args); + i_assert(ret >= 0); + + if ((unsigned int)ret >= init_size) { + /* didn't fit with the first guess. now we know the size, + so try again. */ + tmp = buffer_get_space_unsafe(str, pos, ret + 1); + ret2 = vsnprintf(tmp, ret + 1, fmt, args2); + i_assert(ret2 == ret); } - buffer_append(str, tmp, size - 1); + + /* drop the unused data, including terminating NUL */ + buffer_set_used_size(str, pos + ret); } void str_insert(string_t *str, size_t pos, const char *cstr)