From 685f7ef924dd8dd8d5404d76c39bb95ebfa8b90b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 7 Jan 2015 17:54:13 +0000 Subject: func_config: Add ability to retrieve specific occurrence of a variable I guess nobody uses templates with AST_CONFIG because today if you have a context that inherits from a template and you call AST_CONFIG on the context, you'll get the value from the template even if you've overridden it in the context. This is because AST_CONFIG only gets the first occurrence which is always from the template. This patch adds an optional 'index' parameter to AST_CONFIG which lets you specify the exact occurrence to retrieve, or '-1' to retrieve the last. The default behavior is the current behavior. Tested-by: George Joseph Review: https://reviewboard.asterisk.org/r/4313/ ........ Merged revisions 430315 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@430316 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- funcs/func_config.c | 46 +++++++++++++--- tests/test_config.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+), 7 deletions(-) diff --git a/funcs/func_config.c b/funcs/func_config.c index 1123b0b84..ca6dad1a1 100644 --- a/funcs/func_config.c +++ b/funcs/func_config.c @@ -49,6 +49,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + + If there are multiple variables with the same name, you can specify + 0 for the first item (default), -1 for the last + item, or any other number for that specific item. -1 is useful + when the variable is derived from a template and you want the effective value (the last + occurrence), not the value from the template (the first occurrence). + This function reads a variable from an Asterisk configuration file. @@ -65,14 +72,17 @@ struct config_item { static AST_RWLIST_HEAD_STATIC(configs, config_item); -static int config_function_read(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) +static int config_function_read(struct ast_channel *chan, const char *cmd, char *data, + char *buf, size_t len) { struct ast_config *cfg; struct ast_flags cfg_flags = { CONFIG_FLAG_FILEUNCHANGED }; - const char *val; char *parse; struct config_item *cur; + int index = 0; + struct ast_variable *var; + struct ast_variable *found = NULL; + int ix = 0; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(filename); AST_APP_ARG(category); @@ -103,6 +113,13 @@ static int config_function_read(struct ast_channel *chan, const char *cmd, char return -1; } + if (!ast_strlen_zero(args.index)) { + if (!sscanf(args.index, "%d", &index)) { + ast_log(LOG_ERROR, "AST_CONFIG() index must be an integer\n"); + return -1; + } + } + if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { return -1; } @@ -164,14 +181,29 @@ static int config_function_read(struct ast_channel *chan, const char *cmd, char } } - if (!(val = ast_variable_retrieve(cfg, args.category, args.variable))) { - ast_debug(1, "'%s' not found in [%s] of '%s'\n", args.variable, - args.category, args.filename); + for (var = ast_category_root(cfg, args.category); var; var = var->next) { + if (strcasecmp(args.variable, var->name)) { + continue; + } + found = var; + if (index == -1) { + continue; + } + if (ix == index) { + break; + } + found = NULL; + ix++; + } + + if (!found) { + ast_debug(1, "'%s' not found at index %d in [%s] of '%s'. Maximum index found: %d\n", + args.variable, index, args.category, args.filename, ix); AST_RWLIST_UNLOCK(&configs); return -1; } - ast_copy_string(buf, val, len); + ast_copy_string(buf, found->value, len); /* Unlock down here, so there's no chance the struct goes away while we're using it. */ AST_RWLIST_UNLOCK(&configs); diff --git a/tests/test_config.c b/tests/test_config.c index 84c4ece08..df618f9f7 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$"); #include "asterisk/config_options.h" #include "asterisk/netsock2.h" #include "asterisk/acl.h" +#include "asterisk/pbx.h" #include "asterisk/frame.h" #include "asterisk/utils.h" #include "asterisk/logger.h" @@ -1504,6 +1505,156 @@ AST_TEST_DEFINE(config_options_test) return res; } +AST_TEST_DEFINE(config_dialplan_function) +{ + enum ast_test_result_state res = AST_TEST_PASS; + FILE *config_file; + char filename[PATH_MAX]; + struct ast_str *buf; + + switch (cmd) { + case TEST_INIT: + info->name = "config_dialplan_function"; + info->category = "/main/config/"; + info->summary = "Test AST_CONFIG dialplan function"; + info->description = "Test AST_CONFIG dialplan function"; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + snprintf(filename, sizeof(filename), "%s/%s", + ast_config_AST_CONFIG_DIR, CONFIG_FILE); + config_file = fopen(filename, "w"); + + if (!config_file) { + return AST_TEST_FAIL; + } + + fputs( + "[c1t](!)\n" + "var1=val1\n" + "var1=val2\n" + "var2=val21\n" + "\n" + "[c1](c1t)\n" + "var1=val3\n" + "var1=val4\n" + , config_file); + + fclose(config_file); + + if (!(buf = ast_str_create(32))) { + ast_test_status_update(test, "Failed to allocate return buffer\n"); + res = AST_TEST_FAIL; + goto out; + } + + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var1'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val1")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val1"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,0)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var1'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val1")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val1"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,1)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var1'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val2")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val2"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,2)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var1'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val3")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val3"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,3)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var1'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val4")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val4"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,-1)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var1'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val4")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val4"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var2,-1)", &buf, 32)) { + ast_test_status_update(test, "Failed to retrieve field 'var2'\n"); + res = AST_TEST_FAIL; + goto out; + } + if (strcmp(ast_str_buffer(buf), "val21")) { + ast_test_status_update(test, "Got '%s', should be '%s'\n", + ast_str_buffer(buf), "val21"); + res = AST_TEST_FAIL; + goto out; + } + + ast_str_reset(buf); + if (!ast_func_read2(NULL, "AST_CONFIG("CONFIG_FILE",c1,var1,5)", &buf, 32)) { + ast_test_status_update(test, "Should not have retrieved a value\n"); + res = AST_TEST_FAIL; + goto out; + } + +out: + if (buf) { + ast_free(buf); + } + delete_config_file(); + return res; +} + static int unload_module(void) { AST_TEST_UNREGISTER(config_basic_ops); @@ -1513,6 +1664,7 @@ static int unload_module(void) AST_TEST_UNREGISTER(config_hook); AST_TEST_UNREGISTER(ast_parse_arg_test); AST_TEST_UNREGISTER(config_options_test); + AST_TEST_UNREGISTER(config_dialplan_function); return 0; } @@ -1525,6 +1677,7 @@ static int load_module(void) AST_TEST_REGISTER(config_hook); AST_TEST_REGISTER(ast_parse_arg_test); AST_TEST_REGISTER(config_options_test); + AST_TEST_REGISTER(config_dialplan_function); return AST_MODULE_LOAD_SUCCESS; } -- cgit v1.2.3