Commit 55d81423 authored by Rusty Russell's avatar Rusty Russell

tal/str: always create strings which have tal_count() == strlen() + 1.

This is least-surprise, but also means callers can sometimes do faster
string handling by avoiding strstr().
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 1651e25e
......@@ -7,7 +7,9 @@
*
* This is a grab bag of functions for string operations, designed to enhance
* the standard string.h; these are separated from the non-tal-needing
* string utilities in "str.h".
* string utilities in "str.h". Each string created by this library
* will have tal_count() equal to strlen() + 1 (assuming you didn't create
* a string containing a NUL, such as using tal_fmt("%c", 0)).
*
* Example:
* #include <ccan/tal/str/str.h>
......
......@@ -68,6 +68,8 @@ static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap)
if (ret < max) {
ok = true;
/* Make sure tal_count() is correct! */
tal_resize(buf, off + ret + 1);
break;
}
max *= 2;
......@@ -222,6 +224,8 @@ char *tal_strjoin_(const tal_t *ctx,
totlen += dlen;
}
ret[totlen] = '\0';
/* Make sure tal_count() is correct! */
tal_resize(&ret, totlen+1);
out:
if (taken(strings))
tal_free(strings);
......
......@@ -13,6 +13,8 @@
* tal_strdup - duplicate a string
* @ctx: NULL, or tal allocated object to be parent.
* @p: the string to copy (can be take()).
*
* The returned string will have tal_count() == strlen() + 1.
*/
#define tal_strdup(ctx, p) tal_strdup_(ctx, p, TAL_LABEL(char, "[]"))
char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
......@@ -24,6 +26,7 @@ char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
* @n: the maximum length to copy.
*
* Always gives a nul-terminated string, with strlen() <= @n.
* The returned string will have tal_count() == strlen() + 1.
*/
#define tal_strndup(ctx, p, n) tal_strndup_(ctx, p, n, TAL_LABEL(char, "[]"))
char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
......@@ -33,6 +36,8 @@ char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
* tal_fmt - allocate a formatted string
* @ctx: NULL, or tal allocated object to be parent.
* @fmt: the printf-style format (can be take()).
*
* The returned string will have tal_count() == strlen() + 1.
*/
#define tal_fmt(ctx, ...) \
tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
......@@ -44,6 +49,8 @@ char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt TAKES,
* @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.
*
* The returned string will have tal_count() == strlen() + 1.
*/
#define tal_vfmt(ctx, fmt, va) \
tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
......@@ -57,6 +64,7 @@ char *tal_vfmt_(const tal_t *ctx, const char *fmt TAKES, va_list ap,
* @fmt: the printf-style format (can be take()).
*
* Returns false on allocation failure.
* Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1.
*/
bool tal_append_fmt(char **baseptr, const char *fmt TAKES, ...) PRINTF_FMT(2,3);
......@@ -67,6 +75,7 @@ bool tal_append_fmt(char **baseptr, const char *fmt TAKES, ...) PRINTF_FMT(2,3);
* @va: the va_list containing the format args.
*
* Returns false on allocation failure.
* Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1.
*/
bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
......@@ -75,6 +84,8 @@ bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
* @ctx: NULL, or tal allocated object to be parent.
* @s1: the first string (can be take()).
* @s2: the second string (can be take()).
*
* The returned string will have tal_count() == strlen() + 1.
*/
#define tal_strcat(ctx, s1, s2) tal_strcat_(ctx, s1, s2, TAL_LABEL(char, "[]"))
char *tal_strcat_(const tal_t *ctx, const char *s1 TAKES, const char *s2 TAKES,
......@@ -144,6 +155,8 @@ enum strjoin {
* return value is allocated using tal. Each string in @strings is
* followed by a copy of @delim.
*
* The returned string will have tal_count() == strlen() + 1.
*
* Example:
* // Append the string "--EOL" to each line.
* static char *append_to_all_lines(const char *string)
......@@ -180,6 +193,7 @@ char *tal_strjoin_(const void *ctx,
* non-existent matches (eg "([a-z]*)?") the pointer is set to NULL.
*
* Allocation failures or malformed regular expressions return false.
* The allocated strings will have tal_count() == strlen() + 1.
*
* See Also:
* regcomp(3), regex(3).
......
......@@ -11,11 +11,12 @@ int main(void)
char *str;
const char *fmt = "";
plan_tests(1);
plan_tests(2);
/* GCC complains about empty format string, complains about non-literal
* with no args... */
str = tal_fmt(NULL, fmt, "");
ok1(!strcmp(str, ""));
ok1(tal_count(str) == strlen(str) + 1);
tal_free(str);
return exit_status();
......
......@@ -7,7 +7,7 @@ int main(void)
{
char *parent, *c;
plan_tests(32);
plan_tests(43);
parent = tal(NULL, char);
ok1(parent);
......@@ -15,11 +15,13 @@ int main(void)
c = tal_strdup(parent, "hello");
ok1(strcmp(c, "hello") == 0);
ok1(tal_parent(c) == parent);
ok1(tal_count(c) == strlen(c) + 1);
tal_free(c);
c = tal_strndup(parent, "hello", 3);
ok1(strcmp(c, "hel") == 0);
ok1(tal_parent(c) == parent);
ok1(tal_count(c) == strlen(c) + 1);
tal_free(c);
#ifdef TAL_USE_TALLOC
......@@ -30,6 +32,7 @@ int main(void)
c = tal_dup_arr(parent, char, "hello", 6, 0);
ok1(strcmp(c, "hello") == 0);
ok1(strcmp(tal_name(c), "char[]") == 0);
ok1(tal_count(c) == 6);
ok1(tal_parent(c) == parent);
tal_free(c);
......@@ -37,26 +40,31 @@ int main(void)
c = tal_dup_arr(parent, char, "hello", 6, 1);
ok1(strcmp(c, "hello") == 0);
ok1(strcmp(tal_name(c), "char[]") == 0);
ok1(tal_count(c) == 7);
ok1(tal_parent(c) == parent);
strcat(c, "x");
tal_free(c);
c = tal_fmt(parent, "hello %s", "there");
ok1(strcmp(c, "hello there") == 0);
ok1(tal_count(c) == strlen(c) + 1);
ok1(tal_parent(c) == parent);
tal_free(c);
c = tal_strcat(parent, "hello ", "there");
ok1(strcmp(c, "hello there") == 0);
ok1(tal_count(c) == strlen(c) + 1);
ok1(tal_parent(c) == parent);
/* Make sure take works correctly. */
c = tal_strcat(parent, take(c), " again");
ok1(strcmp(c, "hello there again") == 0);
ok1(tal_count(c) == strlen(c) + 1);
ok1(tal_parent(c) == parent);
ok1(single_child(parent, c));
c = tal_strcat(parent, "And ", take(c));
ok1(tal_count(c) == strlen(c) + 1);
ok1(strcmp(c, "And hello there again") == 0);
ok1(tal_parent(c) == parent);
ok1(single_child(parent, c));
......@@ -77,12 +85,15 @@ int main(void)
/* Appending formatted strings. */
c = tal_strdup(parent, "hi");
ok1(tal_count(c) == strlen(c) + 1);
ok1(tal_append_fmt(&c, "%s %s", "there", "world"));
ok1(strcmp(c, "hithere world") == 0);
ok1(tal_count(c) == strlen(c) + 1);
ok1(tal_parent(c) == parent);
ok1(!tal_append_fmt(&c, take(NULL), "there", "world"));
ok1(strcmp(c, "hithere world") == 0);
ok1(tal_count(c) == strlen(c) + 1);
tal_free(parent);
......
......@@ -9,12 +9,13 @@ int main(void)
{
char *str, *copy;
plan_tests(1);
plan_tests(2);
str = malloc(5);
memcpy(str, "hello", 5);
/* We should be fine to strndup src without nul terminator. */
copy = tal_strndup(NULL, str, 5);
ok1(!strcmp(copy, "hello"));
ok1(tal_count(copy) == strlen(copy) + 1);
tal_free(copy);
free(str);
......
......@@ -21,7 +21,7 @@ int main(void)
/* If it accesses this, it will crash. */
char **invalid = (char **)1L;
plan_tests(41);
plan_tests(54);
/* Simple matching. */
ok1(tal_strreg(ctx, "hello world!", "hello") == true);
ok1(tal_strreg(ctx, "hello world!", "hi") == false);
......@@ -36,12 +36,15 @@ int main(void)
ok1(streq(a, "hello"));
/* Allocated off ctx */
ok1(find_parent(a, ctx));
ok1(tal_count(a) == strlen(a) + 1);
tal_free(a);
ok1(tal_strreg(ctx, "hello world!", "([a-z]*) ([a-z]+)",
&a, &b, invalid) == true);
ok1(streq(a, "hello"));
ok1(streq(b, "world"));
ok1(tal_count(a) == strlen(a) + 1);
ok1(tal_count(b) == strlen(b) + 1);
ok1(find_parent(a, ctx));
ok1(find_parent(b, ctx));
tal_free(a);
......@@ -52,6 +55,8 @@ int main(void)
&a, &b, invalid) == true);
ok1(streq(a, "o"));
ok1(streq(b, "world"));
ok1(tal_count(a) == strlen(a) + 1);
ok1(tal_count(b) == strlen(b) + 1);
tal_free(a);
tal_free(b);
......@@ -60,6 +65,8 @@ int main(void)
&a, &b, invalid) == true);
ok1(streq(a, "hello world"));
ok1(streq(b, "hello"));
ok1(tal_count(a) == strlen(a) + 1);
ok1(tal_count(b) == strlen(b) + 1);
tal_free(a);
tal_free(b);
......@@ -68,6 +75,8 @@ int main(void)
&a, &b, invalid) == true);
ok1(streq(a, "hello world"));
ok1(streq(b, "hello"));
ok1(tal_count(a) == strlen(a) + 1);
ok1(tal_count(b) == strlen(b) + 1);
tal_free(a);
tal_free(b);
......@@ -75,6 +84,7 @@ int main(void)
ok1(tal_strreg(ctx, "hello world!", "((hello|goodbye) world)",
&a, NULL, invalid) == true);
ok1(streq(a, "hello world"));
ok1(tal_count(a) == strlen(a) + 1);
tal_free(a);
/* No leaks! */
......@@ -88,6 +98,7 @@ int main(void)
a = tal_strdup(ctx, "hello world!");
ok1(tal_strreg(ctx, take(a), "([a-z]+)", &b, invalid) == true);
ok1(streq(b, "hello"));
ok1(tal_count(b) == strlen(b) + 1);
ok1(tal_parent(b) == ctx);
tal_free(b);
ok1(no_children(ctx));
......@@ -96,6 +107,7 @@ int main(void)
a = tal_strdup(ctx, "([a-z]+)");
ok1(tal_strreg(ctx, "hello world!", take(a), &b, invalid) == true);
ok1(streq(b, "hello"));
ok1(tal_count(b) == strlen(b) + 1);
ok1(tal_parent(b) == ctx);
tal_free(b);
ok1(no_children(ctx));
......@@ -105,6 +117,7 @@ int main(void)
ok1(tal_strreg(ctx, take(tal_strdup(ctx, "hello world!")),
take(a), &b, invalid) == true);
ok1(streq(b, "hello"));
ok1(tal_count(b) == strlen(b) + 1);
ok1(tal_parent(b) == ctx);
tal_free(b);
ok1(no_children(ctx));
......
......@@ -15,7 +15,7 @@ int main(void)
char **split, *str;
void *ctx;
plan_tests(69);
plan_tests(78);
split = tal_strsplit(NULL, "hello world", " ", STR_EMPTY_OK);
ok1(!strcmp(split[0], "hello"));
ok1(!strcmp(split[1], ""));
......@@ -54,16 +54,20 @@ int main(void)
str = tal_strjoin(NULL, (char **)substrings, ", ", STR_TRAIL);
ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar, "));
ok1(tal_count(str) == strlen(str) + 1);
ctx = str;
str = tal_strjoin(ctx, (char **)substrings, "", STR_TRAIL);
ok1(!strcmp(str, "farbarbazbbazar"));
ok1(tal_count(str) == strlen(str) + 1);
ok1(tal_parent(str) == ctx);
str = tal_strjoin(ctx, (char **)substrings, ", ", STR_NO_TRAIL);
ok1(tal_parent(str) == ctx);
ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar"));
ok1(tal_count(str) == strlen(str) + 1);
str = tal_strjoin(ctx, (char **)substrings, "", STR_NO_TRAIL);
ok1(!strcmp(str, "farbarbazbbazar"));
ok1(tal_parent(str) == ctx);
ok1(tal_count(str) == strlen(str) + 1);
tal_free(ctx);
ctx = tal_strdup(NULL, "context");
......@@ -77,6 +81,7 @@ int main(void)
str = tal_strdup(ctx, "hello world");
ok1(tal_check(ctx, NULL));
ok1(tal_check(str, NULL));
ok1(tal_count(str) == strlen(str) + 1);
split = tal_strsplit(ctx, take(str), " ", STR_EMPTY_OK);
ok1(tal_parent(split) == ctx);
ok1(!strcmp(split[0], "hello"));
......@@ -90,6 +95,7 @@ int main(void)
/* tal_strsplit take delims */
str = tal_strdup(ctx, " ");
ok1(tal_count(str) == strlen(str) + 1);
split = tal_strsplit(ctx, "hello world", take(str), STR_EMPTY_OK);
ok1(tal_parent(split) == ctx);
ok1(!strcmp(split[0], "hello"));
......@@ -124,6 +130,7 @@ int main(void)
split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
str = tal_strjoin(ctx, take(split), " there ", STR_NO_TRAIL);
ok1(!strcmp(str, "hello there world"));
ok1(tal_count(str) == strlen(str) + 1);
ok1(tal_parent(str) == ctx);
/* split is gone... */
ok1(single_child(ctx, str));
......@@ -136,6 +143,7 @@ int main(void)
STR_NO_TRAIL);
ok1(!strcmp(str, "hello there world"));
ok1(tal_parent(str) == ctx);
ok1(tal_count(str) == strlen(str) + 1);
tal_free(split);
/* tmp alloc is gone, str is only remainder. */
ok1(single_child(ctx, str));
......@@ -147,6 +155,7 @@ int main(void)
STR_EMPTY_OK)),
take(tal_strdup(ctx, " there ")), STR_NO_TRAIL);
ok1(!strcmp(str, "hello there world"));
ok1(tal_count(str) == strlen(str) + 1);
ok1(tal_parent(str) == ctx);
/* tmp allocs are gone, str is only remainder. */
ok1(single_child(ctx, str));
......
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