Author: anthm Date: Thu Nov 8 18:46:26 2007 New Revision: 6189 Added: freeswitch/trunk/src/mod/applications/mod_expr/ freeswitch/trunk/src/mod/applications/mod_expr/Makefile freeswitch/trunk/src/mod/applications/mod_expr/conio.h freeswitch/trunk/src/mod/applications/mod_expr/exprconf.h freeswitch/trunk/src/mod/applications/mod_expr/expreval.c freeswitch/trunk/src/mod/applications/mod_expr/expreval.dsp freeswitch/trunk/src/mod/applications/mod_expr/expreval.dsw freeswitch/trunk/src/mod/applications/mod_expr/expreval.h freeswitch/trunk/src/mod/applications/mod_expr/expreval.html freeswitch/trunk/src/mod/applications/mod_expr/exprfunc.c freeswitch/trunk/src/mod/applications/mod_expr/exprilfs.h freeswitch/trunk/src/mod/applications/mod_expr/exprincl.h freeswitch/trunk/src/mod/applications/mod_expr/exprinit.c freeswitch/trunk/src/mod/applications/mod_expr/exprmem.c freeswitch/trunk/src/mod/applications/mod_expr/exprmem.h freeswitch/trunk/src/mod/applications/mod_expr/exprobj.c freeswitch/trunk/src/mod/applications/mod_expr/exprpars.c freeswitch/trunk/src/mod/applications/mod_expr/exprpriv.h freeswitch/trunk/src/mod/applications/mod_expr/exprtmpl.html freeswitch/trunk/src/mod/applications/mod_expr/exprutil.c freeswitch/trunk/src/mod/applications/mod_expr/exprval.c freeswitch/trunk/src/mod/applications/mod_expr/license.txt freeswitch/trunk/src/mod/applications/mod_expr/mod_expr.c freeswitch/trunk/src/mod/applications/mod_expr/readme.txt Modified: freeswitch/trunk/build/modules.conf.in freeswitch/trunk/conf/modules.conf.xml freeswitch/trunk/src/include/switch_utils.h freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c freeswitch/trunk/src/switch_channel.c freeswitch/trunk/src/switch_utils.c Log: add some logic tools Modified: freeswitch/trunk/build/modules.conf.in ============================================================================== --- freeswitch/trunk/build/modules.conf.in (original) +++ freeswitch/trunk/build/modules.conf.in Thu Nov 8 18:46:26 2007 @@ -7,6 +7,7 @@ applications/mod_fifo applications/mod_voicemail applications/mod_limit +applications/mod_expr #applications/mod_ivrtest #applications/mod_soundtouch #applications/mod_rss Modified: freeswitch/trunk/conf/modules.conf.xml ============================================================================== --- freeswitch/trunk/conf/modules.conf.xml (original) +++ freeswitch/trunk/conf/modules.conf.xml Thu Nov 8 18:46:26 2007 @@ -36,6 +36,7 @@ <load module="mod_commands"/> <load module="mod_conference"/> <load module="mod_dptools"/> + <load module="mod_expr"/> <load module="mod_fifo"/> <load module="mod_voicemail"/> <load module="mod_limit"/> Modified: freeswitch/trunk/src/include/switch_utils.h ============================================================================== --- freeswitch/trunk/src/include/switch_utils.h (original) +++ freeswitch/trunk/src/include/switch_utils.h Thu Nov 8 18:46:26 2007 @@ -298,7 +298,10 @@ */ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen); +SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str); +SWITCH_DECLARE(char *) switch_strip_spaces(const char *str); SWITCH_DECLARE(const char *) switch_stristr(const char *str, const char *instr); +SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip); /*! \brief Escape a string by prefixing a list of characters with an escape character Modified: freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c ============================================================================== --- freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c (original) +++ freeswitch/trunk/src/mod/applications/mod_commands/mod_commands.c Thu Nov 8 18:46:26 2007 @@ -40,6 +40,138 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load); SWITCH_MODULE_DEFINITION(mod_commands, mod_commands_load, NULL, NULL); + +typedef enum { + O_NONE, + O_EQ, + O_NE, + O_GT, + O_GE, + O_LT, + O_LE +} o_t; + +SWITCH_STANDARD_API(qq_function) +{ + int argc; + char *mydata = NULL, *argv[3]; + char *expr; + char *a, *b; + float a_f = 0.0, b_f = 0.0; + o_t o = O_NONE; + int is_true = 0; + char *p; + + if (!cmd) { + goto error; + } + + mydata = strdup(cmd); + assert(mydata); + + if ((p = strchr(mydata, '?'))) { + *p = ':'; + } else { + goto error; + } + + argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc != 3) { + goto error; + } + + a = argv[0]; + + if ((expr = strchr(a, '!'))) { + *expr++ = '\0'; + if (*expr == '=') { + o = O_NE; + } + } else if ((expr = strchr(a, '>'))) { + if (*(expr+1) == '=') { + *expr++ = '\0'; + o = O_GE; + } else { + o = O_GT; + } + } else if ((expr = strchr(a, '<'))) { + if (*(expr+1) == '=') { + *expr++ = '\0'; + o = O_LE; + } else { + o = O_LT; + } + } else if ((expr = strchr(a, '='))) { + *expr++ = '\0'; + if (*expr == '=') { + o = O_EQ; + } + } + + + if (o) { + char *s_a = NULL, *s_b = NULL; + int a_is_num, b_is_num; + *expr++ = '\0'; + b = expr; + s_a = switch_strip_spaces(a); + s_b = switch_strip_spaces(b); + a_is_num = switch_is_number(s_a); + b_is_num = switch_is_number(s_b); + + a_f = a_is_num ? atof(s_a) : (float) strlen(s_a); + b_f = b_is_num ? atof(s_b) : (float) strlen(s_b); + + switch (o) { + case O_EQ: + if (!a_is_num && !b_is_num) { + is_true = !strcmp(s_a, s_b); + } else { + is_true = a_f == b_f; + } + break; + case O_NE: + is_true = a_f != b_f; + break; + case O_GT: + is_true = a_f > b_f; + break; + case O_GE: + is_true = a_f >= b_f; + break; + case O_LT: + is_true = a_f < b_f; + break; + case O_LE: + is_true = a_f <= b_f; + break; + default: + break; + } + switch_safe_free(s_a); + switch_safe_free(s_b); + stream->write_function(stream, "%s", is_true ? argv[1] : argv[2]); + goto ok; + } + + error: + stream->write_function(stream, "!err!"); + ok: + + switch_safe_free(mydata); + return SWITCH_STATUS_SUCCESS; + + +} + + +SWITCH_STANDARD_API(lan_addr_function) +{ + stream->write_function(stream, "%s", switch_is_lan_addr(cmd) ? "yes" : "no"); + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(status_function) { uint8_t html = 0; @@ -1502,6 +1634,8 @@ SWITCH_ADD_API(commands_api_interface, "sched_api", "Schedule an api command", sched_api_function, "[+]<time> <group_name> <command_string>"); SWITCH_ADD_API(commands_api_interface, "sched_del", "Delete a Scheduled task", sched_del_function, "<task_id>|<group_id>"); SWITCH_ADD_API(commands_api_interface, "xml_wrap", "Wrap another api command in xml", xml_wrap_api_function, "<command> <args>"); + SWITCH_ADD_API(commands_api_interface, "is_lan_addr", "see if an ip is a lan addr", lan_addr_function, "<ip>"); + SWITCH_ADD_API(commands_api_interface, "qq", "Eval a conditional", qq_function, "<expr> ? <true val> : <false val>"); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_NOUNLOAD; Added: freeswitch/trunk/src/mod/applications/mod_expr/Makefile ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/Makefile Thu Nov 8 18:46:26 2007 @@ -0,0 +1,6 @@ +BASE=../../../.. +LOCAL_SOURCES=expreval.c exprinit.c exprobj.c exprutil.c exprfunc.c exprmem.c exprpars.c exprval.c +LOCAL_OBJS=expreval.o exprinit.o exprobj.o exprutil.o exprfunc.o exprmem.o exprpars.o exprval.o +LOCAL_LIBADD=-lm +include $(BASE)/build/modmake.rules + Added: freeswitch/trunk/src/mod/applications/mod_expr/conio.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/conio.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,161 @@ +/* A conio implementation for Mingw/Dev-C++. + * + * Written by: + * Hongli Lai <hongli@telekabel.nl> + * tkorrovi <tkorrovi@altavista.net> on 2002/02/26. + * Andrew Westcott <ajwestco@users.sourceforge.net> + * + * Offered for use in the public domain without any warranty. + */ + +#ifndef _CONIO_H_ +#define _CONIO_H_ + + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLINK 0 + +typedef enum +{ + BLACK, + BLUE, + GREEN, + CYAN, + RED, + MAGENTA, + BROWN, + LIGHTGRAY, + DARKGRAY, + LIGHTBLUE, + LIGHTGREEN, + LIGHTCYAN, + LIGHTRED, + LIGHTMAGENTA, + YELLOW, + WHITE +} COLORS; + + +#define cgets _cgets +#define cprintf _cprintf +#define cputs _cputs +#define cscanf _cscanf +#define ScreenClear clrscr + +/* blinkvideo */ + +void clreol (void); +void clrscr (void); + +int _conio_gettext (int left, int top, int right, int bottom, + char *str); +/* _conio_kbhit */ + +void delline (void); + +/* gettextinfo */ +void gotoxy(int x, int y); +/* +highvideo +insline +intensevideo +lowvideo +movetext +normvideo +*/ + +void gotoxy(int x, int y); + +void puttext (int left, int top, int right, int bottom, char *str); + +// Screen Variables + +/* ScreenCols +ScreenGetChar +ScreenGetCursor +ScreenMode +ScreenPutChar +ScreenPutString +ScreenRetrieve +ScreenRows +ScreenSetCursor +ScreenUpdate +ScreenUpdateLine +ScreenVisualBell +_set_screen_lines */ + +void _setcursortype (int type); + +void textattr (int _attr); + +void textbackground (int color); + +void textcolor (int color); + +/* textmode */ + +int wherex (void); + +int wherey (void); + +/* window */ + + + +/* The code below was part of Mingw's conio.h */ +/* + * conio.h + * + * Low level console I/O functions. Pretty please try to use the ANSI + * standard ones if you are writing new code. + * + * This file is part of the Mingw32 package. + * + * Contributors: + * Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp> + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.4 $ + * $Author: hongli $ + * $Date: 2002/04/26 19:31:25 $ + * + */ + +char* _cgets (char*); +int _cprintf (const char*, ...); +int _cputs (const char*); +int _cscanf (char*, ...); + +int _getch (void); +int _getche (void); +int _kbhit (void); +int _putch (int); +int _ungetch (int); + + +int getch (void); +int getche (void); +int kbhit (void); +int putch (int); +int ungetch (int); + + +#ifdef __cplusplus +} +#endif + +#endif /* _CONIO_H_ */ Added: freeswitch/trunk/src/mod/applications/mod_expr/exprconf.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprconf.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,29 @@ +/* + File: exprconf.h + Auth: Brian Allen Vanderburg II + Date: Thursday, October 20, 2005 + Desc: Configuration for ExprEval + + This file is part of ExprEval. +*/ + +#ifndef __BAVII_EXPRCONF_H +#define __BAVII_EXPRCONF_H + +/* + Error checking level + + 0: Don't check any errors (don't use errno). Divide by 0 + is avoided and the part that divides by 0 is 0. For example + '4+1/0' is 4. + + 1: Check math errors. +*/ +#define EXPR_ERROR_LEVEL_NONE 0 +#define EXPR_ERROR_LEVEL_CHECK 1 + +#ifndef EXPR_ERROR_LEVEL +#define EXPR_ERROR_LEVEL EXPR_ERROR_LEVEL_CHECK +#endif + +#endif /* __BAVII_EXPRCONF_H */ Added: freeswitch/trunk/src/mod/applications/mod_expr/expreval.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/expreval.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,268 @@ +/* + File: expreval.c + Auth: Brian Allen Vanderburg II + Date: Wednesday, April 30, 2003 + Desc: Evaluation routines for the ExprEval library + + This file is part of ExprEval. +*/ + +/* Includes */ +#include "exprincl.h" + +#include "exprpriv.h" + +/* Defines for error checking */ +#include <errno.h> + +#if(EXPR_ERROR_LEVEL >= EXPR_ERROR_LEVEL_CHECK) +#define EXPR_RESET_ERR() errno = 0 +#define EXPR_CHECK_ERR() if(errno) return EXPR_ERROR_OUTOFRANGE +#else +#define EXPR_RESET_ERR() +#define EXPR_CHECK_ERR() +#endif + + +/* This routine will evaluate an expression */ +int exprEval(exprObj *obj, EXPRTYPE *val) + { + EXPRTYPE dummy; + + if(val == NULL) + val = &dummy; + + /* Make sure it was parsed successfully */ + if(!obj->parsedbad && obj->parsedgood && obj->headnode) + { + /* Do NOT reset the break count. Let is accumulate + between calls until breaker function is called */ + return exprEvalNode(obj, obj->headnode, 0, val); + } + else + return EXPR_ERROR_BADEXPR; + } + +/* Evaluate a node */ +int exprEvalNode(exprObj *obj, exprNode *nodes, int curnode, EXPRTYPE *val) + { + int err; + int pos; + EXPRTYPE d1, d2; + + if(obj == NULL || nodes == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Update n to point to correct node */ + nodes += curnode; + + /* Check breaker count */ + if(obj->breakcur-- <= 0) + { + /* Reset count before returning */ + obj->breakcur = obj->breakcount; + + if(exprGetBreakResult(obj)) + { + return EXPR_ERROR_BREAK; + } + } + + switch(nodes->type) + { + case EXPR_NODETYPE_MULTI: + { + /* Multi for multiple expressions in one string */ + for(pos = 0; pos < nodes->data.oper.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.oper.nodes, pos, val); + if(err) + return err; + } + break; + } + + case EXPR_NODETYPE_ADD: + { + /* Addition */ + err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2); + + if(!err) + *val = d1 + d2; + else + return err; + + break; + } + + case EXPR_NODETYPE_SUBTRACT: + { + /* Subtraction */ + err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2); + + if(!err) + *val = d1 - d2; + else + return err; + + break; + } + + case EXPR_NODETYPE_MULTIPLY: + { + /* Multiplication */ + err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2); + + if(!err) + *val = d1 * d2; + else + return err; + + break; + } + + case EXPR_NODETYPE_DIVIDE: + { + /* Division */ + err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2); + + if(!err) + { + if(d2 != 0.0) + *val = d1 / d2; + else + { +#if(EXPR_ERROR_LEVEL >= EXPR_ERROR_LEVEL_CHECK) + return EXPR_ERROR_DIVBYZERO; +#else + *val = 0.0; + return EXPR_ERROR_NOERROR; +#endif + } + } + else + return err; + + break; + } + + case EXPR_NODETYPE_EXPONENT: + { + /* Exponent */ + err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.oper.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = pow(d1, d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + + case EXPR_NODETYPE_NEGATE: + { + /* Negative value */ + err = exprEvalNode(obj, nodes->data.oper.nodes, 0, &d1); + + if(!err) + *val = -d1; + else + return err; + + break; + } + + + case EXPR_NODETYPE_VALUE: + { + /* Directly access the value */ + *val = nodes->data.value.value; + break; + } + + case EXPR_NODETYPE_VARIABLE: + { + /* Directly access the variable or constant */ + *val = *(nodes->data.variable.vaddr); + break; + } + + case EXPR_NODETYPE_ASSIGN: + { + /* Evaluate assignment subnode */ + err = exprEvalNode(obj, nodes->data.assign.node, 0, val); + + if(!err) + { + /* Directly assign the variable */ + *(nodes->data.assign.vaddr) = *val; + } + else + return err; + + break; + } + + case EXPR_NODETYPE_FUNCTION: + { + /* Evaluate the function */ + if(nodes->data.function.fptr == NULL) + { + /* No function pointer means we are not using + function solvers. See if the function has a + type to solve directly. */ + switch(nodes->data.function.type) + { + /* This is to keep the file from being too crowded. + See exprilfs.h for the definitions. */ +#include "exprilfs.h" + + + default: + { + return EXPR_ERROR_UNKNOWN; + } + } + } + else + { + /* Call the correct function */ + return (*(nodes->data.function.fptr))(obj, + nodes->data.function.nodes, nodes->data.function.nodecount, + nodes->data.function.refs, nodes->data.function.refcount, val); + } + + break; + } + + default: + { + /* Unknown node type */ + return EXPR_ERROR_UNKNOWN; + } + } + + return EXPR_ERROR_NOERROR; + } + + + Added: freeswitch/trunk/src/mod/applications/mod_expr/expreval.dsp ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/expreval.dsp Thu Nov 8 18:46:26 2007 @@ -0,0 +1,164 @@ +# Microsoft Developer Studio Project File - Name="expreval" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=expreval - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "expreval.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "expreval.mak" CFG="expreval - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "expreval - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "expreval - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "expreval - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Op /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "expreval - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /G6 /MTd /Za /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "expreval - Win32 Release" +# Name "expreval - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\expreval.c +# End Source File +# Begin Source File + +SOURCE=.\exprfunc.c +# End Source File +# Begin Source File + +SOURCE=.\exprinit.c +# End Source File +# Begin Source File + +SOURCE=.\exprmem.c +# End Source File +# Begin Source File + +SOURCE=.\exprobj.c +# End Source File +# Begin Source File + +SOURCE=.\exprpars.c +# End Source File +# Begin Source File + +SOURCE=.\exprutil.c +# End Source File +# Begin Source File + +SOURCE=.\exprval.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\exprconf.h +# End Source File +# Begin Source File + +SOURCE=.\expreval.h +# End Source File +# Begin Source File + +SOURCE=.\exprilfs.h +# End Source File +# Begin Source File + +SOURCE=.\exprincl.h +# End Source File +# Begin Source File + +SOURCE=.\exprmem.h +# End Source File +# Begin Source File + +SOURCE=.\exprpriv.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\expreval.html +# End Source File +# Begin Source File + +SOURCE=.\exprtmpl.html +# End Source File +# Begin Source File + +SOURCE=.\license.txt +# End Source File +# Begin Source File + +SOURCE=.\readme.txt +# End Source File +# End Target +# End Project Added: freeswitch/trunk/src/mod/applications/mod_expr/expreval.dsw ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/expreval.dsw Thu Nov 8 18:46:26 2007 @@ -0,0 +1,59 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "expreval"=.\expreval.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "imagegen"=.\imagegen\imagegen.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name expreval + End Project Dependency +}}} + +############################################################################### + +Project: "test"=.\test\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name expreval + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + Added: freeswitch/trunk/src/mod/applications/mod_expr/expreval.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/expreval.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,127 @@ +/* + File: expreval.h + Auth: Brian Allen Vanderburg II + Date: Thursday, April 24, 2003 + Desc: Main include file for ExprEval library + + This file is part of ExprEval. +*/ + + +/* Include once */ +#ifndef __BAVII_EXPREVAL_H +#define __BAVII_EXPREVAL_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Define type of data to use */ +typedef double EXPRTYPE; + +/* Defines for various things */ + +/* Max id size */ +#define EXPR_MAXIDENTSIZE 255 + +/* Error values */ +enum + { + EXPR_ERROR_UNKNOWN = -1, /* Unknown error */ + EXPR_ERROR_NOERROR = 0, /* No Error */ + EXPR_ERROR_MEMORY, /* Memory allocation failed */ + EXPR_ERROR_NULLPOINTER, /* Null pointer passed to function */ + EXPR_ERROR_NOTFOUND, /* Item not found in a list */ + EXPR_ERROR_UNMATCHEDCOMMENT, /* Unmatched comment tags */ + EXPR_ERROR_INVALIDCHAR, /* Invalid characters in expression */ + EXPR_ERROR_ALREADYEXISTS, /* An item already called create */ + EXPR_ERROR_ALREADYPARSEDBAD, /* Expression parsed already, but unsuccessfully. call free or clear */ + EXPR_ERROR_ALREADYPARSEDGOOD, /* Expression parsed already, successfully, call free or clear */ + EXPR_ERROR_EMPTYEXPR, /* Empty expression string passed to parse */ + EXPR_ERROR_UNMATCHEDPAREN, /* Unmatched parenthesis */ + EXPR_ERROR_SYNTAX, /* Syntax error in expression */ + EXPR_ERROR_MISSINGSEMICOLON, /* Missing semicolon at end of expression */ + EXPR_ERROR_BADIDENTIFIER, /* Identifier was to big or not formed right */ + EXPR_ERROR_NOSUCHFUNCTION, /* Function does not exist in function list */ + EXPR_ERROR_BADNUMBERARGUMENTS, /* Bad number of arguments in a function call */ + EXPR_ERROR_BADEXPR, /* This is a bad expression to evaluate. It has not been parsed or has unsuccessfully */ + EXPR_ERROR_UNABLETOASSIGN, /* Unable to do an assignment, maybe no variable list */ + EXPR_ERROR_DIVBYZERO, /* Attempted a division by zero */ + EXPR_ERROR_NOVARLIST, /* No variable list found but one is needed */ + EXPR_ERROR_BREAK, /* Expression was broken by break function */ + EXPR_ERROR_CONSTANTASSIGN, /* Assignment to a constant */ + EXPR_ERROR_REFCONSTANT, /* Constant used as a reference parameter */ + EXPR_ERROR_OUTOFRANGE, /* A bad value was passed to a function */ + + EXPR_ERROR_USER /* Custom errors should be larger than this */ + }; + +/* Macros */ + +/* Forward declarations */ +typedef struct _exprNode exprNode; +typedef struct _exprFuncList exprFuncList; +typedef struct _exprValList exprValList; +typedef struct _exprObj exprObj; + +/* Function types */ +typedef int (*exprFuncType)(exprObj *obj, exprNode *nodes, int nodecount, EXPRTYPE **refs, int refcount, EXPRTYPE *val); +typedef int (*exprBreakFuncType)(exprObj *obj); + + + +/* Functions */ + +/* Version information function */ +void exprGetVersion(int *major, int *minor); + +/* Functions for function lists */ +int exprFuncListCreate(exprFuncList **flist); +int exprFuncListAdd(exprFuncList *flist, char *name, exprFuncType ptr, int min, int max, int refmin, int refmax); +int exprFuncListFree(exprFuncList *flist); +int exprFuncListClear(exprFuncList *flist); +int exprFuncListInit(exprFuncList *flist); + +/* Functions for value lists */ +int exprValListCreate(exprValList **vlist); +int exprValListAdd(exprValList *vlist, char *name, EXPRTYPE val); +int exprValListSet(exprValList *vlist, char *name, EXPRTYPE val); +int exprValListGet(exprValList *vlist, char *name, EXPRTYPE *val); +int exprValListAddAddress(exprValList *vlist, char *name, EXPRTYPE *addr); +int exprValListGetAddress(exprValList *vlist, char *name, EXPRTYPE **addr); +void *exprValListGetNext(exprValList *vlist, char **name, EXPRTYPE *value, EXPRTYPE** addr, void *cookie); +int exprValListFree(exprValList *vlist); +int exprValListClear(exprValList *vlist); +int exprValListInit(exprValList *vlist); + +/* Functions for expression objects */ +int exprCreate(exprObj **obj, exprFuncList *flist, exprValList *vlist, exprValList *clist, + exprBreakFuncType breaker, void *userdata); +int exprFree(exprObj *obj); +int exprClear(exprObj *obj); +int exprParse(exprObj *obj, char *expr); +int exprEval(exprObj *obj, EXPRTYPE *val); +int exprEvalNode(exprObj *obj, exprNode *nodes, int curnode, EXPRTYPE *val); +exprFuncList *exprGetFuncList(exprObj *obj); +exprValList *exprGetVarList(exprObj *obj); +exprValList *exprGetConstList(exprObj *obj); +exprBreakFuncType exprGetBreakFunc(exprObj *obj); +int exprGetBreakResult(exprObj *obj); +void* exprGetUserData(exprObj *obj); +void exprSetUserData(exprObj *obj, void *userdata); +void exprSetBreakCount(exprObj *obj, int count); +void exprGetErrorPosition(exprObj *obj, int *start, int *end); + +/* Other useful routines */ +int exprValidIdent(char *name); + +/* Name mangling */ +#ifdef __cplusplus +} +#endif + + + +#endif /* __BAVII_EXPREVAL_H */ Added: freeswitch/trunk/src/mod/applications/mod_expr/expreval.html ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/expreval.html Thu Nov 8 18:46:26 2007 @@ -0,0 +1,1334 @@ +<html> +<head> +<title>ExprEval Library</title> +<style type="text/css"> +.valid { + color: #00AA00; +} +.invalid { + color: #FF0000; +} +.excomment { + color: #0000FF; +} +.container { + margin-top: 10px; + margin-bottom: 10px; + padding-left: 4px; + padding-right: 4px; + border-top: 1px solid #000000; + border-right: 1px solid #000000; + border-bottom: 1px solid #000000; + border-left: 1px solid #000000; + background-color: #BBBBBB; +} +body { + background-color: #AAAAAA; +} +</style> +</head> +<body> + +<div align="center"> + <h1>ExprEval Library</h1> + <hr> +</div> + +<div align="left" class="container"> + <h2>Contents</h2> + <h3> + <ul> + <a href="#Introduction">Introduction</a><br> + <a href="#License">License</a><br> + <a href="#Syntax">Expression Syntax</a><br> + <a href="#Using">Using ExprEval in an Application</a><br> + <a href="#FastVar">Fast Variable Access</a><br> + <a href="#InternalFuncConst">Using the Internal Functions and Constants</a><br> + <a href="#CustomFunc">Creating Custom Functions</a><br> + <a href="#Reference">Reference</a><br> + <a href="#Compiling">Compiling the ExprEval Library</a><br> + <a href="#Drawbacks">Drawbacks/Problems</a><br> + <a href="#Solutions">Problems and Solutions</a><br> + <a href="#Example">Example Use</a><br> + </ul> + </h3> +</div> + +<div align="left" class="container"> + <h2><a name="Introduction">Introduction</a></h2> + <blockquote> + <p>ExprEval Help document. This document is probably full of + bugs and mispellings. I may get around to proofreading + it later.</p> + <p>ExprEval is a C based expression evaluation library. + It is entirely C based, but can be used in C++ programs + as well.. The source code is provided for the library + so that it can be recompiled for the specific system + or compiler.</p> + <p>ExprEval makes adding mathematical expression support to + an application easy. It takes an expression string and + parses it, and then it can evaluate it over and over. + This library also has support for functions, constants, + and variables. All of these items are stored in + seperate lists so they can be shared among expressions or + they can be private to a single expression or any mix and + match. It is up to the developer how to link them together. + You can also create your own custom functions.</p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="License">License</a></h2> + <blockquote> + <p>This library is licensed under the + <a href="license.txt">ExprEval License.</a> + </p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="Syntax">Expression Syntax</a></h2> + <blockquote> + <p>Expressions have pretty much the same syntax as they + would have on paper, with the following exceptions: + <ul> + <li>Each expression must end with a semicolon. This + is because the expression string can actually + contain multiple expressions. The semicolon is + used to mark the end of the expression.<br> + <b>Examples:</b> + <ul> + <li>4*x+5;</li> + <li>y=5+2;g=4+6;</li> + <li>y=r*sin(a);x=r*cos(a);</li> + </ul> + </li> + <li>The asterisk '*' must be used to multiply.<br> + <b>Examples:</b> + <ul> + <li>y=5*6; <b class="valid">Valid</b></li> + <li>g=(x+1)*(x-1); <b class="valid">Valid</b></li> + <li>g=(x+1)(x-1); <b class="invalid">Invalid</b></li> + </ul> + </li> + </ul> + </p> + <p>More than one expression may be contained within an expression string. + As shown above, each expression must end with a semicolon, even if + only one expression is in the string. The value of an expression + string is the value of the last expression in the string.<br> + <b>Examlples:</b> + <ul> + <li>g=7; <b class="excomment">Value: 7</b></li> + <li>k=z+1; <b class="excomment">Value: z+1</b></li> + <li>r=4;k=6;o=9+r-k; <b class="excomment">Value: 9+r-k</b></li> + </ul> + </p> + <p>Some functions may take reference parameters. These parameters are + references to other variables. You can mix reference parameters + with normal parameters. The order of the normal parameters must + remain the same and the order of the reference parameters must + remain the same.<br> + <b>Examples:</b> + <ul> + <li>min(1,2,3,4,&mval); <b class="excomment">&mval is a reference to a variable mval</b></li> + <li>min(1,2,&mval,3,4); <b class="excomment">You may mix them inside like this.</b></li> + <li>min(1,2,(&mval),3,4); <b class="invalid">You may not nest reference parameters in any way</b></li> + </ul> + </p> + <p>Expressions may also be nested with parenthesis.<br> + <b>Examples:</b> + <ul> + <li>y=sin(x-cos(5+max(4,5,6*x)));</li> + <li>6+(5-2*(x+y));</li> + </ul> + </p> + <p>Expressions may also have whitespace characters and comments. + Whitespace characters such as newlines, linefeeds, carriage + returns, spaces, and tabs are ignored. Comments begin with + the pound sign '#' and end at the end of the line.<br> + <b>Example:</b> + <ul> + <pre> +#Set the x value +x = d * cos(r); + +#Set the y value +y = d * sin(r); + </pre> + </ul> + </p> + <p>If a variable is used in an expression, but that variable does not exist, + it is considered zero. If it does exist then its value is used instead. + </p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="Using">Using ExprEval in an Application</a></h2> + <blockquote> + <p>Using ExprEval in an application can be a little difficult. + You generally follow these steps: + <ul> + <li>Create function, variable, and constant lists</li> + <li>Create the expression object</li> + <li>Parse the expression</li> + <li>Evaluate the expression as needed</li> + <li>Free the expression object</li> + <li>Free the function, variable, and constant lists</li> + </ul> + You can manipulate the lists in any order after their creation. + However, functions are translated during the parse, so after + parsing an expression, manipulating the function list will make + no change to an expression. Variables and constants can be + manipulated after a parse to change the result of an expression. + However, you must add any constants to be used by an expression + to the constant list <b>BEFORE</b> parsing the expression, + otherwise it will be seen as a variable. Applications can change + both variables and constants, however the expression can only + change variables. Expressions may <b>NOT</b> assign to a constant + and expressions may <b>NOT</b> use constants as a reference parameter.</p> + <p><b>Function, variable, and constant list example:</b> + <ul> + <pre> +exprFuncList *flist; +exprValList *vlist; +exprValList *clist; +exprObj *obj; +EXPRTYPE result; +int err; + +/* Create function list */ +err = exprFuncListCreate(&flist); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Initialize internal functions */ +err = exprFuncListInit(flist); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Create variable list */ +err = exprValListCreate(&vlist); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Create the constant list */ +err = exprValListCreate(&clist); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Initialize internal constants */ +err = exprValListInit(clist); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Add any application defined functions, constants, or variables to the lists here or down below */ + </pre> + </ul> + </p> + <p><b>Expression object example:</b> + <ul> + <pre> +err = exprCreate(&obj, flist, vlist, clist, NULL, 0); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Add any application defined functions, constants, or variables to the lists here or down below. + This is the last time you can for the functions or constants. */ + </pre> + </ul> + </p> + <p><b>Expression parse example:</b> + <ul> + <pre> +/* Functions and constants may be added or changed here */ + +err = exprParse(obj, "2+sin(M_PI)+3*x;"); +if(err != EXPR_ERROR_NOERROR) + { + ... + } + +/* Changes to the function or constant lists do not change the expression now */ + </pre> + </ul> + </p> + <p><b>Expression evaluation example:</b> + <ul> + <pre> +/* Add or change any variables */ + +err = exprEval(obj, &result); +if(err != EXPR_ERROR_NOERRO) + { + ... + } +else + { + printf("Expression Result: %f\n", result); + } + </pre> + </ul> + </p> + <p><b>Free the expression object and lists example:</b> + <ul> + <pre> +exprFree(obj); +exprValListFree(vlist); +exprValListFree(clist); +exprFuncListFree(flist); + </pre> + </ul> + </p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="FastVar">Fast Variable Access</a></h2> + <blockquote> + <p>A new feature in ExprEval is fast variable access. This + is simply a technique of quickly accessing variables + by directly accessing their memory locations instead + of using the value list functions. Fast variable access + is always used internally in ExprEval. You must + NOT clear a variable list until after all expressions + using it are completely finished evaluating. Then you + must reparse the expressions before using them again. + The reason is simple. When fast variable access is used, + the variable memory location is directly accessed If you + clear a variable list and then evaluate an expression, + it will access invalid memory.</p> + <p>You can also use fast variable access in you application + to dramatically speed up loops. This is accomplished as + follows: + <ul> + <li>Add the desired variable to the variable list</li> + <li>Get the address of the variable with exprValListGetAddress</li> + <li>In the loop(s), directly set/get the variable any time needed: *var = 0.0;</li> + </ul> + </p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="InternalFuncConst">Using the Internal Functions and Constants</a></h2> + <blockquote> + <p>To use the internal functions, they must first be initialized + into a function list with exprFuncListInit. To use the + internal constants, they must first be initialized into a + value list with exprValListInit. For a list of the + internal functions and constants, see the application + help template file: <a href="exprtmpl.html">ExprTmpl.html</a> + You may use this file in your own applications so you don't + have to write a detail on the functions in ExprEval. All + you have to do is add you own functions and constants to + the file if there are any. + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="CustomFunc">Creating Custom Functions</a></h2> + <blockquote> + <p>Custom functions can be created for use by the library. + This is how a function should look + <ul> + <pre> +int custom_func(exprObj *obj, exprNode *nodes, int nodecount, EXPRTYPE **refs, int refcount, EXPRTYPE *val) + { + } + </pre> + </ul> + + obj is a pointer to the expression object that called + the function, nodes is a pointer to an array of nodes + that are the parameters of this function, nodecount is + the number of items in the array (the number of parameters), + refs is an array of pointers to referenced variables, + refcount is the number of referenced variables, + and val is a pointer to a variable to recieve the result + of the function. The function should return an error value + indicating the error status of the function. + </p> + <p>Solving a function typically goes as follows: + <ul> + <li>Verifiy the number of arguments, if needed</li> + <li>Evaluate the subnodes that you need. You do not have to + evaluate every subnode if you do not need it</li> + <li>Check for possible error conditions (division by zero)</li> + <li>Clear math errors (If function uses any math routines)</li> + <li>Calculate the result</li> + <li>Check for math errors (If the function uses any math routines)</li> + <li>return EXPR_ERROR_NOERROR</li> + </ul> + </p> + <p><b>Example:</b> + <ul> + <pre> +int custom_func(exprObj *obj, exprNode *nodes, int count, EXPRTYPE **refs, int refcount, EXPRTYPE *val) + { + int err; + EXPRTYPE d1, d2; + + /* Need 2 arguments */ + if(nodecount != 2) + return EXPR_ERROR_BADNUMBERARGUMENTS; + + /* Eval arg 1 */ + err = exprEvalNode(obj, nodes, 0, &d1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* Eval arg 2 */ + err = exprEvalNode(obj, nodes, 1, &d2); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* Make sure arg 2 is not 0.0 */ + if(d2 == 0.0) + { + *val = 0.0; + return EXPR_ERROR_NOERROR; + } + + /* Do math */ + *val = atan(d1 / d2); /* No need to worry about divide by zero */ + + + return EXPR_ERROR_NOERROR; + } + </pre> + </ul> + </p> + <p>In order to use a custom function, it must be added to + a function list before the expression is parsed by using + exprFuncListAdd</p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="Reference">Reference</a></h2> + <blockquote> + <p><b>Headers:</b> + <ul> + <li>expreval.h - Include file</li> + </ul> + <p> + <p><b>Defines:</b> + <ul> + <li>EXPR_MAXIDENTSIZE - Maximum identifier, constant, + or function name size</li> + <li>EXPR_ERROR_NOERROR - No error has occurred</li> + <li>EXPR_ERROR_MEMORY - A memory allocation error occured. + For function and value lists, the name may have been + invalid</li> + <li>EXPR_ERROR_NULLPOINTER - A null pointer was passed to + a function that needed a valid pointer.</li> + <li>EXPR_ERROR_NOTFOUND - An item was not found in the + function or value list</li> + <li>EXPR_ERROR_UNMATHEDCOMMENT - Comment is missing opening + or closing mark.</li> + <li>EXPR_ERROR_INVALIDCHAR - Invalid characters were found + in the expression</li> + <li>EXPR_ERROR_ALREADYEXISTS - An item already exists or created.</li> + <li>EXPR_ERROR_ALREADYPARSEDBAD - An expression was already + parsed into this object, but unsuccessfully. Free the + expression before creating and parsing again</li> + <li>EXPR_ERROR_ALREADYPARSEDGOOD - An expression was already + parsed into this object successfully. Free the expression + before creating and parsing again</li> + <li>EXPR_ERROR_EMPTYEXPR - An empty expression string was passed + to be parsed</li> + <li>EXPR_ERROR_UNMATHEDPAREN - Unmathed opening or closing + parenthesis were found</li> + <li>EXPR_ERROR_SYNTAX - A syntax error is in the expression</li> + <li>EXPR_ERROR_MISSINGSEMICOLON - An expression is missing a + semicolon</li> + <li>EXPR_ERROR_BADIDENTIFIER - A bad identifier was used in + the expression</li> + <li>EXPR_ERROR_NOSUCHFUNCTION - Function used in the expression + does not exist in the function list</li> + <li>EXPR_ERROR_BADNUMBERARGUMENTS - A bad number of arguments + was passed to the expression function</li> + <li>EXPR_ERROR_BADEXPR - Can not evaluate an expression because + it does not exist or has not been parsed successfully.</li> + <li>EXPR_ERROR_UNABLETOASSIGN - Unable to do an assignment because + a variable list has not been associated with the expression object</li> + <li>EXPR_ERROR_DIVBYZERO - An attemp to divide by zero has occured</li> + <li>EXPR_ERROR_NOVARLIST - No variable list for the expression</li> + <li>EXPR_ERROR_BREAK - The expression was broken by the break function</li> + <li>EXPR_ERROR_CONSTANTASSIGN - The expresion attempted to assign to a constant.</li> + <li>EXPR_ERROR_REFCONSTANT - The expression attempted to pass a constant as a + reference parameter.</li> + <li>EXPR_ERROR_OUTOFRANGE - A bad value was passed to a function.</li> + <li>EXPR_ERROR_USER - Custom error values need to be larger than this.</li> + </ul> + </p> + <p><b>Objects:</b> + <ul> + <li>exprObj - The expression object</li> + <li>exprFuncList - A function lists for the expresions</li> + <li>exprValList - A value list for constants or variables</li> + <li>exprNode - An individual node in a parsed expression tree</li> + </ul> + </p> + <p><b>Types:</b> + <ul> + <li>EXPRTYPE - Type for the value of an expression (double)</li> + <li>exprFuncType - Custom function type. Defined as:<br> + typedef int (*exprFuncType)(exprObj *obj, exprNode *nodes, int nodecount, EXPRTYPE **refs, int refcount, EXPRTYPE *val);</li> + <li>exprBreakFuncType - Breaker function pointer to stop evaluation if the result is nonzero. + Defined as:<br> + typedef int (*exprBreakFuncType)(exprObj *o);</li> + </ul> + </p> + <p><b>Version information functions:</b> + <ul> + <li>void exprGetVersion(int *major, int *mino);<br> + Comments: + <ul> + <li>Gets the version of the ExprEval library</li> + </ul> + Parameters: + <ul> + <li>*major - Pointer to int to get major version number</li> + <li>*minor - Pointer to int to get minor version number</li> + </ul> + Returns: + <ul> + <li>Nothing</li> + </ul> + </li> + </ul> + </p> + <p><b>Function list functions:</b> + <ul> + <li>int exprFuncListCreate(exprFuncList **flist);<br> + Comments: + <ul> + <li>Creates a function lists and updates a pointer to point to it</li> + </ul> + Parameters: + <ul> + <li>**flist - Pointer to a pointer to the function list</li> + </ul> + Returns + <ul> + <li>Error code of the function. On success, the pointer + passed by address will point to the new function list</li> + </ul> + </li><br> + <li>int exprFuncListAdd(exprFuncList *flist, exprFuncType ptr, char *name, int min, int max, int refmin, int refmax);<br> + Comments: + <ul> + <li>Adds a function to the function list. Returns error if + the function already exists.</li> + </ul> + Parameters: + <ul> + <li>*flist - Pointer to an already created function list</li> + <li>ptr - Pointer to a custom function</li> + <li>*name - Name of the custom function</li> + <li>min - Minimum number of arguments for the function, negative for no minimum</li> + <li>max - Maximum number of arguments for the function, negative for no maximum</li> + <li>refmin - Minimum number of ref arguments</li> + <li>refmax - Maxmimum number of ref arguments</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprFuncListFree(exprFuncList *flist);<br> + Comments: + <ul> + <li>Free the function list entirely</li> + </ul> + Parameters: + <ul> + <li>*flist - Pointer to the function list to free</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprFuncListClear(exprFuncList *flist);<br> + Comments: + <ul> + <li>Clear the functions from the function list</li> + </ul> + Parameters: + <ul> + <li>*flist - Pointer to the function list to clear</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprFuncListInit(exprFuncList *flist);<br> + Comments: + <ul> + <li>Initializes internal functions into the funtion list</li> + </ul> + Parameters: + <ul> + <li>*flist - Function list to initialize</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li> + </ul> + </p> + <p><b>Value list functions:</b> + <ul> + <li>int exprValListCreate(exprValList **vlist);<br> + Comments: + <ul> + <li>Creates a value list for variables or constants</li> + </ul> + Parameters: + <ul> + <li>**vlist - Pointer to a pointer to the value list.</li> + </ul> + Returns: + <ul> + <li>Error code of the function. On success, the pointer will + be updated to point to the value list</li> + </ul> + </li><br> + <li>int exprValListAdd(exprValList *vlist, char *name, EXPRTYPE val);<br> + Comments: + <ul> + <li>Add a value in a value list. Returns error if value + already exists.</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to add a value to</li> + <li>*name - Name of the value to add</li> + <li>val - Value of the value to add</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprValListSet(exprValList *vlist, char *name, EXPRTYPE val);<br> + Comments: + <ul> + <li>Set a value in a value list.</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to set a value in</li> + <li>*name - Name of the value to set</li> + <li>val - Value of the value to set</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprValListGet(exprValList *vlist, char *name, EXPRTYPE *val)<br> + Comment: + <ul> + <li>Get the value of a variable or constant in a value list</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to use</li> + <li>*name - Name of the value to get</li> + <li>*val - Pointer to variable to get the value</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprValListAddAddress(exprValList *vlist, char *name, EXPRTYPE *addr)<br> + Comment: + <ul> + <li>This function is used to add a named value to the value list, but + uses an outside variable such as a stack variable to store the + value. This outside variable is used to set/get the value instead + of the internal list value. You must ensure that this outside + variable exists as long as the expression is using it's address.</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to use</li> + <li>*name - Name of the value to add</li> + <li>*addr - Address of the value being added</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprValListGetAddress(exprValList *vlist, char *name, EXPRTYPE **addr)<br> + Comment: + <ul> + <li>Get the memory address of a variable in a value list</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to use</li> + <li>*name - Name of the value to get</li> + <li>**addr - Pointer to a pointer to store the address of the value + This will be NULL if the name is not in the list.</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>void *exprValListGetNext(exprValList *vlist, char **name, EXPRTYPE *value, EXPRTYPE** addr, void *cookie);<br> + Comment: + <ul> + <li>This is used to enumerate the items in the value list. + Do NOT change the list while enumerating the items. Any + of the information items can be NULL if it is not needed.</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to use</li> + <li>**name - Address of a pointer that will point to the + name. Do not edit the name.</li> + <li>*value - The current value of the item.</li> + <li>**addr - Address of a pointer to store the address of the value.</li> + <li>*cookie - NULL to find the first item, the return value to find + subsequent items.</li> + </ul> + Returns: + <ul> + <li>NULL if the item could not be found. Otherwise a cookie + to be used to find additional items.</li> + </ul> + </li><br> + <li>int exprValListFree(exprValList *vlist);<br> + Comments: + <ul> + <li>Completely free the value list</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to free</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprValListClear(exprValList *vlist);<br> + Comments: + <ul> + <li>Set the values in the list to 0.0</li> + </ul> + Parameters: + <ul> + <li>*vlist - Value list to reset</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprValListInit(exprValList *vlist);<br> + Comments: + <ul> + <li>Initialize internal constants into a value list</li> + </ul> + Paramters: + <ul> + <li>*vlist - Value list to initialize</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li> + </ul> + </p> + <p><b>Expression functions:</b> + <ul> + <li>int exprCreate(exprObj **obj, exprFuncList *flist, exprValList *vlist, exprValList *clist, exprBreakFuncType breaker, void *userdata);<br> + Comments: + <ul> + <li>Create an expression object to use</li> + </ul> + Parameters: + <ul> + <li>**obj - Pointer to a pointer to an expression object</li> + <li>*flist - Function list to associate with the expression</li> + <li>*vlist - Variable value list to associate with the expression</li> + <li>*clist - Constant value list to associate with the expression</li> + <li>breaker - Breaker function callback to associate with the expression. + Used by functions that may be infinite loops (such as the for function)</li> + <li>userdata - User data to associate with the expression</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprFree(exprObj *obj);<br> + Comments: + <ul> + <li>Completely free the expression object</li> + </ul> + Paramters: + <ul> + <li>*obj - Expression object to free</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprClear(exprObj *obj);<br> + Comments: + <ul> + <li>Clear an expression, but keep list and callback associations. + You can then parse another expression without calling create</li> + </ul> + Parameters: + <ul> + <li>*obj - Expression object to clear</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprParse(exprObj *obj, char *expr);<br> + Comments: + <ul> + <li>Parse an expression string into an expression object</li> + </ul> + Paramters: + <ul> + <li>*obj - Expression object to use</li> + <li>*expr - Expression string to parse</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprEval(exprObj *obj, EXPRTYPE *val);<br> + Comments: + <ul> + <li>Evaluate a parsed expression. This function does not + reset the breaker count at each call, but instead accumulates + the count until the breaker function is called. Then the count + is reset to the value specified in exprSetBreakerCount.</li> + </ul> + Paramters: + <ul> + <li>*obj - Expression object to evaluate</li> + <li>*val = Pointer to variable to get result of evaluation. + This can be NULL if the result is not needed.</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>int exprEvalNode(exprObj *obj, exprNode *nodes, int curnode, EXPRTYPE *val);<br> + Comments: + <ul> + <li>Evaluate a node of an expression. + Used by custom functions</li> + </ul> + Parameters: + <ul> + <li>*obj - Expression object being used</li> + <li>*nodes - Pointer to a node or list of nodes</li> + <li>curnode - Index to the node to evaluate</li> + <li>*val - Pointer to variable to get evaluation result</li> + </ul> + Returns: + <ul> + <li>Error code of the function</li> + </ul> + </li><br> + <li>exprFuncList *exprGetFuncList(exprObj *obj);<br> + Comments: + <ul> + <li>Gets the function list associated with an expression</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + </ul> + Returns: + <ul> + <li>Pointer fo an exprFuncList object or NULL</li> + </ul> + </li><br> + <li>exprValList *exprGetVarList(exprObj *obj);<br> + Comments: + <ul> + <li>Gets the variable list associated with an expression</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + </ul> + Returns: + <ul> + <li>Pointer to an exprValList object or NULL</li> + </ul> + </li><br> + <li>exprValList *exprGetConstList(exprObj *obj);<br> + Comments: + <ul> + <li>Gets the constant list associated with an expression</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + </ul> + Returns: + <ul> + <li>Pointer to an exprValList object or NULL</li> + </ul> + </li><br> + <li>exprBreakFuncType exprGetBreakFunc(exprObj *obj);<br> + Comments: + <ul> + <li>Gets the breaker callback of the expression</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + </ul> + Returns: + <ul> + <li>Pointer to the callback function or NULL</li> + </ul> + </li><br> + <li>int exprGetBreakResult(exprObj *obj);<br> + Comments: + <ul> + <li>Get the result of the breaker function</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + </ul> + Returns: + <ul> + <li>zero to continue, nonzero to break</li> + </ul> + </li><br> + <li>void* exprGetUserData(exprObj *obj);<br> + Comments: + <ul> + <li>Gets the user data associated with an expression</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + </ul> + Returns: + <ul> + <li>User data</li> + </ul> + </li><br> + <li>void exprSetUserData(exprObj *obj, void *userdata);<br> + Comments: + <ul> + <li>Sets the user data of an expression</li> + </ul> + Parameters: + <ul> + <li>*obj - expresion object</li> + <li>userdata - user data to set</li> + </ul> + Returns: + <ul> + <li>Nothing</li> + </ul> + </li><br> + <li>void exprSetBreakCount(exprObj *obj, int count);<br> + Comments: + <ul> + <li>Set how often the breaker function is tested. + The default is 100000. This means the breaker + function is tested once every 100000 times the + exprEvalNode function is called for an expression. + A smaller value tests the breaker function more often + and a larger value tests the breaker function less. The + breaker value is NOT reset during each call to exprEval, + but is accumulated across calles to exprEval + until the breaker function is finally called.</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + <li>count - how many times exprEvalNode gets called before the + breaker function is tested</li> + </ul> + Returns: + <ul> + <li>Nothing</li> + </ul> + </li><br> + <li>void exprGetErrorPosition(exprObj *obj, int *start, int *end);<br> + Comments: + <ul> + <li>Gets the start and ending positions in the expression string + of the last parse error. The positions include any newline + characters that may be in the string.</li> + </ul> + Parameters: + <ul> + <li>*obj - expression object</li> + <li>*start - pointer to an integer to get the start error position, + -1 if unknown</li> + <li>*end - pointer to an integer to get the end error position, + -1 if unknown</li> + </ul> + Returns: + <ul> + <li>Nothing</li> + </ul> + </ul> + </p> + <p><b>Some useful functions</b> + <ul> + <li>int exprValidIdent(char *name);<br> + Comments: + <ul> + <li>Determine if an identifier is valid</li> + </ul> + Parameters: + <ul> + <li>*name - identifier to check</li> + </ul> + Returns: + <ul> + <li>0 on invalid. anything else on valid</li> + </ul> + </li><br> + </ul> + </p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="Compiling">Compiling the ExprEval library</a></h2> + <p>Compiling the ExprEval library is pretty simple. Just + compile all of the source files (*.c) and link them into + a library. You need to keep "expreval.h" for the header file.</p> + <p>You may have to make some changes to the library. I've + tried to make doing so as simple as possible. If you + need to change the include files or some macros or whatnot, + edit the file "exprincl.h" This file includes any other files + needed. You should not have to change to much. I have + tried to stick as close to ANSI/ISO C as I can.</p> +</div> + +<div align="left" class="container"> + <h2><a name="Drawbacks">Drawbacks/Problems</a></h2> + <p>The following is a list of some basic drawbacks of this + library: + <ul> + <li>This library is an expression evaluator, and nothing + else. It does not simplify expressions and it + does not do advanced math such as calculating the + integrals and differentials of expression.</li> + <li>This library has no way of detecting overflows + except for those caused by the internal math + routines. Adding two very very large numbers + may cause an overflow to occur.</li> + <li>This library is not super easy to use in an application. + It has been designed to give much control to the + developer. Because of this, the function/value lists + are seperate from the expression objects, allowing + the developer to use them however they need.</li> + <li>There is no way to delete a single function, variable, + or constant from a list. This is because I see no + real need to do so because of the way the library + works. There is no need to delete function from + a function list or constants from a constant list. + There are are also no decent reasons to delete + variables from a variable list until you are completely + done and delete all of them.</li> + </ul> + </p> +</div> + +<div align="left" class="container"> + <h2><a name="Solutions">Problems and Solutions</a></h2> + + <ul> + <li><b>Variables do not seem to change in a release/optimized build.</b><br> + I have noticed a small problem with this. Rarely, a variable may not + appear to change in a release build. The reason is to do with compiler + optimizations. For example, look at the following code: + <blockquote> + <pre> +EXPRTYPE k; + +/* Add variable to the list */ +exprValListAddAddress(list, "k", &k); + +k = 0.0; + +/* Evaluate expression */ +for(int x = 0; x < 100; x++) + { + exprEval(expr, &result); + + doSomething(k); + } + </pre> + </blockquote> + Inside the loop, the variable 'k' does not appear to be changing, so + the compiler may optimize it by loading it into a register before the + loop and not accessing it from memory during the loop, even if + the expression does change it. One way to avoid this is to use the + 'volatile' keyword with the variable. Then the compiler must + accesss it from memory each time it is accessed. + <blockquote> + <pre> +volatile EXPRTYPE k; + +/* Add variable to the list */ +exprValListAddAddress(list, "k", (EXPRTYPE*)&k); + +k = 0.0; + +/* Evaluate expression */ +for(int x = 0; x < 100; x++) + { + exprEval(expr, &result); + + doSomething(k); + } + </pre> + </blockquote> + </li> + +</div> + +<div align="left" class="container"> + <h2><a name="Example">Example Use with Fast Variable Access</a></h2> + + <p>This is an example application of this library. It is a + graphics program that calculates the color value of a + pixel based on it's X,Y co-ordinate. It uses a made-up + image library called graphic-lib. It uses faster variable + access by using the exprValListGetAddress function.</p> + <p>Note that this codes has not actually been tested. See the + test applications (test and imagegen) for other examples.</p> + + <blockquote> + <pre> +/* Include files */ +#include <stdio.h> +#include <stdlib.h> +#include <setjmp.h> +#include "graphiclib.h" +#include "expreval.h" + +char *transerr(int err) + { + /* Translate error code into message */ + } + +void gen_image(char *name, int w, int h, char *expr); + { + exprFuncList *f = NULL; + exprValList *v = NULL; + exprValList *c = NULL; + exprObj *o = NULL; + int x, y, err; + jmp_buf jumper; + int image; + EXPRTYPE *v_x, *v_y; + EXPRTYPE *v_r, *v_g, *v_b; + EXPRTYPE global_value; + + /* Error handling */ + err = setjmp(jumper); + if(err) + { + if(err != ID_IMAGENOERROR) + printf("Error %d occurred: %s\n", err, transerr(err)); + + exprFree(o); + exprFreeFuncList(f); + exprFreeValList(v); + exprFreeValList(c); + + image_free(image); + return; + } + + /* Set up lists */ + + /* Function list */ + err = exprFuncListCreate(&f); + if(err != EXPR_ERROR_NOERROR) + longjmp(jumper, err); + + err = exprFuncListInit(f); + if(err != EXPR_ERROR_NOERROR) + { + printf("Function list init error. Functions may not be available.\n"); + } + + /* Variable list */ + err = exprValListCreate(&v); + if(err != EXPR_ERROR_NOERROR) + longjmp(jumper, err); + + /* Constant list */ + err = exprValListCreate(&c); + if(err != EXPR_ERROR_NOERROR) + { + printf("Constants not available\n"); + } + else + { + err = exprValListInit(c); + if(err != EXPR_ERROR_NOERROR) + printf("Constant list init error. Constants may not be available.\n"); + } + + /* Create and parse the expression */ + + /* Create */ + err = exprCreate(&o, f, v, c, NULL, 0); + if(err != EXPR_ERROR_NOERROR) + longjmp(jumper, err); + + /* Parse expression */ + err = exprParse(o, expr); + if(err != EXPR_ERROR_NOERROR) + longjmp(jumper, err); + + + /* Create the image */ + image = image_create(w, h); + if(image == 0) + { + longjmp(jumper, ID_IMAGECREATEERROR); + } + + /* Add width and height to variable list */ + exprValListAdd(v, "w", (EXPRTYPE)w); + exprValListAdd(v, "h", (EXPRTYPE)h); + + /* Add x and y to the list */ + exprValListAdd(v, "x", 0.0); + exprValListAdd(v, "y", 0.0); + + /* Add r, g, and b to the list */ + exprValListAdd(v, "r", 0.0); + exprValListAdd(v, "g", 0.0); + exprValListAdd(b, "b", 0.0); + + /* Get addresses. Assume no error */ + exprValListGetAddress(v, "x", &v_x); + exprValListGetAddress(v, "y", &v_y); + + exprValListGetAddress(v, "r", &v_r); + exprValListGetAddress(v, "g", &v_g); + exprValListGetAddress(v, "g", &v_b); + + /* A way to add global variables that can be used by two different lists. */ + exprValListAddAddress(v, "global", &global_value); + /* exprValListAddAddress(v2, "global", &global_value); */ + + /* Also, exprValListAddAddress can be used to add variables directly. + Instead of: + + EXPRTYPE *a; + + exprValListAdd(v, "a", 0.0); + exprValListGetAddresss(v, "a", &a); + + You can do: + + EXPRTYPE a; + + exprValListAddAddresss(v, "a", &a); + + If you do this, you must ensure that the stack variable exists as long + as it is used by expression, otherwise it may cause a memory access + violation. */ + + + for(y = 0; y < h; y++) + { + for(x = 0; x < w; x++) + { + /* Directly set the x and y variables */ + *v_x = (EXPRTYPE)x; + *v_y = (EXPRTYPE)y; + + /* Eval expression, ignoring errors */ + exprEval(o); + + /* Set pixel, using variables directly */ + image_setpixel(image, x, y, (int)(*v_r), (int)(*v_g), (int)(*v_b)); + } + } + + /* Save image */ + image_save(image, name); + + /* Done */ + longjmp(jumper, ID_IMAGENOERROR); + } + +void main(void) + { + char name[MAXPATH] + char tmp[10]; + char expr[4096]; + int sx, sy; + + printf("Image name to save: "); + gets(name); + + printf("Image width: "); + gets(tmp); + sx = atoi(tmp); + + printf("Image height: "); + gets(tmp); + sy = atoi(tmp); + + printf("Color Expression (Use x, y, w, h Set r, g, b): "); + gets(expr); + + gen_image(name, sx, sy, expr); + } + + </pre> + </blockquote> +</div> + +</body> +</html> Added: freeswitch/trunk/src/mod/applications/mod_expr/exprfunc.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprfunc.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,329 @@ +/* + File: exprfunc.c + Auth: Brian Allen Vanderburg II + Date: Thursday, April 24, 2003 + Desc: Expression function list routines + + This file is part of ExprEval. +*/ + + + +/* Includes */ +#include "exprincl.h" + +#include "exprpriv.h" +#include "exprmem.h" + +/* Internal functions */ +static exprFunc *exprCreateFunc(char *name, exprFuncType ptr, int type, int min, int max, int refmin, int refmax); +static void exprFuncListFreeData(exprFunc *func); + + +/* This function creates the function list, */ +int exprFuncListCreate(exprFuncList **flist) + { + exprFuncList *tmp; + + if(flist == NULL) + return EXPR_ERROR_NULLPOINTER; + + *flist = NULL; /* Set to NULL initially */ + + tmp = exprAllocMem(sizeof(exprFuncList)); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; /* Could not allocate memory */ + + /* Update pointer */ + *flist = tmp; + + return EXPR_ERROR_NOERROR; + } + +/* Add a function to the list */ +int exprFuncListAdd(exprFuncList *flist, char *name, exprFuncType ptr, int min, int max, int refmin, int refmax) + { + exprFunc *tmp; + exprFunc *cur; + int result; + + if(flist == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Make sure the name is valid */ + if(!exprValidIdent(name)) + return EXPR_ERROR_BADIDENTIFIER; + + /* Fix values only if none are negative (negative values mean no limit) */ + + /* if both are neg, no min or max number of args */ + /* if min is neg, max pos, no min number of args but a maximum */ + /* if min is pos, max neg, there is a min number of args, but no max */ + /* if both pos, then a min and max limit. We swap to make sure it works + right. I.E. Min of 3 and max of 2 would make function unusable */ + if(min >= 0 && max >= 0) + { + if(min > max) + { + result = min; + min = max; + max = result; + } + } + + if(refmin >= 0 && refmax >= 0) + { + if(refmin > refmax) + { + result = refmin; + refmin = max; + refmax = result; + } + } + + if(flist->head == NULL) + { + /* Create the node right here */ + tmp = exprCreateFunc(name, ptr, EXPR_NODETYPE_FUNCTION, min, max, refmin, refmax); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + flist->head = tmp; + return EXPR_ERROR_NOERROR; + } + + /* See if it already exists */ + cur = flist->head; + + while(cur) + { + result = strcmp(name, cur->fname); + + if(result == 0) + return EXPR_ERROR_ALREADYEXISTS; + + cur = cur->next; + } + + /* It did not exist, so add it at the head */ + tmp = exprCreateFunc(name, ptr, EXPR_NODETYPE_FUNCTION, min, max, refmin, refmax); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + tmp->next = flist->head; + flist->head = tmp; + return EXPR_ERROR_NOERROR; + } + +/* Add a function node type to the list + This works pretty much the same way, except the function + pointer is NULL and the node type specifies the function + to do. exprEvalNode handles this, instead of calling + a function solver. */ +int exprFuncListAddType(exprFuncList *flist, char *name, int type, int min, int max, int refmin, int refmax) + { + exprFunc *tmp; + exprFunc *cur; + int result; + + if(flist == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Make sure the name is valid */ + if(!exprValidIdent(name)) + return EXPR_ERROR_BADIDENTIFIER; + + /* Fix values only if none are negative (negative values mean no limit) */ + + /* if both are neg, no min or max number of args */ + /* if min is neg, max pos, no min number of args but a maximum */ + /* if min is pos, max neg, there is a min number of args, but no max */ + /* if both pos, then a min and max limit. We swap to make sure it works + right. I.E. Min of 3 and max of 2 would make function unusable */ + if(min >= 0 && max >= 0) + { + if(min > max) + { + result = min; + min = max; + max = result; + } + } + + if(refmin >= 0 && refmax >= 0) + { + if(refmin > refmax) + { + result = refmin; + refmin = max; + refmax = result; + } + } + + if(flist->head == NULL) + { + /* Create the node right here */ + tmp = exprCreateFunc(name, NULL, type, min, max, refmin, refmax); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + flist->head = tmp; + return EXPR_ERROR_NOERROR; + } + + /* See if it already exists */ + cur = flist->head; + + while(cur) + { + result = strcmp(name, cur->fname); + + if(result == 0) + return EXPR_ERROR_ALREADYEXISTS; + + cur = cur->next; + } + + /* It did not exist, so add it at the head */ + tmp = exprCreateFunc(name, NULL, type, min, max, refmin, refmax); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + tmp->next = flist->head; + flist->head = tmp; + return EXPR_ERROR_NOERROR; + } + + +/* Get the function from a list along with it's min an max data */ +int exprFuncListGet(exprFuncList *flist, char *name, exprFuncType *ptr, int *type, int *min, int *max, int *refmin, int *refmax) + { + exprFunc *cur; + int result; + + if(flist == NULL) + return EXPR_ERROR_NULLPOINTER; + + if(name == NULL || name[0] == '\0') + return EXPR_ERROR_NOTFOUND; + + /* Search for the item */ + cur = flist->head; + + while(cur) + { + result = strcmp(name, cur->fname); + + if(result == 0) + { + /* We found it. */ + *ptr = cur->fptr; + *min = cur->min; + *max = cur->max; + *refmin = cur->refmin; + *refmax = cur->refmax; + *type = cur->type; + + /* return now */ + return EXPR_ERROR_NOERROR; + } + + cur = cur->next; + } + + /* If we got here, we did not find the item in the list */ + return EXPR_ERROR_NOTFOUND; + } + +/* This routine will free the function list */ +int exprFuncListFree(exprFuncList *flist) + { + /* Make sure it exists, if not it is not error */ + if(flist == NULL) + return EXPR_ERROR_NOERROR; + + /* Free the nodes */ + exprFuncListFreeData(flist->head); + + /* Free the container */ + exprFreeMem(flist); + + return EXPR_ERROR_NOERROR; + } + +/* This routine will clear the function list */ +int exprFuncListClear(exprFuncList *flist) + { + if(flist == NULL) + return EXPR_ERROR_NOERROR; + + /* Free the nodes only */ + if(flist->head) + { + exprFuncListFreeData(flist->head); + + flist->head = NULL; + } + + return EXPR_ERROR_NOERROR; + } + +/* This routine will free any child nodes, and then free itself */ +void exprFuncListFreeData(exprFunc *func) + { + exprFunc *next; + + while(func) + { + /* Remember the next item */ + next = func->next; + + /* Free name */ + exprFreeMem(func->fname); + + /* Free ourself */ + exprFreeMem(func); + + func = next; + } + } + +/* This routine will create the function object */ +exprFunc *exprCreateFunc(char *name, exprFuncType ptr, int type, int min, int max, int refmin, int refmax) + { + exprFunc *tmp; + char *vtmp; + + /* We already checked the name in exprFuncListAdd */ + + /* Create it */ + tmp = exprAllocMem(sizeof(exprFunc)); + if(tmp == NULL) + return NULL; + + /* Allocate space for the name */ + vtmp = exprAllocMem(strlen(name) + 1); + + if(vtmp == NULL) + { + exprFreeMem(tmp); + return NULL; + } + + /* Copy the data over */ + strcpy(vtmp, name); + tmp->fname = vtmp; + tmp->fptr = ptr; + tmp->min = min; + tmp->max = max; + tmp->refmin = refmin; + tmp->refmax = refmax; + tmp->type = type; + + return tmp; + } Added: freeswitch/trunk/src/mod/applications/mod_expr/exprilfs.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprilfs.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,1064 @@ +/* + File: exprilfs.h + Auth: Brian Allen Vanderburg II + Date: Tuesday, February 28, 2006 + Desc: Inline Function Solvers for exprEvalNode + + This file is part of ExprEval. +*/ + +/* + This is here to help prevent expreval.c from getting + too crowded. + + Provided variables: + obj: expression object point + nodes: function node with paramters + d1, d2: variables + err: error + val: value pointer for resuld + pos: integer + + Also EXPR_RESET_ERR() and EXPR_CHECK_ERR() + + The chunks below are included inside a statement that looks like this: + + switch(nodes->data.function.type) + { + #include "exprilfs.h" + + default: + { + return EXPR_ERROR_UNKNOWN; + } + } +*/ + + + +/* abs */ +case EXPR_NODEFUNC_ABS: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + if(d1 >= 0) + *val = d1; + else + *val = -d1; + } + else + return err; + + break; + } + +/* mod */ +case EXPR_NODEFUNC_MOD: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = fmod(d1, d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* ipart */ +case EXPR_NODEFUNC_IPART: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + modf(d1, val); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* fpart */ +case EXPR_NODEFUNC_FPART: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = modf(d1, &d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* min */ +case EXPR_NODEFUNC_MIN: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + for(pos = 1; pos < nodes->data.function.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.function.nodes, pos, &d2); + if(!err) + { + if(d2 < d1) + d1 = d2; + } + else + return err; + } + } + else + return err; + + *val = d1; + + break; + } + +/* max */ +case EXPR_NODEFUNC_MAX: + { + int pos; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + for(pos = 1; pos < nodes->data.function.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.function.nodes, pos, &d2); + if(!err) + { + if(d2 > d1) + d1 = d2; + } + else + return err; + } + } + else + return err; + + *val = d1; + + break; + } + +/* pow */ +case EXPR_NODEFUNC_POW: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = pow(d1, d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* sqrt */ +case EXPR_NODEFUNC_SQRT: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = sqrt(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* sin */ +case EXPR_NODEFUNC_SIN: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = sin(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* sinh */ +case EXPR_NODEFUNC_SINH: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = sinh(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* asin */ +case EXPR_NODEFUNC_ASIN: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = asin(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* cos */ +case EXPR_NODEFUNC_COS: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = cos(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* cosh */ +case EXPR_NODEFUNC_COSH: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = cosh(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* acos */ +case EXPR_NODEFUNC_ACOS: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = acos(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* tan */ +case EXPR_NODEFUNC_TAN: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = tan(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* tanh */ +case EXPR_NODEFUNC_TANH: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = tanh(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* atan */ +case EXPR_NODEFUNC_ATAN: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = atan(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* atan2 */ +case EXPR_NODEFUNC_ATAN2: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = atan2(d1, d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* log */ +case EXPR_NODEFUNC_LOG: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = log10(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* pow10 */ +case EXPR_NODEFUNC_POW10: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = pow(10.0, d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* ln */ +case EXPR_NODEFUNC_LN: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = log(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* exp */ +case EXPR_NODEFUNC_EXP: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + EXPR_RESET_ERR(); + *val = exp(d1); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +case EXPR_NODEFUNC_LOGN: + { + EXPRTYPE l1, l2; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + l1 = log(d1); + EXPR_CHECK_ERR(); + l2 = log(d2); + EXPR_CHECK_ERR(); + + + if(l2 == 0.0) + { +#if(EXPR_ERROR_LEVEL >= EXPR_ERROR_LEVEL_CHECK) + return EXPR_ERROR_OUTOFRANGE; +#else + *val = 0.0; + return EXPR_ERROR_NOERROR; +#endif + } + + *val = l1 / l2; + } + else + return err; + + break; + } + +/* ceil */ +case EXPR_NODEFUNC_CEIL: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + *val = ceil(d1); + } + else + return err; + + break; + } + +/* floor */ +case EXPR_NODEFUNC_FLOOR: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + *val = floor(d1); + } + else + return err; + + break; + } + +/* rand */ +case EXPR_NODEFUNC_RAND: + { + long a; + + /* Perform random routine directly */ + a = ((long)(*(nodes->data.function.refs[0]))) * 214013L + 2531011L; + *(nodes->data.function.refs[0]) = (EXPRTYPE)a; + + *val = (EXPRTYPE)((a >> 16) & 0x7FFF) / (EXPRTYPE)(32768); + break; + } + +/* random */ +case EXPR_NODEFUNC_RANDOM: + { + EXPRTYPE diff, rval; + long a; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + diff = d2 - d1; + + /* Perform random routine directly */ + a = ((long)(*(nodes->data.function.refs[0]))) * 214013L + 2531011L; + *(nodes->data.function.refs[0]) = (EXPRTYPE)a; + + rval = (EXPRTYPE)((a >> 16) & 0x7FFF) / (EXPRTYPE)(32767); + + *val = (rval * diff) + d1; + } + else + return err; + + break; + } + +/* randomize */ +case EXPR_NODEFUNC_RANDOMIZE: + { + static int curcall = 0; + + curcall++; + + *(nodes->data.function.refs[0]) = (EXPRTYPE)((clock() + 1024 + curcall) * time(NULL)); + + break; + } + +/* deg */ +case EXPR_NODEFUNC_DEG: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + *val = (180.0 * d1) / M_PI; + } + else + return err; + + break; + } + +/* rad */ +case EXPR_NODEFUNC_RAD: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + *val = (M_PI * d1) / 180.0; + } + else + return err; + + break; + } + +/* recttopolr */ +case EXPR_NODEFUNC_RECTTOPOLR: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = sqrt((d1 * d1) + (d2 * d2)); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* recttopola */ +case EXPR_NODEFUNC_RECTTOPOLA: + { + EXPRTYPE tmp; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + tmp = atan2(d2, d1); + EXPR_CHECK_ERR(); + + if(tmp < 0.0) + *val = tmp = (2.0 * M_PI); + else + *val = tmp; + } + else + return err; + + break; + } + +/* poltorectx */ +case EXPR_NODEFUNC_POLTORECTX: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = d1 * cos(d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* poltorecty */ +case EXPR_NODEFUNC_POLTORECTY: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + *val = d1 * sin(d2); + EXPR_CHECK_ERR(); + } + else + return err; + + break; + } + +/* if */ +case EXPR_NODEFUNC_IF: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + if(d1 != 0.0) + { + err = exprEvalNode(obj, nodes->data.function.nodes, 1, val); + if(err) + return err; + } + else + { + err = exprEvalNode(obj, nodes->data.function.nodes, 2, val); + if(err) + return err; + } + } + else + return err; + + break; + } + +/* select */ +case EXPR_NODEFUNC_SELECT: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + if(d1 < 0.0) + { + err = exprEvalNode(obj, nodes->data.function.nodes, 1, val); + if(err) + return err; + } + else if(d1 == 0.0) + { + err = exprEvalNode(obj, nodes->data.function.nodes, 2, val); + if(err) + return err; + } + else + { + if(nodes->data.function.nodecount == 3) + { + err = exprEvalNode(obj, nodes->data.function.nodes, 2, val); + if(err) + return err; + } + else + { + err = exprEvalNode(obj, nodes->data.function.nodes, 3, val); + if(err) + return err; + } + } + } + else + return err; + + break; + } + +/* equal */ +case EXPR_NODEFUNC_EQUAL: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + *val = (d1 == d2) ? 1.0 : 0.0; + } + else + return err; + + break; + } + +/* above */ +case EXPR_NODEFUNC_ABOVE: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + *val = (d1 > d2) ? 1.0 : 0.0; + } + else + return err; + + break; + } + +/* below */ +case EXPR_NODEFUNC_BELOW: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + *val = (d1 < d2) ? 1.0 : 0.0; + } + else + return err; + + break; + } + +/* avg */ +case EXPR_NODEFUNC_AVG: + { + d2 = 0.0; + + for(pos = 0; pos < nodes->data.function.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.function.nodes, pos, &d1); + if(!err) + { + d2 += d1; + } + else + return err; + } + + *val = d2 / (EXPRTYPE)(nodes->data.function.nodecount); + + break; + } + +/* clip */ +case EXPR_NODEFUNC_CLIP: + { + EXPRTYPE v; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &v); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + if(v < d1) + *val = d1; + else if(v > d2) + *val = d2; + else + *val = v; + } + else + return err; + + break; + } + +/* clamp */ +case EXPR_NODEFUNC_CLAMP: + { + EXPRTYPE v, tmp; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &v); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + EXPR_RESET_ERR(); + tmp = fmod(v - d1, d2 - d1); + EXPR_CHECK_ERR(); + + if(tmp < 0.0) + *val = tmp * d2; + else + *val = tmp + d1; + } + else + return err; + + break; + } + +/* pntchange */ +case EXPR_NODEFUNC_PNTCHANGE: + { + EXPRTYPE n1, n2, pnt; + EXPRTYPE odiff, ndiff, perc; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 2, &n1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 3, &n2); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 4, &pnt); + + if(!err) + { + odiff = d2 - d1; + ndiff = n2 - n1; + + if(odiff == 0.0) + { + *val = d1; + return EXPR_ERROR_NOERROR; + } + + perc = (pnt - d1) / odiff; + + *val = n1 + (perc * ndiff); + } + else + return err; + + break; + } + +/* poly */ +case EXPR_NODEFUNC_POLY: + { + EXPRTYPE total, curpow; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + curpow = (EXPRTYPE)(nodes->data.function.nodecount) - 2.0; + total = 0.0; + + for(pos = 1; pos < nodes->data.function.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.function.nodes, pos, &d2); + if(err) + return err; + + EXPR_RESET_ERR(); + total = total + (d2 * pow(d1, curpow)); + EXPR_CHECK_ERR(); + + curpow = curpow - 1.0; + } + } + else + return err; + + *val = total; + break; + } + +/* and */ +case EXPR_NODEFUNC_AND: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + if(d1 == 0.0 || d2 == 0.0) + *val = 0.0; + else + *val = 1.0; + } + else + return err; + + break; + } + +/* or */ +case EXPR_NODEFUNC_OR: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &d2); + + if(!err) + { + if(d1 != 0.0 || d2 != 0.0) + *val = 1.0; + else + *val = 0.0; + } + else + return err; + + break; + } + +/* not */ +case EXPR_NODEFUNC_NOT: + { + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + { + if(d1 != 0.0) + *val = 0.0; + else + *val = 1.0; + } + else + return err; + + break; + } + +/* for */ +case EXPR_NODEFUNC_FOR: + { + int pos; + EXPRTYPE test; + + err = exprEvalNode(obj, nodes->data.function.nodes, 0, &d1); + + if(!err) + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &test); + + if(!err) + { + while(test != 0.0) + { + for(pos = 3; pos < nodes->data.function.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.function.nodes, pos, val); + if(err) + return err; + } + + err = exprEvalNode(obj, nodes->data.function.nodes, 2, &d1); + if(err) + return err; + + err = exprEvalNode(obj, nodes->data.function.nodes, 1, &test); + if(err) + return err; + } + } + else + return err; + + break; + } + +/* many */ +case EXPR_NODEFUNC_MANY: + { + for(pos = 0; pos < nodes->data.function.nodecount; pos++) + { + err = exprEvalNode(obj, nodes->data.function.nodes, pos, val); + if(err) + return err; + } + + break; + } + Added: freeswitch/trunk/src/mod/applications/mod_expr/exprincl.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprincl.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,101 @@ +/* + File: exprincl.h + Auth: Brian Allen Vanderburg II + Date: Thursday, April 24, 2003 + Desc: Includes, macros, etc needed by this library + + This file is part of ExprEval. +*/ + +#ifndef __BAVII_EXPRINCL_H +#define __BAVII_EXPRINCL_H + + +/* Includes and macros and whatnot for building the library */ + +/* Memory routines. memory.h for VC++, mem.h for BC++ */ +#ifdef __TURBOC__ +#include <mem.h> +#else +#include <memory.h> +#endif + +/* Memory allocation */ +#include <malloc.h> + +/* String routines */ +#include <string.h> + +/* Character manipulation routines */ +#include <ctype.h> + +/* Standard routines */ +#include <stdlib.h> + +/* Math routines */ +#include <math.h> + +/* Time */ +#include <time.h> + + +/* Math constants. VC++ does not seem to have these */ +#ifndef M_E +#define M_E 2.7182818284590452354 +#endif + +#ifndef M_LOG2E +#define M_LOG2E 1.4426950408889634074 +#endif + +#ifndef M_LOG10E +#define M_LOG10E 0.43429448190325182765 +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 +#endif + +#ifndef M_1_PI +#define M_1_PI 0.31830988618379067154 +#endif + +#ifndef M_2_PI +#define M_2_PI 0.63661977236758134308 +#endif + +#ifndef M_1_SQRTPI +#define M_1_SQRTPI 0.56418958354776 +#endif + +#ifndef M_2_SQRTPI +#define M_2_SQRTPI 1.12837916709551257390 +#endif + +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif + +#ifndef M_1_SQRT2 +#define M_1_SQRT2 0.70710678118654752440 +#endif + + + +#endif /* __BAVII_EXPRINCL_H */ Added: freeswitch/trunk/src/mod/applications/mod_expr/exprinit.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprinit.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,115 @@ +/* + File: exprinit.c + Auth: Brian Allen Vanderburg II + Date: Thursday, May 1, 2003 + Desc: Extra functions and routines for ExprEval + + This file is part of ExprEval. +*/ + +/* Include files */ +#include "exprincl.h" + +#include "exprpriv.h" + + +/* Macro for adding a function node type */ +#define EXPR_ADDFUNC_TYPE(name, type, argmin, argmax, refmin, refmax) \ +err = exprFuncListAddType(flist, name, type, argmin, argmax, refmin, refmax); \ +if(err != EXPR_ERROR_NOERROR) \ + return err; + +/* Macro for adding a constant */ +#define EXPR_ADDCONST(name, val) \ +err = exprValListAdd(vlist, name, val); \ +if(err != EXPR_ERROR_NOERROR) \ + return err; + +/* Call this function to initialize these functions into a function list */ +int exprFuncListInit(exprFuncList *flist) + { + int err; + + if(flist == NULL) + return EXPR_ERROR_NULLPOINTER; + + EXPR_ADDFUNC_TYPE("abs", EXPR_NODEFUNC_ABS, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("mod", EXPR_NODEFUNC_MOD, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("ipart", EXPR_NODEFUNC_IPART, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("fpart", EXPR_NODEFUNC_FPART, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("min", EXPR_NODEFUNC_MIN, 1, -1, 0, 0); + EXPR_ADDFUNC_TYPE("max", EXPR_NODEFUNC_MAX, 1, -1, 0, 0); + EXPR_ADDFUNC_TYPE("pow", EXPR_NODEFUNC_POW, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("sqrt", EXPR_NODEFUNC_SQRT, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("sin", EXPR_NODEFUNC_SIN, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("sinh", EXPR_NODEFUNC_SINH, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("asin", EXPR_NODEFUNC_ASIN, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("cos", EXPR_NODEFUNC_COS, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("cosh", EXPR_NODEFUNC_COSH, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("acos", EXPR_NODEFUNC_ACOS, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("tan", EXPR_NODEFUNC_TAN, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("tanh", EXPR_NODEFUNC_TANH, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("atan", EXPR_NODEFUNC_ATAN, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("atan2", EXPR_NODEFUNC_ATAN2, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("log", EXPR_NODEFUNC_LOG, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("pow10", EXPR_NODEFUNC_POW10, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("ln", EXPR_NODEFUNC_LN, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("exp", EXPR_NODEFUNC_EXP, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("logn", EXPR_NODEFUNC_LOGN, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("ceil", EXPR_NODEFUNC_CEIL, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("floor", EXPR_NODEFUNC_FLOOR, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("rand", EXPR_NODEFUNC_RAND, 0, 0, 1, 1); + EXPR_ADDFUNC_TYPE("random", EXPR_NODEFUNC_RANDOM, 2, 2, 1, 1); + EXPR_ADDFUNC_TYPE("randomize", EXPR_NODEFUNC_RANDOMIZE, 0, 0, 1, 1); + EXPR_ADDFUNC_TYPE("deg", EXPR_NODEFUNC_DEG, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("rad", EXPR_NODEFUNC_RAD, 1, 1, 0, 0); + EXPR_ADDFUNC_TYPE("recttopolr", EXPR_NODEFUNC_RECTTOPOLR, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("recttopola", EXPR_NODEFUNC_RECTTOPOLA, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("poltorectx", EXPR_NODEFUNC_POLTORECTX, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("poltorecty", EXPR_NODEFUNC_POLTORECTY, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("if", EXPR_NODEFUNC_IF, 3, 3, 0, 0); + EXPR_ADDFUNC_TYPE("select", EXPR_NODEFUNC_SELECT, 3, 4, 0, 0); + EXPR_ADDFUNC_TYPE("equal", EXPR_NODEFUNC_EQUAL, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("above", EXPR_NODEFUNC_ABOVE, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("below", EXPR_NODEFUNC_BELOW, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("avg", EXPR_NODEFUNC_AVG, 1, -1, 0, 0); + EXPR_ADDFUNC_TYPE("clip", EXPR_NODEFUNC_CLIP, 3, 3, 0, 0); + EXPR_ADDFUNC_TYPE("clamp", EXPR_NODEFUNC_CLAMP, 3, 3, 0, 0); + EXPR_ADDFUNC_TYPE("pntchange", EXPR_NODEFUNC_PNTCHANGE, 5, 5, 0, 0); + EXPR_ADDFUNC_TYPE("poly", EXPR_NODEFUNC_POLY, 2, -1, 0, 0); + EXPR_ADDFUNC_TYPE("and", EXPR_NODEFUNC_AND, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("or", EXPR_NODEFUNC_OR, 2, 2, 0, 0); + EXPR_ADDFUNC_TYPE("not", EXPR_NODEFUNC_NOT, 1 ,1, 0, 0); + EXPR_ADDFUNC_TYPE("for", EXPR_NODEFUNC_FOR, 4, -1, 0, 0); + EXPR_ADDFUNC_TYPE("many", EXPR_NODEFUNC_MANY, 1, -1, 0, 0); + + return EXPR_ERROR_NOERROR; + } + +/* Call this function to initialize some constants into a value list */ +int exprValListInit(exprValList *vlist) + { + int err; + + if(vlist == NULL) + return EXPR_ERROR_NULLPOINTER; + + EXPR_ADDCONST("M_E", M_E); + EXPR_ADDCONST("M_LOG2E", M_LOG2E); + EXPR_ADDCONST("M_LOG10E", M_LOG10E); + EXPR_ADDCONST("M_LN2", M_LN2); + EXPR_ADDCONST("M_LN10", M_LN10); + EXPR_ADDCONST("M_PI", M_PI); + EXPR_ADDCONST("M_PI_2", M_PI_2); + EXPR_ADDCONST("M_PI_4", M_PI_4); + EXPR_ADDCONST("M_1_PI", M_1_PI); + EXPR_ADDCONST("M_2_PI", M_2_PI); + EXPR_ADDCONST("M_1_SQRTPI", M_1_SQRTPI); + EXPR_ADDCONST("M_2_SQRTPI", M_2_SQRTPI); + EXPR_ADDCONST("M_SQRT2", M_SQRT2); + EXPR_ADDCONST("M_1_SQRT2", M_1_SQRT2); + + return EXPR_ERROR_NOERROR; + } + + Added: freeswitch/trunk/src/mod/applications/mod_expr/exprmem.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprmem.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,39 @@ +/* + File: exprmem.c + Auth: Brian Allen Vanderburg II + Date: Wednesday, April 30, 2003 + Desc: Memory functions for ExprEval + + This file is part of ExprEval. +*/ + +/* Includes */ +#include "exprincl.h" + +#include "exprmem.h" + +/* Allocate memory and zero it */ +void* exprAllocMem(size_t size) + { + void *data = malloc(size); + + if(data) + { + memset(data, 0, size); + } + + return data; + } + +/* Free memory */ +void exprFreeMem(void *data) + { + if(data) + free(data); + } + +/* Allocate a list of nodes */ +exprNode *exprAllocNodes(size_t count) + { + return exprAllocMem(count * sizeof(exprNode)); + } Added: freeswitch/trunk/src/mod/applications/mod_expr/exprmem.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprmem.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,21 @@ +/* + File: exprmem.h + Auth: Brian Allen Vanderburg II + Date: Wednesday, April 30, 2003 + Desc: Memory functions for ExprEval + + This file is part of ExprEval. +*/ + +#ifndef __BAVII_EXPRMEM_H +#define __BAVII_EXPRMEM_H + +/* Needed for exprNode */ +#include "exprpriv.h" + +void* exprAllocMem(size_t size); +void exprFreeMem(void *data); +exprNode *exprAllocNodes(size_t count); + + +#endif /* __BAVII_EXPRMEM_H */ Added: freeswitch/trunk/src/mod/applications/mod_expr/exprobj.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprobj.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,237 @@ +/* + File: exprobj.c + Auth: Brian Allen Vanderburg II + Date: Tuesday, April 29, 2003 + Desc: Functions for the exprObj type + + This file is part of ExprEval. +*/ + +/* Includes */ +#include "exprincl.h" + +#include "exprpriv.h" +#include "exprmem.h" + +/* Internal functions */ +static void exprFreeNodeData(exprNode *node); + + +/* Function to create an expression object */ +int exprCreate(exprObj **obj, exprFuncList *flist, exprValList *vlist, exprValList *clist, + exprBreakFuncType breaker, void *userdata) + { + exprObj *tmp; + + /* Allocate memory for the object */ + tmp = exprAllocMem(sizeof(exprObj)); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + + /* Assign data */ + tmp->flist = flist; + tmp->vlist = vlist; + tmp->clist = clist; + tmp->breakerfunc = breaker; + tmp->userdata = userdata; + tmp->breakcount = 100000; /* Default breaker count setting */ + tmp->breakcur = 0; + + /* Update pointer */ + *obj = tmp; + + return EXPR_ERROR_NOERROR; + } + + +/* Free the expression */ +int exprFree(exprObj *obj) + { + if(obj == NULL) + return EXPR_ERROR_NOERROR; + + /* First free the node data */ + exprFreeNodeData(obj->headnode); + exprFreeMem(obj->headnode); + + /* Free ourself */ + exprFreeMem(obj); + + return EXPR_ERROR_NOERROR; + } + +/* Clear expression, keep lists, etc */ +int exprClear(exprObj *obj) + { + if(obj == NULL) + return EXPR_ERROR_NOERROR; + + /* Free the node data only, keep function, variable, constant lists */ + exprFreeNodeData(obj->headnode); + exprFreeMem(obj->headnode); + + obj->headnode = NULL; + obj->parsedbad = 0; + obj->parsedgood = 0; + + return EXPR_ERROR_NOERROR; + } + + +/* Get functions to get information about the expression object */ + +/* Get the function list */ +exprFuncList *exprGetFuncList(exprObj *obj) + { + return (obj == NULL) ? NULL : obj->flist; + } + +/* Get the variable list */ +exprValList *exprGetVarList(exprObj *obj) + { + return (obj == NULL) ? NULL : obj->vlist; + } + +/* Get the constant list */ +exprValList *exprGetConstList(exprObj *obj) + { + return (obj == NULL) ? NULL : obj->clist; + } + +/* Get the breaker function */ +exprBreakFuncType exprGetBreakFunc(exprObj *obj) + { + return (obj == NULL) ? NULL : obj->breakerfunc; + } + +/* Check for break status */ +int exprGetBreakResult(exprObj *obj) + { + if(obj == NULL) + return 0; + + if(obj->breakerfunc == NULL) + return 0; + + return (*(obj->breakerfunc))(obj); + } + +/* Get the user data */ +void *exprGetUserData(exprObj *obj) + { + return (obj == NULL) ? NULL : obj->userdata; + } + + +/* Set functions to set certain data */ + +/* Set user data */ +void exprSetUserData(exprObj *obj, void *userdata) + { + if(obj) + obj->userdata = userdata; + } + + +/* Set breaker count */ +void exprSetBreakCount(exprObj *obj, int count) + { + if(obj) + { + /* If count is negative, make it positive */ + if(count < 0) + count = -count; + + obj->breakcount = count; + + /* Make sure the current value is not bigger than count */ + if(obj->breakcur > count) + obj->breakcur = count; + } + } + +/* Get error position */ +void exprGetErrorPosition(exprObj *obj, int *start, int *end) + { + if(obj) + { + if(start) + *start = obj->starterr; + + if(end) + *end = obj->enderr; + } + } + +/* This function will free a node's data */ +static void exprFreeNodeData(exprNode *node) + { + int pos; + + if(node == NULL) + return; + + /* free data based on type */ + switch(node->type) + { + case EXPR_NODETYPE_ADD: + case EXPR_NODETYPE_SUBTRACT: + case EXPR_NODETYPE_MULTIPLY: + case EXPR_NODETYPE_DIVIDE: + case EXPR_NODETYPE_EXPONENT: + case EXPR_NODETYPE_NEGATE: + case EXPR_NODETYPE_MULTI: + /* Free operation data */ + if(node->data.oper.nodes) + { + for(pos = 0; pos < node->data.oper.nodecount; pos++) + exprFreeNodeData(&(node->data.oper.nodes[pos])); + + exprFreeMem(node->data.oper.nodes); + } + + break; + + + case EXPR_NODETYPE_VALUE: + /* Nothing to free for value */ + break; + + case EXPR_NODETYPE_VARIABLE: + /* Nothing to free for variable */ + break; + + case EXPR_NODETYPE_FUNCTION: + /* Free data of each subnode */ + if(node->data.function.nodes) + { + for(pos = 0; pos < node->data.function.nodecount; pos++) + exprFreeNodeData(&(node->data.function.nodes[pos])); + + /* Free the subnode array */ + exprFreeMem(node->data.function.nodes); + } + + /* Free reference variable list */ + if(node->data.function.refs) + exprFreeMem(node->data.function.refs); + + break; + + case EXPR_NODETYPE_ASSIGN: + /* Free subnode data */ + if(node->data.assign.node) + { + exprFreeNodeData(node->data.assign.node); + + /* Free the subnode */ + exprFreeMem(node->data.assign.node); + } + + break; + } + } + + Added: freeswitch/trunk/src/mod/applications/mod_expr/exprpars.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprpars.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,1558 @@ +/* + File: exprpars.c + Auth: Brian Allen Vanderburg II + Date: Wednesday, April 30, 2003 + Desc: Actual parsing routines for this library + + This file is part of ExprEval. +*/ + +/* Includes */ +#include "exprincl.h" + +#include "exprpriv.h" +#include "exprmem.h" + +/* Data structure used by parser */ +typedef struct _exprToken + { + int type; /* token type */ + int start; /* token start position */ + int end; /* token end position */ + + union _tdata + { + char *str; /* string data */ + EXPRTYPE val; /* value data */ + } data; + } exprToken; + +/* Defines for token types */ +#define EXPR_TOKEN_UNKNOWN 0 +#define EXPR_TOKEN_OPAREN 1 +#define EXPR_TOKEN_CPAREN 2 +#define EXPR_TOKEN_IDENTIFIER 3 +#define EXPR_TOKEN_VALUE 4 +#define EXPR_TOKEN_PLUS 5 +#define EXPR_TOKEN_HYPHEN 6 +#define EXPR_TOKEN_ASTERISK 7 +#define EXPR_TOKEN_FSLASH 8 +#define EXPR_TOKEN_AMPERSAND 9 +#define EXPR_TOKEN_SEMICOLON 10 +#define EXPR_TOKEN_COMMA 11 +#define EXPR_TOKEN_EQUAL 12 +#define EXPR_TOKEN_HAT 13 + +/* Internal functions */ +int exprMultiParse(exprObj *obj, exprNode *node, exprToken *tokens, int count); +int exprInternalParse(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end); +int exprInternalParseAssign(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParseAdd(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParseSub(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParseMul(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParseDiv(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParsePosNeg(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParseExp(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index); +int exprInternalParseFunction(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int p1, int p2); +int exprInternalParseVarVal(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end); +int exprStringToTokenList(exprObj *obj, char *expr, exprToken **tokens, int *count); +void exprFreeTokenList(exprToken *tokens, int count); + +/* This frees a token list */ +void exprFreeTokenList(exprToken *tokens, int count) + { + int pos; + + if(tokens == NULL) + return; + + for(pos = 0; pos < count; pos++) + { + if(tokens[pos].type == EXPR_TOKEN_IDENTIFIER) + exprFreeMem(tokens[pos].data.str); + } + + exprFreeMem(tokens); + } + +/* This converts an expression string to a token list */ +int exprStringToTokenList(exprObj *obj, char *expr, exprToken **tokens, int *count) + { + int found; + exprToken *list; + int pass; + int pos, len; + int tpos; + int comment; /* Is a comment active */ + int start, ilen; + char buf[EXPR_MAXIDENTSIZE + 1]; + + /* Set initial variables */ + found = 0; + tpos = 0; + list = NULL; + comment = 0; + *tokens = NULL; + *count = 0; + + + /* Check string length */ + len = strlen(expr); + if(len == 0) + return EXPR_ERROR_EMPTYEXPR; + + /* Two passes, one to count, one to tokenize */ + for(pass = 0; pass <= 1; pass++) + { + for(pos = 0; pos < len; pos++) + { + switch(expr[pos]) + { + /* Comment */ + case '#': + { + /* Only set it if a comment is not already active */ + if(!comment) + comment = 1; + + break; + } + + /* Newline characters turn off comments */ + case '\r': + case '\n': + { + /* If a comment is active, unset it */ + if(comment) + comment = 0; + + break; + } + + /* Open parenthesis */ + case '(': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_OPAREN; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Close parenthesis */ + case ')': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_CPAREN; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Plus */ + case '+': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_PLUS; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Hyphen */ + case '-': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_HYPHEN; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Asterisk */ + case '*': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_ASTERISK; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Forward slash */ + case '/': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_FSLASH; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Hat */ + case '^': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_HAT; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Ampersand */ + case '&': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_AMPERSAND; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Semicolon */ + case ';': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_SEMICOLON; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Comma */ + case ',': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_COMMA; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Equal sign */ + case '=': + { + if(!comment) + { + if(pass == 0) + found++; + else + { + list[tpos].type = EXPR_TOKEN_EQUAL; + list[tpos].start = pos; + list[tpos].end = pos; + tpos++; + } + } + + break; + } + + /* Identifiers and values */ + default: + { + if(!comment) + { + if(expr[pos] == '.' || isdigit(expr[pos])) + { + /* Value */ + start = pos; + + /* Find digits before a period */ + while(isdigit(expr[pos])) + pos++; + + /* Find a period */ + if(expr[pos] == '.') + pos++; + + /* Find digits after a period */ + while(isdigit(expr[pos])) + pos++; + + /* pos is AFTER last item, back up */ + pos--; + + if(pass == 0) + found++; + else + { + ilen = pos - start + 1; + + /* Is the value to large */ + if(ilen > EXPR_MAXIDENTSIZE) + { + obj->starterr = start; + obj->enderr = pos; + exprFreeTokenList(list, found); + return EXPR_ERROR_BADIDENTIFIER; + } + + /* Create value token */ + strncpy(buf, expr + start, ilen); + buf[ilen] = '\0'; + + list[tpos].type = EXPR_TOKEN_VALUE; + list[tpos].start = start; + list[tpos].end = pos; + list[tpos].data.val = (EXPRTYPE)atof(buf); + tpos++; + } + } + else if(expr[pos] == '_' || isalpha(expr[pos])) + { + /* Identifier */ + start = pos; + + /* Find rest of identifier */ + while(expr[pos] == '_' || isalnum(expr[pos])) + pos++; + + /* pos is AFTER last item, back up */ + pos--; + + if(pass == 0) + found++; + else + { + ilen = pos - start + 1; + + /* Is the value to large */ + if(ilen > EXPR_MAXIDENTSIZE) + { + obj->starterr = start; + obj->enderr = pos; + exprFreeTokenList(list, found); + return EXPR_ERROR_BADIDENTIFIER; + } + + /* Create value token */ + strncpy(buf, expr + start, ilen); + buf[ilen] = '\0'; + + /* Allocate memory for identifier */ + list[tpos].data.str = exprAllocMem(ilen + 1); + if(list[tpos].data.str == NULL) + { + exprFreeTokenList(list, found); + return EXPR_ERROR_MEMORY; + } + + list[tpos].type = EXPR_TOKEN_IDENTIFIER; + list[tpos].start = start; + list[tpos].end = pos; + strcpy(list[tpos].data.str, buf); + tpos++; + } + } + else if(isspace(expr[pos])) + { + /* Spaces are ignored, do nothing */ + } + else + { + /* Unknown */ + obj->starterr = obj->enderr = pos; + exprFreeTokenList(list, found); + return EXPR_ERROR_INVALIDCHAR; + } + } + + break; + } + } + } + + /* If pass is 0, allocate memory for next pass */ + if(pass == 0) + { + /* First, make sure all comments were ended */ + if(comment) + comment = 0; + + /* Make sure the expression is not empty */ + if(found == 0) + return EXPR_ERROR_EMPTYEXPR; + + /* Allocate memory for token list */ + list = exprAllocMem(found * sizeof(exprToken)); + if(list == NULL) + return EXPR_ERROR_MEMORY; + + tpos = 0; + } + } + + *count = found; + *tokens = list; + return EXPR_ERROR_NOERROR; + } + + +/* This is the main parsing routine */ +int exprParse(exprObj *obj, char *expr) + { + exprToken *tokens; + int count; + int err; + exprNode *tmp; + + /* Make sure an object was passed */ + if(obj == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Clear expression error position */ + obj->starterr = obj->enderr = -1; + + /* Have we already been parsed? */ + if(obj->parsedbad != 0) + return EXPR_ERROR_ALREADYPARSEDBAD; + + if(obj->parsedgood != 0) + return EXPR_ERROR_ALREADYPARSEDGOOD; + + /* Make sure an expression was passed */ + if(expr == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Create token list */ + err = exprStringToTokenList(obj, expr, &tokens, &count); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* Create head pointer */ + tmp = exprAllocNodes(1); + if(tmp == NULL) + { + exprFreeTokenList(tokens, count); + return EXPR_ERROR_MEMORY; + } + + obj->headnode = tmp; + + /* Call the multiparse routine to parse subexpressions */ + err = exprMultiParse(obj, tmp, tokens, count); + + /* Free the token list */ + exprFreeTokenList(tokens, count); + + /* successful parse? */ + if(err == EXPR_ERROR_NOERROR) + { + obj->parsedgood = 1; + obj->parsedbad = 0; + } + else + { + obj->parsedbad = 1; + obj->parsedgood = 0; + } + + return err; + } + + +/* Parse the subexpressions, each ending with semicolons */ +int exprMultiParse(exprObj *obj, exprNode *node, exprToken *tokens, int count) + { + int pos, plevel, last; + int num, cur, err; + exprNode *tmp; + + plevel = 0; + num = 0; + last = -1; + + /* First count the number of arguments */ + for(pos = 0; pos < count; pos++) + { + switch(tokens[pos].type) + { + case EXPR_TOKEN_OPAREN: + /* increase plevel */ + plevel++; + break; + + case EXPR_TOKEN_CPAREN: + /* decrease plevel */ + plevel--; + + if(plevel < 0) + { + obj->starterr = tokens[pos].start; + obj->enderr = tokens[pos].end; + return EXPR_ERROR_UNMATCHEDPAREN; + } + + break; + + case EXPR_TOKEN_SEMICOLON: + if(plevel == 0) + { + if(last == pos - 1 || pos == 0) + { + /* last semicolon is before us or we are at the start */ + obj->starterr = tokens[pos].start; + obj->enderr = tokens[pos].end; + return EXPR_ERROR_SYNTAX; + } + else + { + /* last semicolon is not right before us */ + num++; + } + } + else + { + /* Semicolon should not be in a parenthesis */ + obj->starterr = tokens[pos].start; + obj->enderr = tokens[pos].end; + return EXPR_ERROR_SYNTAX; + } + + last = pos; /* update position of last semicolon */ + break; + } + } + + /* plevel should be zero now */ + if(plevel != 0) + return EXPR_ERROR_UNMATCHEDPAREN; + + /* the last character should be a semicolon */ + if(last != pos - 1) + return EXPR_ERROR_MISSINGSEMICOLON; + + /* Now we know how many arguments there are */ + + /* Allocate array of subnodes */ + tmp = exprAllocNodes(num); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + /* Set the current node's data */ + node->type = EXPR_NODETYPE_MULTI; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = num; + + /* now we parse each subexpression */ + last = 0; /* Not for last semicolon, but for first char of subexpr */ + cur = 0; + + for(pos = 0; pos < count; pos++) + { + if(tokens[pos].type == EXPR_TOKEN_SEMICOLON) + { + /* Everything from last up to pos - 1 is a parameter */ + err = exprInternalParse(obj, &(tmp[cur]), tokens, last, pos - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* Update last position and current argument */ + last = pos + 1; + cur++; + } + } + + return EXPR_ERROR_NOERROR; + } + +/* This function parses each subnode and recurses if needed */ +int exprInternalParse(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end) + { + int pos; + int plevel = 0; /* Paren level */ + int fgopen = -1; /* First paren group open index */ + int fgclose = -1; /* First paren group close index */ + int assignindex = -1; /* First = at plevel 0 for assignment */ + int addsubindex = -1; /* Last + or - at plevel 0 for adding or subtracting */ + int muldivindex = -1; /* Last * or / at plevel 0 for multiplying or dividing */ + int expindex = -1; /* Last ^ fount at plevel 0 for exponents */ + int posnegindex = -1; /* First +,- at plevel 0 for positive,negative */ + + /* Make sure some conditions are right */ + if(start > end) + return EXPR_ERROR_UNKNOWN; + + /* Scan the string for certain characters */ + for(pos = start; pos <= end; pos++) + { + switch(tokens[pos].type) + { + case EXPR_TOKEN_OPAREN: + plevel++; + + /* First group open? */ + if(plevel == 1 && fgopen == -1) + fgopen = pos; + break; + + case EXPR_TOKEN_CPAREN: + plevel--; + + /* First group close? */ + if(plevel == 0 && fgclose == -1) + fgclose = pos; + + if(plevel < 0) + { + obj->starterr = tokens[pos].start; + obj->enderr = tokens[pos].end; + return EXPR_ERROR_UNMATCHEDPAREN; + } + break; + + case EXPR_TOKEN_EQUAL: + /* Assignment found */ + if(plevel == 0) + { + if(assignindex == -1) + assignindex = pos; + } + break; + + case EXPR_TOKEN_ASTERISK: + case EXPR_TOKEN_FSLASH: + /* Multiplication or division */ + if(plevel == 0) + muldivindex = pos; + break; + + case EXPR_TOKEN_HAT: + /* Exponent */ + if(plevel == 0) + expindex = pos; + break; + + + case EXPR_TOKEN_PLUS: + case EXPR_TOKEN_HYPHEN: + /* Addition or positive or subtraction or negative*/ + if(plevel == 0) + { + if(pos == start) + { + /* At the start area, positive/negative */ + if(posnegindex == -1) + posnegindex = pos; + } + else + { + /* Not at start, check item in front */ + switch(tokens[pos - 1].type) + { + case EXPR_TOKEN_EQUAL: /* Equal sign */ + case EXPR_TOKEN_PLUS: /* Add/positive sign */ + case EXPR_TOKEN_HYPHEN: /* Subtract/negative sign */ + case EXPR_TOKEN_ASTERISK: /* Multiply sign */ + case EXPR_TOKEN_FSLASH: /* Divide sign */ + case EXPR_TOKEN_HAT: /* Exponent sign */ + + /* After theses, it is positive/negative */ + if(posnegindex == -1) + posnegindex = pos; + + break; + + default: + /* Otherwise it is addition/subtraction */ + addsubindex = pos; + break; + } + } + } + break; + + } + } + + /* plevel should now be zero */ + if(plevel != 0) + return EXPR_ERROR_UNMATCHEDPAREN; + + /* We must parse the data in a certain order to maintain the + correct order of operators at evaluation time */ + + /* First, take care of assignment */ + if(assignindex != -1) + return exprInternalParseAssign(obj, node, tokens, start, end, assignindex); + + /* Addition or subtraction is next */ + if(addsubindex != -1) + { + if(tokens[addsubindex].type == EXPR_TOKEN_PLUS) + return exprInternalParseAdd(obj, node, tokens, start, end, addsubindex); + else + return exprInternalParseSub(obj, node, tokens, start, end, addsubindex); + } + + + /* Multiplycation or division */ + if(muldivindex != -1) + { + if(tokens[muldivindex].type == EXPR_TOKEN_ASTERISK) + return exprInternalParseMul(obj, node, tokens, start, end, muldivindex); + else + return exprInternalParseDiv(obj, node, tokens, start, end, muldivindex); + } + + /* Exponent */ + if(expindex != -1) + return exprInternalParseExp(obj, node, tokens, start, end, expindex); + + /* Negation */ + if(posnegindex != -1) + return exprInternalParsePosNeg(obj, node, tokens, start, end, posnegindex); + + + /* Grouped parenthesis */ + if(fgopen == start) + { + /* Closing paren. should be at the end */ + if(fgclose == end) + { + /* Anything between them */ + if(fgclose > fgopen + 1) + { + return exprInternalParse(obj, node, tokens, fgopen + 1, fgclose - 1); + } + else + { + /* Nothing between them */ + obj->starterr = tokens[fgopen].start; + obj->enderr = tokens[fgclose].end; + return EXPR_ERROR_SYNTAX; + } + } + else /* Closing paren not at the end */ + return EXPR_ERROR_SYNTAX; + } + + /* Functions */ + if(fgopen > start) + { + /* Closing paren should be at end */ + if(fgclose == end) + { + return exprInternalParseFunction(obj, node, tokens, start, end, fgopen, fgclose); + } + else /* Closing paren not at end */ + return EXPR_ERROR_SYNTAX; + } + + /* If it was none of the above, it must be a variable or value */ + return exprInternalParseVarVal(obj, node, tokens, start, end); + } + +/* Function to parse an assignment node */ +int exprInternalParseAssign(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + exprValList *l; + EXPRTYPE *addr; + + /* Make sure the equal sign is not at the start or end */ + if(index != start + 1 || index >= end) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + /* Make sure item before equal sign is an identifier */ + if(tokens[index - 1].type != EXPR_TOKEN_IDENTIFIER) + { + obj->starterr = tokens[index - 1].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + /* Create expression subnode */ + tmp = exprAllocNodes(1); + if(tmp == NULL) + { + return EXPR_ERROR_MEMORY; + } + + + /* Set the data */ + node->type = EXPR_NODETYPE_ASSIGN; + node->data.assign.node = tmp; + + + /* + The fast access method directly accesses the memory address + of the variable's value at evaluation time. Because of this, + we must make sure the variable does exists in the variable list. + */ + + /* Make sure name is not a constant name */ + l = exprGetConstList(obj); + if(l) + { + exprValListGetAddress(l, tokens[index - 1].data.str, &addr); + if(addr) + { + obj->starterr = tokens[index - 1].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_CONSTANTASSIGN; + } + } + + /* Get the variable list */ + l = exprGetVarList(obj); + if(l == NULL) + return EXPR_ERROR_NOVARLIST; + + /* Get variable address if already in the list */ + exprValListGetAddress(l, tokens[index - 1].data.str, &addr); + if(addr == NULL) /* Variable not in the list, add it */ + { + exprValListAdd(l, tokens[index - 1].data.str, 0.0); + + /* Try to get address again */ + exprValListGetAddress(l, tokens[index - 1].data.str, &addr); + if(addr == NULL) /* Could not add variable */ + return EXPR_ERROR_MEMORY; /* Could not add variable to list */ + } + + node->data.assign.vaddr = addr; + + /* Parse the subnode */ + return exprInternalParse(obj, tmp, tokens, index + 1, end); + } + +/* Function to parse an addition operator */ +int exprInternalParseAdd(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + int err; + + /* Make sure plus sign is at a good place */ + if(index <= start || index >= end) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + /* Allocate space for 2 subnodes */ + tmp = exprAllocNodes(2); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + + /* Set the data */ + node->type = EXPR_NODETYPE_ADD; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = 2; + + /* parse the left side */ + err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* parse the right side */ + return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end); + } + +/* Function to parse a subtraction operator */ +int exprInternalParseSub(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + int err; + + /* Make sure minus sign is at a good place */ + if(index <= start || index >= end) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + /* Allocate space for 2 subnodes */ + tmp = exprAllocNodes(2); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + + /* Set the data */ + node->type = EXPR_NODETYPE_SUBTRACT; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = 2; + + /* parse the left side */ + err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* parse the right side */ + return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end); + } + +/* Function to parse a multiplication operator */ +int exprInternalParseMul(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + int err; + + /* Make sure times sign is at a good place */ + if(index <= start || index >= end) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + + /* Allocate space for 2 subnodes */ + tmp = exprAllocNodes(2); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + + /* Set the data */ + node->type = EXPR_NODETYPE_MULTIPLY; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = 2; + + /* parse the left side */ + err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* parse the right side */ + return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end); + } + +/* Function to parse a division operator */ +int exprInternalParseDiv(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + int err; + + /* Make sure slash sign is at a good place */ + if(index <= start || index >= end) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + + /* Allocate space for 2 subnodes */ + tmp = exprAllocNodes(2); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + + /* Set the data */ + node->type = EXPR_NODETYPE_DIVIDE; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = 2; + + /* parse the left side */ + err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* parse the right side */ + return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end); + } + +/* Function to parse an exponent operator */ +int exprInternalParseExp(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + int err; + + /* Make sure exponent sign is at a good place */ + if(index <= start || index >= end) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_SYNTAX; + } + + + /* Allocate space for 2 subnodes */ + tmp = exprAllocNodes(2); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + + /* Set the data */ + node->type = EXPR_NODETYPE_EXPONENT; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = 2; + + /* parse the left side */ + err = exprInternalParse(obj, &(tmp[0]), tokens, start, index - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* parse the right side */ + return exprInternalParse(obj, &(tmp[1]), tokens, index + 1, end); + } + +/* Function to parse for positive and negative */ +int exprInternalParsePosNeg(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int index) + { + exprNode *tmp; + + /* Position should be the same as start */ + if(index != start) + { + obj->starterr = tokens[index].start; + obj->enderr = tokens[index].end; + return EXPR_ERROR_UNKNOWN; + } + + /* If it is a positive, just parse the internal of it */ + if(tokens[index].type == EXPR_TOKEN_PLUS) + return exprInternalParse(obj, node, tokens, index + 1, end); + else + { + /* Allocate subnode */ + tmp = exprAllocNodes(1); + if(tmp == NULL) + return EXPR_ERROR_NOERROR; + + + /* Set data */ + node->type = EXPR_NODETYPE_NEGATE; + node->data.oper.nodes = tmp; + node->data.oper.nodecount = 1; + + /* Parse the subnode */ + return exprInternalParse(obj, tmp, tokens, index + 1, end); + } + } + +/* Function will parse a call to a function */ +int exprInternalParseFunction(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end, int p1, int p2) + { + int pos; + int num, cur; + int refnum, refcur; + int plevel = 0; + int lv, err; + exprNode *tmp; + exprFuncType fptr; + int argmin, argmax; + int refargmin, refargmax; + int type; + exprFuncList *l; + exprValList *vars; + EXPRTYPE *addr; + EXPRTYPE **reftmp; + + /* We should have a function list */ + l = exprGetFuncList(obj); + if(l == NULL) + return EXPR_ERROR_NOSUCHFUNCTION; + + /* check paren. location */ + if(p2 <= p1) + return EXPR_ERROR_SYNTAX; + + /* second paren. should not be after the end */ + if(p2 > end) + return EXPR_ERROR_SYNTAX; + + /* Item before parenthesis should be an identifier */ + if(tokens[p1 - 1].type != EXPR_TOKEN_IDENTIFIER) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p1].end; + return EXPR_ERROR_SYNTAX; + } + + + /* Look up the function */ + err = exprFuncListGet(l, tokens[p1 - 1].data.str, &fptr, &type, &argmin, &argmax, &refargmin, &refargmax); + if(err != EXPR_ERROR_NOERROR) + { + if(err == EXPR_ERROR_NOTFOUND) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p1 - 1].end; + return EXPR_ERROR_NOSUCHFUNCTION; + } + else + return err; + } + + /* Make sure the function exists */ + if(fptr == NULL && type == 0) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p1 - 1].end; + return EXPR_ERROR_NOSUCHFUNCTION; + } + + /* Count arguments */ + if(p2 == p1 + 1) + { + num = 0; + refnum = 0; + } + else + { + num = 1; + refnum = 0; + + + /* count commas */ + for(pos = p1 + 1; pos < p2; pos++) + { + switch(tokens[pos].type) + { + case EXPR_TOKEN_OPAREN: + plevel++; + break; + + case EXPR_TOKEN_CPAREN: + plevel--; + if(plevel < 0) + { + obj->starterr = tokens[pos].start; + obj->enderr = tokens[pos].end; + return EXPR_ERROR_UNMATCHEDPAREN; + } + break; + + case EXPR_TOKEN_COMMA: + /* Found comma */ + if(plevel == 0) + num++; + break; + + case EXPR_TOKEN_AMPERSAND: + /* Found reference mark */ + if(plevel == 0) + { + /* This may only occur after the open parenthesis or comma */ + if(tokens[pos - 1].type == EXPR_TOKEN_OPAREN || tokens[pos - 1].type == EXPR_TOKEN_COMMA) + refnum++; + else + return EXPR_ERROR_SYNTAX; + } + break; + } + } + + /* plevel should be zero */ + if(plevel != 0) + return EXPR_ERROR_UNMATCHEDPAREN; + } + + /* We now have the number of total arguments and + number of ref arguments. Get number of normal + arguments */ + num = num - refnum; + + /* Make sure number of arguments is correct */ + /* Here we make sure the limits are greater + or equal to zero because any negative number + could be used to specify no limit */ + if(argmin >= 0 && num < argmin) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p2].end; + return EXPR_ERROR_BADNUMBERARGUMENTS; + } + + if(argmax >= 0 && num > argmax) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p2].end; + return EXPR_ERROR_BADNUMBERARGUMENTS; + } + + if(refargmin >= 0 && refnum < refargmin) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p2].end; + return EXPR_ERROR_BADNUMBERARGUMENTS; + } + + if(refargmax >= 0 && refnum > refargmax) + { + obj->starterr = tokens[p1 - 1].start; + obj->enderr = tokens[p2].end; + return EXPR_ERROR_BADNUMBERARGUMENTS; + } + + /* Set tmp to null in case of no arguments */ + tmp = NULL; + reftmp = NULL; + + if(num > 0) + { + /* Allocate subnodes */ + tmp = exprAllocNodes(num); + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + } + + if(refnum > 0) + { + /* Allocate ref pointers */ + reftmp = exprAllocMem(sizeof(EXPRTYPE*) * refnum); + if(reftmp == NULL) + { + exprFreeMem(tmp); + return EXPR_ERROR_MEMORY; + } + } + + + + /* Set this node's data */ + node->type = EXPR_NODETYPE_FUNCTION; + node->data.function.fptr = fptr; + node->data.function.nodecount = num; + node->data.function.nodes = tmp; + node->data.function.refcount = refnum; + node->data.function.refs = reftmp; + node->data.function.type = type; + + /* parse each subnode */ + if(num + refnum > 0) + { + plevel = 0; + cur = 0; + refcur = 0; + lv = p1 + 1; + + /* look for commas if more than 1 arg */ + if(num + refnum > 1) + { + for(pos = p1 + 1; pos < p2; pos++) + { + switch(tokens[pos].type) + { + case EXPR_TOKEN_OPAREN: + plevel++; + break; + + case EXPR_TOKEN_CPAREN: + plevel--; + break; /* Already checked paren nesting above */ + + case EXPR_TOKEN_COMMA: + /* Found comma */ + if(plevel == 0) + { + /* parse inside */ + if(tokens[lv].type == EXPR_TOKEN_AMPERSAND) + { + if(lv != pos - 2) + { + obj->starterr = tokens[lv].start; + obj->enderr = tokens[pos].end; + return EXPR_ERROR_SYNTAX; + } + + /* It is a reference */ + if(tokens[lv + 1].type != EXPR_TOKEN_IDENTIFIER) + { + obj->starterr = tokens[lv].start; + obj->enderr = tokens[lv + 1].end; + return EXPR_ERROR_SYNTAX; + } + + + /* Make sure it is not a constant */ + vars = exprGetConstList(obj); + if(vars) + { + exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); + if(addr) + { + obj->starterr = tokens[lv].start; + obj->enderr = tokens[lv + 1].start; + return EXPR_ERROR_REFCONSTANT; + } + } + + /* Get variable list */ + vars = exprGetVarList(obj); + if(vars == NULL) + return EXPR_ERROR_NOVARLIST; + + /* Get variable address */ + exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); + if(addr == NULL) + { + /* Add variable to list */ + exprValListAdd(vars, tokens[lv + 1].data.str, 0.0); + + /* Try to get address again */ + exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); + if(addr == NULL) + return EXPR_ERROR_MEMORY; /* Could not add variable */ + } + + /* Set reference item */ + reftmp[refcur] = addr; + + /* increase ref arg number and lv position*/ + refcur++; + lv = pos + 1; + } + else + { + err = exprInternalParse(obj, &(tmp[cur]), tokens, lv, pos - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + + /* increase arg number and lv position*/ + lv = pos + 1; + cur++; + } + } + break; + } + } + } + + /* lv should point after the last comma, or open paren. if only 1 arg */ + if(tokens[lv].type == EXPR_TOKEN_AMPERSAND) + { + if(lv != p2 - 2) + { + obj->starterr = tokens[lv].start; + obj->enderr = tokens[p2].end; + return EXPR_ERROR_SYNTAX; + } + + /* It is a reference */ + if(tokens[lv + 1].type != EXPR_TOKEN_IDENTIFIER) + { + obj->starterr = tokens[lv].start; + obj->enderr = tokens[lv + 1].end; + return EXPR_ERROR_SYNTAX; + } + + /* Make sure it is not a constant */ + vars = exprGetConstList(obj); + if(vars) + { + exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); + if(addr) + { + obj->starterr = tokens[lv].start; + obj->enderr = tokens[lv + 1].start; + return EXPR_ERROR_REFCONSTANT; + } + } + + /* Get variable list */ + vars = exprGetVarList(obj); + if(vars == NULL) + return EXPR_ERROR_NOVARLIST; + + /* Get variable address */ + exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); + if(addr == NULL) + { + /* Add variable to list */ + exprValListAdd(vars, tokens[lv + 1].data.str, 0.0); + + /* Try to get address again */ + exprValListGetAddress(vars, tokens[lv + 1].data.str, &addr); + if(addr == NULL) + return EXPR_ERROR_MEMORY; /* Could not add variable */ + } + + /* Set reference item */ + reftmp[refcur] = addr; + } + else + { + err = exprInternalParse(obj, &(tmp[cur]), tokens, lv, p2 - 1); + if(err != EXPR_ERROR_NOERROR) + return err; + } + } + + + return EXPR_ERROR_NOERROR; + } + +/* Parse a variable or value */ +int exprInternalParseVarVal(exprObj *obj, exprNode *node, exprToken *tokens, int start, int end) + { + exprValList *l; + EXPRTYPE *addr; + + + /* Make sure positions are correct */ + if(start != end) + { + return EXPR_ERROR_UNKNOWN; + } + + + /* Are we an identifier */ + if(tokens[start].type == EXPR_TOKEN_IDENTIFIER) + { + /* we are an identifier */ + + /* check to see if it is a constant */ + l = exprGetConstList(obj); + if(l != NULL) + { + if(exprValListGetAddress(l, tokens[start].data.str, &addr) == EXPR_ERROR_NOERROR) + { + /* We found it in the constant list */ + + /* + Treat is like a variable node so application can change + constant value and it will reflect in expression + */ + + node->type = EXPR_NODETYPE_VARIABLE; + node->data.variable.vaddr = addr; + return EXPR_ERROR_NOERROR; + } + } + + /* Not found in the constant list, so it must be a variable */ + + /* Set node type */ + node->type = EXPR_NODETYPE_VARIABLE; + + /* + The fast access method directly accesses the memory address + of the variable's value at evaluation time. Because of this, + we must make sure the variable does exists in the variable list. + */ + + /* Get the variable list */ + l = exprGetVarList(obj); + if(l == NULL) + return EXPR_ERROR_NOVARLIST; + + /* Get variable address if already in the list */ + exprValListGetAddress(l, tokens[start].data.str, &addr); + if(addr == NULL) /* Variable not in the list, add it */ + { + exprValListAdd(l, tokens[start].data.str, 0.0); + + /* Try to get address again */ + exprValListGetAddress(l, tokens[start].data.str, &addr); + if(addr == NULL) /* Could not add variable */ + return EXPR_ERROR_MEMORY; /* Could not add variable to list */ + } + + node->data.variable.vaddr = addr; + + return EXPR_ERROR_NOERROR; + } + else if(tokens[start].type == EXPR_TOKEN_VALUE) + { + /* we are a value */ + node->type = EXPR_NODETYPE_VALUE; + node->data.value.value = tokens[start].data.val; + return EXPR_ERROR_NOERROR; + } + else + { + obj->starterr = tokens[start].start; + obj->enderr = tokens[end].end; + return EXPR_ERROR_UNKNOWN; + } + } Added: freeswitch/trunk/src/mod/applications/mod_expr/exprpriv.h ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprpriv.h Thu Nov 8 18:46:26 2007 @@ -0,0 +1,215 @@ +/* + File: exprpriv.h + Auth: Brian Allen Vanderburg II + Date: Tuesday, February 28, 2006 + Desc: Private include file for ExprEval library + + This file is part of ExprEval. +*/ + + +/* Include once */ +#ifndef __BAVII_EXPRPRIV_H +#define __BAVII_EXPRPRIV_H + +/* Need some definitions, NULL, etc */ +#include <stddef.h> + +/* Include config and main expreval header */ +#include "expreval.h" +#include "exprconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Version number +*/ +#define EXPR_VERSIONMAJOR 2 +#define EXPR_VERSIONMINOR 7 + +/* Node types */ +enum + { + EXPR_NODETYPE_UNKNOWN = 0, + EXPR_NODETYPE_MULTI, + EXPR_NODETYPE_ADD, + EXPR_NODETYPE_SUBTRACT, + EXPR_NODETYPE_MULTIPLY, + EXPR_NODETYPE_DIVIDE, + EXPR_NODETYPE_EXPONENT, + EXPR_NODETYPE_NEGATE, + EXPR_NODETYPE_VALUE, + EXPR_NODETYPE_VARIABLE, + EXPR_NODETYPE_ASSIGN, + EXPR_NODETYPE_FUNCTION + }; + +/* Functions can be evaluated directly in EXPREVAL. If fptr + is NULL, type is used to determine what the function is */ +enum + { + EXPR_NODEFUNC_UNKNOWN = 0, + EXPR_NODEFUNC_ABS, + EXPR_NODEFUNC_MOD, + EXPR_NODEFUNC_IPART, + EXPR_NODEFUNC_FPART, + EXPR_NODEFUNC_MIN, + EXPR_NODEFUNC_MAX, + EXPR_NODEFUNC_POW, + EXPR_NODEFUNC_SQRT, + EXPR_NODEFUNC_SIN, + EXPR_NODEFUNC_SINH, + EXPR_NODEFUNC_ASIN, + EXPR_NODEFUNC_COS, + EXPR_NODEFUNC_COSH, + EXPR_NODEFUNC_ACOS, + EXPR_NODEFUNC_TAN, + EXPR_NODEFUNC_TANH, + EXPR_NODEFUNC_ATAN, + EXPR_NODEFUNC_ATAN2, + EXPR_NODEFUNC_LOG, + EXPR_NODEFUNC_POW10, + EXPR_NODEFUNC_LN, + EXPR_NODEFUNC_EXP, + EXPR_NODEFUNC_LOGN, + EXPR_NODEFUNC_CEIL, + EXPR_NODEFUNC_FLOOR, + EXPR_NODEFUNC_RAND, + EXPR_NODEFUNC_RANDOM, + EXPR_NODEFUNC_RANDOMIZE, + EXPR_NODEFUNC_DEG, + EXPR_NODEFUNC_RAD, + EXPR_NODEFUNC_RECTTOPOLR, + EXPR_NODEFUNC_RECTTOPOLA, + EXPR_NODEFUNC_POLTORECTX, + EXPR_NODEFUNC_POLTORECTY, + EXPR_NODEFUNC_IF, + EXPR_NODEFUNC_SELECT, + EXPR_NODEFUNC_EQUAL, + EXPR_NODEFUNC_ABOVE, + EXPR_NODEFUNC_BELOW, + EXPR_NODEFUNC_AVG, + EXPR_NODEFUNC_CLIP, + EXPR_NODEFUNC_CLAMP, + EXPR_NODEFUNC_PNTCHANGE, + EXPR_NODEFUNC_POLY, + EXPR_NODEFUNC_AND, + EXPR_NODEFUNC_OR, + EXPR_NODEFUNC_NOT, + EXPR_NODEFUNC_FOR, + EXPR_NODEFUNC_MANY + }; + +/* Forward declarations */ +typedef struct _exprFunc exprFunc; +typedef struct _exprVal exprVal; + +/* Expression object */ +struct _exprObj + { + struct _exprFuncList *flist; /* Functions */ + struct _exprValList *vlist; /* Variables */ + struct _exprValList *clist; /* Constants */ + struct _exprNode *headnode; /* Head parsed node */ + + exprBreakFuncType breakerfunc; /* Break function type */ + + void *userdata; /* User data, can be any 32 bit value */ + int parsedgood; /* non-zero if successfully parsed */ + int parsedbad; /* non-zero if parsed but unsuccessful */ + int breakcount; /* how often to check the breaker function */ + int breakcur; /* do we check the breaker function yet */ + int starterr; /* start position of an error */ + int enderr; /* end position of an error */ + }; + +/* Object for a function */ +struct _exprFunc + { + char *fname; /* Name of the function */ + exprFuncType fptr; /* Function pointer */ + int min, max; /* Min and max args for the function. */ + int refmin, refmax; /* Min and max ref. variables for the function */ + int type; /* Function node type. exprEvalNOde solves the function */ + + struct _exprFunc *next; /* For linked list */ + }; + +/* Function list object */ +struct _exprFuncList + { + struct _exprFunc *head; + }; + +/* Object for values */ +struct _exprVal + { + char *vname; /* Name of the value */ + EXPRTYPE vval; /* Value of the value */ + EXPRTYPE *vptr; /* Pointer to a value. Used only if not NULL */ + + struct _exprVal *next; /* For linked list */ + }; + +/* Value list */ +struct _exprValList + { + struct _exprVal *head; + }; + +/* Expression node type */ +struct _exprNode + { + int type; /* Node type */ + + union _data /* Union of info for various types */ + { + struct _oper + { + struct _exprNode *nodes; /* Operation arguments */ + int nodecount; /* Number of arguments */ + } oper; + + struct _variable + { + EXPRTYPE *vaddr; /* Used if EXPR_FAST_VAR_ACCESS defined */ + } variable; + + struct _value + { + EXPRTYPE value; /* Value if type is value */ + } value; + + struct _assign /* Assignment struct */ + { + EXPRTYPE *vaddr; /* Used if EXPR_FAST_VAR_ACCESS defined */ + struct _exprNode *node; /* Node to evaluate */ + } assign; + + struct _function + { + exprFuncType fptr; /* Function pointer */ + struct _exprNode *nodes; /* Array of argument nodes */ + int nodecount; /* Number of argument nodes */ + EXPRTYPE **refs; /* Reference variables */ + int refcount; /* Number of variable references (not a reference counter) */ + int type; /* Type of function for exprEvalNode if fptr is NULL */ + } function; + } data; + }; + + + +/* Functions for function lists */ +int exprFuncListAddType(exprFuncList *flist, char *name, int type, int min, int max, int refmin, int refmax); +int exprFuncListGet(exprFuncList *flist, char *name, exprFuncType *ptr, int *type, int *min, int *max, int *refmin, int *refmax); + + +#ifdef __cplusplus +} +#endif + +#endif /* __BAVII_EXPRPRIV_H */ + Added: freeswitch/trunk/src/mod/applications/mod_expr/exprtmpl.html ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprtmpl.html Thu Nov 8 18:46:26 2007 @@ -0,0 +1,828 @@ +<html> + +<head> +<title>Expression Help</title> +<style type="text/css"> +.valid { + color: #00AA00; +} +.invalid { + color: #FF0000; +} +.excomment { + color: #0000FF; +} +.container { + margin-top: 10px; + margin-bottom: 10px; + padding-left: 4px; + padding-right: 4px; + border-top: 1px solid #000000; + border-right: 1px solid #000000; + border-bottom: 1px solid #000000; + border-left: 1px solid #000000; + background-color: #BBBBBB; +} +body { + background-color: #AAAAAA; +} +</style> +</head> + +<body> + +<div align="center"> + <h1>Expression Help</h1> + <hr> +</div> + +<div align="left" class="container"> + <h2>Contents</h2> + <h3> + <ul> + <li><a href="#Syntax">Expression Syntax</a></li> + <li><a href="#Operators">Order of Operators</a></li> + <li><a href="#InternalFunc">ExprEval Internal Functions</a></li> + <li><a href="#InternalConst">ExprEval Internal Constants</a></li> + <li><a href="#AppFunc">Application Internal Functions</a></li> + <li><a href="#AppConst">Application Internal Constants</a></li> + <li><a href="#AppVar">Application Internal Variables</a></li> + </ul> + </h3> +</div> + +<div align="left" class="container"> + <h2><a name="Syntax">Expression Syntax</a></h2> + <blockquote> + <p>Expressions have pretty much the same syntax as they + would have on paper, with the following exceptions: + <ul> + <li>Each expression must end with a semicolon. This + is because the expression string can actually + contain multiple expressions. The semicolon is + used to mark the end of the expression.<br> + <b>Examples:</b> + <ul> + <li>4*x+5;</li> + <li>y=5+2;g=4+6;</li> + <li>y=r*sin(a);x=r*cos(a);</li> + </ul> + </li> + <li>The asterisk '*' must be used to multiply.<br> + <b>Examples:</b> + <ul> + <li>y=5*6; <b class="valid">Valid</b></li> + <li>g=(x+1)*(x-1); <b class="valid">Valid</b></li> + <li>g=(x+1)(x-1); <b class="invalid">Invalid</b></li> + </ul> + </li> + </ul> + </p> + <p>More than one expression may be contained within an expression string. + As shown above, each expression must end with a semicolon, even if + only one expression is in the string. The value of an expression + string is the value of the last expression in the string.<br> + <b>Examlples:</b> + <ul> + <li>g=7; <b class="excomment">Value: 7</b></li> + <li>k=z+1; <b class="excomment">Value: z+1</b></li> + <li>r=4;k=6;o=9+r-k; <b class="excomment">Value: 9+r-k</b></li> + </ul> + </p> + <p>Some functions may take reference parameters. These parameters are + references to other variables. You can mix reference parameters + with normal parameters. The order of the normal parameters must + remain the same and the order of the reference parameters must + remain the same.<br> + <b>Examples:</b> + <ul> + <li>min(1,2,3,4,&mval); <b class="excomment">&mval is a reference to a variable mval</b></li> + <li>min(1,2,&mval,3,4); <b class="excomment">You may mix them inside like this.</b></li> + <li>min(1,2,(&mval),3,4); <b class="invalid">You may not nest reference parameters in any way</b></li> + </ul> + </p> + <p>Expressions may also be nested with parenthesis.<br> + <b>Examples:</b> + <ul> + <li>y=sin(x-cos(5+max(4,5,6*x)));</li> + <li>6+(5-2*(x+y));</li> + </ul> + </p> + <p>Expressions may also have whitespace characters and comments. + Whitespace characters such as newlines, linefeeds, carriage + returns, spaces, and tabs are ignored. Comments begin with + the pound sign '#' and end at the end of the line.<br> + <b>Example:</b> + <ul> + <pre> +#Set the x value +x = d * cos(r); + +#Set the y value +y = d * sin(r); + </pre> + </ul> + </p> + <p>If a variable is used in an expression, but that variable does not exist, + it is considered zero. If it does exist then its value is used instead. + </p> + <p><b>Notice:</b> An expression can <b>NOT</b> assign to a constant and an + expression can <b>NOT</b> use a constant as a reference parameter. + </p> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="Operators">Order of operators.</a></h2> + <blockquote> + <p>The order of operators are processed correctly in ExprEval. + The parameters to functions may be evaluated out of order, depending + on the function itself.</p> + + The following illustrates the order of operators: + <table align="center" border="1" width="75%"> + <tr> + <td align="center"><b>Operator</b></td> + <td align="center"><b>Direction</b></td> + <td align="center"><b>Example</b></td> + </tr> + <tr> + <td>Functions and Parenthesis</td> + <td>N/A</td> + <td>(x + 5) * sin(d);</td> + </tr> + <tr> + <td>Negation</td> + <td>Right to Left</td> + <td>y = -2;</td> + </tr> + <tr> + <td>Exponents</td> + <td>Left to Right</td> + <td>y = x ^ 2;</td> + </tr> + <tr> + <td>Multiplication and Division</td> + <td>Left to Right</td> + <td>x * 5 / y;</td> + </tr> + <tr> + <td>Addition and Subtraction</td> + <td>Left to Right</td> + <td>4 + 5 - 3;</td> + </tr> + <tr> + <td>Assignment</td> + <td>Right to Left</td> + <td>x = y = z = 0;</td> + </tr> + </table> + + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="InternalFunc">ExprEval Internal Functions</a></h2> + <blockquote> + The following functions are provided with ExprEval: + <table align="center" border="1" width="75%"> + <tr> + <td align="center"><b>Function</b></td> + <td align="center"><b>Min. Args</b></td> + <td align="center"><b>Max. Args</b></td> + <td align="center"><b>Min. Ref Args</b></td> + <td align="center"><b>Max. Ref Args</b></td> + <td align="center"><b>Result/Comment</b></td> + </tr> + <tr> + <td>abs(v)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>Absolute value of v.<br> + abs(-4.3) returns 4.3</td> + </tr> + <tr> + <td>mod(v,d)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Remainder of v/d.<br> + mod(5.2,2.5) return 0.2</td> + </tr> + <tr> + <td>ipart(v)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The integer part of v.<br> + ipart(3.2) returns 3</td> + </tr> + <tr> + <td>fpart(v)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The fractional part of v.<br> + fpart(3.2) returns 0.2</td> + </tr> + <tr> + <td>min(v,...)</td> + <td>1</td> + <td>None</td> + <td>0</td> + <td>0</td> + <td>The minimum number passed.<br> + min(3,2,-5,-2,7) returns -5</td> + </tr> + <tr> + <td>max(v,...)</td> + <td>1</td> + <td>None</td> + <td>0</td> + <td>0</td> + <td>The maximum number passed.<br> + max(3,2,-5,-2,7) returns 7</td> + </tr> + + <tr> + <td>pow(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>The value a raised to the power b.<br> + pow(3.2,1.7) returns 3.2<sup>1.7</sup></td> + </tr> + <tr> + <td>sqrt(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The square root of a.</br> + sqrt(16) returns 4</td> + </tr> + + <tr> + <td>sin(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The sine of a radians.<br> + sin(1.5) returns around 0.997</td> + </tr> + <tr> + <td>sinh(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The hyperbolic sine of a.<br> + sinh(1.5) returns around 2.129</td> + </tr> + <tr> + <td>asin(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The arc-sine of a in radians.<br> + asin(0.5) returns around 0.524</td> + </tr> + + <tr> + <td>cos(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The cosine of a radians.<br> + cos(1.5) returns around 0.0707</td> + </tr> + <tr> + <td>cosh(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The hyperbolic cosine of a.</br> + cosh(1.5) returns around 2.352</td> + </tr> + <tr> + <td>acos(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The arc-cosine of a in radians.<br> + acos(0.5) returns around 1.047</td> + </tr> + + <tr> + <td>tan(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The tangent of a radians.<br> + tan(1.5) returns around 14.101</td> + </tr> + <tr> + <td>tanh(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The hyperbolic tangent of a.</br> + tanh(1.5) returns around 0.905</td> + </tr> + <tr> + <td>atan(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The arc-tangent of a in radians.<br> + atan(0.3) returns about 0.291</td> + </tr> + <tr> + <td>atan2(y,x)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>The arc-tangent of y/x, with quadrant correction.<br> + atan2(4,3) returns about 0.927</td> + </tr> + + <tr> + <td>log(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The base 10 logarithm of a.<br> + log(100) returns 2</td> + </tr> + <tr> + <td>pow10(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>10 raised to the power of a.<br> + pow10(2) returns 100</td> + </tr> + <tr> + <td>ln(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>The base e logarithm of a.<br> + ln(2.8) returns around 1.030</td> + </tr> + <tr> + <td>exp(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>e raised to the power of a.<br> + exp(2) returns around 7.389</td> + </tr> + <tr> + <td>logn(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>The base b logarithm of a.<br> + logn(16,2) returns 4</td> + </tr> + + <tr> + <td>ceil(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>Rounds a up to the nearest integer.<br> + ceil(3.2) returns 4</td> + </tr> + <tr> + <td>floor(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>Rounds a down to the nearest integer.<br> + floor(3.2) returns 3</td> + </tr> + + <tr> + <td>rand(&seed)</td> + <td>0</td> + <td>0</td> + <td>1</td> + <td>1</td> + <td>Returns a number between 0 up to but not including 1.</td> + </tr> + <tr> + <td>random(a,b,&seed)</td> + <td>2</td> + <td>2</td> + <td>1</td> + <td>1</td> + <td>Returns a number between a up to and including b.</td> + </tr> + <tr> + <td>randomize(&seed)</td> + <td>0</td> + <td>0</td> + <td>1</td> + <td>1</td> + <td>Seed the random number generator with a value + based on the current time.<br> + Return value is unknown</td> + </tr> + + <tr> + <td>deg(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>Returns a radians converted to degrees.<br> + deg(3.14) returns around 179.909</td> + </tr> + <tr> + <td>rad(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>Returns a degrees converted to radians.<br> + rad(180) returns around 3.142</td> + </tr> + <tr> + <td>recttopolr(x,y)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns the polar radius of the rectangular co-ordinates.<br> + recttopolr(2,3) returns around 3.606</td> + </tr> + <tr> + <td>recttopola(x,y)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns the polar angle (0...2PI) in radians of the rectangular co-ordinates.<br> + recttopola(2,3) returns around 0.588</td> + </tr> + <tr> + <td>poltorectx(r,a)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns the x rectangular co-ordinate of the polar + co-ordinates.<br> + poltorectx(3,1.5) returns around 0.212</td> + </tr> + <tr> + <td>poltorecty(r,a)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns the y rectangular co-ordinate of the polar + co-ordinates.<br> + poltorecty(3,1.5) returns around 2.992</td> + </tr> + + <tr> + <td>if(c,t,f)</td> + <td>3</td> + <td>3</td> + <td>0</td> + <td>0</td> + <td>Evaluates and returns t if c is not 0.0. + Else evaluates and returns f.<br> + if(0.1,2.1,3.9) returns 2.1</td> + </tr> + <tr> + <td>select(c,n,z[,p])</td> + <td>3</td> + <td>4</td> + <td>0</td> + <td>0</td> + <td>Returns n if c is less than 0.0. Returns z + if c is 0.0. If c is greater than 0.0 and only + three arguments were passed, returns z. If c + is greater than 0.0 and four arguments were passed, + return p.<br> + select(3,1,4,5) returns 5</td> + </tr> + <tr> + <td>equal(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns 1.0 if a is equal to b. Else returns 0.0<br> + equal(3,2) returns 0.0</td> + </tr> + <tr> + <td>above(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns 1.0 if a is above b. Else returns 0.0<br> + above(3,2) returns 1.0</td> + </tr> + <tr> + <td>below(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns 1.0 if a is below b. Else returns 0.0<br> + below(3,2) returns 0.0</td> + </tr> + + <tr> + <td>avg(a,...)</td> + <td>1</td> + <td>None</td> + <td>0</td> + <td>0</td> + <td>Returns the average of the values passed.<br> + avg(3,3,6) returns 4</td> + </tr> + <tr> + <td>clip(v,min,max)</td> + <td>3</td> + <td>3</td> + <td>0</td> + <td>0</td> + <td>Clips v to the range from min to max. If v is less + than min, it returns min. If v is greater than + max it returns max. Otherwise it returns v.<br> + clip(3,1,2) returns 2</td> + </tr> + <tr> + <td>clamp(v,min,max)</td> + <td>3</td> + <td>3</td> + <td>0</td> + <td>0</td> + <td>Clamps v to the range from min to max, looping + if needed.<br> + clamp(8.2,1.3,4.7) returns 1.4</td> + </tr> + <tr> + <td>pntchange(side1old, side2old, side1new, side2new, oldpnt)</td> + <td>5</td> + <td>5</td> + <td>0</td> + <td>0</td> + <td>This is used to translate points from different + scale. It works no matter the orientation as long + as the sides are lined up correctly.<br> + pntchange(-1,1,0,480,-0.5) returns 120 (x example)<br> + pntchange(-1,1,480,0,-0.5) returns 360 (y example)</td> + </tr> + <tr> + <td>poly(x,c1,...)</td> + <td>2</td> + <td>None</td> + <td>0</td> + <td>0</td> + <td>This function calculates the polynomial. x is the value + to use in the polynomial. c1 and on are the coefficients.<br> + poly(4,6,9,3,1,4) returns 2168<br> + same as 6*4<sup>4</sup> + 9*4<sup>3</sup> + 3*4<sup>2</sup> + 1*4<sup>1</sup> + 4*4<sup>0</sup></td> + </tr> + + <tr> + <td>and(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns 0.0 if either a or b are 0.0 Else returns 1.0<br> + and(2.1,0.0) returns 0.0</td> + </tr> + <tr> + <td>or(a,b)</td> + <td>2</td> + <td>2</td> + <td>0</td> + <td>0</td> + <td>Returns 0.0 if both a and b are 0.0 Else returns 1.0<br> + or(2.1,0.0) returns 1.0</td> + </tr> + <tr> + <td>not(a)</td> + <td>1</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>Returns 1.0 if a is 0.0 Else returns 0.0<br> + not(0.3) returns 0.0</td> + </tr> + <tr> + <td>for(init,test,inc,a1,...)</td> + <td>4</td> + <td>None</td> + <td>0</td> + <td>0</td> + <td>This function acts like a for loop in C. First init is + evaluated. Then test is evaluated. As long as the + test is not 0.0, the action statements (a1 to an) are + evaluated, the inc statement is evaluated, and the test + is evaluated again. The result is the result of the + final action statement.<br> + for(x=0,below(x,11),x=x+1,y=y+x) returns 55.0 (if y was + initially 0.0)</td> + </tr> + <tr> + <td>many(expr,...)</td> + <td>1</td> + <td>None</td> + <td>0</td> + <td>0</td> + <td>This function treats many subexpressions as a single object + (function). It is mainly for the 'for' function.<br> + for(many(j=5,k=1),above(j*k,0.001),many(j=j+5,k=k/2),0)</td> + </tr> + + + </table> + + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="InternalConst">ExprEval Internal Constants</a></h2> + <blockquote> + The following constants are provided with ExprEval: + <table align="center" border="1" width="75%"> + <tr> + <td align="center"><b>Constant</b></td> + <td align="center"><b>Math Form</b></td> + <td align="center"><b>Value</b></td> + </tr> + <tr> + <td>M_E</td> + <td>e</td> + <td>2.7182818284590452354</td> + </tr> + <tr> + <td>M_LOG2E</td> + <td>log<sub>2</sub>(e)</td> + <td>1.4426950408889634074</td> + </tr> + <tr> + <td>M_LOG10E</td> + <td>log<sub>10</sub>(e)</td> + <td>0.43429448190325182765</td> + </tr> + <tr> + <td>M_LN2</td> + <td>ln(2)</td> + <td>0.69314718055994530942</td> + </tr> + <tr> + <td>M_LN10</td> + <td>ln(10)</td> + <td>2.30258509299404568402</td> + </tr> + <tr> + <td>M_PI</td> + <td>π</td> + <td>3.14159265358979323846</td> + </tr> + <tr> + <td>M_PI_2</td> + <td>π/2</td> + <td>1.57079632679489661923</td> + </tr> + <tr> + <td>M_PI_4</td> + <td>π/4</td> + <td>0.78539816339744830962</td> + </tr> + <tr> + <td>M_1_PI</td> + <td>1/π</td> + <td>0.31830988618379067154</td> + </tr> + <tr> + <td>M_2_PI</td> + <td>2/π</td> + <td>0.63661977236758134308</td> + </tr> + <tr> + <td>M_1_SQRTPI</td> + <td>1/√(π)</td> + <td>0.56418958354776</td> + </tr> + <tr> + <td>M_2_SQRTPI</td> + <td>2/√(π)</td> + <td>1.12837916709551257390</td> + </tr> + <tr> + <td>M_SQRT2</td> + <td>√(2)</td> + <td>1.41421356237309504880</td> + </tr> + <tr> + <td>M_1_SQRT2</td> + <td>1/√(2)</td> + <td>0.70710678118654752440</td> + </tr> + </table> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="AppFunc">Application Internal Functions</a></h2> + <blockquote> + Application defined expression functions go here. + <table align="center" border="1" width="75%"> + <tr> + <td align="center"><b>Function</b></td> + <td align="center"><b>Min. Args</b></td> + <td align="center"><b>Max. Args</b></td> + <td align="center"><b>Min. Ref Args</b></td> + <td align="center"><b>Max. Ref Args</b></td> + <td align="center"><b>Result/Comment</b></td> + </tr> + <tr> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + <td></td> + </tr> + </table> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="AppConst">Application Internal Constants</a></h2> + <blockquote> + Application defined expression constants go here. + <table align="center" border="1" width="75%"> + <tr> + <td align="center"><b>Constant</b></td> + <td align="center"><b>Math Form</b></td> + <td align="center"><b>Value</b></td> + </tr> + <tr> + <td></td> + <td></td> + <td></td> + </tr> + </table> + </blockquote> +</div> + +<div align="left" class="container"> + <h2><a name="AppVar">Application Internal Variables</a></h2> + <blockquote> + Application defined expression variables go here. + <table align="center" border="1" width="75%"> + <tr> + <td align="center"><b>Variable</b></td> + <td align="center"><b>Math Form</b></td> + <td align="center"><b>Value</b></td> + </tr> + <tr> + <td></td> + <td></td> + <td></td> + </tr> + </table> + </blockquote> +</div> + +</body> + +</html> + + Added: freeswitch/trunk/src/mod/applications/mod_expr/exprutil.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprutil.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,43 @@ +/* + File: exprutil.c + Auth: Brian Allen Vanderburg II + Date: Monday, April 28, 2003 + Desc: Utility functions for use by this library + + This file is part of ExprEval. +*/ + +/* Include files */ +#include "exprincl.h" + +#include "exprpriv.h" + + +/* Return the version number */ +void exprGetVersion(int *major, int *minor) + { + *major = EXPR_VERSIONMAJOR; + *minor = EXPR_VERSIONMINOR; + } + +/* This utility function determines if an identifier is valid */ +int exprValidIdent(char *name) + { + if(name == NULL) /* Null string */ + return 0; + + /* First must be letter or underscore */ + if(isalpha(*name) || *name == '_') + name++; /* Point to next letter */ + else + return 0; /* Not letter or underscore, maybe empty*/ + + /* others can be letter, number, or underscore */ + while(isalnum(*name) || *name == '_') + name++; + + /* When the while breaks out, we should be at the end */ + return (*name == '\0') ? 1 : 0; + } + + Added: freeswitch/trunk/src/mod/applications/mod_expr/exprval.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/exprval.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,395 @@ +/* + File: exprval.c + Auth: Brian Allen Vanderburg II + Date: Thursday, April 24, 2003 + Desc: Value lists for variables and constants + + This file is part of ExprEval. +*/ + +/* Includes */ +#include "exprincl.h" + +#include "exprpriv.h" +#include "exprmem.h" + + +/* Internal functions */ +static exprVal *exprCreateVal(char *name, EXPRTYPE val, EXPRTYPE *addr); +static void exprValListFreeData(exprVal *val); +static void exprValListResetData(exprVal *val); + +/* This function creates the value list, */ +int exprValListCreate(exprValList **vlist) + { + exprValList *tmp; + + if(vlist == NULL) + return EXPR_ERROR_NULLPOINTER; + + *vlist = NULL; /* Set to NULL initially */ + + tmp = exprAllocMem(sizeof(exprValList)); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; /* Could not allocate memory */ + + /* Update pointer */ + *vlist = tmp; + + return EXPR_ERROR_NOERROR; + } + +/* Add a value to the list */ +int exprValListAdd(exprValList *vlist, char *name, EXPRTYPE val) + { + exprVal *tmp; + exprVal *cur; + int result; + + if(vlist == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Make sure the name is valid */ + if(!exprValidIdent(name)) + return EXPR_ERROR_BADIDENTIFIER; + + if(vlist->head == NULL) + { + /* Create the node right here */ + tmp = exprCreateVal(name, val, NULL); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + vlist->head = tmp; + return EXPR_ERROR_NOERROR; + } + + /* See if already exists */ + cur = vlist->head; + + while(cur) + { + result = strcmp(name, cur->vname); + + if(result == 0) + return EXPR_ERROR_ALREADYEXISTS; + + cur = cur->next; + } + + /* We did not find it, create it and add it to the beginning */ + tmp = exprCreateVal(name, val, NULL); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + tmp->next = vlist->head; + vlist->head = tmp; + + return EXPR_ERROR_NOERROR; + } + +/* Set a value in the list */ +int exprValListSet(exprValList *vlist, char *name, EXPRTYPE val) + { + exprVal *cur; + int result; + + if(vlist == NULL) + return EXPR_ERROR_NULLPOINTER; + + if(name == NULL || name[0] == '\0') + return EXPR_ERROR_NOTFOUND; + + /* Find and set it */ + cur = vlist->head; + + while(cur) + { + result = strcmp(name, cur->vname); + + if(result == 0) + { + if(cur->vptr) + *(cur->vptr) = val; + else + cur->vval = val; + + return EXPR_ERROR_NOERROR; + } + + cur = cur->next; + } + + return EXPR_ERROR_NOTFOUND; + } + +/* Get the value from a list */ +int exprValListGet(exprValList *vlist, char *name, EXPRTYPE *val) + { + exprVal *cur; + int result; + + if(vlist == NULL) + return EXPR_ERROR_NULLPOINTER; + + if(name == NULL || name[0] == '\0') + return EXPR_ERROR_NOTFOUND; + + /* Search for the item */ + cur = vlist->head; + + while(cur) + { + result = strcmp(name, cur->vname); + + if(result == 0) + { + /* We found it. */ + if(cur->vptr) + *val = *(cur->vptr); + else + *val = cur->vval; + + /* return now */ + return EXPR_ERROR_NOERROR; + } + + cur = cur->next; + } + + /* If we got here, we did not find the item in the list */ + return EXPR_ERROR_NOTFOUND; + } + +/* Add an address to the list */ +int exprValListAddAddress(exprValList *vlist, char *name, EXPRTYPE *addr) + { + exprVal *tmp; + exprVal *cur; + int result; + + if(vlist == NULL) + return EXPR_ERROR_NULLPOINTER; + + /* Make sure the name is valid */ + if(!exprValidIdent(name)) + return EXPR_ERROR_BADIDENTIFIER; + + if(vlist->head == NULL) + { + /* Create the node right here */ + tmp = exprCreateVal(name, (EXPRTYPE)0.0, addr); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + vlist->head = tmp; + return EXPR_ERROR_NOERROR; + } + + /* See if it already exists */ + cur = vlist->head; + + while(cur) + { + result = strcmp(name, cur->vname); + + if(result == 0) + return EXPR_ERROR_ALREADYEXISTS; + + cur = cur->next; + } + + /* Add it to the list */ + tmp = exprCreateVal(name, (EXPRTYPE)0.0, addr); + + if(tmp == NULL) + return EXPR_ERROR_MEMORY; + + tmp->next = vlist->head; + vlist->head = tmp; + + return EXPR_ERROR_NOERROR; + } + +/* Get memory address of a variable value in a value list */ +int exprValListGetAddress(exprValList *vlist, char *name, EXPRTYPE **addr) + { + exprVal *cur; + int result; + + /* Not found yet */ + *addr = NULL; + + if(vlist == NULL || addr == NULL) + return EXPR_ERROR_NULLPOINTER; + + + if(name == NULL || name[0] == '\0') + return EXPR_ERROR_NOTFOUND; + + /* Search for the item */ + cur = vlist->head; + + while(cur) + { + result = strcmp(name, cur->vname); + + if(result == 0) + { + /* We found it. */ + if(cur->vptr) + *addr = cur->vptr; + else + *addr = &(cur->vval); + + /* return now */ + return EXPR_ERROR_NOERROR; + } + + cur = cur->next; + } + + /* If we got here, we did not find it in the list */ + return EXPR_ERROR_NOTFOUND; + } + +/* This function is used to enumerate the values in a value list */ +void *exprValListGetNext(exprValList *vlist, char **name, EXPRTYPE *value, EXPRTYPE** addr, void *cookie) + { + exprVal *cur; + + if(vlist == NULL) + return NULL; + + /* Get the current item */ + cur = (exprVal*)cookie; + + /* Find the next item */ + if(cur == NULL) + cur = vlist->head; + else + cur = cur->next; + + /* Set up the data */ + if(cur) + { + if(name) + *name = cur->vname; + + if(value) + { + if(cur->vptr) + *value = *(cur->vptr); + else + *value = cur->vval; + } + + if(addr) + { + if(cur->vptr) + *addr = cur->vptr; + else + *addr = &(cur->vval); + } + } + + /* If there was no value, return NULL, otherwise, return the item */ + return (void*)cur; + } + +/* This routine will free the value list */ +int exprValListFree(exprValList *vlist) + { + /* Make sure it exists, if not it is not error */ + if(vlist == NULL) + return EXPR_ERROR_NOERROR; + + /* Free the nodes */ + exprValListFreeData(vlist->head); + + /* Freethe container */ + exprFreeMem(vlist); + + return EXPR_ERROR_NOERROR; + } + +/* This routine will reset the value list to 0.0 */ +int exprValListClear(exprValList *vlist) + { + if(vlist == NULL) + return EXPR_ERROR_NOERROR; + + exprValListResetData(vlist->head); + + return EXPR_ERROR_NOERROR; + } + +/* This routine will free any child nodes, and then free itself */ +static void exprValListFreeData(exprVal *val) + { + exprVal *next; + + while(val) + { + /* Remember the next */ + next = val->next; + + /* Free name */ + exprFreeMem(val->vname); + + /* Free ourself */ + exprFreeMem(val); + + val = next; + } + } + +/* This routine will reset variables to 0.0 */ +static void exprValListResetData(exprVal *val) + { + while(val) + { + /* Reset data */ + if(val->vptr) + *(val->vptr) = 0.0; + + val->vval = 0.0; + + val = val->next; + } + } + +/* This routine will create the value object */ +static exprVal *exprCreateVal(char *name, EXPRTYPE val, EXPRTYPE *addr) + { + exprVal *tmp; + char *vtmp; + + /* Name already tested in exprValListAdd */ + + /* Create it */ + tmp = exprAllocMem(sizeof(exprVal)); + if(tmp == NULL) + return NULL; + + /* Allocate space for the name */ + vtmp = exprAllocMem(strlen(name) + 1); + + if(vtmp == NULL) + { + exprFreeMem(tmp); + return NULL; + } + + /* Copy the data over */ + strcpy(vtmp, name); + tmp->vname = vtmp; + tmp->vval = val; + tmp->vptr = addr; + + return tmp; + } Added: freeswitch/trunk/src/mod/applications/mod_expr/license.txt ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/license.txt Thu Nov 8 18:46:26 2007 @@ -0,0 +1,21 @@ +ExprEval - Expression Evaluation Library +Version 2.0 + +Copyright (C) 2004 Brian Allen Vanderburg II + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + Added: freeswitch/trunk/src/mod/applications/mod_expr/mod_expr.c ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/mod_expr.c Thu Nov 8 18:46:26 2007 @@ -0,0 +1,198 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com> + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II <anthmct@yahoo.com> + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II <anthmct@yahoo.com> + * + * mod_expr.c -- Framework Demo Module + * + */ +#include <switch.h> +#include "expreval.h" + +/* Breaker function to break out of long expression functions + such as the 'for' function */ +int breaker(exprObj *o) +{ + /* Return nonzero to break out */ + return -1; +} + + +SWITCH_STANDARD_API(expr_function) +{ + exprObj *e = NULL; + exprFuncList *f = NULL; + exprValList *v = NULL; + exprValList *c = NULL; + EXPRTYPE last_expr; + const char *expr; + int err; + char val[512] = "", *p; + char *m_cmd = NULL; + size_t len = strlen(cmd) + 3; + + + m_cmd = malloc(len); + assert(m_cmd); + switch_copy_string(m_cmd, cmd, len); + + for (p = m_cmd; p && *p; p++) { + if (*p == '|') { + *p = ';'; + } + } + + p = m_cmd + (strlen(m_cmd) - 1); + if (*p != ';') { + p++; + *p = ';'; + p++; + *p = '\0'; + } + + expr = m_cmd; + + /* Create function list */ + err = exprFuncListCreate(&f); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Init function list with internal functions */ + err = exprFuncListInit(f); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Add custom function */ + //err = exprFuncListAdd(f, my_func, "myfunc", 1, 1, 1, 1); + //if(err != EXPR_ERROR_NOERROR) + //goto error; + + /* Create constant list */ + err = exprValListCreate(&c); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Init constant list with internal constants */ + err = exprValListInit(c); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Create variable list */ + err = exprValListCreate(&v); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Create expression object */ + err = exprCreate(&e, f, v, c, breaker, NULL); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Parse expression */ + err = exprParse(e, (char *)expr); + printf("WTF %s\n", expr); + if(err != EXPR_ERROR_NOERROR) + goto error; + + /* Enable soft errors */ + //exprSetSoftErrors(e, 1); + + do { + err = exprEval(e, &last_expr); + } while (err); + + snprintf(val, sizeof(val), "%0.10f", last_expr); + for (p = (val + strlen(val) - 1); p != val; p--) { + if (*p != '0') { + *(p+1) = '\0'; + break; + } + } + + p = val + strlen(val) - 1; + if (*p == '.') { + *p = '\0'; + } + + stream->write_function(stream, "%s", val); + + + goto done; + + error: + /* Alert user of error */ + stream->write_function(stream, "!err!"); + + + done: + /* Do cleanup */ + if(e) { + exprFree(e); + } + + if(f) { + exprFuncListFree(f); + } + + if(v) { + exprValListFree(v); + } + + if(c) { + exprValListFree(c); + } + + switch_safe_free(m_cmd); + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_MODULE_LOAD_FUNCTION(mod_expr_load); +SWITCH_MODULE_DEFINITION(mod_expr, mod_expr_load, NULL, NULL); + +SWITCH_MODULE_LOAD_FUNCTION(mod_expr_load) +{ + switch_api_interface_t *commands_api_interface; + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + SWITCH_ADD_API(commands_api_interface, "expr", "Eval an expession", expr_function, "<expr>"); + + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:nil + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ Added: freeswitch/trunk/src/mod/applications/mod_expr/readme.txt ============================================================================== --- (empty file) +++ freeswitch/trunk/src/mod/applications/mod_expr/readme.txt Thu Nov 8 18:46:26 2007 @@ -0,0 +1,170 @@ +ExprEval - A C/C++ based expression evaluation library +Written by: Brian Allen Vanderburg II +Licensed under the ExprEval License +------------------------------------------------------ +ExprEval is a mostly a C based expression evaluation +library. The only C++ part is the C++ Wrapper which +encapsulates the complexity of the library usage. + +ExprEval supports the parsing of multiple expressions +in a single expression string. Each sub-expression +must end with a semicolon. It also supports the use +of variables, constants, and functions. Functions +can take multiple arguments. These arguments can +also be expressions. + +ExprEval is very fast. It first parses the expression +string into a tree of actions to take. After it has +been parsed, an expression can be evaluated many times +over an over. + +Functions, variables, and constants are stored in +their own seperate lists. This makes is where the +lists can be shared among multiple expression objects. +A function list can add all the functions needed, and +then be added to each expression object, instead of +added each needed function to each object. The same +goes for constant lists. Variable lists make it where +one expression can depend on a variable set in another. + + +Saturday, July 1, 2006 +---------------------- +Version 2.6 + +* Added a new value list function 'exprValListGetNext' that can be used to + enumerate the items in a value list. Any of the items not needed (name, + value, or address) can be NULL. For example: + + char *name; + EXPRTYPE val; + void *cookie; + + cookie = exprValListGetNext(vlist, &name, &value, NULL, NULL); + while(cookie) + { + /* Do something with name and value */ + cookie = exprValListGetNext(vlist, &name, &value, NULL, cookie); + } + + You must make sure not to actually edit the returned name, because it is a + pointer into the value list to the name. This can also be used to have one + value list store globals. Global variables can be added to a value list, then + additional lists can be created, and before any variables are added + or the expression is parsed, the global list can be enumerated for name and + address and the exprValListAddAddress can be used to add them. This way, + expressions can have their own private list, but some variables may be shared + on each expression through the global list. This is useful especially if the + globals are not known at compile time, but can be adjusted by the user. + For example: + + exprValList *globals; + exprValList *v1; + exprValList *v2; + char *name; + EXPRTYPE *addr; + void *cookie; + + exprValListCreate(&globals); + /* Add variables to the list, perhaps read from a user file or something */ + + exprValListCreate(&v1); + cookie = exprValListGetNext(globals, &name, NULL, &addr, NULL); + while(cookie) + { + exprValListAddAddress(v1, name, addr); + cookie = exprValListGetNext(globals, &name, NULL, &addr, cookie); + } + + +Friday, June 30, 2006 +--------------------- +Version 2.5 + +* Added a new value list function 'exprValListAddAddress'. This function adds + a named value to the list, but uses the addresss of a stack variable. The + stack variable is then used to set/get the value instead of the internal list + value. You must ensure that the stack variable exists as long as it is used + by the expression. This can permit, for example, a value name to be shared + with two different value lists like such: + + EXPRTYPE global_value; + exprValListAddAddress(vlist, "global", &global_value); + exprValListAddAddress(vlist2, "global", &global_value); + + Like this, the value can be directly accessed by the application, and each + value list will share it. This can also be used to replace code from this: + + EXPRTYPE *a; + exprValListAdd(vlist, "var", 0.0); + exprValListGetAddress(vlist, "var", &a); + + To look like this: + + EXPRTYPE a; + exprValListAddAddress(vlist, "var", &a); +* Added a value list function exprValListSet to set the value of a variable + (using the slow search method). This is because the add functions now return + and error if the item (function/value) already exists instead of setting the + value of the item. You can still use the fast direct access method. +* Changed internal lists for function and value lists from binary trees to + linked lists. + + + + +Thursday, May 4, 2006 +--------------------- +Version 2.0 + +* All internal functions are evaluated directly in the exprEvalNode call. + This gives some speed increase. +* Removed parameter and reference count macros as well as functin creation + macro. Parameter and reference count information can be set when adding + a function solver. +* Removed exprMsgFuncType, since it is unused by the library. +* Changed much of the internal names from one-letter variable names to + more meaningful names. + +Thursday, December 1, 2005 +-------------------------- +Version 1.8 + +* Added support for the ^ operator to raise to a power. + The pow function can still be used. +* Moved basic math code (add,subtract,multiply,divide,negate,exponent) + and multiple expression support from function solvers to the exprEvalNode + function. + +Tuesday, November 22, 2005 +-------------------------- +I still haven't been keeping up with history much. + +* Removed < and > as comments. Instead use # as a + comment to the end of the line +* Added function exprGetErrorPosition to get start and + end position of parse error. + +Monday, May 3, 2004: Version 1.0 +--------------------------------- +This is a pretty bad time to start the history part since +ExprEval is pretty much up and running and very operational. + +* Added macro EXPR_MAJORVERSION +* Added macro EXPR_MINORVERSION +* Added function exprGetVersion +* Added macro to make declaring functions easy: + EXPR_FUNCTIONSOLVER(func_name) +* Added support for passing variable references to functions + with the ampersand. Example: minmax(1,2,3,&min,&max) +* Added macros for reference support: + EXPR_REQUIREREFCOUNT + EXPR_REQUIREREFCOUNTMIN + EXPR_REQUIREREFCOUNTMAX + EXPR_REQUIREREFCOUNTRANGE +* Added feature to disable assigning to a variable with the + same name as a constant. +* Added feature to enable applications to change the value of + a constant while the expression can not. You must add + any constants to the constant list BEFORE you parse the + expression. Modified: freeswitch/trunk/src/switch_channel.c ============================================================================== --- freeswitch/trunk/src/switch_channel.c (original) +++ freeswitch/trunk/src/switch_channel.c Thu Nov 8 18:46:26 2007 @@ -1374,9 +1374,20 @@ while(*e == ' ') { *e-- = '\0'; } - if ((e = strchr(vval, ')'))) { - *e = '\0'; + e = vval; + br = 1; + while(e && *e) { + if (*e == '(') { + br++; + } else if (br > 1 && *e == ')') { + br--; + } else if (br == 1 && *e == ')') { + *e = '\0'; + break; + } + e++; } + vtype = 2; } @@ -1398,7 +1409,7 @@ if (stream.data) { char *expanded_vname = NULL; - + if ((expanded_vname = switch_channel_expand_variables(channel, (char *)vname)) == vname) { expanded_vname = NULL; } else { @@ -1462,6 +1473,7 @@ } } free(indup); + return data; } Modified: freeswitch/trunk/src/switch_utils.c ============================================================================== --- freeswitch/trunk/src/switch_utils.c (original) +++ freeswitch/trunk/src/switch_utils.c Thu Nov 8 18:46:26 2007 @@ -197,6 +197,67 @@ return SWITCH_TRUE; } +SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip) +{ + + + return ( + strncmp(ip, "10.", 3) && + strncmp(ip, "192.168.", 8) && + strncmp(ip, "127.", 4) && + strncmp(ip, "255.", 4) && + strncmp(ip, "0.", 2) && + strncmp(ip, "1.", 2) && + strncmp(ip, "2.", 2) && + strncmp(ip, "172.16.", 7) && + strncmp(ip, "172.17.", 7) && + strncmp(ip, "172.18.", 7) && + strncmp(ip, "172.19.", 7) && + strncmp(ip, "172.2", 5) && + strncmp(ip, "172.30.", 7) && + strncmp(ip, "172.31.", 7) && + strncmp(ip, "192.0.2.", 8) && + strncmp(ip, "169.254.", 8) + ) ? SWITCH_FALSE : SWITCH_TRUE; + +} + + +SWITCH_DECLARE(char *) switch_strip_spaces(const char *str) +{ + const char *sp = str; + char *p, *s = NULL; + + while(sp && *sp && *sp == ' ') { + sp++; + } + + s = strdup(sp); + + p = s + (strlen(s) - 1); + + while(*p == ' ') { + *p-- = '\0'; + } + + return s; +} + +SWITCH_DECLARE(switch_bool_t) switch_is_number(const char *str) +{ + const char *p; + switch_bool_t r = SWITCH_TRUE; + + for (p = str; p && *p; p++) { + if (!(*p == '.' || (*p > 47 && *p < 58))) { + r = SWITCH_FALSE; + break; + } + } + + return r; +} + SWITCH_DECLARE(const char *) switch_stristr(const char *str, const char *instr) { @@ -536,8 +597,7 @@ int argc; char *ptr; int quot = 0; - char qc = '"'; - char *e; + char qc = '\''; int x; if (!buf || !array || !arraylen) { @@ -568,13 +628,21 @@ array[argc++] = ptr; } - /* strip quotes */ + /* strip quotes and leading / trailing spaces */ for (x = 0; x < argc; x++) { - if (*(array[x]) == qc) { + char *p; + + while(*(array[x]) == ' ') { (array[x])++; - if ((e = strchr(array[x], qc))) { - *e = '\0'; - } + } + p = array[x]; + while((p = strchr(array[x], qc))) { + memmove(p, p+1, strlen(p)); + p++; + } + p = array[x] + (strlen(array[x]) - 1); + while(*p == ' ') { + *p-- = '\0'; } }