From 338a674faa96ae321560efa3f1b1e8122d61aac4 Mon Sep 17 00:00:00 2001 From: Andreas Fritiofson Date: Tue, 24 Nov 2009 21:24:06 +0100 Subject: [PATCH] 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 Signed-off-by: Zachary T Welch --- src/helper/log.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/src/helper/log.c b/src/helper/log.c index caaed423..2dcf7bb6 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -395,37 +395,26 @@ int log_remove_callback(log_callback_fn fn, void *priv) /* return allocated string w/printf() result */ char *alloc_vprintf(const char *fmt, va_list ap) { - /* no buffer at the beginning, force realloc to do the job */ - char *string = NULL; - - /* start with buffer size suitable for typical messages */ - int size = 128; - - for (;;) - { - char *t = string; - va_list ap_copy; - int ret; - string = realloc(string, size); - if (string == NULL) - { - if (t != NULL) - free(t); - return NULL; - } + va_list ap_copy; + int len; + char *string; - va_copy(ap_copy, ap); + /* determine the length of the buffer needed */ + va_copy(ap_copy, ap); + len = vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); - 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; + /* allocate and make room for terminating zero. */ + /* FIXME: The old version always allocated at least one byte extra and + * other code depend on that. They should be probably be fixed, but for + * now reserve the extra byte. */ + string = malloc(len + 2); + if (string == NULL) + return NULL; - /* there was just enough or not enough space, allocate more in the next round */ - size *= 2; /* double the buffer size */ - } + /* do the real work */ + vsnprintf(string, len + 1, fmt, ap); - /* the returned buffer is by principle guaranteed to be at least one character longer */ return string; } -- 2.39.5