176 enum TypeOfFunctions {
202 static int math(
struct ast_channel *chan,
const char *cmd,
char *parse,
203 char *buf,
size_t len)
210 int type_of_result = FLOAT_RESULT;
211 char *mvalue1, *mvalue2 = NULL, *mtype_of_result;
218 if (ast_strlen_zero(parse)) {
219 ast_log(LOG_WARNING,
"Syntax: MATH(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n");
226 ast_log(LOG_WARNING,
"Syntax: MATH(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n");
230 mvalue1 = args.argv0;
232 if (mvalue1[0] ==
'-') {
237 if ((op = strchr(mvalue1,
'*'))) {
238 iaction = MULTIPLYFUNCTION;
240 }
else if ((op = strchr(mvalue1,
'/'))) {
241 iaction = DIVIDEFUNCTION;
243 }
else if ((op = strchr(mvalue1,
'%'))) {
244 iaction = MODULUSFUNCTION;
246 }
else if ((op = strchr(mvalue1,
'^'))) {
247 iaction = POWFUNCTION;
249 }
else if ((op = strstr(mvalue1,
"AND"))) {
250 iaction = BITWISEANDFUNCTION;
253 }
else if ((op = strstr(mvalue1,
"XOR"))) {
254 iaction = BITWISEXORFUNCTION;
257 }
else if ((op = strstr(mvalue1,
"OR"))) {
258 iaction = BITWISEORFUNCTION;
261 }
else if ((op = strchr(mvalue1,
'>'))) {
262 iaction = GTFUNCTION;
264 if (*(op + 1) ==
'=') {
265 iaction = GTEFUNCTION;
267 }
else if (*(op + 1) ==
'>') {
268 iaction = SHRIGHTFUNCTION;
271 }
else if ((op = strchr(mvalue1,
'<'))) {
272 iaction = LTFUNCTION;
274 if (*(op + 1) ==
'=') {
275 iaction = LTEFUNCTION;
277 }
else if (*(op + 1) ==
'<') {
278 iaction = SHLEFTFUNCTION;
281 }
else if ((op = strchr(mvalue1,
'='))) {
283 if (*(op + 1) ==
'=') {
284 iaction = EQFUNCTION;
288 }
else if ((op = strchr(mvalue1,
'+'))) {
289 iaction = ADDFUNCTION;
291 }
else if ((op = strchr(mvalue1,
'-'))) {
292 iaction = SUBTRACTFUNCTION;
300 mtype_of_result = args.argv1;
301 if (mtype_of_result) {
302 if (!strcasecmp(mtype_of_result,
"float")
303 || !strcasecmp(mtype_of_result,
"f"))
304 type_of_result = FLOAT_RESULT;
305 else if (!strcasecmp(mtype_of_result,
"int")
306 || !strcasecmp(mtype_of_result,
"i"))
307 type_of_result = INT_RESULT;
308 else if (!strcasecmp(mtype_of_result,
"hex")
309 || !strcasecmp(mtype_of_result,
"h"))
310 type_of_result = HEX_RESULT;
311 else if (!strcasecmp(mtype_of_result,
"char")
312 || !strcasecmp(mtype_of_result,
"c"))
313 type_of_result = CHAR_RESULT;
315 ast_log(LOG_WARNING,
"Unknown type of result requested '%s'.\n",
323 "Supply all the parameters - just this once, please\n");
327 if (sscanf(mvalue1,
"%30lf", &fnum1) != 1) {
328 ast_log(LOG_WARNING,
"'%s' is not a valid number\n", mvalue1);
332 if (sscanf(mvalue2,
"%30lf", &fnum2) != 1) {
333 ast_log(LOG_WARNING,
"'%s' is not a valid number\n", mvalue2);
342 ftmp = fnum1 + fnum2;
348 ftmp = (fnum1 / fnum2);
350 case MULTIPLYFUNCTION:
351 ftmp = (fnum1 * fnum2);
353 case SUBTRACTFUNCTION:
354 ftmp = (fnum1 - fnum2);
356 case MODULUSFUNCTION:
364 ftmp = (inum1 % inum2);
370 ftmp = pow(fnum1, fnum2);
377 ftmp = (inum1 << inum2);
380 case SHRIGHTFUNCTION:
385 ftmp = (inum1 >> inum2);
388 case BITWISEANDFUNCTION:
392 ftmp = (inum1 & inum2);
395 case BITWISEXORFUNCTION:
399 ftmp = (inum1 ^ inum2);
402 case BITWISEORFUNCTION:
406 ftmp = (inum1 | inum2);
426 "Something happened that neither of us should be proud of %d\n",
431 if (iaction < GTFUNCTION || iaction > EQFUNCTION) {
432 if (type_of_result == FLOAT_RESULT)
433 snprintf(buf, len,
"%f", ftmp);
434 else if (type_of_result == INT_RESULT)
435 snprintf(buf, len,
"%i", (
int) ftmp);
436 else if (type_of_result == HEX_RESULT)
437 snprintf(buf, len,
"%x", (
unsigned int) ftmp);
438 else if (type_of_result == CHAR_RESULT)
439 snprintf(buf, len,
"%c", (
unsigned char) ftmp);
445 static int crement_function_read(
struct ast_channel *chan,
const char *cmd,
446 char *data,
char *buf,
size_t len)
452 char endchar = 0, returnvar[12];
454 if (ast_strlen_zero(data)) {
455 ast_log(LOG_WARNING,
"Syntax: %s(<data>) - missing argument!\n", cmd);
460 ast_log(LOG_WARNING,
"No channel was provided to %s function.\n", cmd);
464 ast_channel_lock(chan);
467 ast_log(LOG_NOTICE,
"Failed to obtain variable %s, bailing out\n", data);
468 ast_channel_unlock(chan);
472 if (ast_strlen_zero(var)) {
473 ast_log(LOG_NOTICE,
"Variable %s doesn't exist - are you sure you wrote it correctly?\n", data);
474 ast_channel_unlock(chan);
478 if (sscanf(var,
"%30d%1c", &int_value, &endchar) == 0 || endchar != 0) {
479 ast_log(LOG_NOTICE,
"The content of ${%s} is not a numeric value - bailing out!\n", data);
480 ast_channel_unlock(chan);
485 if (!strcasecmp(cmd,
"INC")) {
488 }
else if (!strcasecmp(cmd,
"DEC")) {
493 if (snprintf(returnvar,
sizeof(returnvar),
"%d", int_value) > 0) {
504 ast_log(LOG_NOTICE,
"Variable %s refused to be %sREMENTED, setting value to 0", data, cmd);
508 ast_channel_unlock(chan);
513 static int acf_min_exec(
struct ast_channel *chan,
const char *cmd,
514 char *parse,
char *buffer,
size_t buflen)
516 double num1, num2, response_num = 0;
524 if (ast_strlen_zero(args.num1) && ast_strlen_zero(args.num2)) {
525 ast_log(LOG_ERROR,
"Missing argument for number(s).");
529 if (ast_strlen_zero(args.num1)) {
531 }
else if (sscanf(args.num1,
"%30lf", &num1) != 1) {
532 ast_log(LOG_WARNING,
"'%s' is not a valid number\n", args.num1);
536 if (ast_strlen_zero(args.num2)) {
538 }
else if (sscanf(args.num2,
"%30lf", &num2) != 1) {
539 ast_log(LOG_WARNING,
"'%s' is not a valid number\n", args.num2);
543 if (response_num == -1) {
546 response_num = (num1 > num2) ? num2 : num1;
549 ast_debug(1,
"%f is the minimum of [%f,%f]\n", response_num, num1, num2);
550 if ((
int) response_num == response_num) {
551 snprintf(buffer, buflen,
"%d", (
int) response_num);
553 snprintf(buffer, buflen,
"%f", response_num);
559 static int acf_max_exec(
struct ast_channel *chan,
const char *cmd,
560 char *parse,
char *buffer,
size_t buflen)
562 double num1, num2, response_num = 0;
570 if (ast_strlen_zero(args.num1) && ast_strlen_zero(args.num2)) {
571 ast_log(LOG_ERROR,
"Missing argument for number(s).");
575 if (ast_strlen_zero(args.num1)) {
577 }
else if (sscanf(args.num1,
"%30lf", &num1) != 1) {
578 ast_log(LOG_WARNING,
"'%s' is not a valid number\n", args.num1);
582 if (ast_strlen_zero(args.num2)) {
584 }
else if (sscanf(args.num2,
"%30lf", &num2) != 1) {
585 ast_log(LOG_WARNING,
"'%s' is not a valid number\n", args.num2);
589 if (response_num == -1) {
592 response_num = (num1 < num2) ? num2 : num1;
595 ast_debug(1,
"%f is the maximum of [%f,%f]\n", response_num, num1, num2);
596 if ((
int) response_num == response_num) {
597 snprintf(buffer, buflen,
"%d", (
int) response_num);
599 snprintf(buffer, buflen,
"%f", response_num);
605 static int acf_abs_exec(
struct ast_channel *chan,
const char *cmd,
606 char *parse,
char *buffer,
size_t buflen)
608 double num1, response_num;
615 if (ast_strlen_zero(args.num1) || sscanf(args.num1,
"%30lf", &num1) != 1) {
616 ast_log(LOG_WARNING,
"Bad or missing argument for number: %s", args.num1);
620 response_num = fabs(num1);
621 ast_debug(1,
"%f is the absolute value of %f\n", response_num, num1);
622 if ((
int) response_num == response_num) {
623 snprintf(buffer, buflen,
"%d", (
int) response_num);
625 snprintf(buffer, buflen,
"%f", response_num);
638 .read = crement_function_read,
643 .read = crement_function_read,
648 .read = acf_min_exec,
654 .read = acf_max_exec,
660 .read = acf_abs_exec,
664 #ifdef TEST_FRAMEWORK
667 enum ast_test_result_state res = AST_TEST_PASS;
672 info->name =
"test_MATH_function";
673 info->category =
"/main/pbx/";
674 info->summary =
"Test MATH function substitution";
676 "Executes a series of variable substitutions using the MATH function and ensures that the expected results are received.";
677 return AST_TEST_NOT_RUN;
682 ast_test_status_update(
test,
"Testing MATH() substitution ...\n");
685 return AST_TEST_FAIL;
689 return AST_TEST_FAIL;
695 ast_test_status_update(
test,
"Expected result '42' not returned! ('%s')\n",
703 ast_test_status_update(
test,
"Expected result '42' not returned! ('%s')\n",
715 static int unload_module(
void)
725 AST_TEST_UNREGISTER(test_MATH_function);
730 static int load_module(
void)
740 AST_TEST_REGISTER(test_MATH_function);
745 AST_MODULE_INFO_STANDARD(
ASTERISK_GPL_KEY,
"Mathematical dialplan function");
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Configuration File Parser.
General Asterisk PBX channel definitions.
Data structure associated with a custom dialplan function.
Conversion utility functions.
#define ast_debug(level,...)
Log a DEBUG message.
Core PBX routines and definitions.
Support for dynamic strings.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define AST_TEST_DEFINE(hdr)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define AST_APP_ARG(name)
Define an application argument.