diff options
author | Andreas Fritiofson <andreas.fritiofson@gmail.com> | 2009-11-24 21:24:06 +0100 |
---|---|---|
committer | Zachary T Welch <zw@superlucidity.net> | 2009-11-24 12:48:02 -0800 |
commit | 338a674faa96ae321560efa3f1b1e8122d61aac4 (patch) | |
tree | c5ceee16364ea110d55d1e15abc19aca84c7d8d6 /src/helper | |
parent | 5507b5f430e3d6bef00a7ffcd51df29c13d7477e (diff) | |
download | openocd_libswd-338a674faa96ae321560efa3f1b1e8122d61aac4.tar.gz openocd_libswd-338a674faa96ae321560efa3f1b1e8122d61aac4.tar.bz2 openocd_libswd-338a674faa96ae321560efa3f1b1e8122d61aac4.tar.xz openocd_libswd-338a674faa96ae321560efa3f1b1e8122d61aac4.zip |
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>
Diffstat (limited to 'src/helper')
-rw-r--r-- | src/helper/log.c | 43 |
1 files 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; } |