diff options
-rw-r--r-- | Makefile-ccan | 1 | ||||
l--------- | ccan/stringbuilder/LICENSE | 1 | ||||
-rw-r--r-- | ccan/stringbuilder/_info | 59 | ||||
-rw-r--r-- | ccan/stringbuilder/stringbuilder.c | 77 | ||||
-rw-r--r-- | ccan/stringbuilder/stringbuilder.h | 138 | ||||
-rw-r--r-- | ccan/stringbuilder/test/run.c | 67 |
6 files changed, 343 insertions, 0 deletions
diff --git a/Makefile-ccan b/Makefile-ccan index 432705f4..54430c03 100644 --- a/Makefile-ccan +++ b/Makefile-ccan @@ -90,6 +90,7 @@ MODS_WITH_SRC := antithread \ siphash \ sparse_bsearch \ str \ + stringbuilder \ stringmap \ strmap \ strset \ diff --git a/ccan/stringbuilder/LICENSE b/ccan/stringbuilder/LICENSE new file mode 120000 index 00000000..b7951dab --- /dev/null +++ b/ccan/stringbuilder/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0
\ No newline at end of file diff --git a/ccan/stringbuilder/_info b/ccan/stringbuilder/_info new file mode 100644 index 00000000..4c782544 --- /dev/null +++ b/ccan/stringbuilder/_info @@ -0,0 +1,59 @@ +#include "config.h" +#include <stdio.h> +#include <string.h> + +/** + * stringbuilder - join lists of strings + * + * This is a small set of functions for building up strings from a list. + * The destination buffer is bounds-checked, the functions return failure + * if the concatenated strings overflow the buffer. + * + * Example: + * #include <stdio.h> + * #include <string.h> + * #include <errno.h> + * #include <ccan/stringbuilder/stringbuilder.h> + * + * int main(int argc, char *argv[]) + * { + * char mystring[128]; + * int res; + * + * res = stringbuilder_array(mystring, 128, "', '", + * argc, (const char**)argv); + * if (!res) + * printf("My arguments: '%s'\n", mystring); + * else + * printf("Failed to join arguments: %s\n", + * strerror(res)); + * if (!res) { + * res = stringbuilder(mystring, 128, ", ", + * "This", "Is", "A", "Test"); + * if (!res) + * printf("My string: '%s'\n", mystring); + * else + * printf("Failed to join strings: %s\n", + * strerror(res)); + * } + * return 0; + * } + * + * License: CC0 (Public domain) + * Author: Stuart Longland <stuartl@longlandclan.yi.org> + */ +int main(int argc, char *argv[]) +{ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + /* + * This triggers a circular dependency! + * printf("ccan/str\n"); + */ + return 0; + } + + return 1; +} diff --git a/ccan/stringbuilder/stringbuilder.c b/ccan/stringbuilder/stringbuilder.c new file mode 100644 index 00000000..d34de811 --- /dev/null +++ b/ccan/stringbuilder/stringbuilder.c @@ -0,0 +1,77 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#include <ccan/stringbuilder/stringbuilder.h> +#include <string.h> +#include <errno.h> + +int stringbuilder_args(char* str, size_t str_sz, const char* delim, ...) +{ + int res; + va_list ap; + va_start(ap, delim); + res = stringbuilder_va(str, str_sz, delim, ap); + va_end(ap); + return res; +} + +static int stringbuilder_cpy( + char** str, size_t* str_sz, const char* s, size_t s_len) +{ + if (!s) + return 0; + + if (*str != s) { + if (!s_len) + s_len = strlen(s); + if (s_len > *str_sz) + return EMSGSIZE; + strcpy(*str, s); + } + *str += s_len; + *str_sz -= s_len; + return 0; +} + +int stringbuilder_va(char* str, size_t str_sz, const char* delim, va_list ap) +{ + int res = 0; + size_t delim_len = 0; + const char* s = va_arg(ap, const char*); + + if (delim) + delim_len = strlen(delim); + + res = stringbuilder_cpy(&str, &str_sz, s, 0); + s = va_arg(ap, const char*); + while(s && !res) { + res = stringbuilder_cpy(&str, &str_sz, + delim, delim_len); + if (!res) { + res = stringbuilder_cpy(&str, &str_sz, + s, 0); + s = va_arg(ap, const char*); + } + } + return res; +} + +int stringbuilder_array(char* str, size_t str_sz, const char* delim, + size_t n_strings, const char** strings) +{ + int res = 0; + size_t delim_len = 0; + + if (delim) + delim_len = strlen(delim); + + res = stringbuilder_cpy(&str, &str_sz, + *(strings++), 0); + while(--n_strings && !res) { + res = stringbuilder_cpy(&str, &str_sz, + delim, delim_len); + if (!res) + res = stringbuilder_cpy(&str, &str_sz, + *(strings++), 0); + } + return res; + +} diff --git a/ccan/stringbuilder/stringbuilder.h b/ccan/stringbuilder/stringbuilder.h new file mode 100644 index 00000000..84d79ece --- /dev/null +++ b/ccan/stringbuilder/stringbuilder.h @@ -0,0 +1,138 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_STRINGBUILDER_H +#define CCAN_STRINGBUILDER_H +#include "config.h" +#include <stdarg.h> +#include <sys/types.h> + +/** + * stringbuilder - Join strings from a varadic list. The list of arguments + * are all assumed to be of type const char*. If the first argument is str, + * then the contents of str are preserved and appended to. + * + * @str: A pointer to a string buffer that will receive the result. + * @str_sz: Size of the buffer pointed to by str. + * @delim: A delimiter to separate the strings with, or NULL. + * + * Returns: 0 on success + * EMSGSIZE if the resulting string would overflow the buffer. + * If an overflow condition is detected, the buffer content is + * NOT defined. + * + * Example: + * int res; + * char file_name[80]; + * res = stringbuilder(file_name, sizeof(file_name), "/", + * "/var/lib/foo", "bar", "baz"); + * if (res) + * printf("Failed to determine file name: %s", + * strerror(res)); + * else + * printf("File is at %s", file_name); + */ +#define stringbuilder(str, str_sz, delim, ...) \ + stringbuilder_args(str, str_sz, delim, __VA_ARGS__, NULL) +/** + * stringbuilder_args - Join strings from a varadic list. The list of + * arguments are all assumed to be of type const char* and must end with a NULL. + * If the first argument is str, then the contents of str are preserved and + * appended to. + * + * @str: A pointer to a string buffer that will receive the result. + * @str_sz: Size of the buffer pointed to by str. + * @delim: A delimiter to separate the strings with, or NULL. + * + * Returns: 0 on success + * EMSGSIZE if the resulting string would overflow the buffer. + * If an overflow condition is detected, the buffer content is + * NOT defined. + * + * Example: + * int res; + * char file_name[80]; + * res = stringbuilder_args(file_name, sizeof(file_name), "/", + * "/var/lib/foo", "bar", "baz", + * NULL); + * if (res) + * printf("Failed to determine file name: %s", + * strerror(res)); + * else + * printf("File is at %s", file_name); + */ +int stringbuilder_args(char* str, size_t str_sz, const char* delim, ...); + +/** + * stringbuilder_va - Join strings from a varadic list. The list of arguments + * are all assumed to be of type const char* and must end with a NULL. If the + * first argument is str, then the contents of str are preserved and appended + * to. + * + * @str: A pointer to a string buffer that will receive the result. + * @str_sz: Size of the buffer pointed to by str. + * @delim: A delimiter to separate the strings with, or NULL. + * + * Returns: 0 on success + * EMSGSIZE if the resulting string would overflow the buffer. + * If an overflow condition is detected, the buffer content is + * NOT defined. + * + * Example: + * #include <ccan/stringbuilder/stringbuilder.h> + * #include <stdarg.h> + * #include <stdio.h> + * #include <string.h> + * #include <errno.h> + * + * int my_stringbuilder(char* str, size_t str_sz, + * const char* delim, ...); + * + * int my_stringbuilder(char* str, size_t str_sz, + * const char* delim, ...) + * { + * int res; + * va_list ap; + * va_start(ap, delim); + * res = stringbuilder_va(str, str_sz, delim, ap); + * va_end(ap); + * return res; + * } + * + * int main(void) { + * char my_string[80]; + * int res = my_stringbuilder(my_string, + * sizeof(my_string), " ", "foo", "bar", NULL); + * if (!res) + * printf("%s\n", my_string); + * return res ? 1 : 0; + * } + */ +int stringbuilder_va(char* str, size_t str_sz, const char* delim, va_list ap); + +/** + * stringbuilder_array - Join strings from an array of const char* pointers. + * + * @str: A pointer to a string buffer that will receive the result. + * @str_sz: Size of the buffer pointed to by str. + * @delim: A delimiter to separate the strings with, or NULL. + * @n_strings: The number of strings to join. + * @strings: The array of strings to join. + * + * Returns: 0 on success + * EMSGSIZE if the resulting string would overflow the buffer. + * If an overflow condition is detected, the buffer content is + * NOT defined. + * + * Example: + * char my_args[128]; + * int res = stringbuilder_array(my_args, sizeof(my_args), ", ", + * argc, (const char**)argv); + * if (res) + * printf("Failed to list arguments: %s", + * strerror(res)); + * else + * printf("My arguments were %s", my_args); + */ +int stringbuilder_array(char* str, size_t str_sz, const char* delim, + size_t n_strings, const char** strings); + +#endif /* CCAN_STRINGBUILDER_H */ diff --git a/ccan/stringbuilder/test/run.c b/ccan/stringbuilder/test/run.c new file mode 100644 index 00000000..2d119f25 --- /dev/null +++ b/ccan/stringbuilder/test/run.c @@ -0,0 +1,67 @@ +#include <ccan/stringbuilder/stringbuilder.h> +#include <ccan/stringbuilder/stringbuilder.c> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +/* + * This triggers a circular dependency + * #include <ccan/str/str.h> + * + * We only want the following macro: + */ +#define streq(s1,s2) (!strcmp(s1,s2)) + +#include <ccan/tap/tap.h> + +int main(int argc, char *argv[]) +{ + char string[20]; + const char* str_array[] = { + "xxx", "yyy" + }; + int res; + + res = stringbuilder(string, sizeof(string), NULL, + "aaa", "bbb"); + printf("res: %s, string: %s\n", + strerror(res), string); + ok1(res == 0); + ok1(streq(string, "aaabbb")); + + res = stringbuilder(string, sizeof(string), NULL, + "aaaaa", "bbbbb", "ccccc", "ddddd", + "eeeee", "fffff"); + printf("res: %s, string: %s\n", + strerror(res), string); + ok1(res == EMSGSIZE); + + res = stringbuilder(string, sizeof(string), ", ", + "aaa"); + printf("res: %s, string: %s\n", + strerror(res), string); + ok1(res == 0); + ok1(streq(string, "aaa")); + + res = stringbuilder(string, sizeof(string), ", ", + "aaa", "bbb"); + printf("res: %s, string: %s\n", + strerror(res), string); + ok1(res == 0); + ok1(streq(string, "aaa, bbb")); + + res = stringbuilder_array(string, sizeof(string), NULL, + sizeof(str_array)/sizeof(str_array[0]), str_array); + printf("res: %s, string: %s\n", + strerror(res), string); + ok1(res == 0); + ok1(streq(string, "xxxyyy")); + + res = stringbuilder_array(string, sizeof(string), ", ", + sizeof(str_array)/sizeof(str_array[0]), str_array); + printf("res: %s, string: %s\n", + strerror(res), string); + ok1(res == 0); + ok1(streq(string, "xxx, yyy")); + + return exit_status(); +} |