diff options
Diffstat (limited to 'grammar/rainerscript.c')
-rw-r--r-- | grammar/rainerscript.c | 163 |
1 files changed, 160 insertions, 3 deletions
diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index a5cc10c2..f542b7f2 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -41,6 +41,11 @@ #include "grammar.h" #include "queue.h" #include "srUtils.h" +#include "regexp.h" +#include "obj.h" + +DEFobjCurrIf(obj) +DEFobjCurrIf(regexp) void readConfFile(FILE *fp, es_str_t **str) @@ -749,8 +754,7 @@ var2Number(struct var *r, int *bSuccess) return n; } -/* ensure that retval is a string; if string is no number, - * emit error message and set number to 0. +/* ensure that retval is a string */ static inline es_str_t * var2String(struct var *r, int *bMustFree) @@ -774,6 +778,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) int bMustFree; es_str_t *estr; char *str; + int retval; struct var r[CNFFUNC_MAX_ARGS]; dbgprintf("rainerscript: executing function id %d\n", func->fID); @@ -816,6 +821,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) es_tolower(estr); ret->datatype = 'S'; ret->d.estr = estr; + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_CSTR: cnfexprEval(func->expr[0], &r[0], usrptr); @@ -824,6 +830,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) estr = es_strdup(estr); ret->datatype = 'S'; ret->d.estr = estr; + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_CNUM: if(func->expr[0]->nodetype == 'N') { @@ -838,6 +845,24 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) } ret->datatype = 'N'; break; + case CNFFUNC_RE_MATCH: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = var2String(&r[0], &bMustFree); + str = es_str2cstr(estr, NULL); + retval = regexp.regexec(func->funcdata, str, 0, NULL, 0); + if(retval == 0) + ret->d.n = 1; + else { + ret->d.n = 0; + if(retval != REG_NOMATCH) { + DBGPRINTF("re_match: regexec returned error %d\n", retval); + } + } + ret->datatype = 'N'; + if(bMustFree) es_deleteStr(estr); + free(str); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + break; default: if(Debug) { fname = es_str2cstr(func->fname, NULL); @@ -891,7 +916,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) int bMustFree, bMustFree2; long long n_r, n_l; - //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { /* note: comparison operations are extremely similar. The code can be copyied, only * places flagged with "CMP" need to be changed. @@ -1199,6 +1224,78 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) } } +//--------------------------------------------------------- + +static inline void +cnffuncDestruct(struct cnffunc *func) +{ + unsigned short i; + + for(i = 0 ; i < func->nParams ; ++i) { + cnfexprDestruct(func->expr[i]); + } + /* some functions require special destruction */ + switch(func->fID) { + case CNFFUNC_RE_MATCH: + regexp.regfree(func->funcdata); + free(func->funcdata); + free(func->fname); + break; + default:break; + } +} + +/* Destruct an expression and all sub-expressions contained in it. + */ +void +cnfexprDestruct(struct cnfexpr *expr) +{ + + dbgprintf("cnfexprDestruct expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_NE: + case CMP_EQ: + case CMP_LE: + case CMP_GE: + case CMP_LT: + case CMP_GT: + case CMP_STARTSWITH: + case CMP_STARTSWITHI: + case CMP_CONTAINS: + case CMP_CONTAINSI: + case OR: + case AND: + case '+': + case '-': + case '*': + case '/': + case '%': /* binary */ + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + break; + case NOT: + case 'M': /* unary */ + cnfexprDestruct(expr->r); + break; + case 'N': + break; + case 'S': + es_deleteStr(((struct cnfstringval*)expr)->estr); + break; + case 'V': + free(((struct cnfvar*)expr)->name); + break; + case 'F': + cnffuncDestruct((struct cnffunc*)expr); + break; + default:break; + } + free(expr); +} + +//---- END + + /* Evaluate an expression as a bool. This is added because expressions are * mostly used inside filters, and so this function is quite common and * important. @@ -1488,11 +1585,53 @@ funcName2ID(es_str_t *fname, unsigned short nParams) return CNFFUNC_INVALID; } return CNFFUNC_CNUM; + } else if(!es_strbufcmp(fname, (unsigned char*)"re_match", sizeof("re_match") - 1)) { + if(nParams != 2) { + parser_errmsg("number of parameters for re_match() must be two " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } + return CNFFUNC_RE_MATCH; } else { return CNFFUNC_INVALID; } } + +static inline rsRetVal +initFunc_re_match(struct cnffunc *func) +{ + rsRetVal localRet; + char *regex = NULL; + regex_t *re; + DEFiRet; + + func->funcdata = NULL; + if(func->expr[1]->nodetype != 'S') { + parser_errmsg("param 2 of re_match() must be a constant string"); + FINALIZE; + } + + CHKmalloc(re = malloc(sizeof(regex_t))); + func->funcdata = re; + + regex = es_str2cstr(((struct cnfstringval*) func->expr[1])->estr, NULL); + + if((localRet = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + if(regexp.regcomp(re, (char*) regex, REG_EXTENDED) != 0) { + parser_errmsg("cannot compile regex '%s'", regex); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { /* regexp object could not be loaded */ + parser_errmsg("could not load regex support - regex ignored"); + ABORT_FINALIZE(RS_RET_ERR); + } + +finalize_it: + free(regex); + RETiRet; +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -1519,6 +1658,14 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) param = param->next; free(toDel); } + /* some functions require special initialization */ + switch(func->fID) { + case CNFFUNC_RE_MATCH: + /* need to compile the regexp in param 2, so this MUST be a constant */ + initFunc_re_match(func); + break; + default:break; + } } return func; } @@ -1616,3 +1763,13 @@ cstrPrint(char *text, es_str_t *estr) dbgprintf("%s%s", text, str); free(str); } + +/* init must be called once before any parsing of the script files start */ +rsRetVal +initRainerscript(void) +{ + DEFiRet; + CHKiRet(objGetObjInterface(&obj)); +finalize_it: + RETiRet; +} |