summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-02-20 09:54:58 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2008-02-20 09:54:58 +0000
commitf02d615052e325616d7042096cea6e5247a980dc (patch)
treefed57a226daf1f0e052ead727fe99b858c3f1331
parent0af8d22ff6e9fbd8eb89a1612ecf4604f058f78c (diff)
downloadrsyslog-f02d615052e325616d7042096cea6e5247a980dc.tar.gz
rsyslog-f02d615052e325616d7042096cea6e5247a980dc.tar.xz
rsyslog-f02d615052e325616d7042096cea6e5247a980dc.zip
- basic implementation of expression parser parsing done
- improved ABNF a bit
-rw-r--r--conf.c15
-rw-r--r--ctok.c7
-rw-r--r--ctok_token.h20
-rw-r--r--debug.c19
-rw-r--r--doc/expression.html2
-rw-r--r--expr.c95
6 files changed, 132 insertions, 26 deletions
diff --git a/conf.c b/conf.c
index 6e03e5b8..fbf3e224 100644
--- a/conf.c
+++ b/conf.c
@@ -733,6 +733,7 @@ static rsRetVal cflineProcessIfFilter(uchar **pline, register selector_t *f)
{
DEFiRet;
ctok_t *ctok;
+ ctok_token_t *pToken;
ASSERT(pline != NULL);
ASSERT(*pline != NULL);
@@ -759,11 +760,19 @@ dbgprintf("calling expression parser, pp %p ('%s')\n", *pline, *pline);
/* ready to go... */
CHKiRet(exprParse(f->f_filterData.f_expr, ctok));
- /* we are back, so we now need to restore things */
- CHKiRet(ctokGetpp(ctok, pline));
+ /* we now need to parse off the "then" - and note an error if it is
+ * missing...
+ */
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ if(pToken->tok != ctok_THEN) {
+ ABORT_FINALIZE(RS_RET_SYNTAX_ERROR);
+ }
+ /* we are done, so we now need to restore things */
+ CHKiRet(ctokGetpp(ctok, pline));
CHKiRet(ctokDestruct(&ctok));
-dbgprintf("end expression parser, pp %p ('%s')\n", *pline, *pline);
+
+dbgprintf("expression parser successfully ended, pp %p ('%s')\n", *pline, *pline);
finalize_it:
if(iRet == RS_RET_SYNTAX_ERROR) {
diff --git a/ctok.c b/ctok.c
index eca6daa5..0cf1eeb2 100644
--- a/ctok.c
+++ b/ctok.c
@@ -95,7 +95,8 @@ ctokGetCharFromStream(ctok_t *pThis, uchar *pc)
ISOBJ_TYPE_assert(pThis, ctok);
ASSERT(pc != NULL);
- if(*pThis->pp == '\0') {
+ /* end of string or begin of comment terminates the "stream" */
+ if(*pThis->pp == '\0' || *pThis->pp == '#') {
ABORT_FINALIZE(RS_RET_EOS);
} else {
*pc = *pThis->pp;
@@ -359,7 +360,7 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
uchar szWord[128];
ISOBJ_TYPE_assert(pThis, ctok);
- ASSERT(pToken != NULL);
+ ASSERT(ppToken != NULL);
/* first check if we have an ungotten token and, if so, provide that
* one back (without any parsing). -- rgerhards, 2008-02-20
@@ -450,6 +451,8 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
pToken->tok = ctok_OR;
} else if(!strcasecmp((char*)szWord, "not")) {
pToken->tok = ctok_NOT;
+ } else if(!strcasecmp((char*)szWord, "then")) {
+ pToken->tok = ctok_THEN;
} else {
/* finally, we check if it is a function */
CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */
diff --git a/ctok_token.h b/ctok_token.h
index 45aeb017..ccde6325 100644
--- a/ctok_token.h
+++ b/ctok_token.h
@@ -46,19 +46,23 @@ typedef struct {
ctok_MSGVAR = 13,
ctok_SIMPSTR = 14,
ctok_TPLSTR = 15,
- ctok_CMP_EQ = 16,
- ctok_CMP_NEQ = 17,
- ctok_CMP_LT = 18,
- ctok_CMP_GT = 19,
- ctok_CMP_LTEQ = 20,
- ctok_CMP_GTEQ = 21,
- ctok_NUMBER = 22,
- ctok_FUNCTION = 23
+ ctok_NUMBER = 16,
+ ctok_FUNCTION = 17,
+ ctok_THEN = 18,
+ ctok_CMP_EQ = 100, /* all compare operations must be in a row */
+ ctok_CMP_NEQ = 101,
+ ctok_CMP_LT = 102,
+ ctok_CMP_GT = 103,
+ ctok_CMP_LTEQ = 104,
+ ctok_CMP_GTEQ = 105, /* end compare operations */
} tok;
rsCStrObj *pstrVal;
int64 intVal;
} ctok_token_t;
+/* defines to handle compare operation tokens in a single if... */
+#define ctok_tokenIsCmpOp(x) ((x)->tok >= ctok_CMP_EQ && (x)->tok <= ctok_CMP_GTEQ)
+
/* prototypes */
rsRetVal ctok_tokenConstruct(ctok_token_t **ppThis);
diff --git a/debug.c b/debug.c
index 5887f5dc..00b7916b 100644
--- a/debug.c
+++ b/debug.c
@@ -57,7 +57,7 @@ static dbgThrdInfo_t *dbgGetThrdInfo(void);
/* static data (some time to be replaced) */
int Debug; /* debug flag - read-only after startup */
int debugging_on = 0; /* read-only, except on sig USR1 */
-static int bLogFuncFlow = 0; /* shall the function entry and exit be logged to the debug log? */
+static int bLogFuncFlow = 1; /* shall the function entry and exit be logged to the debug log? */
static int bLogAllocFree = 0; /* shall calls to (m/c)alloc and free be logged to the debug log? */
static int bPrintFuncDBOnExit = 0; /* shall the function entry and exit be logged to the debug log? */
static int bPrintMutexAction = 0; /* shall mutex calls be printed to the debug log? */
@@ -741,6 +741,17 @@ dbgoprint(obj_t *pObj, char *fmt, ...)
if(!(Debug && debugging_on))
return;
+ /* a quick and very dirty hack to enable us to display just from those objects
+ * that we are interested in. So far, this must be changed at compile time (and
+ * chances are great it is commented out while you read it. Later, this shall
+ * be selectable via the environment. -- rgerhards, 2008-02-20
+ */
+#if 0
+ if(objGetObjID(pObj) != OBJexpr)
+ return;
+#endif
+
+
pthread_mutex_lock(&mutdbgoprint);
pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgoprint);
@@ -918,7 +929,8 @@ int dbgEntrFunc(dbgFuncDB_t *pFuncDB, int line)
/* when we reach this point, we have a fully-initialized FuncDB! */
- if(bLogFuncFlow)
+ //if(bLogFuncFlow) /* quick debug hack... select the best for you! */
+ if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "expr.c")) /* quick debug hack... select the best for you! */
dbgprintf("%s:%d: %s: enter\n", pFuncDB->file, pFuncDB->line, pFuncDB->func);
if(pThrd->stackPtr >= (int) (sizeof(pThrd->callStack) / sizeof(dbgFuncDB_t*))) {
dbgprintf("%s:%d: %s: debug module: call stack for this thread full, suspending call tracking\n",
@@ -947,7 +959,8 @@ void dbgExitFunc(dbgFuncDB_t *pFuncDB, int iStackPtrRestore)
assert(pFuncDB->magic == dbgFUNCDB_MAGIC);
dbgFuncDBPrintActiveMutexes(pFuncDB, "WARNING: mutex still owned by us as we exit function, mutex: ", pthread_self());
- if(bLogFuncFlow)
+ //if(bLogFuncFlow) /* quick debug hack... select the best for you! */
+ if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "expr.c")) /* quick debug hack... select the best for you! */
dbgprintf("%s:%d: %s: exit\n", pFuncDB->file, pFuncDB->line, pFuncDB->func);
pThrd->stackPtr = iStackPtrRestore;
if(pThrd->stackPtr < 0) {
diff --git a/doc/expression.html b/doc/expression.html
index 7ce9429a..dbb9f68c 100644
--- a/doc/expression.html
+++ b/doc/expression.html
@@ -11,7 +11,7 @@ far, they are supported for filtering messages.</p>
<h2>Formal Definition</h2>
<p>Below is the formal definition of expression format (in ABNF, RFC 2234):<br>
-</p><pre>expr := e_and *("or" e_and)<br>e_and := e_cmp *("and" e_cmp)<br>e_cmp := val cmp_op val<br>val := ["+" / "-"] term *(("+" / "-") term)<br>term := factor *(("*" / "/" / "%") factor)<br>factor := ["not"] terminal<br>terminal := var / constant / function / "(" expr ")"<br>function := name "(" *("," expr) ")"<br>var := "$" varname<br>varname := msgvar / sysvar<br>msgvar := name<br>sysvar := "$" name<br>name := alpha *(alnum)<br>constant := string / number<br>string := simpstr / tplstr ; tplstr will be implemented in next phase<br>simpstr := "'" *char "'" ; use your imagination for char ;)<br>tplstr := '"' template '"' ; not initially implemented<br>number := 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal<br>cmp_op := "==" / "!=" / "&lt;&gt;" / "&lt;" / "&gt;" / "&lt;=" / "&gt;=" <br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_"<br></pre>
+</p><pre>if_stmt := "if" expr "then" # an aid, not part of expression itself<br><br>expr := e_and *("or" e_and)<br>e_and := e_cmp *("and" e_cmp)<br>e_cmp := val 0*1(cmp_op val)<br>val := ["+" / "-"] term *(("+" / "-") term)<br>term := factor *(("*" / "/" / "%") factor)<br>factor := ["not"] terminal<br>terminal := var / constant / function / "(" expr ")"<br>function := name "(" *("," expr) ")"<br>var := "$" varname<br>varname := msgvar / sysvar<br>msgvar := name<br>sysvar := "$" name<br>name := alpha *(alnum)<br>constant := string / number<br>string := simpstr / tplstr ; tplstr will be implemented in next phase<br>simpstr := "'" *char "'" ; use your imagination for char ;)<br>tplstr := '"' template '"' ; not initially implemented<br>number := 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal<br>cmp_op := "==" / "!=" / "&lt;&gt;" / "&lt;" / "&gt;" / "&lt;=" / "&gt;=" <br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_"<br></pre>
<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
diff --git a/expr.c b/expr.c
index b059dac7..bb72cb89 100644
--- a/expr.c
+++ b/expr.c
@@ -50,12 +50,14 @@ DEFobjStaticHelpers
* rgerhards, 2008-02-19
*/
+/* forward definiton - thanks to recursive ABNF, we can not avoid at least one ;) */
+static rsRetVal expr(expr_t *pThis, ctok_t *ctok);
+
#if 0
static rsRetVal
template(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
-RUNLOG_STR("");
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
@@ -73,7 +75,6 @@ terminal(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
ctok_token_t *pToken;
-RUNLOG_STR("terminal");
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
@@ -82,8 +83,33 @@ RUNLOG_STR("terminal");
switch(pToken->tok) {
case ctok_SIMPSTR:
+ dbgoprint((obj_t*) pThis, "simpstr\n");
+ break;
+ case ctok_NUMBER:
+ dbgoprint((obj_t*) pThis, "number\n");
+ break;
+ case ctok_FUNCTION:
+ dbgoprint((obj_t*) pThis, "function\n");
+ break;
+ case ctok_MSGVAR:
+ dbgoprint((obj_t*) pThis, "MSGVAR\n");
+ break;
+ case ctok_SYSVAR:
+ dbgoprint((obj_t*) pThis, "SYSVAR\n");
+ break;
+ case ctok_LPAREN:
+ dbgoprint((obj_t*) pThis, "expr\n");
+ CHKiRet(ctok_tokenDestruct(&pToken)); /* "eat" processed token */
+ CHKiRet(expr(pThis, ctok));
+ CHKiRet(ctokGetToken(ctok, &pToken)); /* get next one */
+ if(pToken->tok != ctok_RPAREN)
+ ABORT_FINALIZE(RS_RET_SYNTAX_ERROR);
+ CHKiRet(ctok_tokenDestruct(&pToken)); /* "eat" processed token */
+ dbgoprint((obj_t*) pThis, "end expr, rparen eaten\n");
+ /* fill structure */
break;
default:
+ dbgoprint((obj_t*) pThis, "invalid token %d\n", pToken->tok);
ABORT_FINALIZE(RS_RET_SYNTAX_ERROR);
break;
}
@@ -96,11 +122,21 @@ static rsRetVal
factor(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
-RUNLOG_STR("factor");
+ ctok_token_t *pToken;
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ if(pToken->tok == ctok_NOT) {
+ /* TODO: fill structure */
+ dbgprintf("not\n");
+ CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
+ CHKiRet(ctokGetToken(ctok, &pToken)); /* get next one */
+ } else {
+ /* we could not process the token, so push it back */
+ CHKiRet(ctokUngetToken(ctok, pToken));
+ }
CHKiRet(terminal(pThis, ctok));
finalize_it:
@@ -112,7 +148,6 @@ static rsRetVal
term(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
-RUNLOG_STR("term");
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
@@ -128,7 +163,6 @@ val(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
ctok_token_t *pToken;
-RUNLOG_STR("val");
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
@@ -155,13 +189,26 @@ static rsRetVal
e_cmp(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
-RUNLOG_STR("e_cmp");
+ ctok_token_t *pToken;
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
CHKiRet(val(pThis, ctok));
+ /* 0*1(cmp_op val) part */
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ if(ctok_tokenIsCmpOp(pToken)) {
+ dbgoprint((obj_t*) pThis, "cmp\n");
+ /* fill structure */
+ CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
+ CHKiRet(val(pThis, ctok));
+ } else {
+ /* we could not process the token, so push it back */
+ CHKiRet(ctokUngetToken(ctok, pToken));
+ }
+
+
finalize_it:
RETiRet;
}
@@ -171,13 +218,28 @@ static rsRetVal
e_and(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
-RUNLOG_STR("e_and");
+ ctok_token_t *pToken;
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
CHKiRet(e_cmp(pThis, ctok));
+ /* *("and" e_cmp) part */
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ while(pToken->tok == ctok_AND) {
+ dbgoprint((obj_t*) pThis, "and\n");
+ /* fill structure */
+ CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
+ CHKiRet(e_cmp(pThis, ctok));
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ }
+
+ /* unget the token that made us exit the loop - it's obviously not one
+ * we can process.
+ */
+ CHKiRet(ctokUngetToken(ctok, pToken));
+
finalize_it:
RETiRet;
}
@@ -187,13 +249,28 @@ static rsRetVal
expr(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
-RUNLOG_STR("expr");
+ ctok_token_t *pToken;
ISOBJ_TYPE_assert(pThis, expr);
ISOBJ_TYPE_assert(ctok, ctok);
CHKiRet(e_and(pThis, ctok));
+ /* *("or" e_and) part */
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ while(pToken->tok == ctok_OR) {
+ /* fill structure */
+ dbgoprint((obj_t*) pThis, "found OR\n");
+ CHKiRet(ctok_tokenDestruct(&pToken)); /* no longer needed */
+ CHKiRet(e_and(pThis, ctok));
+ CHKiRet(ctokGetToken(ctok, &pToken));
+ }
+
+ /* unget the token that made us exit the loop - it's obviously not one
+ * we can process.
+ */
+ CHKiRet(ctokUngetToken(ctok, pToken));
+
finalize_it:
RETiRet;
}
@@ -281,8 +358,8 @@ exprParse(expr_t *pThis, ctok_t *ctok)
ISOBJ_TYPE_assert(ctok, ctok);
CHKiRet(expr(pThis, ctok));
+ dbgoprint((obj_t*) pThis, "successfully parsed/created expression\n");
-RUNLOG_STR("expr parser being called");
finalize_it:
RETiRet;
}