Added new features: matching by function, message renaming, new message.

git-svn-id: http://voip.null.ro/svn/yate@1306 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2007-05-09 22:47:18 +00:00
parent b2a1165731
commit 5a1be97e8f
2 changed files with 93 additions and 5 deletions

View File

@ -10,6 +10,9 @@
; * matches preceeding expression any number of times (including zero)
; \+ matches preceeding expression at least one time
; \? matches preceeding expression zero or one time
; \{N\} matches preceeding expression exactly N times
; \{N,\} matches preceeding expression N or more times
; \{N,M\} matches preceeding expression between N and M times
; \( \) captures the contained subexpression
; Remember matches are greedy, they will match as much as possible
; You must escape ^ $ . * [ and \ with \ whenever you want them to be normal
@ -28,10 +31,14 @@
; $(mul,VAL1,VAL2[,LEN]) = VAL1*VAL2 left filled to LEN or length of VAL1
; $(div,VAL1,VAL2[,LEN]) = VAL1/VAL2 left filled to LEN or length of VAL1
; $(mod,VAL1,VAL2[,LEN]) = VAL1%VAL2 left filled to LEN or length of VAL1
; $(eq,VAL1,VAL2) = "true" if VAL1 = VAL2 (numerically), "false" otherwise
; $(ne,VAL1,VAL2) = "true" if VAL1 != VAL2 (numerically), "false" otherwise
; $(lt,VAL1,VAL2) = "true" if VAL1 < VAL2, "false" otherwise
; $(gt,VAL1,VAL2) = "true" if VAL1 > VAL2, "false" otherwise
; $(le,VAL1,VAL2) = "true" if VAL1 <= VAL2, "false" otherwise
; $(ge,VAL1,VAL2) = "true" if VAL1 >= VAL2, "false" otherwise
; $(streq,VAL1,VAL2) = "true" if VAL1 = VAL2 (string), "false" otherwise
; $(strne,VAL1,VAL2) = "true" if VAL1 != VAL2 (string), "false" otherwise
; $(random,STRING) = STRING with each ? character replaced with a random digit
; $(index,N,ITEM1,ITEM2,...) = N-th (modulo length of list) item in list
; $(rotate,N,ITEM1,ITEM2,...) = list rotated N (modulo length of list) times
@ -100,6 +107,8 @@
; regexp=target
; To match a message parameter you can use the format:
; ${paramname}regexp=target
; To match a function possibly containing parameters you can use the format:
; $(function,param...)regexp=target
; Strings captured with the regular expression construct \(...\) can be
; inserted in the target using \1, \2, \3, ...
; Message parameters can be inserted in the target using ${paramname}
@ -111,6 +120,9 @@
; context did not return successfully
; jump - jumps another context, does not return to this context
; match - modify the matched string instead of specifying a target
; rename - changes the name of the message
; enqueue - puts a new message in the engine, parameters are taken from the
; old message but placed in the new one
; echo - displays that line after making substitutions
;
; It is possible to set message parameters by appending them as name=value

View File

@ -62,6 +62,8 @@ enum {
OPER_MUL,
OPER_DIV,
OPER_MOD,
OPER_EQ,
OPER_NE,
OPER_GT,
OPER_LT,
OPER_GE,
@ -97,17 +99,29 @@ static void mathOper(String& str, String& par, int sep, int oper)
case OPER_MOD:
str = p2 ? p1%p2 : 0;
break;
case OPER_EQ:
str = (p1 == p2);
len = 0;
return;
case OPER_NE:
str = (p1 != p2);
len = 0;
return;
case OPER_GT:
str = (p1 > p2);
len = 0;
return;
case OPER_LT:
str = (p1 < p2);
len = 0;
return;
case OPER_GE:
str = (p1 >= p2);
len = 0;
return;
case OPER_LE:
str = (p1 <= p2);
len = 0;
return;
}
// TODO: deal with negative results
@ -145,6 +159,15 @@ static void evalFunc(String& str)
str = vars(par).toUpper();
else if (str == "lower")
str = vars(par).toLower();
else if ((sep > 0) && ((str == "streq") || (str == "strne"))) {
bool ret = (str == "strne");
str = par.substr(sep+1);
par = par.substr(0,sep);
vars(str);
vars(par);
ret ^= (str == par);
str = ret;
}
else if ((sep > 0) && ((str == "add") || (str == "+")))
mathOper(str,par,sep,OPER_ADD);
else if ((sep > 0) && ((str == "sub") || (str == "-")))
@ -155,13 +178,17 @@ static void evalFunc(String& str)
mathOper(str,par,sep,OPER_DIV);
else if ((sep > 0) && ((str == "mod") || (str == "%")))
mathOper(str,par,sep,OPER_MOD);
else if ((sep > 0) && (str == "eq"))
mathOper(str,par,sep,OPER_EQ);
else if ((sep > 0) && (str == "ne"))
mathOper(str,par,sep,OPER_NE);
else if ((sep > 0) && ((str == "gt") || (str == ">")))
mathOper(str,par,sep,OPER_GT);
else if ((sep > 0) && ((str == "lt") || (str == "<")))
mathOper(str,par,sep,OPER_LT);
else if ((sep > 0) && ((str == "ge") || (str == ">=")))
else if ((sep > 0) && (str == "ge"))
mathOper(str,par,sep,OPER_GE);
else if ((sep > 0) && ((str == "le") || (str == "<=")))
else if ((sep > 0) && (str == "le"))
mathOper(str,par,sep,OPER_LE);
else if (str == "random") {
str.clear();
@ -251,8 +278,10 @@ static void replaceFuncs(String &str)
}
// handle ;paramname[=value] assignments
static void setMessage(Message &msg, String &line)
static void setMessage(Message& msg, String& line, Message* target = 0)
{
if (!target)
target = &msg;
ObjList *strs = line.split(';');
bool first = true;
for (ObjList *p = strs; p; p=p->next()) {
@ -277,14 +306,14 @@ static void setMessage(Message &msg, String &line)
if (n.startSkip("$",false))
s_vars.setParam(n,v);
else
msg.setParam(n,v);
target->setParam(n,v);
}
else {
DDebug("RegexRoute",DebugAll,"Clearing parameter '%s'",s->c_str());
if (s->startSkip("$",false))
s_vars.clearParam(*s);
else
msg.clearParam(*s);
target->clearParam(*s);
}
}
}
@ -329,6 +358,27 @@ static bool oneContext(Message &msg, String &str, const String &context, String
val.c_str());
val = msg.getValue(val);
}
else if (r.startsWith("$(")) {
// handle special matching by param $(function)regexp
int p = r.find(')');
if (p < 3) {
Debug("RegexRoute",DebugWarn,"Invalid function match '%s' in rule #%u in context '%s'",
r.c_str(),i+1,context.c_str());
continue;
}
val = r.substr(0,p+1);
r = r.substr(p+1);
r.trimBlanks();
if (r.null()) {
Debug("RegexRoute",DebugWarn,"Missing rule in rule #%u in context '%s'",
i+1,context.c_str());
continue;
}
DDebug("RegexRoute",DebugAll,"Using function '%s'",
val.c_str());
msg.replaceParams(val);
replaceFuncs(val);
}
else
val = str;
val.trimBlanks();
@ -342,6 +392,25 @@ static bool oneContext(Message &msg, String &str, const String &context, String
Output("%s",val.safe());
continue;
}
else if (val.startSkip("enqueue")) {
// special case: enqueue a new message
if (val && (val[0] != ';')) {
Message* m = new Message("");
// parameters are set in the new message
setMessage(msg,val,m);
val.trimBlanks();
if (val) {
*m = val;
m->userData(msg.userData());
NDebug("RegexRoute",DebugAll,"Enqueueing new message '%s' by rule #%u '%s' in context '%s'",
val.c_str(),i+1,n->name().c_str(),context.c_str());
Engine::enqueue(m);
}
else
m->destruct();
}
continue;
}
setMessage(msg,val);
val.trimBlanks();
if (val.null()) {
@ -372,6 +441,13 @@ static bool oneContext(Message &msg, String &str, const String &context, String
str = val;
}
}
else if (val.startSkip("rename")) {
if (!val.null()) {
NDebug("RegexRoute",DebugAll,"Renaming message '%s' to '%s' by rule #%u '%s' in context '%s'",
msg.c_str(),val.c_str(),i+1,n->name().c_str(),context.c_str());
msg = val;
}
}
else {
DDebug("RegexRoute",DebugAll,"Returning '%s' for '%s' in context '%s' by rule #%u '%s'",
val.c_str(),str.c_str(),context.c_str(),i+1,n->name().c_str());