// 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;
const char *ScriptChecks::chkKeywords(Line *line, ScriptImage *img)
{
char proto[80];
Name *scr = img->getCurrent();
unsigned idx = 0;
const char *cp;
if(getMember(line))
return "no members defined";
if(hasKeywords(line))
return "keywords defined, not used";
if(!line->argc)
return "keyword list missing";
while(NULL != (cp = getOption(line, &idx)))
{
if(!isalpha(*cp) && !isdigit(*cp))
return "invalid keyword entry";
}
snprintf(proto, sizeof(proto), "keywords.%s", scr->name);
if(img->getPointer(proto))
return "keywords already defined for this function";
img->setPointer(proto, line);
return "";
}
const char *ScriptChecks::chkUse(Line *line, ScriptImage *img)
{
return ScriptBinder::check(line, img);
}
const char *ScriptChecks::chkRestart(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used in this command";
return chkNoArgs(line, img);
}
const char *ScriptChecks::chkCall(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
unsigned idx = 0;
Line *list = NULL;
char proto[256];
unsigned len = 0, diff;
Name *scr = img->getCurrent();
char *p;
if(cp)
return "members not used in this command";
cp = getOption(line, &idx);
if(!cp)
return "target label missing";
if(*cp == '&')
++cp;
if(strchr(cp, ':') || stricmp(line->cmd, "call"))
{
snprintf(proto, sizeof(proto), "keywords.%s", cp);
list = (Line *)img->getPointer(proto);
}
else if(!stricmp(line->cmd, "call"))
{
snprintf(proto, sizeof(proto), "keywords.%s", scr->name);
p = strchr(proto, ':');
if(!p)
p = proto + strlen(proto);
diff = (unsigned)(p - proto);
snprintf(proto + diff, sizeof(proto) - diff, "::%s", cp);
list = (Line *)img->getPointer(proto);
}
if(*cp == '^' || *cp == '@')
return "invalid label used";
if(!list)
return NULL;
idx = 0;
while(NULL != (cp = getOption(list, &idx)))
{
snprintf(proto + len, sizeof(proto) - len, "=%s", cp);
len = (unsigned)strlen(proto);
}
if(len)
{
if(!useKeywords(line, proto))
return "invalid keyword used for function call";
}
return NULL;
}
const char *ScriptChecks::chkSession(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used in this command";
if(!line->argc)
return NULL;
if(line->argc > 1)
return "only one session allowed";
return NULL;
}
const char *ScriptChecks::chkLock(Line *line, ScriptImage *img)
{
const char *cp;
if(getMember(line))
return "member not used in this command";
if(!line->argc)
return "lock symbol missing";
if(line->argc > 1)
return "only one lock symbol allowed";
cp = line->args[0];
if(*cp != '%' && *cp != '&')
return "lock target must be symbol";
return NULL;
}
const char *ScriptChecks::chkSignal(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp)
return "member not used in this command";
if(!line->argc)
return "target handler missing";
if(line->argc > 1)
return "only single target handler allowed";
cp = line->args[0];
if(*cp != '^')
return "target must refer to signal handler";
return NULL;
}
const char *ScriptChecks::chkThrow(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp)
return "member not used in this command";
if(!line->argc)
return "target handler missing";
if(line->argc > 1)
return "only single target handler allowed";
cp = line->args[0];
if(*cp != '@' && *cp != '{')
return "target must refer to event handler";
return NULL;
}
const char *ScriptChecks::chkGoto(Line *line, ScriptImage *img)
{
unsigned opt = 0;
if(getMember(line))
return "goto has no member";
if(!getOption(line, &opt))
return "goto label missing";
if(getOption(line, &opt))
return "only one goto label";
return NULL;
}
const char *ScriptChecks::chkLabel(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp)
return "member not used in this command";
if(!line->argc)
return "target label missing";
if(line->argc > 1)
return "only single target label allowed";
cp = line->args[0];
if(*cp == '^' || *cp == '{' || *cp == '@')
return "invalid label used";
return NULL;
}
const char *ScriptChecks::chkReturn(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp)
return "member not used in this command";
return NULL;
}
const char *ScriptChecks::chkIgnore(Line *line, ScriptImage *img)
{
return NULL;
}
const char *ScriptChecks::chkDecimal(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(line->argc != 1)
return "decimal argument missing";
return NULL;
}
const char *ScriptChecks::chkOnlyCommand(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
return chkNoArgs(line, img);
}
const char *ScriptChecks::chkConditional(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(hasKeywords(line))
return "keywords not used for this command";
return chkExpression(line, img);
}
const char *ScriptChecks::chkError(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
return chkOnlyArgs(line, img);
}
const char *ScriptChecks::chkNoArgs(Line *line, ScriptImage *img)
{
if(line->argc)
return "arguments not used for this command";
return NULL;
}
const char *ScriptChecks::chkSlog(Line *line, ScriptImage *img)
{
const char *member = getMember(line);
if(member)
{
if(!stricmp(member, ".debug"))
member = NULL;
else if(!stricmp(member, ".info"))
member = NULL;
else if(!stricmp(member, ".notice"))
member = NULL;
else if(!strnicmp(member, ".warn", 5))
member = NULL;
else if(!strnicmp(member, ".err", 4))
member = NULL;
else if(!strnicmp(member, ".crit", 5))
member = NULL;
else if(!stricmp(member, ".alert"))
member = NULL;
else if(!strnicmp(member, ".emerg", 6))
member = NULL;
}
if(member)
return "invalid or unknown log level used";
return chkHasArgs(line, img);
}
const char *ScriptChecks::chkHasArgs(Line *line, ScriptImage *img)
{
if(!line->argc)
return "arguments missing";
return NULL;
}
const char *ScriptChecks::chkOnlyArgs(Line *line, ScriptImage *img)
{
if(!line->argc)
return "arguments missing";
if(hasKeywords(line))
return "keywords not used for this command";
return NULL;
}
const char *ScriptChecks::chkOnlyOneArg(Line *line, ScriptImage *img)
{
if(line->argc > 1)
return "too many arguments";
return chkOnlyArgs(line, img);
}
const char *ScriptChecks::chkRepeat(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(hasKeywords(line))
return "keywords not used for this command";
if(line->argc < 1)
return "at least repeat value required";
return chkExpression(line, img);
}
const char *ScriptChecks::chkIndex(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(hasKeywords(line))
return "keywords not used for this command";
return chkExpression(line, img);
}
const char *ScriptChecks::chkExpr(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && !isdigit(cp[0]))
{
cp = chkProperty(line, img);
if(cp)
return cp;
}
if(cp && atoi(cp) > 6)
return "numbers only valid to 6 decimal places";
if(hasKeywords(line))
return "keywords not used in this command";
return chkExpression(line, img);
}
const char *ScriptChecks::chkChar(Line *line, ScriptImage *img)
{
if(getMember(line))
return "char always size 1";
if(hasKeywords(line))
return "no keywords used in char";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkString(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && !isdigit(cp[0]))
return "member when used must be size";
if(!useKeywords(line, "=size"))
return "invalid keyword used for this command";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkDefine(Line *line, ScriptImage *img)
{
unsigned idx = 0;
const char *cp = line->cmd;
if(!line->argc)
return "define requires arguments";
while(idx < line->argc)
{
cp = line->args[idx++];
if(*cp == '=')
{
++cp;
++idx;
}
if(*cp == '%' || *cp == '&')
continue;
if(*cp == '.')
++cp;
cp = strchr(cp, ':');
if(cp)
{
++cp;
if(!isdigit(*cp))
return "invalid field size used";
}
}
return NULL;
}
const char *ScriptChecks::chkVarType(Line *line, ScriptImage *img)
{
if(getMember(line))
return "no members in type";
if(hasKeywords(line))
return "no keywords in type";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkVar(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && !isdigit(cp[0]))
{
cp = chkProperty(line, img);
if(!cp)
return "property invalid for var";
}
else
cp = NULL;
if(!useKeywords(line, "=size=value"))
return "invalid keyword used";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkNumber(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && !isdigit(cp[0]))
return "member must be decimal place";
if(cp && atoi(cp) > 6)
return "numbers supported only to 6 decimal places";
if(!useKeywords(line, "=decimal"))
return "invalid keyword used";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkConstruct(Line *line, ScriptImage *img)
{
unsigned int idx = 0;
const char *cp = getOption(line, &idx);
if(getMember(line))
return "no members for this command";
if(!cp)
return "destination for contruct is missing";
if(*cp != '%' && *cp != '&')
return "destination of contruct must be symbol";
if(getOption(line,&idx))
return "only one target for contruct";
return NULL;
}
const char *ScriptChecks::chkPack(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && stricmp(cp, "struct"))
return "only .struct may be used for this command";
if(!stricmp(cp, "struct"))
if(!useKeywords(line, "=size"))
return "invalid keyword used for pack.struct";
if(!useKeywords(line, "=field=offset=token=size=quote=prefix=suffix"))
return "invalid keyword used for this command";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkClear(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(hasKeywords(line))
return "keywords not used for this command";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkExpression(Line *line, ScriptImage *img)
{
unsigned idx = 0;
unsigned paren = 0;
const char *cp;
while(NULL != (cp = getOption(line, &idx)))
{
if(*cp == '(')
++paren;
else if(*cp == ')')
--paren;
if(paren < 0)
return "unbalanced parenthesis in expression";
}
if(paren)
return "unbalanced parenthesis in expression";
return NULL;
}
const char *ScriptChecks::chkAllVars(Line *line, ScriptImage *img)
{
unsigned idx = 0;
const char *cp;
while(NULL != (cp = getOption(line, &idx)))
{
switch(*cp)
{
case '%':
case '@':
case '&':
break;
default:
return "arguments must be symbols";
}
}
return chkHasArgs(line, img);
}
const char *ScriptChecks::chkType(Line *line, ScriptImage *img)
{
if(getMember(line))
return "type does not use member";
if(hasKeywords(line))
return "type does not use keyword";
if(line->argc < 1)
return "type requires at least one var";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkFirstVar(Line *line, ScriptImage *img)
{
const char *cp;
unsigned idx = 0;
cp = getOption(line, &idx);
if(!cp)
return "too few arguments";
if(*cp != '%' && *cp != '@' && *cp != '&')
return "first argument must be symbol";
return chkProperty(line, img);
}
const char *ScriptChecks::chkArray(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && !isdigit(*cp))
return "invalid member used";
if(!useKeywords(line, "=count=size"))
return "invalid keywords used";
if(!getMember(line))
if(!findKeyword(line, "count"))
return "requires count either in member or keyword";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkSet(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && !isdigit(*cp))
cp = chkProperty(line, img);
else
cp = NULL;
if(cp)
return cp;
if(!useKeywords(line, "=size=offset"))
return "invalid keyword used";
return chkFirstVar(line, img);
}
const char *ScriptChecks::chkFor(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(!useKeywords(line, "=index=size"))
return "invalid keyword used";
return chkFirstVar(line, img);
}
const char *ScriptChecks::chkForeach(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(!useKeywords(line, "=index=size=token"))
return "invalid keyword used";
if(getCount(line) != 2)
return "incorrect number of arguments";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkCat(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(hasKeywords(line))
return "keywords not used for this command";
return chkFirstVar(line, img);
}
const char *ScriptChecks::chkRemove(Line *line, ScriptImage *img)
{
if(getMember(line))
return "member not used for this command";
if(!useKeywords(line, "=field=token=offset"))
return "invalid keyword used for this command";
return chkFirstVar(line, img);
}
const char *ScriptChecks::chkSequence(Line *line, ScriptImage *img)
{
if(hasKeywords(line))
return "keywords not used for this command";
if(getMember(line))
return "member not used for this command";
return chkFirstVar(line, img);
}
const char *ScriptChecks::chkConst(Line *line, ScriptImage *img)
{
const char *cp = chkProperty(line, img);
if(cp)
return cp;
if(hasKeywords(line))
return "keywords not used for this command";
return chkFirstVar(line, img);
}
const char *ScriptChecks::chkCounter(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
if(cp && atoi(cp) < 1)
return "member must be initial value and greater than zero";
if(hasKeywords(line))
return "keywords not used for this command";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkTimer(Line *line, ScriptImage *img)
{
if(getMember(line))
return "timer has no member";
if(!useKeywords(line, "=offset=expires"))
return "invalid keyword used for this command";
return chkAllVars(line, img);
}
const char *ScriptChecks::chkRefArgs(Line *line, ScriptImage *img)
{
if(hasKeywords(line))
return "keywords not used for this command";
if(getMember(line))
return "member not used for this command";
if(line->argc != 2)
return "invalid number of arguments";
if(!isSymbol(line->args[0]))
return "reference target not symbol";
if(!isSymbol(line->args[1]))
return "reference source not symbol";
return NULL;
}
const char *ScriptChecks::chkProperty(Line *line, ScriptImage *img)
{
const char *cp = getMember(line);
ScriptProperty *prop;
if(!cp)
return NULL;
prop = ScriptProperty::find(cp);
if(!prop)
return "unknown script property referenced";
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1