[Freeswitch-svn] [commit] r6189 - in freeswitch/trunk: build conf src src/include src/mod/applications/mod_commands src/mod/applications/mod_expr
Freeswitch SVN
anthm at freeswitch.org
Thu Nov 8 18:46:27 EST 2007
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 at telekabel.nl>
+ * tkorrovi <tkorrovi at altavista.net> on 2002/02/26.
+ * Andrew Westcott <ajwestco at 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 at 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 at 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 at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct at 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';
}
}
More information about the Freeswitch-svn
mailing list