From e7ae27d64226dda9865f1e4b5d9a55adcee04694 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 3 Dec 2012 19:29:39 +1030 Subject: [PATCH] tal/str: add tal_append_fmt() and tal_append_vfmt() helpers. They are far too convenient, despite their inefficiency. Signed-off-by: Rusty Russell --- ccan/tal/str/str.c | 66 ++++++++++++++++++++++++++-------- ccan/tal/str/str.h | 19 ++++++++++ ccan/tal/str/test/run-string.c | 11 +++++- 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/ccan/tal/str/str.c b/ccan/tal/str/str.c index 771c07c2..15aa0c04 100644 --- a/ccan/tal/str/str.c +++ b/ccan/tal/str/str.c @@ -52,35 +52,71 @@ char *tal_fmt(const tal_t *ctx, const char *fmt, ...) return ret; } -char *tal_vfmt(const tal_t *ctx, const char *fmt, va_list ap) +static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap) { - size_t max; - char *buf; - int ret; - - if (!fmt && taken(fmt)) - return NULL; - /* A decent guess to start. */ - max = strlen(fmt) * 2; - buf = tal_arr(ctx, char, max); - while (buf) { + size_t max = strlen(fmt) * 2; + bool ok; + + for (;;) { va_list ap2; + int ret; + + if (!tal_resize(buf, off + max)) { + ok = false; + break; + } va_copy(ap2, ap); - ret = vsnprintf(buf, max, fmt, ap2); + ret = vsnprintf(*buf + off, max, fmt, ap2); va_end(ap2); - if (ret < max) + if (ret < max) { + ok = true; break; - if (!tal_resize(&buf, max *= 2)) - buf = tal_free(buf); + } + max *= 2; } + if (taken(fmt)) tal_free(fmt); + return ok; +} + +char *tal_vfmt(const tal_t *ctx, const char *fmt, va_list ap) +{ + char *buf; + + if (!fmt && taken(fmt)) + return NULL; + + /* A decent guess to start. */ + buf = tal_arr(ctx, char, strlen(fmt) * 2); + if (!do_vfmt(&buf, 0, fmt, ap)) + buf = tal_free(buf); return buf; } +bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap) +{ + if (!fmt && taken(fmt)) + return false; + + return do_vfmt(baseptr, strlen(*baseptr), fmt, ap); +} + +bool tal_append_fmt(char **baseptr, const char *fmt, ...) +{ + va_list ap; + bool ret; + + va_start(ap, fmt); + ret = tal_append_vfmt(baseptr, fmt, ap); + va_end(ap); + + return ret; +} + char *tal_strcat(const tal_t *ctx, const char *s1, const char *s2) { size_t len1, len2; diff --git a/ccan/tal/str/str.h b/ccan/tal/str/str.h index 4a6c474a..f2a69489 100644 --- a/ccan/tal/str/str.h +++ b/ccan/tal/str/str.h @@ -39,6 +39,25 @@ char *tal_fmt(const tal_t *ctx, const char *fmt, ...) PRINTF_FMT(2,3); char *tal_vfmt(const tal_t *ctx, const char *fmt, va_list ap) PRINTF_FMT(2,0); +/** + * tal_append_fmt - append a formatted string to a talloc string. + * @baseptr: a pointer to the tal string to be appended to. + * @fmt: the printf-style format (can be take()). + * + * Returns false on allocation failure. + */ +bool tal_append_fmt(char **baseptr, const char *fmt, ...) PRINTF_FMT(2,3); + +/** + * tal_append_vfmt - append a formatted string to a talloc string (va_list) + * @baseptr: a pointer to the tal string to be appended to. + * @fmt: the printf-style format (can be take()). + * @va: the va_list containing the format args. + * + * Returns false on allocation failure. + */ +bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap); + /** * tal_strcat - join two strings together * @ctx: NULL, or tal allocated object to be parent. diff --git a/ccan/tal/str/test/run-string.c b/ccan/tal/str/test/run-string.c index bb614ae2..7bf31a6c 100644 --- a/ccan/tal/str/test/run-string.c +++ b/ccan/tal/str/test/run-string.c @@ -6,7 +6,7 @@ int main(void) { char *parent, *c; - plan_tests(27); + plan_tests(32); parent = tal(NULL, char); ok1(parent); @@ -70,6 +70,15 @@ int main(void) ok1(!c); ok1(!tal_first(parent)); + /* Appending formatted strings. */ + c = tal_strdup(parent, "hi"); + ok1(tal_append_fmt(&c, "%s %s", "there", "world")); + ok1(strcmp(c, "hithere world") == 0); + ok1(tal_parent(c) == parent); + + ok1(!tal_append_fmt(&c, take(NULL), "there", "world")); + ok1(strcmp(c, "hithere world") == 0); + tal_free(parent); return exit_status(); -- 2.39.2