Use the same delimited character as the FILTER function in FIELDQTY and CUT.
[asterisk/asterisk.git] / funcs / func_math.c
index 608135c..70882d1 100644 (file)
@@ -22,6 +22,8 @@
  *
  * \author Andy Powell
  * \author Mark Spencer <markster@digium.com>
+ *
+ * \ingroup functions
  */
 
 #include "asterisk.h"
@@ -31,6 +33,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <math.h>
 #include <sys/types.h>
 
 #include "asterisk/module.h"
@@ -47,6 +50,12 @@ enum TypeOfFunctions {
        MULTIPLYFUNCTION,
        SUBTRACTFUNCTION,
        MODULUSFUNCTION,
+       POWFUNCTION,
+       SHLEFTFUNCTION,
+       SHRIGHTFUNCTION,
+       BITWISEANDFUNCTION,
+       BITWISEXORFUNCTION,
+       BITWISEORFUNCTION,
        GTFUNCTION,
        LTFUNCTION,
        GTEFUNCTION,
@@ -61,16 +70,17 @@ enum TypeOfResult {
        CHAR_RESULT
 };
 
-static int math(struct ast_channel *chan, char *cmd, char *parse,
+static int math(struct ast_channel *chan, const char *cmd, char *parse,
                char *buf, size_t len)
 {
-       float fnum1;
-       float fnum2;
-       float ftmp = 0;
+       double fnum1;
+       double fnum2;
+       double ftmp = 0;
        char *op;
        int iaction = -1;
        int type_of_result = FLOAT_RESULT;
        char *mvalue1, *mvalue2 = NULL, *mtype_of_result;
+       int negvalue1 = 0;
        AST_DECLARE_APP_ARGS(args,
                             AST_APP_ARG(argv0);
                             AST_APP_ARG(argv1);
@@ -90,13 +100,12 @@ static int math(struct ast_channel *chan, char *cmd, char *parse,
 
        mvalue1 = args.argv0;
 
-       if ((op = strchr(mvalue1, '+'))) {
-               iaction = ADDFUNCTION;
-               *op = '\0';
-       } else if ((op = strchr(mvalue1, '-'))) {
-               iaction = SUBTRACTFUNCTION;
-               *op = '\0';
-       } else if ((op = strchr(mvalue1, '*'))) {
+       if (mvalue1[0] == '-') {
+               negvalue1 = 1;
+               mvalue1++;
+       }
+
+       if ((op = strchr(mvalue1, '*'))) {
                iaction = MULTIPLYFUNCTION;
                *op = '\0';
        } else if ((op = strchr(mvalue1, '/'))) {
@@ -105,12 +114,30 @@ static int math(struct ast_channel *chan, char *cmd, char *parse,
        } else if ((op = strchr(mvalue1, '%'))) {
                iaction = MODULUSFUNCTION;
                *op = '\0';
+       } else if ((op = strchr(mvalue1, '^'))) {
+               iaction = POWFUNCTION;
+               *op = '\0';
+       } else if ((op = strstr(mvalue1, "AND"))) {
+               iaction = BITWISEANDFUNCTION;
+               op += 3;
+               *op = '\0';
+       } else if ((op = strstr(mvalue1, "XOR"))) {
+               iaction = BITWISEXORFUNCTION;
+               op += 3;
+               *op = '\0';
+       } else if ((op = strstr(mvalue1, "OR"))) {
+               iaction = BITWISEORFUNCTION;
+               op += 2;
+               *op = '\0';
        } else if ((op = strchr(mvalue1, '>'))) {
                iaction = GTFUNCTION;
                *op = '\0';
                if (*(op + 1) == '=') {
                        *++op = '\0';
                        iaction = GTEFUNCTION;
+               } else if (*(op + 1) == '>') {
+                       *++op = '\0';
+                       iaction = SHRIGHTFUNCTION;
                }
        } else if ((op = strchr(mvalue1, '<'))) {
                iaction = LTFUNCTION;
@@ -118,15 +145,23 @@ static int math(struct ast_channel *chan, char *cmd, char *parse,
                if (*(op + 1) == '=') {
                        *++op = '\0';
                        iaction = LTEFUNCTION;
+               } else if (*(op + 1) == '<') {
+                       *++op = '\0';
+                       iaction = SHLEFTFUNCTION;
                }
        } else if ((op = strchr(mvalue1, '='))) {
-               iaction = GTFUNCTION;
                *op = '\0';
                if (*(op + 1) == '=') {
                        *++op = '\0';
                        iaction = EQFUNCTION;
                } else
                        op = NULL;
+       } else if ((op = strchr(mvalue1, '+'))) {
+               iaction = ADDFUNCTION;
+               *op = '\0';
+       } else if ((op = strchr(mvalue1, '-'))) { /* subtraction MUST always be last, in case we have a negative first number */
+               iaction = SUBTRACTFUNCTION;
+               *op = '\0';
        }
 
        if (op)
@@ -160,16 +195,19 @@ static int math(struct ast_channel *chan, char *cmd, char *parse,
                return -1;
        }
 
-       if (sscanf(mvalue1, "%f", &fnum1) != 1) {
+       if (sscanf(mvalue1, "%lf", &fnum1) != 1) {
                ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue1);
                return -1;
        }
 
-       if (sscanf(mvalue2, "%f", &fnum2) != 1) {
+       if (sscanf(mvalue2, "%lf", &fnum2) != 1) {
                ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue2);
                return -1;
        }
 
+       if (negvalue1)
+               fnum1 = 0 - fnum1;
+
        switch (iaction) {
        case ADDFUNCTION:
                ftmp = fnum1 + fnum2;
@@ -195,6 +233,46 @@ static int math(struct ast_channel *chan, char *cmd, char *parse,
 
                        break;
                }
+       case POWFUNCTION:
+               ftmp = pow(fnum1, fnum2);
+               break;
+       case SHLEFTFUNCTION:
+               {
+                       int inum1 = fnum1;
+                       int inum2 = fnum2;
+
+                       ftmp = (inum1 << inum2);
+                       break;
+               }
+       case SHRIGHTFUNCTION:
+               {
+                       int inum1 = fnum1;
+                       int inum2 = fnum2;
+
+                       ftmp = (inum1 >> inum2);
+                       break;
+               }
+       case BITWISEANDFUNCTION:
+               {
+                       int inum1 = fnum1;
+                       int inum2 = fnum2;
+                       ftmp = (inum1 & inum2);
+                       break;
+               }
+       case BITWISEXORFUNCTION:
+               {
+                       int inum1 = fnum1;
+                       int inum2 = fnum2;
+                       ftmp = (inum1 ^ inum2);
+                       break;
+               }
+       case BITWISEORFUNCTION:
+               {
+                       int inum1 = fnum1;
+                       int inum2 = fnum2;
+                       ftmp = (inum1 | inum2);
+                       break;
+               }
        case GTFUNCTION:
                ast_copy_string(buf, (fnum1 > fnum2) ? "TRUE" : "FALSE", len);
                break;
@@ -234,9 +312,9 @@ static int math(struct ast_channel *chan, char *cmd, char *parse,
 static struct ast_custom_function math_function = {
        .name = "MATH",
        .synopsis = "Performs Mathematical Functions",
-       .syntax = "MATH(<number1><op><number 2>[,<type_of_result>])",
-       .desc = "Perform calculation on number 1 to number 2. Valid ops are: \n"
-               "    +,-,/,*,%,<,>,>=,<=,==\n"
+       .syntax = "MATH(<number1><op><number2>[,<type_of_result>])",
+       .desc = "Perform calculation on number1 to number2. Valid ops are: \n"
+               "    +,-,/,*,%,<<,>>,^,AND,OR,XOR,<,>,>=,<=,==\n"
                "and behave as their C equivalents.\n"
                "<type_of_result> - wanted type of result:\n"
                "       f, float - float(default)\n"