summaryrefslogtreecommitdiff
path: root/src/helper/log.c
diff options
context:
space:
mode:
authorAndreas Fritiofson <andreas.fritiofson@gmail.com>2009-11-24 21:24:06 +0100
committerZachary T Welch <zw@superlucidity.net>2009-11-24 12:48:02 -0800
commit338a674faa96ae321560efa3f1b1e8122d61aac4 (patch)
treec5ceee16364ea110d55d1e15abc19aca84c7d8d6 /src/helper/log.c
parent5507b5f430e3d6bef00a7ffcd51df29c13d7477e (diff)
downloadopenocd+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/log.c')
-rw-r--r--src/helper/log.c43
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;
}