diff options
author | EuAndreh <eu@euandre.org> | 2021-08-22 12:42:23 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2021-08-22 12:42:23 -0300 |
commit | d25ab34dc757168109f46b0974b5b068f6a77413 (patch) | |
tree | 1ebbdb6ccbcf3773fbce792d61d31525c5a4bcc8 | |
parent | src/lib.c: Differentiate between -1 and other errors when looping through Git... (diff) | |
download | gistatic-d25ab34dc757168109f46b0974b5b068f6a77413.tar.gz gistatic-d25ab34dc757168109f46b0974b5b068f6a77413.tar.xz |
src/lib.c: Add strsjoin() with tests
Diffstat (limited to '')
-rw-r--r-- | src/lib.c | 104 |
1 files changed, 104 insertions, 0 deletions
@@ -597,6 +597,109 @@ static void test_strjoin(void) { } #endif +static char *strsjoin(const char *const strs[]) { + size_t size = sizeof('\0'); + for (size_t i = 0; strs[i]; i++) { + const size_t curr_len = strnlen(strs[i], SIZE_MAX); + if (SIZE_MAX - size < curr_len) { + errno = EOVERFLOW; + logerr("strsjoin()", strerror(errno), __LINE__); + return NULL; + } + if (SIZE_MAX == i) { + errno = EOVERFLOW; + logerr("strsjoin()", strerror(errno), __LINE__); + return NULL; + } + size += curr_len; + } + + char *const s = malloc(size); + if (!s) { + logerrl("malloc(", size, ")", strerror(errno), __LINE__); + return NULL; + } + *s = '\0'; + + // "i" can't overflow now, as it was already checked above + for (size_t i = 0; strs[i]; i++) { + strcat(s, strs[i]); + } + + return s; +} + +#ifdef TEST +static void test_strsjoin(void) { + test_start("test_strsjoin"); + { + testing("joining empty strings"); + char *const s = strsjoin((const char *const []) + { "", "", NULL }); + assert(s); + assert(strcmp(s, "") == 0); + free(s); + test_ok(); + } + { + testing("joining empty strs array"); + char *const s = strsjoin((const char *const []) + { NULL }); + assert(s); + assert(strcmp(s, "") == 0); + free(s); + test_ok(); + } + { + testing("first string is empty"); + char *const s = strsjoin((const char *const []) + { "", "second not empty", NULL }); + assert(s); + assert(strcmp(s, "second not empty") == 0); + free(s); + test_ok(); + } + { + testing("third string is empty"); + char *const s = strsjoin((const char *const []) + { "first not empty", "second not empty", "", NULL }); + assert(s); + assert(strcmp(s, "first not emptysecond not empty") == 0); + free(s); + test_ok(); + } + { + testing("four non-empty strings"); + char *const s = strsjoin((const char *const []) + { "abc", "def", "ghi", "jkl", NULL }); + assert(s); + assert(strcmp(s, "abcdefghijkl") == 0); + free(s); + test_ok(); + } + { + testing("example usage: with file names"); + char *const s = strsjoin((const char *const []) + { "../repository.git", "/description", NULL }); + assert(s); + assert(strcmp(s, "../repository.git/description") == 0); + free(s); + test_ok(); + } + { + testing("example usage: with file name parts"); + char *const s = strsjoin((const char *const []){ + "/tmp/gistatic.ABCDEF", "/", "project", + "-", "main", NULL + }); + assert(s); + assert(strcmp(s, "/tmp/gistatic.ABCDEF/project-main") == 0); + free(s); + test_ok(); + } +} +#endif + static char *formatted_date(const time_t time_sec) { const struct tm *const time_utc = gmtime(&time_sec); if (!time_utc) { @@ -2058,6 +2161,7 @@ void unit_tests_gistatic(void) { test_underscore(); test_remove_suffix(); test_strjoin(); + test_strsjoin(); test_formatted_date(); test_max(); test_escape_html(); |