From b5391ff69101fd8d72693554537d144c6af25c01 Mon Sep 17 00:00:00 2001 From: George Joseph <gjoseph@digium.com> Date: Sun, 20 Feb 2022 13:16:22 -0700 Subject: [PATCH] core: Config and XML tweaks needed for geolocation Added: Replace a variable in a list: int ast_variable_list_replace_variable(struct ast_variable **head, struct ast_variable *old, struct ast_variable *new); Added test as well. Create a "name=value" string from a variable list: 'name1="val1",name2="val2"', etc. struct ast_str *ast_variable_list_join( const struct ast_variable *head, const char *item_separator, const char *name_value_separator, const char *quote_char, struct ast_str **str); Added test as well. Allow the name of an XML element to be changed. void ast_xml_set_name(struct ast_xml_node *node, const char *name); Change-Id: I330a5f63dc0c218e0d8dfc0745948d2812141ccb --- include/asterisk/config.h | 38 ++++++++++++++++++++++++++++ include/asterisk/xml.h | 7 ++++++ main/config.c | 43 ++++++++++++++++++++++++++++++++ main/xml.c | 9 +++++++ tests/test_config.c | 52 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+) diff --git a/include/asterisk/config.h b/include/asterisk/config.h index f4d1dd29d0..f4f6c9d5f7 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -967,6 +967,44 @@ struct ast_variable *ast_variable_list_append_hint(struct ast_variable **head, s */ int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement); +/*! + * \brief Replace a variable in the given list with a new variable + * + * \param head A pointer to the current variable list head. Since the variable to be + * replaced, this pointer may be updated with the new head. + * \param old A pointer to the existing variable to be replaced. + * \param new A pointer to the new variable that will replace the old one. + * + * \retval 0 if a variable was replaced in the list + * \retval -1 if no replacement occured + * + * \note The search for the old variable is done simply on the pointer. + * \note If a variable is replaced, its memory is freed. + */ +int ast_variable_list_replace_variable(struct ast_variable **head, struct ast_variable *old, + struct ast_variable *new); + +/*! + * \brief Join an ast_variable list with specified separators and quoted values + * + * \param head A pointer to an ast_variable list head. + * \param item_separator The string to use to separate the list items. + * If NULL, "," will be used. + * \param name_value_separator The string to use to separate each item's name and value. + * If NULL, "=" will be used. + * \param str A pointer to a pre-allocated ast_str in which to put the results. + * If NULL, one will be allocated and returned. + * \param quote_char The quote char to use for the values. + * May be NULL or empty for no quoting. + * + * \retval A pointer to the result ast_str. This may NOT be the same as the pointer + * passed in if the original ast_str wasn't large enough to hold the result. + * Regardless, the pointer MUST be freed after use. + * \retval NULL if there was an error. + */ +struct ast_str *ast_variable_list_join(const struct ast_variable *head, const char *item_separator, + const char *name_value_separator, const char *quote_char, struct ast_str **str); + /*! * \brief Update variable value within a config * diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h index 3217750ad1..13af3c6b60 100644 --- a/include/asterisk/xml.h +++ b/include/asterisk/xml.h @@ -201,6 +201,13 @@ const char *ast_xml_get_text(struct ast_xml_node *node); */ void ast_xml_set_text(struct ast_xml_node *node, const char *content); +/*! + * \brief Set or reset an element's name. + * \param node Node whose name is to be set. + * \param name New name. + */ +void ast_xml_set_name(struct ast_xml_node *node, const char *name); + /*! * \brief Get the name of a node. */ const char *ast_xml_node_get_name(struct ast_xml_node *node); diff --git a/main/config.c b/main/config.c index 7b3b457d72..92a24de634 100644 --- a/main/config.c +++ b/main/config.c @@ -679,6 +679,49 @@ int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *r return -1; } +int ast_variable_list_replace_variable(struct ast_variable **head, struct ast_variable *old, + struct ast_variable *new) +{ + struct ast_variable *v, **prev = head; + + for (v = *head; v; prev = &v->next, v = v->next) { + if (v == old) { + new->next = v->next; + *prev = new; + ast_free(v); + return 0; + } + } + + return -1; +} + +struct ast_str *ast_variable_list_join(const struct ast_variable *head, const char *item_separator, + const char *name_value_separator, const char *quote_char, struct ast_str **str) +{ + struct ast_variable *var = (struct ast_variable *)head; + struct ast_str *local_str = NULL; + + if (str == NULL || *str == NULL) { + local_str = ast_str_create(AST_MAX_USER_FIELD); + if (!local_str) { + return NULL; + } + } else { + local_str = *str; + } + + for (; var; var = var->next) { + ast_str_append(&local_str, 0, "%s%s%s%s%s%s", var->name, name_value_separator, S_OR(quote_char, ""), + var->value, S_OR(quote_char, ""), var->next ? item_separator : ""); + } + + if (str != NULL) { + *str = local_str; + } + return local_str; +} + const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var) { const char *tmp; diff --git a/main/xml.c b/main/xml.c index d60dd90bcd..88c9edffde 100644 --- a/main/xml.c +++ b/main/xml.c @@ -332,6 +332,15 @@ void ast_xml_set_text(struct ast_xml_node *node, const char *content) xmlNodeSetContent((xmlNode *) node, (const xmlChar *) content); } +void ast_xml_set_name(struct ast_xml_node *node, const char *name) +{ + if (!node || !name) { + return; + } + + xmlNodeSetName((xmlNode *) node, (const xmlChar *) name); +} + int ast_xml_doc_dump_file(FILE *output, struct ast_xml_doc *doc) { return xmlDocDump(output, (xmlDocPtr)doc); diff --git a/tests/test_config.c b/tests/test_config.c index 770aa15bb9..5b44b446e0 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -1893,6 +1893,56 @@ AST_TEST_DEFINE(variable_lists_match) return AST_TEST_PASS; } +AST_TEST_DEFINE(variable_list_join_replace) +{ + RAII_VAR(struct ast_variable *, list, NULL, ast_variables_destroy); + RAII_VAR(struct ast_str *, str, NULL, ast_free); + struct ast_variable *bbb; + int rc; + + switch (cmd) { + case TEST_INIT: + info->name = "variable_list_join_replace"; + info->category = "/main/config/"; + info->summary = "Test joining a variable list"; + info->description = info->summary; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + list = ast_variable_new("aaa", "111", ""); + bbb = ast_variable_new("bbb", "222", ""); + ast_variable_list_append(&list, bbb); + ast_variable_list_append(&list, ast_variable_new("ccc", "33 33", "")); + + str = ast_variable_list_join(list, ", ", " = ", "\"", &str); + ast_test_validate(test, strcmp(ast_str_buffer(str), "aaa = \"111\", bbb = \"222\", ccc = \"33 33\"") == 0); + ast_free(str); + + str = ast_str_create(AST_MAX_USER_FIELD); + str = ast_variable_list_join(list, ", ", " = ", "\"", &str); + ast_test_validate(test, strcmp(ast_str_buffer(str), "aaa = \"111\", bbb = \"222\", ccc = \"33 33\"") == 0); + ast_free(str); + + str = ast_variable_list_join(list, ", ", " = ", "\"", NULL); + ast_test_validate(test, strcmp(ast_str_buffer(str), "aaa = \"111\", bbb = \"222\", ccc = \"33 33\"") == 0); + ast_free(str); + + /* Replace the head item in the list */ + rc = ast_variable_list_replace_variable(&list, list, ast_variable_new("ddd", "444", "")); + ast_test_validate(test, rc == 0); + str = ast_variable_list_join(list, ", ", " = ", "\"", NULL); + ast_test_validate(test, strcmp(ast_str_buffer(str), "ddd = \"444\", bbb = \"222\", ccc = \"33 33\"") == 0); + ast_free(str); + + rc = ast_variable_list_replace_variable(&list, bbb, ast_variable_new("eee", "555", "")); + ast_test_validate(test, rc == 0); + str = ast_variable_list_join(list, ", ", " = ", "\"", NULL); + ast_test_validate(test, strcmp(ast_str_buffer(str), "ddd = \"444\", eee = \"555\", ccc = \"33 33\"") == 0); + + return AST_TEST_PASS; +} static int unload_module(void) { AST_TEST_UNREGISTER(config_save); @@ -1905,6 +1955,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(config_options_test); AST_TEST_UNREGISTER(config_dialplan_function); AST_TEST_UNREGISTER(variable_lists_match); + AST_TEST_UNREGISTER(variable_list_join_replace); return 0; } @@ -1920,6 +1971,7 @@ static int load_module(void) AST_TEST_REGISTER(config_options_test); AST_TEST_REGISTER(config_dialplan_function); AST_TEST_REGISTER(variable_lists_match); + AST_TEST_REGISTER(variable_list_join_replace); return AST_MODULE_LOAD_SUCCESS; } -- GitLab