diff --git a/libutils/string_lib.c b/libutils/string_lib.c index 94783019..24f3cb49 100644 --- a/libutils/string_lib.c +++ b/libutils/string_lib.c @@ -1781,3 +1781,23 @@ bool StringMatchesOption( } return StringEqualN_IgnoreCase(supplied, longopt, length); } + +char *StringJoin(const Seq *const seq, const char *sep) +{ + assert(seq != NULL); + + Writer *const writer = StringWriter(); + const size_t len = SeqLength(seq); + for (size_t i = 0; i < len; i++) + { + if (i != 0 && sep != NULL) + { + WriterWrite(writer, sep); + } + const char *const str = SeqAt(seq, i); + WriterWrite(writer, str); + } + + char *const data = StringWriterClose(writer); + return data; +} diff --git a/libutils/string_lib.h b/libutils/string_lib.h index 519b0707..75f903b0 100644 --- a/libutils/string_lib.h +++ b/libutils/string_lib.h @@ -322,4 +322,14 @@ void CanonifyNameInPlace(char *str); bool StringMatchesOption( const char *supplied, const char *longopt, const char *shortopt); +/** + * @brief Join elements in sequence into a string + * @param[in] seq Sequence of strings to join + * @param[in] sep Separator between elements (can be NULL) + * @return The concatenation of the elements in sequence + * @note Sequence must contain only NUL-terminated strings, otherwise behavior + * is undefined + */ +char *StringJoin(const Seq *seq, const char *sep); + #endif diff --git a/tests/unit/string_lib_test.c b/tests/unit/string_lib_test.c index 20ce13f6..44288122 100644 --- a/tests/unit/string_lib_test.c +++ b/tests/unit/string_lib_test.c @@ -1470,6 +1470,43 @@ static void test_StringMatchesOption(void) assert_true(StringMatchesOption("--host", "--hosts", "-H")); } +static void test_StringJoin(void) +{ + const char *argv[] = { "one", "two", "three" }; + const int argc = sizeof(argv) / sizeof(argv[0]); + + Seq *seq = SeqFromArgv(argc, argv); + + char *actual = StringJoin(seq, NULL); + assert_string_equal(actual, "onetwothree"); + free(actual); + + actual = StringJoin(seq, ""); + assert_string_equal(actual, "onetwothree"); + free(actual); + + actual = StringJoin(seq, ", "); + assert_string_equal(actual, "one, two, three"); + free(actual); + + SeqDestroy(seq); + seq = SeqNew(0, NULL); + + actual = StringJoin(seq, NULL); + assert_string_equal(actual, ""); + free(actual); + + actual = StringJoin(seq, ""); + assert_string_equal(actual, ""); + free(actual); + + actual = StringJoin(seq, ", "); + assert_string_equal(actual, ""); + free(actual); + + SeqDestroy(seq); +} + int main() { PRINT_TEST_BANNER(); @@ -1564,6 +1601,7 @@ int main() unit_test(test_StrCatDelim), unit_test(test_StringMatchesOption), + unit_test(test_StringJoin), }; return run_tests(tests);