summaryrefslogtreecommitdiffstats
path: root/grammar
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2011-07-09 09:30:17 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2011-07-09 09:30:17 +0200
commitf5e0bbe2d9d1d9594a01fc869392374d1a44afbe (patch)
tree9900da75c78f9da18a3d74414bc0fbb800d2ba15 /grammar
parentf2ef6cd10699ab9f91b9e3e53726512cd290ea68 (diff)
downloadrsyslog-f5e0bbe2d9d1d9594a01fc869392374d1a44afbe.tar.gz
rsyslog-f5e0bbe2d9d1d9594a01fc869392374d1a44afbe.tar.xz
rsyslog-f5e0bbe2d9d1d9594a01fc869392374d1a44afbe.zip
milestone/[PARTWORK]: implemented RainerScript functions
Diffstat (limited to 'grammar')
-rw-r--r--grammar/rainerscript.c116
-rw-r--r--grammar/rainerscript.h19
-rw-r--r--grammar/testdriver.c1
3 files changed, 129 insertions, 7 deletions
diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c
index de15d5f3..41107de5 100644
--- a/grammar/rainerscript.c
+++ b/grammar/rainerscript.c
@@ -316,6 +316,91 @@ exprret2String(struct exprret *r, int *bMustFree)
return r->d.estr;
}
+/* Perform a function call. This has been moved out of cnfExprEval in order
+ * to keep the code small and easier to maintain.
+ */
+static inline void
+doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr)
+{
+ char *fname;
+ char *envvar;
+ int bMustFree;
+ es_str_t *estr;
+ char *str;
+ struct exprret r[CNFFUNC_MAX_ARGS];
+
+ dbgprintf("rainerscript: executing function id %d\n", func->fID);
+ switch(func->fID) {
+ case CNFFUNC_STRLEN:
+ if(func->expr[0]->nodetype == 'S') {
+ /* if we already have a string, we do not need to
+ * do one more recursive call.
+ */
+ ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr);
+ } else {
+ cnfexprEval(func->expr[0], &r[0], usrptr);
+ estr = exprret2String(&r[0], &bMustFree);
+ ret->d.n = es_strlen(estr);
+ if(bMustFree) es_deleteStr(estr);
+ }
+ ret->datatype = 'N';
+ break;
+ case CNFFUNC_GETENV:
+ /* note: the optimizer shall have replaced calls to getenv()
+ * with a constant argument to a single string (once obtained via
+ * getenv()). So we do NOT need to check if there is just a
+ * string following.
+ */
+ cnfexprEval(func->expr[0], &r[0], usrptr);
+ estr = exprret2String(&r[0], &bMustFree);
+ str = (char*) es_str2cstr(estr, NULL);
+ envvar = getenv(str);
+ ret->datatype = 'S';
+ ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar));
+ if(bMustFree) es_deleteStr(estr);
+ if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr);
+ free(str);
+ break;
+ case CNFFUNC_TOLOWER:
+ cnfexprEval(func->expr[0], &r[0], usrptr);
+ estr = exprret2String(&r[0], &bMustFree);
+ if(!bMustFree) /* let caller handle that M) */
+ estr = es_strdup(estr);
+ es_tolower(estr);
+ ret->datatype = 'S';
+ ret->d.estr = estr;
+ break;
+ case CNFFUNC_CSTR:
+ cnfexprEval(func->expr[0], &r[0], usrptr);
+ estr = exprret2String(&r[0], &bMustFree);
+ if(!bMustFree) /* let caller handle that M) */
+ estr = es_strdup(estr);
+ ret->datatype = 'S';
+ ret->d.estr = estr;
+ break;
+ case CNFFUNC_CNUM:
+ if(func->expr[0]->nodetype == 'N') {
+ ret->d.n = ((struct cnfnumval*)func->expr[0])->val;
+ } else if(func->expr[0]->nodetype == 'S') {
+ ret->d.n = es_str2num(((struct cnfstringval*) func->expr[0])->estr,
+ NULL);
+ } else {
+ cnfexprEval(func->expr[0], &r[0], usrptr);
+ ret->d.n = exprret2Number(&r[0], NULL);
+ if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr);
+ }
+ ret->datatype = 'N';
+ break;
+ default:
+ if(Debug) {
+ fname = es_str2cstr(func->fname, NULL);
+ dbgprintf("rainerscript: invalid function id %u (name '%s')\n",
+ (unsigned) func->fID, fname);
+ free(fname);
+ }
+ }
+}
+
#define FREE_BOTH_RET \
if(r.datatype == 'S') es_deleteStr(r.d.estr); \
if(l.datatype == 'S') es_deleteStr(l.d.estr)
@@ -329,10 +414,9 @@ exprret2String(struct exprret *r, int *bMustFree)
#define PREP_TWO_STRINGS \
cnfexprEval(expr->l, &l, usrptr); \
- cnfexprEval(expr->r, &r, usrptr); \
- estr_r = exprret2String(&r, &bMustFree); \
estr_l = exprret2String(&l, &bMustFree2); \
- FREE_BOTH_RET
+ cnfexprEval(expr->r, &r, usrptr); \
+ estr_r = exprret2String(&r, &bMustFree)
#define FREE_TWO_STRINGS \
if(bMustFree) es_deleteStr(estr_r); \
@@ -652,6 +736,9 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr)
ret->d.n = -exprret2Number(&r, &convok_r);
if(r.datatype == 'S') es_deleteStr(r.d.estr);
break;
+ case 'F':
+ doFuncCall((struct cnffunc*) expr, ret, usrptr);
+ break;
default:
ret->datatype = 'N';
ret->d.n = 0ll;
@@ -684,7 +771,6 @@ doIndent(int indent)
void
cnfexprPrint(struct cnfexpr *expr, int indent)
{
- struct cnffparamlst *param;
struct cnffunc *func;
int i;
@@ -784,7 +870,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent)
doIndent(indent);
func = (struct cnffunc*) expr;
cstrPrint("function '", func->fname);
- dbgprintf("' (%u params)\n", (unsigned) func->nParams);
+ dbgprintf("' (id:%d, params:%hu)\n", func->fID, func->nParams);
for(i = 0 ; i < func->nParams ; ++i) {
cnfexprPrint(func->expr[i], indent+1);
}
@@ -886,6 +972,24 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next)
return lst;
}
+static inline enum cnffuncid
+funcName2ID(es_str_t *fname)
+{
+ if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) {
+ return CNFFUNC_STRLEN;
+ } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) {
+ return CNFFUNC_GETENV;
+ } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) {
+ return CNFFUNC_TOLOWER;
+ } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) {
+ return CNFFUNC_CSTR;
+ } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) {
+ return CNFFUNC_CNUM;
+ } else {
+ return CNFFUNC_INVALID;
+ }
+}
+
struct cnffunc *
cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst)
{
@@ -903,7 +1007,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst)
func->nodetype = 'F';
func->fname = fname;
func->nParams = nParams;
- func->fID = 0; /* use name */
+ func->fID = funcName2ID(fname);
/* shuffle params over to array (access speed!) */
param = paramlst;
for(i = 0 ; i < nParams ; ++i) {
diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h
index b7abf153..5d9eff7f 100644
--- a/grammar/rainerscript.h
+++ b/grammar/rainerscript.h
@@ -3,6 +3,13 @@
#include <stdio.h>
#include <libestr.h>
+#define CNFFUNC_MAX_ARGS 32
+ /**< maximum number of arguments that any function can have (among
+ * others, this is used to size data structures).
+ */
+
+extern int Debug; /* 1 if in debug mode, 0 otherwise -- to be enhanced */
+
enum cnfobjType {
CNFOBJ_ACTION,
CNFOBJ_GLOBAL,
@@ -125,11 +132,21 @@ struct cnffparamlst {
struct cnfexpr *expr;
};
+enum cnffuncid {
+ CNFFUNC_INVALID = 0, /**< defunct entry, do not use (should normally not be present) */
+ CNFFUNC_NAME = 1, /**< use name to call function (for future use) */
+ CNFFUNC_STRLEN,
+ CNFFUNC_GETENV,
+ CNFFUNC_TOLOWER,
+ CNFFUNC_CSTR,
+ CNFFUNC_CNUM
+};
+
struct cnffunc {
unsigned nodetype;
es_str_t *fname;
unsigned short nParams;
- unsigned short *fID; /* function ID for built-ins, 0 means use name */
+ enum cnffuncid fID; /* function ID for built-ins, 0 means use name */
struct cnfexpr *expr[];
};
diff --git a/grammar/testdriver.c b/grammar/testdriver.c
index 3e161d38..784e286e 100644
--- a/grammar/testdriver.c
+++ b/grammar/testdriver.c
@@ -30,6 +30,7 @@
#include "parserif.h"
extern int yylineno;
+int Debug = 1;
void
parser_errmsg(char *fmt, ...)