void str_vprintfa(string_t *str, const char *fmt, va_list args) { #define SNPRINTF_INITIAL_EXTRA_SIZE 128 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; /* @UNSAFE */ if (pos+init_size > buffer_get_size(str) && pos < buffer_get_size(str)) { /* avoid growing buffer larger if possible. this is also required if buffer isn't dynamically growing. */ init_size = buffer_get_size(str)-pos; } 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); } /* drop the unused data, including terminating NUL */ buffer_set_used_size(str, pos + ret); }
char *t_noalloc_strdup_vprintf(const char *format, va_list args, unsigned int *size_r) { #define SNPRINTF_INITIAL_EXTRA_SIZE 256 va_list args2; char *tmp; unsigned int init_size; int ret; #ifdef DEBUG int old_errno = errno; #endif 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. */ format = printf_format_fix_get_len(format, &init_size); init_size += SNPRINTF_INITIAL_EXTRA_SIZE; tmp = t_buffer_get(init_size); ret = vsnprintf(tmp, init_size, format, args); i_assert(ret >= 0); *size_r = ret + 1; if ((unsigned int)ret >= init_size) { /* didn't fit with the first guess. now we know the size, so try again. */ tmp = t_buffer_get(*size_r); ret = vsnprintf(tmp, *size_r, format, args2); i_assert((unsigned int)ret == *size_r-1); } #ifdef DEBUG /* we rely on errno not changing. it shouldn't. */ i_assert(errno == old_errno); #endif va_end(args2); return tmp; }