]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add some logic tools
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 8 Nov 2007 23:46:26 +0000 (23:46 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 8 Nov 2007 23:46:26 +0000 (23:46 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6189 d0543943-73ff-0310-b7d9-9358b9ac24b2

29 files changed:
build/modules.conf.in
conf/modules.conf.xml
src/include/switch_utils.h
src/mod/applications/mod_commands/mod_commands.c
src/mod/applications/mod_expr/Makefile [new file with mode: 0644]
src/mod/applications/mod_expr/conio.h [new file with mode: 0644]
src/mod/applications/mod_expr/exprconf.h [new file with mode: 0644]
src/mod/applications/mod_expr/expreval.c [new file with mode: 0644]
src/mod/applications/mod_expr/expreval.dsp [new file with mode: 0644]
src/mod/applications/mod_expr/expreval.dsw [new file with mode: 0644]
src/mod/applications/mod_expr/expreval.h [new file with mode: 0644]
src/mod/applications/mod_expr/expreval.html [new file with mode: 0644]
src/mod/applications/mod_expr/exprfunc.c [new file with mode: 0644]
src/mod/applications/mod_expr/exprilfs.h [new file with mode: 0644]
src/mod/applications/mod_expr/exprincl.h [new file with mode: 0644]
src/mod/applications/mod_expr/exprinit.c [new file with mode: 0644]
src/mod/applications/mod_expr/exprmem.c [new file with mode: 0644]
src/mod/applications/mod_expr/exprmem.h [new file with mode: 0644]
src/mod/applications/mod_expr/exprobj.c [new file with mode: 0644]
src/mod/applications/mod_expr/exprpars.c [new file with mode: 0644]
src/mod/applications/mod_expr/exprpriv.h [new file with mode: 0644]
src/mod/applications/mod_expr/exprtmpl.html [new file with mode: 0644]
src/mod/applications/mod_expr/exprutil.c [new file with mode: 0644]
src/mod/applications/mod_expr/exprval.c [new file with mode: 0644]
src/mod/applications/mod_expr/license.txt [new file with mode: 0644]
src/mod/applications/mod_expr/mod_expr.c [new file with mode: 0644]
src/mod/applications/mod_expr/readme.txt [new file with mode: 0644]
src/switch_channel.c
src/switch_utils.c

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