Commit 5582b011 authored by Rusty Russell's avatar Rusty Russell

tal/str: move tal string functions here from tal.

They don't need anything internal to tal, they're just helpers.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 15ed4f45
......@@ -12,27 +12,29 @@
* 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.
......@@ -43,21 +45,22 @@
*
* // 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) {
......@@ -75,7 +78,7 @@
* 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");
......
......@@ -9,10 +9,78 @@
#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)
{
......
......@@ -6,6 +6,39 @@
#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
......
#include <ccan/tal/tal.h>
#include <ccan/tal/tal.c>
#include <ccan/tal/str/str.h>
#include <ccan/tal/str/str.c>
#include <ccan/tap/tap.h>
int main(void)
......
#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();
}
......@@ -5,7 +5,6 @@
#include <ccan/take/take.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include <limits.h>
......@@ -713,32 +712,6 @@ bool tal_resize_(tal_t **ctxp, size_t size, size_t count)
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)
......@@ -776,47 +749,6 @@ void *tal_dup_(const tal_t *ctx, const void *p, size_t size,
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 *),
......
......@@ -286,39 +286,6 @@ tal_t *tal_parent(const tal_t *ctx);
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
......
......@@ -6,7 +6,7 @@ int main(void)
{
char *parent, *c;
plan_tests(32);
plan_tests(21);
/* We can take NULL. */
ok1(take(NULL) == NULL);
......@@ -24,20 +24,8 @@ int main(void)
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);
......@@ -56,23 +44,13 @@ int main(void)
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();
}
......@@ -53,7 +53,8 @@ int main(void)
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment