Commit 1139cb14 authored by John Levon's avatar John Levon Committed by Tomasz Zawadzki
Browse files

lib/util: add strarray utility functions



Add some basic utilities for handling arrays of strings.

Signed-off-by: default avatarJohn Levon <john.levon@nutanix.com>
Change-Id: I2333f3e4605175b1717a7f289847ff2d48745e8d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15274


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarPaul Luse <paul.e.luse@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: default avatarThanos Makatos <thanos.makatos@nutanix.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent c3e62d77
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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 \
+3 −0
Original line number Diff line number Diff line
@@ -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;
+96 −0
Original line number Diff line number Diff line
@@ -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;
}
+62 −0
Original line number Diff line number Diff line
@@ -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);