Browse Source

tal/str: add tal_append_fmt() and tal_append_vfmt() helpers.

They are far too convenient, despite their inefficiency.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 13 years ago
parent
commit
e7ae27d642
3 changed files with 80 additions and 16 deletions
  1. 51 15
      ccan/tal/str/str.c
  2. 19 0
      ccan/tal/str/str.h
  3. 10 1
      ccan/tal/str/test/run-string.c

+ 51 - 15
ccan/tal/str/str.c

@@ -52,35 +52,71 @@ char *tal_fmt(const tal_t *ctx, const char *fmt, ...)
 	return ret;
 	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. */
 	/* 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;
 		va_list ap2;
+		int ret;
+
+		if (!tal_resize(buf, off + max)) {
+			ok = false;
+			break;
+		}
 
 
 		va_copy(ap2, ap);
 		va_copy(ap2, ap);
-		ret = vsnprintf(buf, max, fmt, ap2);
+		ret = vsnprintf(*buf + off, max, fmt, ap2);
 		va_end(ap2);
 		va_end(ap2);
 
 
-		if (ret < max)
+		if (ret < max) {
+			ok = true;
 			break;
 			break;
-		if (!tal_resize(&buf, max *= 2))
-			buf = tal_free(buf);
+		}
+		max *= 2;
 	}
 	}
+
 	if (taken(fmt))
 	if (taken(fmt))
 		tal_free(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;
 	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)
 char *tal_strcat(const tal_t *ctx, const char *s1, const char *s2)
 {
 {
 	size_t len1, len2;
 	size_t len1, len2;

+ 19 - 0
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)
 char *tal_vfmt(const tal_t *ctx, const char *fmt, va_list ap)
 	PRINTF_FMT(2,0);
 	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
  * tal_strcat - join two strings together
  * @ctx: NULL, or tal allocated object to be parent.
  * @ctx: NULL, or tal allocated object to be parent.

+ 10 - 1
ccan/tal/str/test/run-string.c

@@ -6,7 +6,7 @@ int main(void)
 {
 {
 	char *parent, *c;
 	char *parent, *c;
 
 
-	plan_tests(27);
+	plan_tests(32);
 
 
 	parent = tal(NULL, char);
 	parent = tal(NULL, char);
 	ok1(parent);
 	ok1(parent);
@@ -70,6 +70,15 @@ int main(void)
 	ok1(!c);
 	ok1(!c);
 	ok1(!tal_first(parent));
 	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);
 	tal_free(parent);
 
 
 	return exit_status();
 	return exit_status();