Thu Apr 28 2011 17:15:22

Asterisk developer's documentation


func_math.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2004 - 2006, Andy Powell 
00005  *
00006  * Updated by Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Math related dialplan function
00022  *
00023  * \author Andy Powell
00024  * \author Mark Spencer <markster@digium.com>
00025  *
00026  * \ingroup functions
00027  */
00028 
00029 #include "asterisk.h"
00030 
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 244334 $")
00032 
00033 #include <math.h>
00034 
00035 #include "asterisk/module.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/app.h"
00040 #include "asterisk/config.h"
00041 
00042 /*** DOCUMENTATION
00043    <function name="MATH" language="en_US">
00044       <synopsis>
00045          Performs Mathematical Functions.
00046       </synopsis>
00047       <syntax>
00048          <parameter name="expression" required="true">
00049             <para>Is of the form:
00050             <replaceable>number1</replaceable><replaceable>op</replaceable><replaceable>number2</replaceable>
00051             where the possible values for <replaceable>op</replaceable>
00052             are:</para>
00053             <para>+,-,/,*,%,&lt;&lt;,&gt;&gt;,^,AND,OR,XOR,&lt;,%gt;,&gt;=,&lt;=,== (and behave as their C equivalents)</para>
00054          </parameter>
00055          <parameter name="type">
00056             <para>Wanted type of result:</para>
00057             <para>f, float - float(default)</para>
00058             <para>i, int - integer</para>
00059             <para>h, hex - hex</para>
00060             <para>c, char - char</para>
00061          </parameter>
00062       </syntax>
00063       <description>
00064          <para>Performs mathematical functions based on two parameters and an operator.  The returned
00065          value type is <replaceable>type</replaceable></para>
00066          <para>Example: Set(i=${MATH(123%16,int)}) - sets var i=11</para>
00067       </description>
00068    </function>
00069  ***/
00070 
00071 enum TypeOfFunctions {
00072    ADDFUNCTION,
00073    DIVIDEFUNCTION,
00074    MULTIPLYFUNCTION,
00075    SUBTRACTFUNCTION,
00076    MODULUSFUNCTION,
00077    POWFUNCTION,
00078    SHLEFTFUNCTION,
00079    SHRIGHTFUNCTION,
00080    BITWISEANDFUNCTION,
00081    BITWISEXORFUNCTION,
00082    BITWISEORFUNCTION,
00083    GTFUNCTION,
00084    LTFUNCTION,
00085    GTEFUNCTION,
00086    LTEFUNCTION,
00087    EQFUNCTION
00088 };
00089 
00090 enum TypeOfResult {
00091    FLOAT_RESULT,
00092    INT_RESULT,
00093    HEX_RESULT,
00094    CHAR_RESULT
00095 };
00096 
00097 static int math(struct ast_channel *chan, const char *cmd, char *parse,
00098       char *buf, size_t len)
00099 {
00100    double fnum1;
00101    double fnum2;
00102    double ftmp = 0;
00103    char *op;
00104    int iaction = -1;
00105    int type_of_result = FLOAT_RESULT;
00106    char *mvalue1, *mvalue2 = NULL, *mtype_of_result;
00107    int negvalue1 = 0;
00108    AST_DECLARE_APP_ARGS(args,
00109               AST_APP_ARG(argv0);
00110               AST_APP_ARG(argv1);
00111    );
00112 
00113    if (ast_strlen_zero(parse)) {
00114       ast_log(LOG_WARNING, "Syntax: MATH(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n");
00115       return -1;
00116    }
00117 
00118    AST_STANDARD_APP_ARGS(args, parse);
00119 
00120    if (args.argc < 1) {
00121       ast_log(LOG_WARNING, "Syntax: MATH(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n");
00122       return -1;
00123    }
00124 
00125    mvalue1 = args.argv0;
00126 
00127    if (mvalue1[0] == '-') {
00128       negvalue1 = 1;
00129       mvalue1++;
00130    }
00131 
00132    if ((op = strchr(mvalue1, '*'))) {
00133       iaction = MULTIPLYFUNCTION;
00134       *op = '\0';
00135    } else if ((op = strchr(mvalue1, '/'))) {
00136       iaction = DIVIDEFUNCTION;
00137       *op = '\0';
00138    } else if ((op = strchr(mvalue1, '%'))) {
00139       iaction = MODULUSFUNCTION;
00140       *op = '\0';
00141    } else if ((op = strchr(mvalue1, '^'))) {
00142       iaction = POWFUNCTION;
00143       *op = '\0';
00144    } else if ((op = strstr(mvalue1, "AND"))) {
00145       iaction = BITWISEANDFUNCTION;
00146       *op = '\0';
00147       op += 2;
00148    } else if ((op = strstr(mvalue1, "XOR"))) {
00149       iaction = BITWISEXORFUNCTION;
00150       *op = '\0';
00151       op += 2;
00152    } else if ((op = strstr(mvalue1, "OR"))) {
00153       iaction = BITWISEORFUNCTION;
00154       *op = '\0';
00155       ++op;
00156    } else if ((op = strchr(mvalue1, '>'))) {
00157       iaction = GTFUNCTION;
00158       *op = '\0';
00159       if (*(op + 1) == '=') {
00160          iaction = GTEFUNCTION;
00161          ++op;
00162       } else if (*(op + 1) == '>') {
00163          iaction = SHRIGHTFUNCTION;
00164          ++op;
00165       }
00166    } else if ((op = strchr(mvalue1, '<'))) {
00167       iaction = LTFUNCTION;
00168       *op = '\0';
00169       if (*(op + 1) == '=') {
00170          iaction = LTEFUNCTION;
00171          ++op;
00172       } else if (*(op + 1) == '<') {
00173          iaction = SHLEFTFUNCTION;
00174          ++op;
00175       }
00176    } else if ((op = strchr(mvalue1, '='))) {
00177       *op = '\0';
00178       if (*(op + 1) == '=') {
00179          iaction = EQFUNCTION;
00180          ++op;
00181       } else
00182          op = NULL;
00183    } else if ((op = strchr(mvalue1, '+'))) {
00184       iaction = ADDFUNCTION;
00185       *op = '\0';
00186    } else if ((op = strchr(mvalue1, '-'))) { /* subtraction MUST always be last, in case we have a negative second number */
00187       iaction = SUBTRACTFUNCTION;
00188       *op = '\0';
00189    }
00190 
00191    if (op)
00192       mvalue2 = op + 1;
00193 
00194    /* detect wanted type of result */
00195    mtype_of_result = args.argv1;
00196    if (mtype_of_result) {
00197       if (!strcasecmp(mtype_of_result, "float")
00198           || !strcasecmp(mtype_of_result, "f"))
00199          type_of_result = FLOAT_RESULT;
00200       else if (!strcasecmp(mtype_of_result, "int")
00201           || !strcasecmp(mtype_of_result, "i"))
00202          type_of_result = INT_RESULT;
00203       else if (!strcasecmp(mtype_of_result, "hex")
00204           || !strcasecmp(mtype_of_result, "h"))
00205          type_of_result = HEX_RESULT;
00206       else if (!strcasecmp(mtype_of_result, "char")
00207           || !strcasecmp(mtype_of_result, "c"))
00208          type_of_result = CHAR_RESULT;
00209       else {
00210          ast_log(LOG_WARNING, "Unknown type of result requested '%s'.\n",
00211                mtype_of_result);
00212          return -1;
00213       }
00214    }
00215 
00216    if (!mvalue1 || !mvalue2) {
00217       ast_log(LOG_WARNING,
00218             "Supply all the parameters - just this once, please\n");
00219       return -1;
00220    }
00221 
00222    if (sscanf(mvalue1, "%30lf", &fnum1) != 1) {
00223       ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue1);
00224       return -1;
00225    }
00226 
00227    if (sscanf(mvalue2, "%30lf", &fnum2) != 1) {
00228       ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue2);
00229       return -1;
00230    }
00231 
00232    if (negvalue1)
00233       fnum1 = 0 - fnum1;
00234 
00235    switch (iaction) {
00236    case ADDFUNCTION:
00237       ftmp = fnum1 + fnum2;
00238       break;
00239    case DIVIDEFUNCTION:
00240       if (fnum2 <= 0)
00241          ftmp = 0;         /* can't do a divide by 0 */
00242       else
00243          ftmp = (fnum1 / fnum2);
00244       break;
00245    case MULTIPLYFUNCTION:
00246       ftmp = (fnum1 * fnum2);
00247       break;
00248    case SUBTRACTFUNCTION:
00249       ftmp = (fnum1 - fnum2);
00250       break;
00251    case MODULUSFUNCTION:
00252       {
00253          int inum1 = fnum1;
00254          int inum2 = fnum2;
00255 
00256          if (inum2 == 0) {
00257             ftmp = 0;
00258          } else {
00259             ftmp = (inum1 % inum2);
00260          }
00261 
00262          break;
00263       }
00264    case POWFUNCTION:
00265       ftmp = pow(fnum1, fnum2);
00266       break;
00267    case SHLEFTFUNCTION:
00268       {
00269          int inum1 = fnum1;
00270          int inum2 = fnum2;
00271 
00272          ftmp = (inum1 << inum2);
00273          break;
00274       }
00275    case SHRIGHTFUNCTION:
00276       {
00277          int inum1 = fnum1;
00278          int inum2 = fnum2;
00279 
00280          ftmp = (inum1 >> inum2);
00281          break;
00282       }
00283    case BITWISEANDFUNCTION:
00284       {
00285          int inum1 = fnum1;
00286          int inum2 = fnum2;
00287          ftmp = (inum1 & inum2);
00288          break;
00289       }
00290    case BITWISEXORFUNCTION:
00291       {
00292          int inum1 = fnum1;
00293          int inum2 = fnum2;
00294          ftmp = (inum1 ^ inum2);
00295          break;
00296       }
00297    case BITWISEORFUNCTION:
00298       {
00299          int inum1 = fnum1;
00300          int inum2 = fnum2;
00301          ftmp = (inum1 | inum2);
00302          break;
00303       }
00304    case GTFUNCTION:
00305       ast_copy_string(buf, (fnum1 > fnum2) ? "TRUE" : "FALSE", len);
00306       break;
00307    case LTFUNCTION:
00308       ast_copy_string(buf, (fnum1 < fnum2) ? "TRUE" : "FALSE", len);
00309       break;
00310    case GTEFUNCTION:
00311       ast_copy_string(buf, (fnum1 >= fnum2) ? "TRUE" : "FALSE", len);
00312       break;
00313    case LTEFUNCTION:
00314       ast_copy_string(buf, (fnum1 <= fnum2) ? "TRUE" : "FALSE", len);
00315       break;
00316    case EQFUNCTION:
00317       ast_copy_string(buf, (fnum1 == fnum2) ? "TRUE" : "FALSE", len);
00318       break;
00319    default:
00320       ast_log(LOG_WARNING,
00321             "Something happened that neither of us should be proud of %d\n",
00322             iaction);
00323       return -1;
00324    }
00325 
00326    if (iaction < GTFUNCTION || iaction > EQFUNCTION) {
00327       if (type_of_result == FLOAT_RESULT)
00328          snprintf(buf, len, "%f", ftmp);
00329       else if (type_of_result == INT_RESULT)
00330          snprintf(buf, len, "%i", (int) ftmp);
00331       else if (type_of_result == HEX_RESULT)
00332          snprintf(buf, len, "%x", (unsigned int) ftmp);
00333       else if (type_of_result == CHAR_RESULT)
00334          snprintf(buf, len, "%c", (unsigned char) ftmp);
00335    }
00336 
00337    return 0;
00338 }
00339 
00340 static struct ast_custom_function math_function = {
00341    .name = "MATH",
00342    .read = math
00343 };
00344 
00345 static int unload_module(void)
00346 {
00347    return ast_custom_function_unregister(&math_function);
00348 }
00349 
00350 static int load_module(void)
00351 {
00352    return ast_custom_function_register(&math_function);
00353 }
00354 
00355 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mathematical dialplan function");