They don't need anything internal to tal, they're just helpers.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
* This allows you to build complex objects based on their lifetimes, eg:
*
* struct foo *X = tal(NULL, struct foo);
- * X->name = tal_strdup(X, "foo");
+ * X->val = tal(X, int);
*
- * and the pointer X->name would be a "child" of the tal context "X";
- * tal_free(X->name) would free X->name as expected, by tal_free(X) would
- * free X and X->name.
+ * and the pointer X->val would be a "child" of the tal context "X";
+ * tal_free(X->val) would free X->val as expected, by tal_free(X) would
+ * free X and X->val.
*
* With an overhead of approximately 4 pointers per object
* (vs. talloc's 12 pointers), it uses dynamic allocation for
* destructors and child lists, so those operations can fail. It does
* not support talloc's references or failing destructors.
*
+ * See Also:
+ * ccan/tal/str (useful string helpers)
+ *
* Example:
* #include <stdio.h>
- * #include <stdarg.h>
* #include <err.h>
* #include <ccan/talloc/talloc.h>
*
* // A structure containing a popened command.
* struct command {
* FILE *f;
- * const char *command;
+ * char *command;
* };
*
* // When struct command is freed, we also want to pclose pipe.
*
* // This function opens a writable pipe to the given command.
* static struct command *open_output_cmd(const tal_t *ctx,
- * const char *fmt, ...)
+ * const char *a0, const char *a1)
* {
- * va_list ap;
* struct command *cmd = tal(ctx, struct command);
*
* if (!cmd)
* return NULL;
*
- * va_start(ap, fmt);
- * cmd->command = tal_vasprintf(cmd, fmt, ap);
- * va_end(ap);
+ * // Note that tal/str has helpers to make this much easier!
+ * cmd->command = tal_arrz(cmd, char, strlen(a0) + strlen(a1) + 2);
* if (!cmd->command) {
* tal_free(cmd);
* return NULL;
* }
+ * strcat(cmd->command, a0);
+ * strcat(cmd->command, " ");
+ * strcat(cmd->command, a1);
*
* cmd->f = popen(cmd->command, "w");
* if (!cmd->f) {
* if (argc != 2)
* errx(1, "Usage: %s <command>\n", argv[0]);
*
- * cmd = open_output_cmd(NULL, "%s hello", argv[1]);
+ * cmd = open_output_cmd(NULL, argv[1], "hello");
* if (!cmd)
* err(1, "Running '%s hello'", argv[1]);
* fprintf(cmd->f, "This is a test\n");
#include <regex.h>
#include <stdarg.h>
#include <unistd.h>
+#include <stdio.h>
#include <ccan/str/str.h>
#include <ccan/tal/tal.h>
#include <ccan/take/take.h>
+char *tal_strdup(const tal_t *ctx, const char *p)
+{
+ /* We have to let through NULL for take(). */
+ return tal_dup_(ctx, p, 1, p ? strlen(p) + 1: 1, 0, false,
+ TAL_LABEL(char, "[]"));
+}
+
+char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
+{
+ size_t len;
+ char *ret;
+
+ /* 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, p, 1, len, 1, false, TAL_LABEL(char, "[]"));
+ if (ret)
+ ret[len] = '\0';
+ return ret;
+}
+
+char *tal_asprintf(const tal_t *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = tal_vasprintf(ctx, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+char *tal_vasprintf(const tal_t *ctx, 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) {
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ ret = vsnprintf(buf, max, fmt, ap2);
+ va_end(ap2);
+
+ if (ret < max)
+ break;
+ if (!tal_resize(&buf, max *= 2))
+ buf = tal_free(buf);
+ }
+ if (taken(fmt))
+ tal_free(fmt);
+ return buf;
+}
+
char **tal_strsplit(const tal_t *ctx,
const char *string, const char *delims, enum strsplit flags)
{
#include <string.h>
#include <stdbool.h>
+/**
+ * tal_strdup - duplicate a string
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @p: the string to copy (can be take()).
+ */
+char *tal_strdup(const tal_t *ctx, const char *p);
+
+/**
+ * tal_strndup - duplicate a limited amount of a string.
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @p: the string to copy (can be take()).
+ * @n: the maximum length to copy.
+ *
+ * Always gives a nul-terminated string, with strlen() <= @n.
+ */
+char *tal_strndup(const tal_t *ctx, const char *p, size_t n);
+
+/**
+ * tal_asprintf - allocate a formatted string
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @fmt: the printf-style format (can be take()).
+ */
+char *tal_asprintf(const tal_t *ctx, const char *fmt, ...) PRINTF_FMT(2,3);
+
+/**
+ * tal_vasprintf - allocate a formatted string (va_list version)
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @fmt: the printf-style format (can be take()).
+ * @va: the va_list containing the format args.
+ */
+char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
+ PRINTF_FMT(2,0);
+
enum strsplit {
STR_EMPTY_OK,
STR_NO_EMPTY
--- /dev/null
+#include <ccan/tal/str/str.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+
+int main(void)
+{
+ char *parent, *c;
+
+ plan_tests(13);
+
+ parent = tal(NULL, char);
+ ok1(parent);
+
+ c = tal_strdup(parent, "hello");
+ ok1(strcmp(c, "hello") == 0);
+ ok1(tal_parent(c) == parent);
+
+ c = tal_strndup(parent, "hello", 3);
+ ok1(strcmp(c, "hel") == 0);
+ ok1(tal_parent(c) == parent);
+
+ c = tal_typechk_(parent, char *);
+ c = tal_dup(parent, char, "hello", 6, 0);
+ ok1(strcmp(c, "hello") == 0);
+ ok1(strcmp(tal_name(c), "char[]") == 0);
+ ok1(tal_parent(c) == parent);
+
+ /* Now with an extra byte. */
+ c = tal_dup(parent, char, "hello", 6, 1);
+ ok1(strcmp(c, "hello") == 0);
+ ok1(strcmp(tal_name(c), "char[]") == 0);
+ ok1(tal_parent(c) == parent);
+ strcat(c, "x");
+
+ c = tal_asprintf(parent, "hello %s", "there");
+ ok1(strcmp(c, "hello there") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(parent);
+
+ return exit_status();
+}
--- /dev/null
+#include <ccan/tal/str/str.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+
+int main(void)
+{
+ char *parent, *c;
+
+ plan_tests(14);
+
+ parent = tal(NULL, char);
+ ok1(parent);
+
+ c = tal_strdup(parent, "hello");
+
+ c = tal_strdup(parent, take(c));
+ ok1(strcmp(c, "hello") == 0);
+ ok1(tal_parent(c) == parent);
+
+ c = tal_strndup(parent, take(c), 5);
+ ok1(strcmp(c, "hello") == 0);
+ ok1(tal_parent(c) == parent);
+
+ c = tal_strndup(parent, take(c), 3);
+ ok1(strcmp(c, "hel") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(c);
+
+ c = tal_strdup(parent, "hello %s");
+ c = tal_asprintf(parent, take(c), "there");
+ ok1(strcmp(c, "hello there") == 0);
+ ok1(tal_parent(c) == parent);
+ /* No leftover allocations. */
+ tal_free(c);
+ ok1(tal_first(parent) == NULL);
+
+ tal_free(parent);
+ 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_asprintf(NULL, take(c), 0) == NULL);
+
+ return exit_status();
+}
#include <ccan/take/take.h>
#include <assert.h>
#include <stdio.h>
-#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include <limits.h>
return true;
}
-char *tal_strdup(const tal_t *ctx, const char *p)
-{
- /* We have to let through NULL for take(). */
- return tal_dup_(ctx, p, 1, p ? strlen(p) + 1: 1, 0, false,
- TAL_LABEL(char, "[]"));
-}
-
-char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
-{
- size_t len;
- char *ret;
-
- /* 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, p, 1, len, 1, false, TAL_LABEL(char, "[]"));
- if (ret)
- ret[len] = '\0';
- return ret;
-}
-
void *tal_dup_(const tal_t *ctx, const void *p, size_t size,
size_t n, size_t extra, bool add_count,
const char *label)
return ret;
}
-char *tal_asprintf(const tal_t *ctx, const char *fmt, ...)
-{
- va_list ap;
- char *ret;
-
- va_start(ap, fmt);
- ret = tal_vasprintf(ctx, fmt, ap);
- va_end(ap);
-
- return ret;
-}
-
-char *tal_vasprintf(const tal_t *ctx, 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) {
- va_list ap2;
-
- va_copy(ap2, ap);
- ret = vsnprintf(buf, max, fmt, ap2);
- va_end(ap2);
-
- if (ret < max)
- break;
- if (!tal_resize(&buf, max *= 2))
- buf = tal_free(buf);
- }
- if (taken(fmt))
- tal_free(fmt);
- return buf;
-}
-
void tal_set_backend(void *(*alloc_fn)(size_t size),
void *(*resize_fn)(void *, size_t size),
void (*free_fn)(void *),
sizeof(type), (n), (extra), \
true, TAL_LABEL(type, "[]")))
-/**
- * tal_strdup - duplicate a string
- * @ctx: NULL, or tal allocated object to be parent.
- * @p: the string to copy (can be take()).
- */
-char *tal_strdup(const tal_t *ctx, const char *p);
-
-/**
- * tal_strndup - duplicate a limited amount of a string.
- * @ctx: NULL, or tal allocated object to be parent.
- * @p: the string to copy (can be take()).
- * @n: the maximum length to copy.
- *
- * Always gives a nul-terminated string, with strlen() <= @n.
- */
-char *tal_strndup(const tal_t *ctx, const char *p, size_t n);
-
-/**
- * tal_asprintf - allocate a formatted string
- * @ctx: NULL, or tal allocated object to be parent.
- * @fmt: the printf-style format (can be take()).
- */
-char *tal_asprintf(const tal_t *ctx, const char *fmt, ...) PRINTF_FMT(2,3);
-
-/**
- * tal_vasprintf - allocate a formatted string (va_list version)
- * @ctx: NULL, or tal allocated object to be parent.
- * @fmt: the printf-style format (can be take()).
- * @va: the va_list containing the format args.
- */
-char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
- PRINTF_FMT(2,0);
-
/**
* tal_set_backend - set the allocation or error functions to use
+++ /dev/null
-#include <ccan/tal/tal.h>
-#include <ccan/tal/tal.c>
-#include <ccan/tap/tap.h>
-
-int main(void)
-{
- char *parent, *c;
-
- plan_tests(13);
-
- parent = tal(NULL, char);
- ok1(parent);
-
- c = tal_strdup(parent, "hello");
- ok1(strcmp(c, "hello") == 0);
- ok1(tal_parent(c) == parent);
-
- c = tal_strndup(parent, "hello", 3);
- ok1(strcmp(c, "hel") == 0);
- ok1(tal_parent(c) == parent);
-
- c = tal_typechk_(parent, char *);
- c = tal_dup(parent, char, "hello", 6, 0);
- ok1(strcmp(c, "hello") == 0);
- ok1(strcmp(tal_name(c), "char[]") == 0);
- ok1(tal_parent(c) == parent);
-
- /* Now with an extra byte. */
- c = tal_dup(parent, char, "hello", 6, 1);
- ok1(strcmp(c, "hello") == 0);
- ok1(strcmp(tal_name(c), "char[]") == 0);
- ok1(tal_parent(c) == parent);
- strcat(c, "x");
-
- c = tal_asprintf(parent, "hello %s", "there");
- ok1(strcmp(c, "hello there") == 0);
- ok1(tal_parent(c) == parent);
- tal_free(parent);
-
- return exit_status();
-}
{
char *parent, *c;
- plan_tests(32);
+ plan_tests(21);
/* We can take NULL. */
ok1(take(NULL) == NULL);
ok1(!is_taken(parent));
ok1(!taken(parent));
- c = tal_strdup(parent, "hello");
-
- c = tal_strdup(parent, take(c));
- ok1(strcmp(c, "hello") == 0);
- ok1(tal_parent(c) == parent);
-
- c = tal_strndup(parent, take(c), 5);
- ok1(strcmp(c, "hello") == 0);
- ok1(tal_parent(c) == parent);
-
- c = tal_strndup(parent, take(c), 3);
- ok1(strcmp(c, "hel") == 0);
- ok1(tal_parent(c) == parent);
-
+ c = tal(parent, char);
+ *c = 'h';
c = tal_dup(parent, char, take(c), 1, 0);
ok1(c[0] == 'h');
ok1(tal_parent(c) == parent);
tal_free(c);
ok1(tal_first(parent) == NULL);
- c = tal_strdup(parent, "hello %s");
- c = tal_asprintf(parent, take(c), "there");
- ok1(strcmp(c, "hello there") == 0);
- ok1(tal_parent(c) == parent);
- /* No leftover allocations. */
- tal_free(c);
- ok1(tal_first(parent) == NULL);
-
tal_free(parent);
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);
+ ok1(!taken_any());
return exit_status();
}
tal_add_destructor(p, destroy_p);
tal_set_name(p, "test");
- name = tal_asprintf(NULL, "test2");
+ name = tal_arr(NULL, char, 6);
+ strcpy(name, "test2");
tal_set_name(p, name);
/* makes us free old name */
tal_set_name(p, name);