From 89e178e7c950ccedac7d560fb54960ca5589b315 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Wed, 15 Feb 2023 00:50:28 -0500 Subject: [PATCH] Add function to split string into list. - With working unit tests. --- common/list.c | 89 +++++++++++++++++++++++++++++----- common/list.h | 18 +++++++ common/string_calls.c | 1 + tests/common/test_list_calls.c | 46 +++++++++++++++++- 4 files changed, 141 insertions(+), 13 deletions(-) diff --git a/common/list.c b/common/list.c index 83fde45a..73035ad8 100644 --- a/common/list.c +++ b/common/list.c @@ -36,7 +36,7 @@ enum DEFAULT_GROW_BY_SIZE = 10 }; -/*****************************************************************************/ +/******************************************************************************/ struct list * list_create_sized(unsigned int size) { @@ -64,14 +64,14 @@ list_create_sized(unsigned int size) return self; } -/*****************************************************************************/ +/******************************************************************************/ struct list * list_create(void) { return list_create_sized(DEFAULT_LIST_SIZE); } -/*****************************************************************************/ +/******************************************************************************/ void list_delete(struct list *self) { @@ -95,7 +95,7 @@ list_delete(struct list *self) free(self); } -/*****************************************************************************/ +/******************************************************************************/ static int grow_list(struct list *self) { @@ -128,7 +128,7 @@ list_add_item(struct list *self, tbus item) return 1; } -/*****************************************************************************/ +/******************************************************************************/ tbus list_get_item(const struct list *self, int index) { @@ -140,7 +140,7 @@ list_get_item(const struct list *self, int index) return self->items[index]; } -/*****************************************************************************/ +/******************************************************************************/ void list_clear(struct list *self) { @@ -161,7 +161,7 @@ list_clear(struct list *self) self->items = (tbus *)realloc(self->items, sizeof(tbus) * self->alloc_size); } -/*****************************************************************************/ +/******************************************************************************/ int list_index_of(struct list *self, tbus item) { @@ -178,7 +178,7 @@ list_index_of(struct list *self, tbus item) return -1; } -/*****************************************************************************/ +/******************************************************************************/ void list_remove_item(struct list *self, int index) { @@ -201,7 +201,6 @@ list_remove_item(struct list *self, int index) } } -/*****************************************************************************/ int list_insert_item(struct list *self, int index, tbus item) { @@ -234,7 +233,7 @@ list_insert_item(struct list *self, int index, tbus item) return 1; } -/*****************************************************************************/ +/******************************************************************************/ /* append one list to another using strdup for each item in the list */ /* begins copy at start_index, a zero based index on the source list */ int @@ -282,7 +281,7 @@ list_append_list_strdup(struct list *self, struct list *dest, int start_index) return rv; } -/*****************************************************************************/ +/******************************************************************************/ void list_dump_items(struct list *self) { @@ -298,3 +297,71 @@ list_dump_items(struct list *self) LOG_DEVEL(LOG_LEVEL_TRACE, "%d: %p", index, (void *) list_get_item(self, index)); } } + +/******************************************************************************/ +/** + * Appends a string fragment to a list + * @param[in,out] start Pointer to start of fragment (by reference) + * @param end Pointer to one past end of fragment + * @param list List to append to + * @result 1 for success + * + * In the event of a memory failure, 0 is returned and the list is deleted. + */ +int +split_string_append_fragment(const char **start, const char *end, + struct list *list) +{ + const unsigned int len = end - *start; + char *copy = (char *)malloc(len + 1); + if (copy == NULL) + { + list_delete(list); + return 0; + } + g_memcpy(copy, *start, len); + copy[len] = '\0'; + if (!list_add_item(list, (tintptr)copy)) + { + g_free(copy); + list_delete(list); + return 0; + } + *start = end + 1; + return 1; +} + +/******************************************************************************/ +struct list * +split_string_into_list(const char *str, char character) +{ + struct list *result = list_create(); + if (result == NULL) + { + return result; + } + result->auto_free = 1; + + if (str == NULL) + { + return result; + } + + const char *p; + while ((p = g_strchr(str, character)) != NULL) + { + if (!split_string_append_fragment(&str, p, result)) + { + return NULL; + } + } + + if (*str != '\0') + { + if (!split_string_append_fragment(&str, str + g_strlen(str), result)) + { + return NULL; + } + } + return result; +} diff --git a/common/list.h b/common/list.h index 7536a171..41b9fe76 100644 --- a/common/list.h +++ b/common/list.h @@ -95,4 +95,22 @@ list_append_list_strdup(struct list *self, struct list *dest, int start_index); void list_dump_items(struct list *self); +/** + * Splits a string on a separation character and then returns a list of + * the string split by the character, without the character contained within + * the pieces. + * + * The list must be disposed of by the caller. + * + * @param str String to split. + * @param character Character used as the delimiter between strings. + * @param start_index Index to start on the source list (zero based) + * + * @result 0 if a memory allocation failure occurred. + * + * String fragments in the list are created with strdup() + */ +struct list * +split_string_into_list(const char *str, char character); + #endif diff --git a/common/string_calls.c b/common/string_calls.c index 20e28959..de74f9e5 100644 --- a/common/string_calls.c +++ b/common/string_calls.c @@ -1142,3 +1142,4 @@ g_charstr_to_bitmask(const char *str, const struct bitmask_char bitdefs[], return bitmask; } + diff --git a/tests/common/test_list_calls.c b/tests/common/test_list_calls.c index af6f41c2..917c09a7 100644 --- a/tests/common/test_list_calls.c +++ b/tests/common/test_list_calls.c @@ -1,4 +1,3 @@ - #if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif @@ -112,8 +111,49 @@ START_TEST(test_list__simple_append_list) } END_TEST -/******************************************************************************/ +int +split_string_append_fragment(const char **start, const char *end, + struct list *list); +START_TEST(test_list__append_fragment) +{ + struct list *l = list_create(); + l->auto_free = 1; + + const char *test_string = "split this"; + + int fragment_ret = split_string_append_fragment(&test_string, + test_string + 5, l); + ck_assert_int_eq(fragment_ret, 1); + ck_assert_str_eq((const char *)l->items[0], "split"); + + fragment_ret = split_string_append_fragment(&test_string, + test_string + 1000, l); + ck_assert_int_eq(fragment_ret, 1); + ck_assert_str_eq((const char *)l->items[1], "this"); + + list_delete(l); +} +END_TEST + +START_TEST(test_list__split_string_into_list) +{ + struct list *l = split_string_into_list("The fat cat sat on my hat.", ' '); + + ck_assert_int_eq(l->count, 7); + ck_assert_str_eq((const char *)l->items[0], "The"); + ck_assert_str_eq((const char *)l->items[1], "fat"); + ck_assert_str_eq((const char *)l->items[2], "cat"); + ck_assert_str_eq((const char *)l->items[3], "sat"); + ck_assert_str_eq((const char *)l->items[4], "on"); + ck_assert_str_eq((const char *)l->items[5], "my"); + ck_assert_str_eq((const char *)l->items[6], "hat."); + + list_delete(l); +} +END_TEST + +/******************************************************************************/ Suite * make_suite_test_list(void) { @@ -127,6 +167,8 @@ make_suite_test_list(void) tcase_add_test(tc_simple, test_list__simple); tcase_add_test(tc_simple, test_list__simple_auto_free); tcase_add_test(tc_simple, test_list__simple_append_list); + tcase_add_test(tc_simple, test_list__append_fragment); + tcase_add_test(tc_simple, test_list__split_string_into_list); return s; }