lib/util: add strarray utility functions

Add some basic utilities for handling arrays of strings.

Signed-off-by: John Levon <john.levon@nutanix.com>
Change-Id: I2333f3e4605175b1717a7f289847ff2d48745e8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15274
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Paul Luse <paul.e.luse@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
John Levon 2022-11-04 17:59:14 +00:00 committed by Tomasz Zawadzki
parent c3e62d7729
commit 1139cb1415
5 changed files with 191 additions and 1 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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);