// Copyright (C) 1999-2005 Open Source Telecom Corporation.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free software
// library without restriction. Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License. This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// ccScript. If you copy code from other releases into a copy of GNU
// ccScript, as the General Public License permits, the exception does
// not apply to the code that you add in this way. To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU ccScript, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//
#include "engine.h"
using namespace std;
using namespace ost;
static long tens[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
long ScriptInterp::getRealValue(double d, unsigned prec)
{
char buf[20];
char *cp;
char lval[9];
unsigned count;
long rval;
snprintf(buf, sizeof(buf), "%f", d);
rval = atol(buf) * tens[prec];
cp = strchr(buf, '.');
if(!cp)
return rval;
count = (unsigned)strlen(++cp);
if(count > prec)
count = prec;
strcpy(lval, "00000000");
strncpy(lval, cp, count);
lval[prec] = 0;
if(rval < 0)
return rval - atol(lval);
return rval + atol(lval);
}
long ScriptInterp::getIntValue(const char *text, unsigned prec, ScriptProperty *p)
{
Fun *fun = ifun;
unsigned count;
const char *arg;
long *ival, rval;
char lval[9];
const char *orig = text;
if(p && p->isProperty(text))
{
rval = p->getValue(text);
return rval * tens[prec];
}
if(!isalpha(*text))
{
if(!strnicmp("0x", text, 2))
{
rval = strtol(text, NULL, 16);
return rval * tens[prec];
}
rval = atol(text);
rval *= tens[prec];
text = strchr(text, '.');
if(!text)
text = strrchr(orig, decimal);
if(!text)
return rval;
count = (unsigned)strlen(++text);
if(count > prec)
count = prec;
strcpy(lval, "00000000");
strncpy(lval, text, count);
lval[prec] = 0;
if(rval < 0)
return rval - atol(lval);
return rval + atol(lval);
}
while(NULL != fun)
{
if(!stricmp(fun->id, text))
break;
fun = fun->next;
}
if(!fun)
return 0;
if(!fun->args)
return fun->fn(NULL, prec);
arg = getValue(NULL);
if(!arg)
return 0;
if(stricmp(arg, "("))
return 0;
ival = new long[fun->args];
count = numericExpression(ival, fun->args, prec);
if(count != fun->args)
return 0;
rval = fun->fn(ival, prec);
delete[] ival;
return rval;
}
double ScriptInterp::getDouble(long value, unsigned prec)
{
return (double)value / (double)tens[prec];
}
long ScriptInterp::getInteger(long value, unsigned prec)
{
return value / tens[prec];
}
long ScriptInterp::getTens(unsigned prec)
{
return tens[prec];
}
int ScriptInterp::numericExpression(long *vals, int max, unsigned prec, ScriptProperty *p)
{
char estack[32];
unsigned esp = 0;
long vstack[32], val;
const char *value;
char **expr;
int count = 0;
long nval;
static char *elist[] = {"*", "+", "-", "/", "%", NULL};
vstack[0] = 0;
while(NULL != (value = getValue(NULL)))
{
expr = elist;
while(*expr)
{
if(!stricmp(*expr, value))
break;
++expr;
}
if(*expr)
estack[esp] = *value;
else
estack[esp] = 0;
if(!stricmp(value, "("))
{
if(esp < 31)
{
++esp;
vstack[esp] = 0;
continue;
}
return -1;
}
if(!stricmp(value, ","))
{
if(esp)
return -1;
if(count < max)
*(vals++) = vstack[0];
vstack[0] = 0;
++count;
continue;
}
if(!stricmp(value, ")"))
{
if(!esp)
{
if(count < max)
*(vals++) = vstack[0];
return ++count;
}
switch(estack[--esp])
{
case '+':
vstack[esp] = vstack[esp] + vstack[esp + 1];
break;
case '*':
vstack[esp] = vstack[esp] * vstack[esp + 1] / tens[prec];
break;
case '/':
if(vstack[esp + 1] == 0)
return -1;
vstack[esp] = vstack[esp] * tens[prec] / vstack[esp + 1];
break;
case '-':
vstack[esp] = vstack[esp] - vstack[esp + 1];
break;
case '%':
vstack[esp] = vstack[esp] % vstack[esp + 1];
break;
default:
vstack[esp] = vstack[esp + 1];
}
if(p)
{
nval = p->adjustValue(getInteger(vstack[esp], prec));
vstack[esp] = nval * tens[prec];
}
continue;
}
if(!*expr)
{
vstack[esp] = getIntValue(value, prec, p);
continue;
}
value = getValue("0");
if(!stricmp(value, "("))
{
if(esp > 31)
return -1;
vstack[++esp] = 0;
continue;
}
val = getIntValue(value, prec, p);
switch(estack[esp])
{
case '+':
vstack[esp] = vstack[esp] + val;
break;
case '-':
vstack[esp] = vstack[esp] - val;
break;
case '/':
if(!val)
return -1;
vstack[esp] = vstack[esp] * tens[prec] / val;
break;
case '*':
vstack[esp] = vstack[esp] * val / tens[prec];
break;
case '%':
vstack[esp] = vstack[esp] % atol(value);
break;
}
if(p)
{
nval = p->adjustValue(getInteger(vstack[esp], prec));
vstack[esp] = nval * tens[prec];
}
}
if(count < max)
{
if(p)
*(vals++) = p->adjustValue(getInteger(vstack[esp], prec));
else
*(vals++) = vstack[esp];
}
if(!esp)
return ++count;
else
return -1;
}
bool ScriptInterp::conditionalExpression(void)
{
#ifdef HAVE_REGEX_H
regex_t *regex;
bool rtn;
#endif
Symbol *sym;
Test *node = NULL;
const char *v1, *op = NULL, *v2;
char n1[12], n2[12];
size_t l1, l2;
long ival;
time_t now;
Array *a;
char buf[65];
// no first parm, invalid
v1 = getOption(NULL);
if(!v1)
return false;
if(*v1 == '-' || *v1 == '!')
{
node = Script::test;
while(node)
{
if(!stricmp(node->id, v1 + 1))
break;
node = node->next;
}
if(node)
op = (char *)node->id;
}
if(!strcmp(v1, "("))
{
numericExpression(&ival, 1, frame[stack].decimal);
snprintf(n1, sizeof(n1), "%ld", ival);
v1 = n1;
}
else if(!stricmp(v1, "-script") || !stricmp(v1, "!script"))
op = v1;
else if(!stricmp(v1, "-defined") || !stricmp(v1, "!defined"))
op = v1;
else if(!stricmp(v1, "-const") || !stricmp(v1, "!const"))
op = v1;
else if(!stricmp(v1, "-expired") || !stricmp(v1, "!expired"))
op = v1;
else if(!stricmp(v1, "-modify") || !stricmp(v1, "!modify"))
op = v1;
else if(!stricmp(v1, "-array") || !stricmp(v1, "!array"))
op = v1;
else if(!stricmp(v1, "-queue") || !stricmp(v1, "!queue"))
op = v1;
else if(!stricmp(v1, "-empty") || !stricmp(v1, "!empty"))
op = v1;
else if(!stricmp(v1, "-active") || !stricmp(v1, "!active"))
op = v1;
else if(!stricmp(v1, "-module") || !stricmp(v1, "-command") || !stricmp(v1, "-has"))
op = "-module";
else if(!stricmp(v1, "!module") || !stricmp(v1, "!command"))
op = "!module";
else
v1 = getContent(v1);
// sym/label by itself, invalid
if(!op)
op = getValue(NULL);
if(!op)
{
frame[stack].index = 0;
if(v1 && *v1)
return true;
return false;
}
// ifdef sym ... format assumed
v2 = getOption(NULL);
if(!v2)
{
frame[stack].index = 1;
if(v1 && *v1)
return true;
return false;
}
if(node)
{
if(*v1 == '!')
return !node->handler(this, getContent(v2));
else
return node->handler(this, getContent(v2));
}
if(!stricmp(op, "-script"))
{
if(getScript(getContent(v2)))
return true;
return false;
}
if(!stricmp(op, "!script"))
{
if(!getScript(getContent(v2)))
return true;
return false;
}
if(!stricmp(op, "-module"))
{ v2 = getContent(v2);
if(!v2)
return false;
if(cmd->getHandler(v2))
return true;
snprintf(buf, sizeof(buf), "definitions::%s", v2);
if(getScript(buf))
return true;
return false;
}
if(!stricmp(op, "!module"))
{
v2 = getContent(v2);
if(!v2)
return false;
if(cmd->getHandler(v2))
return false;
snprintf(buf, sizeof(buf), "definitions::%s", v2);
if(getScript(buf))
return false;
return true;
}
if(!stricmp(op, "!expired"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
if(sym->type != symTIMER)
return false;
if(!sym->data[0])
return true;
time(&now);
if((long)now >= atol(sym->data))
return false;
return true;
}
if(!stricmp(op, "-expired"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
if(sym->type != symTIMER)
return false;
if(!sym->data[0])
return false;
time(&now);
if((long)now >= atol(sym->data))
return true;
return false;
}
if(!stricmp(op, "-modify") || !stricmp(op, "!const"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
switch(sym->type)
{
case symLOCK:
case symCONST:
case symSEQUENCE:
return false;
default:
return true;
}
}
if(!stricmp(op, "!modify") || !stricmp(op, "-const"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return true;
switch(sym->type)
{
case symLOCK:
case symCONST:
case symSEQUENCE:
return true;
default:
return false;
}
}
if(!stricmp(op, "-queue"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
switch(sym->type)
{
case symSTACK:
case symFIFO:
return true;
default:
return false;
}
}
if(!stricmp(op, "!queue"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
switch(sym->type)
{
case symFIFO:
case symSTACK:
return false;
default:
return true;
}
}
if(!stricmp(op, "-array"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
switch(sym->type)
{
case symARRAY:
return true;
default:
return false;
}
}
if(!stricmp(op, "!array"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return true;
switch(sym->type)
{
case symARRAY:
return false;
default:
return true;
}
}
if(!stricmp(op, "-defined"))
{
sym = mapSymbol(v2, 0);
if(sym && sym->type != symINITIAL)
return true;
return false;
}
if(!stricmp(op, "!defined"))
{
sym = mapSymbol(v2, 0);
if(!sym || sym->type == symINITIAL)
return true;
return false;
}
if(!stricmp(op, "-active"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
a = (Array *)&sym->data;
switch(sym->type)
{
case symARRAY:
if(!a->tail)
return false;
return true;
case symSTACK:
case symFIFO:
if(a->tail == a->head)
return false;
return true;
case symLOCK:
if(strchr(sym->data, ':'))
return true;
return false;
case symCONST:
case symSEQUENCE:
case symNORMAL:
case symPROPERTY:
case symORIGINAL:
case symMODIFIED:
case symCOUNTER:
return true;
case symINITIAL:
return false;
case symTIMER:
case symNUMBER:
case symBOOL:
if(!sym->data[0])
return false;
default:
return true;
}
}
if(!stricmp(op, "!active"))
{
sym = mapSymbol(v2, 0);
if(!sym)
return false;
a = (Array *)&sym->data;
switch(sym->type)
{
case symARRAY:
if(!a->tail)
return true;
return false;
case symSTACK:
case symFIFO:
a = (Array *)&sym->data;
if(a->tail == a->head)
return true;
return false;
case symLOCK:
if(strchr(sym->data, ':'))
return false;
return true;
case symCONST:
case symSEQUENCE:
case symNORMAL:
case symPROPERTY:
case symORIGINAL:
case symMODIFIED:
case symCOUNTER:
return false;
case symINITIAL:
return true;
case symTIMER:
case symNUMBER:
case symBOOL:
if(!sym->data[0])
return true;
default:
return false;
}
}
if(!stricmp(op, "-empty"))
{
v2 = getContent(v2);
if(!v2)
return true;
if(!*v2)
return true;
return false;
}
if(!stricmp(op, "!empty"))
{
v2 = getContent(v2);
if(!v2)
return false;
if(!*v2)
return false;
return true;
}
if(!strcmp(v2, "("))
{
numericExpression(&ival, 1, frame[stack].decimal);
snprintf(n2, sizeof(n2), "%ld", ival);
v2 = n2;
}
else
v2 = getContent(v2);
if(!v1)
v1 = "";
if(!v2)
v2 = "";
if(!stricmp(op, "=") || !stricmp(op, "-eq"))
{
if(atol(v1) == atol(v2))
return true;
return false;
}
if(!stricmp(op, "<>") || !stricmp(op, "-ne"))
{
if(atol(v1) != atol(v2))
return true;
return false;
}
if(!stricmp(op, "==") || !stricmp(op, ".eq."))
{
if(!stricmp(v1, v2))
return true;
return false;
}
if(!stricmp(op, "!=") || !stricmp(op, ".ne."))
{
if(stricmp(v1, v2))
return true;
return false;
}
if(!stricmp(op, ".of.") || !stricmp(op, "?"))
{
l1 = strlen(v1);
while(v2 && *v2)
{
if(!strnicmp(v1, v2, l1))
{
if(v2[l1] == '=' || v2[l1] == ':')
return true;
}
v2 = strchr(v2, ';');
if(v2)
++v2;
}
return false;
}
if(!stricmp(op, "!?"))
{
l1 = strlen(v1);
while(v2 && *v2)
{
if(!strnicmp(v1, v2, l1))
{
if(v2[l1] == '=' || v2[l1] == ':')
return false;
}
v2 = strchr(v2, ';');
if(v2)
++v2;
}
return true;
}
if(!stricmp(op, "$") || !stricmp(op, ".in."))
{
if(strstr(v2, v1))
return true;
return false;
}
if(!stricmp(op, "!$"))
{
if(strstr(v2, v1))
return false;
return true;
}
#ifdef HAVE_REGEX_H
if(!stricmp(op, "~") || !stricmp(op, "!~"))
{
frame[stack].tranflag = false;
rtn = false;
regex = new regex_t;
memset(regex, 0, sizeof(regex_t));
if(regcomp(regex, v2, REG_ICASE|REG_NOSUB|REG_NEWLINE))
{
regfree(regex);
delete regex;
return false;
}
if(regexec(regex, v1, 0, NULL, 0))
rtn = false;
else
rtn = true;
regfree(regex);
delete regex;
if(*op == '!')
return !rtn;
return rtn;
}
#endif
if(!stricmp(op, "$<") || !stricmp(op, "$+") || !stricmp(op, ".prefix."))
{
if(!strnicmp(v1, v2, strlen(v1)))
return true;
return false;
}
if(!stricmp(op, "$>") || !stricmp(op, "$-") || !stricmp(op, ".suffix."))
{
l1 = strlen(v1);
l2 = strlen(v2);
if(l1 <= l2)
if(!strnicmp(v1, v2 + l2 - l1, l1))
return true;
return false;
}
if(!stricmp(op, "<") || !stricmp(op, "-lt"))
{
if(atol(v1) < atol(v2))
return true;
return false;
}
if(!stricmp(op, ".le."))
{
if(stricmp(v1, v2) <= 0)
return true;
return false;
}
if(!stricmp(op, ".ge."))
{
if(stricmp(v1, v2) >= 0)
return true;
return false;
}
if(!stricmp(op, "<=") || !stricmp(op, "=<") || !stricmp(op, "-le"))
{
if(atol(v1) <= atol(v2))
return true;
return false;
}
if(!stricmp(op, ">") || !stricmp(op, "-gt"))
{
if(atol(v1) > atol(v2))
return true;
return false;
}
if(!stricmp(op, ">=") || !stricmp(op, "=>") || !stricmp(op, "-ge"))
{
if(atol(v1) >= atol(v2))
return true;
return false;
}
// if no op, assume ifdef format
frame[stack].index = 1;
if(*v1)
return true;
return false;
}
bool ScriptInterp::conditional(void)
{
Line *line = getLine();
const char *joiner;
bool rtn;
bool andfalse = false;
bool ortrue = false;
for(;;)
{
rtn = conditionalExpression();
if(frame[stack].index < line->argc)
joiner = line->args[frame[stack].index];
else
joiner = "";
if(!stricmp(joiner, "and"))
{
if(!rtn)
andfalse = true;
}
else if(!stricmp(joiner, "or"))
{
if(rtn)
ortrue = true;
}
else
break;
++frame[stack].index;
}
if(andfalse)
return false;
if(ortrue)
return true;
return rtn;
}
syntax highlighted by Code2HTML, v. 0.9.1