From 1139cb141533bc804725511eea570a4cc30ef77a Mon Sep 17 00:00:00 2001 From: John Levon Date: Fri, 4 Nov 2022 17:59:14 +0000 Subject: [PATCH] lib/util: add strarray utility functions Add some basic utilities for handling arrays of strings. Signed-off-by: John Levon Change-Id: I2333f3e4605175b1717a7f289847ff2d48745e8d Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15274 Tested-by: SPDK CI Jenkins Community-CI: Mellanox Build Bot Reviewed-by: Paul Luse Reviewed-by: Aleksey Marchuk Reviewed-by: Thanos Makatos Reviewed-by: Jim Harris --- include/spdk/string.h | 29 ++++++++ lib/util/Makefile | 2 +- lib/util/spdk_util.map | 3 + lib/util/string.c | 96 +++++++++++++++++++++++++ test/unit/lib/util/string.c/string_ut.c | 62 ++++++++++++++++ 5 files changed, 191 insertions(+), 1 deletion(-) diff --git a/include/spdk/string.h b/include/spdk/string.h index 355a3f451..dea244422 100644 --- a/include/spdk/string.h +++ b/include/spdk/string.h @@ -236,6 +236,35 @@ long int spdk_strtol(const char *nptr, int base); */ long long int spdk_strtoll(const char *nptr, int base); +/** + * Build a NULL-terminated array of strings from the given string separated by + * the given chars in delim, as if split by strpbrk(). Empty items are pointers + * to an empty string. + * + * \param str Input string + * \param delim Separating delimiter set. + * + * \return the string array, or NULL on failure. + */ +char **spdk_strarray_from_string(const char *str, const char *delim); + +/** + * Duplicate a NULL-terminated array of strings. Returns NULL on failure. + * The array, and the strings, are allocated with the standard allocator (e.g. + * calloc()). + * + * \param strarray input array of strings. + */ +char **spdk_strarray_dup(const char **strarray); + +/** + * Free a NULL-terminated array of strings. The array and its strings must have + * been allocated with the standard allocator (calloc() etc.). + * + * \param strarray array of strings. + */ +void spdk_strarray_free(char **strarray); + #ifdef __cplusplus } #endif diff --git a/lib/util/Makefile b/lib/util/Makefile index fc9adb7d4..bf3037207 100644 --- a/lib/util/Makefile +++ b/lib/util/Makefile @@ -7,7 +7,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) include $(SPDK_ROOT_DIR)/mk/spdk.common.mk SO_VER := 5 -SO_MINOR := 1 +SO_MINOR := 2 C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c \ dif.c fd.c file.c hexlify.c iov.c math.c pipe.c strerror_tls.c string.c uuid.c \ diff --git a/lib/util/spdk_util.map b/lib/util/spdk_util.map index 41f94089d..ffe9253ca 100644 --- a/lib/util/spdk_util.map +++ b/lib/util/spdk_util.map @@ -123,6 +123,9 @@ spdk_mem_all_zero; spdk_strtol; spdk_strtoll; + spdk_strarray_from_string; + spdk_strarray_dup; + spdk_strarray_free; # public functions in util.h spdk_u32log2; diff --git a/lib/util/string.c b/lib/util/string.c index 80df11cf4..ded464d60 100644 --- a/lib/util/string.c +++ b/lib/util/string.c @@ -446,3 +446,99 @@ spdk_strtoll(const char *nptr, int base) return val; } + +void +spdk_strarray_free(char **strarray) +{ + size_t i; + + if (strarray == NULL) { + return; + } + + for (i = 0; strarray[i] != NULL; i++) { + free(strarray[i]); + } + free(strarray); +} + +char ** +spdk_strarray_from_string(const char *str, const char *delim) +{ + const char *c = str; + size_t count = 0; + char **result; + size_t i; + + assert(str != NULL); + assert(delim != NULL); + + /* Count number of entries. */ + for (;;) { + const char *next = strpbrk(c, delim); + + count++; + + if (next == NULL) { + break; + } + + c = next + 1; + } + + /* Account for the terminating NULL entry. */ + result = calloc(count + 1, sizeof(char *)); + if (result == NULL) { + return NULL; + } + + c = str; + + for (i = 0; i < count; i++) { + const char *next = strpbrk(c, delim); + + if (next == NULL) { + result[i] = strdup(c); + } else { + result[i] = strndup(c, next - c); + } + + if (result[i] == NULL) { + spdk_strarray_free(result); + return NULL; + } + + if (next != NULL) { + c = next + 1; + } + } + + return result; +} + +char ** +spdk_strarray_dup(const char **strarray) +{ + size_t count, i; + char **result; + + assert(strarray != NULL); + + for (count = 0; strarray[count] != NULL; count++) + ; + + result = calloc(count + 1, sizeof(char *)); + if (result == NULL) { + return NULL; + } + + for (i = 0; i < count; i++) { + result[i] = strdup(strarray[i]); + if (result[i] == NULL) { + spdk_strarray_free(result); + return NULL; + } + } + + return result; +} diff --git a/test/unit/lib/util/string.c/string_ut.c b/test/unit/lib/util/string.c/string_ut.c index d9c218827..90c4f24f1 100644 --- a/test/unit/lib/util/string.c/string_ut.c +++ b/test/unit/lib/util/string.c/string_ut.c @@ -375,6 +375,67 @@ test_strtoll(void) CU_ASSERT(val == 0); } +static void +test_strarray(void) +{ + char **r; + char **r2; + + r = spdk_strarray_from_string("", ":"); + CU_ASSERT(strcmp(r[0], "") == 0); + CU_ASSERT(r[1] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string(":", ":"); + CU_ASSERT(strcmp(r[0], "") == 0); + CU_ASSERT(strcmp(r[1], "") == 0); + CU_ASSERT(r[2] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string("a", ":"); + CU_ASSERT(strcmp(r[0], "a") == 0); + CU_ASSERT(r[1] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string("ab:", ":"); + CU_ASSERT(strcmp(r[0], "ab") == 0); + CU_ASSERT(strcmp(r[1], "") == 0); + CU_ASSERT(r[2] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string(":ab", ":"); + CU_ASSERT(strcmp(r[0], "") == 0); + CU_ASSERT(strcmp(r[1], "ab") == 0); + CU_ASSERT(r[2] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string("ab:c", ":"); + CU_ASSERT(strcmp(r[0], "ab") == 0); + CU_ASSERT(strcmp(r[1], "c") == 0); + CU_ASSERT(r[2] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string(":ab.:c:", ":."); + CU_ASSERT(strcmp(r[0], "") == 0); + CU_ASSERT(strcmp(r[1], "ab") == 0); + CU_ASSERT(strcmp(r[2], "") == 0); + CU_ASSERT(strcmp(r[3], "c") == 0); + CU_ASSERT(strcmp(r[4], "") == 0); + CU_ASSERT(r[5] == NULL); + spdk_strarray_free(r); + + r = spdk_strarray_from_string(":ab.:c:", ":."); + r2 = spdk_strarray_dup((const char **)r); + CU_ASSERT(strcmp(r2[0], "") == 0); + CU_ASSERT(strcmp(r2[1], "ab") == 0); + CU_ASSERT(strcmp(r2[2], "") == 0); + CU_ASSERT(strcmp(r2[3], "c") == 0); + CU_ASSERT(strcmp(r2[4], "") == 0); + CU_ASSERT(r2[5] == NULL); + spdk_strarray_free(r); + spdk_strarray_free(r2); +} + int main(int argc, char **argv) { @@ -392,6 +453,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, test_sprintf_append_realloc); CU_ADD_TEST(suite, test_strtol); CU_ADD_TEST(suite, test_strtoll); + CU_ADD_TEST(suite, test_strarray); CU_basic_set_mode(CU_BRM_VERBOSE);