Browse Source

tal: take implies NULL passthrough.

This makes error handling much more convenient, since take is usually
used for chaining functions.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 13 years ago
parent
commit
bb480e553f
3 changed files with 32 additions and 8 deletions
  1. 19 6
      ccan/tal/tal.c
  2. 1 1
      ccan/tal/tal.h
  3. 12 1
      ccan/tal/test/run-take.c

+ 19 - 6
ccan/tal/tal.c

@@ -718,18 +718,26 @@ bool tal_resize_(tal_t **ctxp, size_t size)
 
 
 char *tal_strdup(const tal_t *ctx, const char *p)
 char *tal_strdup(const tal_t *ctx, const char *p)
 {
 {
-	return tal_dup(ctx, char, p, strlen(p)+1, 0);
+	/* We have to let through NULL for take(). */
+	return tal_dup(ctx, char, p, p ? strlen(p) + 1: 1, 0);
 }
 }
 
 
 char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
 char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
 {
 {
+	size_t len;
 	char *ret;
 	char *ret;
 
 
-	if (strlen(p) < n)
-		n = strlen(p);
-	ret = tal_dup(ctx, char, p, n, 1);
+	/* We have to let through NULL for take(). */
+	if (likely(p)) {
+		len = strlen(p);
+		if (len > n)
+			len = n;
+	} else
+		len = n;
+
+	ret = tal_dup(ctx, char, p, len, 1);
 	if (ret)
 	if (ret)
-		ret[n] = '\0';
+		ret[len] = '\0';
 	return ret;
 	return ret;
 }
 }
 
 
@@ -779,10 +787,15 @@ char *tal_asprintf(const tal_t *ctx, const char *fmt, ...)
 
 
 char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
 char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
 {
 {
-	size_t max = strlen(fmt) * 2;
+	size_t max;
 	char *buf;
 	char *buf;
 	int ret;
 	int ret;
 
 
+	if (!fmt && taken(fmt))
+		return NULL;
+
+	/* A decent guess to start. */
+	max = strlen(fmt) * 2;
 	buf = tal_arr(ctx, char, max);
 	buf = tal_arr(ctx, char, max);
 	while (buf) {
 	while (buf) {
 		va_list ap2;
 		va_list ap2;

+ 1 - 1
ccan/tal/tal.h

@@ -304,7 +304,7 @@ static inline size_t tal_sizeof_(size_t size, size_t count)
 #if HAVE_STATEMENT_EXPR
 #if HAVE_STATEMENT_EXPR
 /* Careful: ptr can be const foo *, ptype is foo *.  Also, ptr could
 /* Careful: ptr can be const foo *, ptype is foo *.  Also, ptr could
  * be an array, eg "hello". */
  * be an array, eg "hello". */
-#define tal_typechk_(ptr, ptype) ({ __typeof__(&*(ptr)) _p = (ptype)(ptr); _p; })
+#define tal_typechk_(ptr, ptype) ({ __typeof__((ptr)+0) _p = (ptype)(ptr); _p; })
 #else
 #else
 #define tal_typechk_(ptr, ptype) (ptr)
 #define tal_typechk_(ptr, ptype) (ptr)
 #endif
 #endif

+ 12 - 1
ccan/tal/test/run-take.c

@@ -6,18 +6,22 @@ int main(void)
 {
 {
 	char *parent, *c;
 	char *parent, *c;
 
 
-	plan_tests(24);
+	plan_tests(32);
 
 
 	/* We can take NULL. */
 	/* We can take NULL. */
 	ok1(take(NULL) == NULL);
 	ok1(take(NULL) == NULL);
+	ok1(is_taken(NULL));
 	ok1(taken(NULL)); /* Undoes take() */
 	ok1(taken(NULL)); /* Undoes take() */
+	ok1(!is_taken(NULL));
 	ok1(!taken(NULL));
 	ok1(!taken(NULL));
 
 
 	parent = tal(NULL, char);
 	parent = tal(NULL, char);
 	ok1(parent);
 	ok1(parent);
 
 
 	ok1(take(parent) == parent);
 	ok1(take(parent) == parent);
+	ok1(is_taken(parent));
 	ok1(taken(parent)); /* Undoes take() */
 	ok1(taken(parent)); /* Undoes take() */
+	ok1(!is_taken(parent));
 	ok1(!taken(parent));
 	ok1(!taken(parent));
 
 
 	c = tal_strdup(parent, "hello");
 	c = tal_strdup(parent, "hello");
@@ -63,5 +67,12 @@ int main(void)
 	tal_free(parent);
 	tal_free(parent);
 	ok1(!taken_any());
 	ok1(!taken_any());
 
 
+	/* NULL pass-through. */
+	c = NULL;
+	ok1(tal_strdup(NULL, take(c)) == NULL);
+	ok1(tal_strndup(NULL, take(c), 5) == NULL);
+	ok1(tal_dup(NULL, char, take(c), 5, 5) == NULL);
+	ok1(tal_asprintf(NULL, take(c), 0) == NULL);
+
 	return exit_status();
 	return exit_status();
 }
 }