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>
This commit is contained in:
parent
5507b5f430
commit
338a674faa
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue