summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
1651e25)
This is least-surprise, but also means callers can sometimes do faster
string handling by avoiding strstr().
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
*
* 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
*
* 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>
*
* Example:
* #include <ccan/tal/str/str.h>
if (ret < max) {
ok = true;
if (ret < max) {
ok = true;
+ /* Make sure tal_count() is correct! */
+ tal_resize(buf, off + ret + 1);
totlen += dlen;
}
ret[totlen] = '\0';
totlen += dlen;
}
ret[totlen] = '\0';
+ /* Make sure tal_count() is correct! */
+ tal_resize(&ret, totlen+1);
out:
if (taken(strings))
tal_free(strings);
out:
if (taken(strings))
tal_free(strings);
* tal_strdup - duplicate a string
* @ctx: NULL, or tal allocated object to be parent.
* @p: the string to copy (can be take()).
* 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);
*/
#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);
* @n: the maximum length to copy.
*
* Always gives a nul-terminated string, with strlen() <= @n.
* @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,
*/
#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,
* tal_fmt - allocate a formatted string
* @ctx: NULL, or tal allocated object to be parent.
* @fmt: the printf-style format (can be take()).
* 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__)
*/
#define tal_fmt(ctx, ...) \
tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
* @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.
* @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, "[]"))
*/
#define tal_vfmt(ctx, fmt, va) \
tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
* @fmt: the printf-style format (can be take()).
*
* Returns false on allocation failure.
* @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);
*/
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.
* @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);
*/
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()).
* @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,
*/
#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,
* return value is allocated using tal. Each string in @strings is
* followed by a copy of @delim.
*
* 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)
* Example:
* // Append the string "--EOL" to each line.
* static char *append_to_all_lines(const char *string)
* non-existent matches (eg "([a-z]*)?") the pointer is set to NULL.
*
* Allocation failures or malformed regular expressions return false.
* 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).
*
* See Also:
* regcomp(3), regex(3).
char *str;
const char *fmt = "";
char *str;
const char *fmt = "";
/* GCC complains about empty format string, complains about non-literal
* with no args... */
str = tal_fmt(NULL, fmt, "");
ok1(!strcmp(str, ""));
/* 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();
tal_free(str);
return exit_status();
parent = tal(NULL, char);
ok1(parent);
parent = tal(NULL, char);
ok1(parent);
c = tal_strdup(parent, "hello");
ok1(strcmp(c, "hello") == 0);
ok1(tal_parent(c) == parent);
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);
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
tal_free(c);
#ifdef TAL_USE_TALLOC
c = tal_dup_arr(parent, char, "hello", 6, 0);
ok1(strcmp(c, "hello") == 0);
ok1(strcmp(tal_name(c), "char[]") == 0);
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);
ok1(tal_parent(c) == parent);
tal_free(c);
c = tal_dup_arr(parent, char, "hello", 6, 1);
ok1(strcmp(c, "hello") == 0);
ok1(strcmp(tal_name(c), "char[]") == 0);
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_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_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_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_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));
ok1(strcmp(c, "And hello there again") == 0);
ok1(tal_parent(c) == parent);
ok1(single_child(parent, c));
/* Appending formatted strings. */
c = tal_strdup(parent, "hi");
/* 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_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_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);
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"));
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);
tal_free(copy);
free(str);
/* If it accesses this, it will crash. */
char **invalid = (char **)1L;
/* If it accesses this, it will crash. */
char **invalid = (char **)1L;
/* Simple matching. */
ok1(tal_strreg(ctx, "hello world!", "hello") == true);
ok1(tal_strreg(ctx, "hello world!", "hi") == false);
/* Simple matching. */
ok1(tal_strreg(ctx, "hello world!", "hello") == true);
ok1(tal_strreg(ctx, "hello world!", "hi") == false);
ok1(streq(a, "hello"));
/* Allocated off ctx */
ok1(find_parent(a, ctx));
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"));
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);
ok1(find_parent(a, ctx));
ok1(find_parent(b, ctx));
tal_free(a);
&a, &b, invalid) == true);
ok1(streq(a, "o"));
ok1(streq(b, "world"));
&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);
tal_free(a);
tal_free(b);
&a, &b, invalid) == true);
ok1(streq(a, "hello world"));
ok1(streq(b, "hello"));
&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);
tal_free(a);
tal_free(b);
&a, &b, invalid) == true);
ok1(streq(a, "hello world"));
ok1(streq(b, "hello"));
&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);
tal_free(a);
tal_free(b);
ok1(tal_strreg(ctx, "hello world!", "((hello|goodbye) world)",
&a, NULL, invalid) == true);
ok1(streq(a, "hello world"));
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! */
tal_free(a);
/* No leaks! */
a = tal_strdup(ctx, "hello world!");
ok1(tal_strreg(ctx, take(a), "([a-z]+)", &b, invalid) == true);
ok1(streq(b, "hello"));
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));
ok1(tal_parent(b) == ctx);
tal_free(b);
ok1(no_children(ctx));
a = tal_strdup(ctx, "([a-z]+)");
ok1(tal_strreg(ctx, "hello world!", take(a), &b, invalid) == true);
ok1(streq(b, "hello"));
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));
ok1(tal_parent(b) == ctx);
tal_free(b);
ok1(no_children(ctx));
ok1(tal_strreg(ctx, take(tal_strdup(ctx, "hello world!")),
take(a), &b, invalid) == true);
ok1(streq(b, "hello"));
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));
ok1(tal_parent(b) == ctx);
tal_free(b);
ok1(no_children(ctx));
char **split, *str;
void *ctx;
char **split, *str;
void *ctx;
split = tal_strsplit(NULL, "hello world", " ", STR_EMPTY_OK);
ok1(!strcmp(split[0], "hello"));
ok1(!strcmp(split[1], ""));
split = tal_strsplit(NULL, "hello world", " ", STR_EMPTY_OK);
ok1(!strcmp(split[0], "hello"));
ok1(!strcmp(split[1], ""));
str = tal_strjoin(NULL, (char **)substrings, ", ", STR_TRAIL);
ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar, "));
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"));
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_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);
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");
tal_free(ctx);
ctx = tal_strdup(NULL, "context");
str = tal_strdup(ctx, "hello world");
ok1(tal_check(ctx, NULL));
ok1(tal_check(str, NULL));
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"));
split = tal_strsplit(ctx, take(str), " ", STR_EMPTY_OK);
ok1(tal_parent(split) == ctx);
ok1(!strcmp(split[0], "hello"));
/* tal_strsplit take delims */
str = tal_strdup(ctx, " ");
/* 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"));
split = tal_strsplit(ctx, "hello world", take(str), STR_EMPTY_OK);
ok1(tal_parent(split) == ctx);
ok1(!strcmp(split[0], "hello"));
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"));
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));
ok1(tal_parent(str) == ctx);
/* split is gone... */
ok1(single_child(ctx, str));
STR_NO_TRAIL);
ok1(!strcmp(str, "hello there world"));
ok1(tal_parent(str) == ctx);
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));
tal_free(split);
/* tmp alloc is gone, str is only remainder. */
ok1(single_child(ctx, str));
STR_EMPTY_OK)),
take(tal_strdup(ctx, " there ")), STR_NO_TRAIL);
ok1(!strcmp(str, "hello there world"));
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));
ok1(tal_parent(str) == ctx);
/* tmp allocs are gone, str is only remainder. */
ok1(single_child(ctx, str));