From 43e00ef75e2a425486aa7b9cb308565ce79c51ce Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 27 Oct 2014 16:53:44 +0100 Subject: [PATCH 1/5] Add add_strings_lists() utility function --- src/tests/cmocka/test_utils.c | 111 ++++++++++++++++++++++++++++++++++++++++++ src/util/util.c | 65 +++++++++++++++++++++++++ src/util/util.h | 18 +++++++ 3 files changed, 194 insertions(+) diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c index 9d6cbf3..d978137 100644 --- a/src/tests/cmocka/test_utils.c +++ b/src/tests/cmocka/test_utils.c @@ -875,6 +875,114 @@ void test_expand_homedir_template(void **state) talloc_free(tmp_ctx); } +void setup_add_strings_lists(void **state) +{ + assert_true(leak_check_setup()); + + check_leaks_push(global_talloc_context); +} + +void teardown_add_strings_lists(void **state) +{ + assert_true(check_leaks_pop(global_talloc_context) == true); + assert_true(leak_check_teardown()); +} + +void test_add_strings_lists(void **state) +{ + const char *l1[] = {"a", "b", "c", NULL}; + const char *l2[] = {"1", "2", "3", NULL}; + char **res; + int ret; + size_t c; + size_t d; + + ret = add_strings_lists(global_talloc_context, NULL, NULL, true, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + assert_null(res[0]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, NULL, NULL, false, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + assert_null(res[0]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, l1, NULL, false, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + for (c = 0; l1[c] != NULL; c++) { + /* 'copy_strings' is 'false', pointers must be equal */ + assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0); + } + assert_null(res[c]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, l1, NULL, true, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + for (c = 0; l1[c] != NULL; c++) { + /* 'copy_strings' is 'true', pointers must be different, but strings + * must be equal */ + assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0); + assert_string_equal(l1[c], res[c]); + } + assert_null(res[c]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, NULL, l1, false, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + for (c = 0; l1[c] != NULL; c++) { + /* 'copy_strings' is 'false', pointers must be equal */ + assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0); + } + assert_null(res[c]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, NULL, l1, true, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + for (c = 0; l1[c] != NULL; c++) { + /* 'copy_strings' is 'true', pointers must be different, but strings + * must be equal */ + assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0); + assert_string_equal(l1[c], res[c]); + } + assert_null(res[c]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, l1, l2, false, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + for (c = 0; l1[c] != NULL; c++) { + /* 'copy_strings' is 'false', pointers must be equal */ + assert_int_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0); + } + for (d = 0; l2[d] != NULL; d++) { + assert_int_equal(memcmp(&l2[d], &res[c+d], sizeof(char *)), 0); + } + assert_null(res[c+d]); + talloc_free(res); + + ret = add_strings_lists(global_talloc_context, l1, l2, true, &res); + assert_int_equal(ret, EOK); + assert_non_null(res); + for (c = 0; l1[c] != NULL; c++) { + /* 'copy_strings' is 'true', pointers must be different, but strings + * must be equal */ + assert_int_not_equal(memcmp(&l1[c], &res[c], sizeof(char *)), 0); + assert_string_equal(l1[c], res[c]); + } + for (d = 0; l2[d] != NULL; d++) { + assert_int_not_equal(memcmp(&l2[d], &res[c+d], sizeof(char *)), 0); + assert_string_equal(l2[d], res[c+d]); + } + assert_null(res[c+d]); + talloc_free(res); +} + int main(int argc, const char *argv[]) { poptContext pc; @@ -919,6 +1027,9 @@ int main(int argc, const char *argv[]) unit_test(test_textual_public_key), unit_test(test_replace_whitespaces), unit_test(test_reverse_replace_whitespaces), + unit_test_setup_teardown(test_add_strings_lists, + setup_add_strings_lists, + teardown_add_strings_lists), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ diff --git a/src/util/util.c b/src/util/util.c index d78d37d..2acb860 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -815,3 +815,68 @@ const char * const * get_known_services(void) return svc; } + +errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2, + bool copy_strings, char ***_new_list) +{ + size_t c; + size_t l1_count = 0; + size_t l2_count = 0; + size_t new_count = 0; + char **new; + int ret; + + if (l1 != NULL) { + for (l1_count = 0; l1[l1_count] != NULL; l1_count++); + } + + if (l2 != NULL) { + for (l2_count = 0; l2[l2_count] != NULL; l2_count++); + } + + new_count = l1_count + l2_count; + + new = talloc_array(mem_ctx, char *, new_count + 1); + if (new == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); + return ENOMEM; + } + new [new_count] = NULL; + + if (copy_strings) { + for(c = 0; c < l1_count; c++) { + new[c] = talloc_strdup(new, l1[c]); + if (new[c] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + } + for(c = 0; c < l2_count; c++) { + new[l1_count + c] = talloc_strdup(new, l2[c]); + if (new[l1_count + c] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + } + } else { + if (l1 != NULL) { + memcpy(new, l1, sizeof(char *) * l1_count); + } + + if (l2 != NULL) { + memcpy(&new[l1_count], l2, sizeof(char *) * l2_count); + } + } + + *_new_list = new; + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(new); + } + + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 69074c9..ffc8a87 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -426,6 +426,24 @@ errno_t sss_hash_create_ex(TALLOC_CTX *mem_ctx, hash_delete_callback *delete_callback, void *delete_private_data); +/** + * @brief Add two list of strings + * + * Create a new NULL-termintated list of strings by adding two lists together. + * + * @param[in] mem_ctx Talloc memory context for the new list. + * @param[in] l1 First NULL-termintated list of strings. + * @param[in] l2 Second NULL-termintated list of strings. + * @param[in] copy_strings If set to 'true' the list items will be copied + * otherwise only the pointers to the items are + * copied. + * @param[out] new_list New NULL-terminated list of strings. Must be freed + * with talloc_free() by the caller. If copy_strings + * is 'true' the new elements will be freed as well. + */ +errno_t add_strings_lists(TALLOC_CTX *mem_ctx, const char **l1, const char **l2, + bool copy_strings, char ***_new_list); + /* Copy a NULL-terminated string list * Returns NULL on out of memory error or invalid input */ -- 1.8.3.1