diff --git a/doc/CHANGES-staging/func_min_max.txt b/doc/CHANGES-staging/func_min_max.txt new file mode 100644 index 0000000000000000000000000000000000000000..df2b6653e0ac4be6342df63c1c3c4647e4a559ef --- /dev/null +++ b/doc/CHANGES-staging/func_min_max.txt @@ -0,0 +1,4 @@ +Subject: func_math: Three new dialplan functions + +Introduce three new functions, MIN, MAX, and ABS, which can be used to +obtain the minimum or maximum of up to two integers or absolute value. diff --git a/funcs/func_math.c b/funcs/func_math.c index 6fc725581b130e280dc60fc94559bde75aed22b3..b8a6eb6fdef70a58fe7e464d29fa1ab4181fdfec 100644 --- a/funcs/func_math.c +++ b/funcs/func_math.c @@ -5,6 +5,7 @@ * * Updated by Mark Spencer <markster@digium.com> * Updated by Nir Simionovich <nirs@greenfieldtech.net> + * Updated by Naveen Albert <asterisk@phreaknet.org> * * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact @@ -24,6 +25,7 @@ * \author Andy Powell * \author Mark Spencer <markster@digium.com> * \author Nir Simionovich <nirs@greenfieldtech.net> + * \author Naveen Albert <asterisk@phreaknet.org> * * \ingroup functions */ @@ -40,6 +42,7 @@ #include "asterisk/channel.h" #include "asterisk/pbx.h" #include "asterisk/utils.h" +#include "asterisk/conversions.h" #include "asterisk/app.h" #include "asterisk/config.h" #include "asterisk/test.h" @@ -105,6 +108,47 @@ <para>Note: DEC(${MyVAR}) - Is wrong, as DEC expects the variable name, not its value</para> </description> </function> + <function name="MIN" language="en_US"> + <synopsis> + Returns the minimum of two numbers. + </synopsis> + <syntax> + <parameter name="num1" /> + <parameter name="num2" /> + </syntax> + <description> + <para>Returns the minimum of two numbers <replaceable>num1</replaceable> and <replaceable>num2</replaceable>.</para> + <para>Example: Set(min=${MIN(7,4)}); + Sets the min variable equal to 4.</para> + </description> + </function> + <function name="MAX" language="en_US"> + <synopsis> + Returns the maximum of two numbers. + </synopsis> + <syntax> + <parameter name="num1" /> + <parameter name="num2" /> + </syntax> + <description> + <para>Returns the maximum of two numbers <replaceable>num1</replaceable> and <replaceable>num2</replaceable>.</para> + <para>Example: Set(max=${MAX(4,7)}); + Sets the max variable equal to 7.</para> + </description> + </function> + <function name="ABS" language="en_US"> + <synopsis> + Returns absolute value of a number. + </synopsis> + <syntax> + <parameter name="num" /> + </syntax> + <description> + <para>Returns the absolute value of a number <replaceable>num</replaceable>.</para> + <para>Example: Set(absval=${ABS(-13)}); + Sets the absval variable equal to 13.</para> + </description> + </function> ***/ enum TypeOfFunctions { @@ -444,6 +488,111 @@ static int crement_function_read(struct ast_channel *chan, const char *cmd, return ret; } +static int acf_min_exec(struct ast_channel *chan, const char *cmd, + char *parse, char *buffer, size_t buflen) +{ + double num1, num2, response_num = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(num1); + AST_APP_ARG(num2); + ); + + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.num1) && ast_strlen_zero(args.num2)) { + ast_log(LOG_ERROR, "Missing argument for number(s)."); + return -1; + } + + if (ast_strlen_zero(args.num1)) { + response_num = -1; /* couldn't read num1 successfully */ + } else if (sscanf(args.num1, "%30lf", &num1) != 1) { + ast_log(LOG_WARNING, "'%s' is not a valid number\n", args.num1); + return -1; + } + + if (ast_strlen_zero(args.num2)) { + num2 = num1; /* num1 must be a valid integer here */ + } else if (sscanf(args.num2, "%30lf", &num2) != 1) { + ast_log(LOG_WARNING, "'%s' is not a valid number\n", args.num2); + return -1; + } + + if (response_num == -1) { /* could only read num2 */ + response_num = num2; + } else { + response_num = (num1 > num2) ? num2 : num1; + } + + ast_debug(1, "%f is the minimum of [%f,%f]\n", response_num, num1, num2); + snprintf(buffer, buflen, "%f", response_num); + + return 0; +} + +static int acf_max_exec(struct ast_channel *chan, const char *cmd, + char *parse, char *buffer, size_t buflen) +{ + double num1, num2, response_num = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(num1); + AST_APP_ARG(num2); + ); + + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.num1) && ast_strlen_zero(args.num2)) { + ast_log(LOG_ERROR, "Missing argument for number(s)."); + return -1; + } + + if (ast_strlen_zero(args.num1)) { + response_num = -1; /* couldn't read num1 successfully */ + } else if (sscanf(args.num1, "%30lf", &num1) != 1) { + ast_log(LOG_WARNING, "'%s' is not a valid number\n", args.num1); + return -1; + } + + if (ast_strlen_zero(args.num2)) { + num2 = num1; /* num1 must be a valid integer here */ + } else if (sscanf(args.num2, "%30lf", &num2) != 1) { + ast_log(LOG_WARNING, "'%s' is not a valid number\n", args.num2); + return -1; + } + + if (response_num == -1) { /* could only read num2 */ + response_num = num2; + } else { + response_num = (num1 < num2) ? num2 : num1; + } + + ast_debug(1, "%f is the maximum of [%f,%f]\n", response_num, num1, num2); + snprintf(buffer, buflen, "%f", response_num); + + return 0; +} + +static int acf_abs_exec(struct ast_channel *chan, const char *cmd, + char *parse, char *buffer, size_t buflen) +{ + double num1, response_num; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(num1); + ); + + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.num1) || sscanf(args.num1, "%30lf", &num1) != 1) { + ast_log(LOG_WARNING, "Bad or missing argument for number: %s", args.num1); + return -1; + } + + response_num = fabs(num1); + ast_debug(1, "%f is the absolute value of %f\n", response_num, num1); + snprintf(buffer, buflen, "%f", response_num); + + return 0; +} static struct ast_custom_function math_function = { .name = "MATH", @@ -460,6 +609,24 @@ static struct ast_custom_function decrement_function = { .read = crement_function_read, }; +static struct ast_custom_function acf_min = { + .name = "MIN", + .read = acf_min_exec, + .read_max = 12, +}; + +static struct ast_custom_function acf_max = { + .name = "MAX", + .read = acf_max_exec, + .read_max = 12, +}; + +static struct ast_custom_function acf_abs = { + .name = "ABS", + .read = acf_abs_exec, + .read_max = 12, +}; + #ifdef TEST_FRAMEWORK AST_TEST_DEFINE(test_MATH_function) { @@ -518,6 +685,9 @@ static int unload_module(void) res |= ast_custom_function_unregister(&math_function); res |= ast_custom_function_unregister(&increment_function); res |= ast_custom_function_unregister(&decrement_function); + res |= ast_custom_function_unregister(&acf_min); + res |= ast_custom_function_unregister(&acf_max); + res |= ast_custom_function_unregister(&acf_abs); AST_TEST_UNREGISTER(test_MATH_function); return res; @@ -530,6 +700,9 @@ static int load_module(void) res |= ast_custom_function_register(&math_function); res |= ast_custom_function_register(&increment_function); res |= ast_custom_function_register(&decrement_function); + res |= ast_custom_function_register(&acf_min); + res |= ast_custom_function_register(&acf_max); + res |= ast_custom_function_register(&acf_abs); AST_TEST_REGISTER(test_MATH_function); return res;