improve alloc_vprintf

The previous implementation was unnecessarily complex. Get rid of the loops,
let vsnprintf() tell us directly how much storage we need and allocate that. A
second pass writes the actual string. Also add a va_end() that was missing.
This should be much faster for large strings and less wasteful for small ones.

A quirk that has been retained is that some callers patch in a newline at the
end of the returned string and depend on alloc_vprintf to allocate at least
one byte extra.

Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Signed-off-by: Zachary T Welch <zw@superlucidity.net>
__archive__
Andreas Fritiofson 2009-11-24 21:24:06 +01:00 committed by Zachary T Welch
parent 5507b5f430
commit 338a674faa
1 changed files with 16 additions and 27 deletions

View File

@ -395,37 +395,26 @@ int log_remove_callback(log_callback_fn fn, void *priv)
/* return allocated string w/printf() result */ /* return allocated string w/printf() result */
char *alloc_vprintf(const char *fmt, va_list ap) char *alloc_vprintf(const char *fmt, va_list ap)
{ {
/* no buffer at the beginning, force realloc to do the job */ va_list ap_copy;
char *string = NULL; int len;
char *string;
/* start with buffer size suitable for typical messages */ /* determine the length of the buffer needed */
int size = 128; va_copy(ap_copy, ap);
len = vsnprintf(NULL, 0, fmt, ap_copy);
va_end(ap_copy);
for (;;) /* allocate and make room for terminating zero. */
{ /* FIXME: The old version always allocated at least one byte extra and
char *t = string; * other code depend on that. They should be probably be fixed, but for
va_list ap_copy; * now reserve the extra byte. */
int ret; string = malloc(len + 2);
string = realloc(string, size); if (string == NULL)
if (string == NULL) return NULL;
{
if (t != NULL)
free(t);
return NULL;
}
va_copy(ap_copy, ap); /* do the real work */
vsnprintf(string, len + 1, fmt, ap);
ret = vsnprintf(string, size, fmt, ap_copy);
/* NB! The result of the vsnprintf() might be an *EMPTY* string! */
if ((ret >= 0) && ((ret + 1) < size))
break;
/* there was just enough or not enough space, allocate more in the next round */
size *= 2; /* double the buffer size */
}
/* the returned buffer is by principle guaranteed to be at least one character longer */
return string; return string;
} }