summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-02-25 15:23:57 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2008-02-25 15:23:57 +0000
commit50ddd3fd7de672a2fa2df67adb27401cc38ce38c (patch)
treee509dc31fce2c6edb230147ee547b3967bc636c2
parentc9fc3fc06d2566aa6aed977af66392dce97d1264 (diff)
downloadrsyslog-50ddd3fd7de672a2fa2df67adb27401cc38ce38c.tar.gz
rsyslog-50ddd3fd7de672a2fa2df67adb27401cc38ce38c.tar.xz
rsyslog-50ddd3fd7de672a2fa2df67adb27401cc38ce38c.zip
added string concatenation operator & to RainerScript
-rw-r--r--ctok.c3
-rw-r--r--ctok_token.h1
-rw-r--r--doc/rainerscript.html10
-rw-r--r--expr.c4
-rwxr-xr-xstringbuf.c9
-rwxr-xr-xstringbuf.h1
-rw-r--r--vm.c16
-rw-r--r--vmop.c3
-rw-r--r--vmop.h1
9 files changed, 44 insertions, 4 deletions
diff --git a/ctok.c b/ctok.c
index 66305171..a8057a99 100644
--- a/ctok.c
+++ b/ctok.c
@@ -476,6 +476,9 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
case ',':
pToken->tok = ctok_COMMA;
break;
+ case '&':
+ pToken->tok = ctok_STRADD;
+ break;
case '$':
CHKiRet(ctokGetVar(pThis, pToken));
break;
diff --git a/ctok_token.h b/ctok_token.h
index 696a769e..c2b8aeba 100644
--- a/ctok_token.h
+++ b/ctok_token.h
@@ -52,6 +52,7 @@ typedef struct {
ctok_NUMBER = 16,
ctok_FUNCTION = 17,
ctok_THEN = 18,
+ ctok_STRADD = 19,
ctok_CMP_EQ = 100, /* all compare operations must be in a row */
ctok_CMP_NEQ = 101,
ctok_CMP_LT = 102,
diff --git a/doc/rainerscript.html b/doc/rainerscript.html
index 22415258..6ffd4c37 100644
--- a/doc/rainerscript.html
+++ b/doc/rainerscript.html
@@ -23,9 +23,15 @@ and many other languages).</p>
<p>Below is the formal language definitionin ABNF (RFC 2234)
format: <br>
</p>
-<pre>; <span style="font-weight: bold;">all of this is a working document and may change!</span> -- rgerhards, 2008-02-24<br><br>script := *stmt<br>stmt := (if_stmt / block / vardef / run_s / load_s)<br>vardef := "var" ["scope" = ("global" / "event")] <br>block := "begin" stmt "end"<br>load_s := "load" constraint ("module") modpath params ; load mod only if expr is true<br>run_s := "run" constraint ("input") name<br>constraint:= "if" expr ; constrains some one-time commands<br>modpath := expr<br>params := ["params" *1param *("," param) "endparams"]<br>param := paramname) "=" expr<br>paramname := [*(obqualifier ".") name]<br>modpath:= ; path to module<br>?line? := cfsysline / cfli<br>cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)<br>BOL := ; Begin of Line - implicitely set on file beginning and after each EOL<br>EOL := 0x0a ;LF<br>if_stmt := "if" expr "then"<br>old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!<br>facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" / <br> "mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" / <br> "local0" .. "local7" / "mark"<br> ; The keyword security should not be used anymore<br> ; mark is just internal<br>severity := TBD ; not really relevant in this context<br><br>; and now the actual expression<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;=" / "contains" / "startswith"<br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_"<br></pre>
+<pre>; <span style="font-weight: bold;">all of this is a working document and may change!</span> -- rgerhards, 2008-02-24<br><br>script := *stmt<br>stmt := (if_stmt / block / vardef / run_s / load_s)<br>vardef := "var" ["scope" = ("global" / "event")] <br>block := "begin" stmt "end"<br>load_s := "load" constraint ("module") modpath params ; load mod only if expr is true<br>run_s := "run" constraint ("input") name<br>constraint:= "if" expr ; constrains some one-time commands<br>modpath := expr<br>params := ["params" *1param *("," param) "endparams"]<br>param := paramname) "=" expr<br>paramname := [*(obqualifier ".") name]<br>modpath:= ; path to module<br>?line? := cfsysline / cfli<br>cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)<br>BOL := ; Begin of Line - implicitely set on file beginning and after each EOL<br>EOL := 0x0a ;LF<br>if_stmt := "if" expr "then"<br>old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!<br>facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" / <br> "mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" / <br> "local0" .. "local7" / "mark"<br> ; The keyword security should not be used anymore<br> ; mark is just internal<br>severity := TBD ; not really relevant in this context<br><br>; and now the actual expression<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 *(("+" / "-" / "&amp;") 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;=" / "contains" / "startswith"<br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_"<br></pre>
<h2>Samples</h2>
-<p>Some samples of RainerScript:</p><p>define function IsLinux<br>begin<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>end</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp; endaction<br><br>... or ...</p><p>define action writeMySQL<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp; &nbsp;endaction</p><p>if $message contains "error" then action writeMySQL</p><p>ALTERNATE APPROACH</p><p>define function IsLinux(<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>)</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action(<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp;&nbsp;)<br><br>... or ...</p><p>define action writeMySQL(<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp; &nbsp;)</p><p>if $message contains "error" then action writeMySQL(action.dbname='differentDB')</p><p></p><p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+<p>Some samples of RainerScript:</p><p>define function IsLinux<br>begin<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>end</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp;
+&nbsp; [?action.template='templatename'?] or [?action.sql='insert into
+table... values('&amp;$facility&amp;','&amp;$severity&amp;...?]<br>&nbsp; endaction<br><br>... or ...</p><p>define action writeMySQL<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('<span style="font-family: monospace;"> &amp;</span> $facility &amp; ',' &nbsp;&amp; $severity &amp;...?]<br>&nbsp; &nbsp;endaction</p><p>if $message contains "error" then action writeMySQL</p><p>ALTERNATE APPROACH</p><p>define function IsLinux(<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>)</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action(<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp;
+&nbsp; [?action.template='templatename'?] or [?action.sql='insert into
+table... values('&amp;$facility&amp;','&amp;$severity&amp;...?]<br>&nbsp;&nbsp;)<br><br>... or ...</p><p>define action writeMySQL(<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp;
+&nbsp; [?action.template='templatename'?] or [?action.sql='insert into
+table... values('&amp;$facility&amp;','&amp;$severity&amp;...?]<br>&nbsp; &nbsp;)</p><p>if $message contains "error" then action writeMySQL(action.dbname='differentDB')</p><p></p><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
<a href="http://www.rsyslog.com/">rsyslog</a>
diff --git a/expr.c b/expr.c
index 156621c1..03ced285 100644
--- a/expr.c
+++ b/expr.c
@@ -211,8 +211,8 @@ val(expr_t *pThis, ctok_t *tok)
/* *(("+" / "-") term) part */
CHKiRet(ctok.GetToken(tok, &pToken));
- while(pToken->tok == ctok_PLUS || pToken->tok == ctok_MINUS) {
- dbgoprint((obj_t*) pThis, "+/-\n");
+ while(pToken->tok == ctok_PLUS || pToken->tok == ctok_MINUS || pToken->tok == ctok_STRADD) {
+ dbgoprint((obj_t*) pThis, "+/-/&\n");
CHKiRet(term(pThis, tok));
CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */
CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */
diff --git a/stringbuf.c b/stringbuf.c
index 80f1bb97..ecd70113 100755
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -236,6 +236,15 @@ rsRetVal rsCStrAppendStr(cstr_t *pThis, uchar* psz)
}
+/* append the contents of one cstr_t object to another
+ * rgerhards, 2008-02-25
+ */
+rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend)
+{
+ return rsCStrAppendStrWithLen(pThis, pstrAppend->pBuf, pstrAppend->iStrLen);
+}
+
+
rsRetVal rsCStrAppendInt(cstr_t *pThis, long i)
{
DEFiRet;
diff --git a/stringbuf.h b/stringbuf.h
index d8e72999..c3db2486 100755
--- a/stringbuf.h
+++ b/stringbuf.h
@@ -140,6 +140,7 @@ int rsCStrSzStrStartsWithCStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz);
rsRetVal rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber);
rsRetVal rsCStrConvertToBool(cstr_t *pStr, number_t *pBool);
+rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend);
/* now come inline-like functions */
#ifdef NDEBUG
diff --git a/vm.c b/vm.c
index c85df45f..d0b5e141 100644
--- a/vm.c
+++ b/vm.c
@@ -205,6 +205,21 @@ ENDop(CMP_CONTAINS)
/* end comare operations that work on strings, only */
+BEGINop(STRADD) /* remember to set the instruction also in the ENDop macro! */
+ var_t *operand1;
+ var_t *operand2;
+CODESTARTop(STRADD)
+ vmstk.PopString(pThis->pStk, &operand2);
+ vmstk.PopString(pThis->pStk, &operand1);
+
+ CHKiRet(rsCStrAppendCStr(operand1->val.pStr, operand2->val.pStr));
+
+ /* we have a result, so let's push it */
+ vmstk.Push(pThis->pStk, operand1);
+ var.Destruct(&operand2); /* no longer needed */
+finalize_it:
+ENDop(STRADD)
+
BEGINop(NOT) /* remember to set the instruction also in the ENDop macro! */
var_t *operand;
CODESTARTop(NOT)
@@ -332,6 +347,7 @@ execProg(vm_t *pThis, vmprg_t *pProg)
doOP(PUSHCONSTANT);
doOP(PUSHMSGVAR);
doOP(PUSHSYSVAR);
+ doOP(STRADD);
doOP(PLUS);
doOP(MINUS);
doOP(TIMES);
diff --git a/vmop.c b/vmop.c
index 56112be5..8e3ae90c 100644
--- a/vmop.c
+++ b/vmop.c
@@ -173,6 +173,9 @@ vmopOpcode2Str(vmop_t *pThis, uchar **ppName)
case opcode_UNARY_MINUS:
*ppName = (uchar*) "UNARY_MINUS";
break;
+ case opcode_STRADD:
+ *ppName = (uchar*) "STRADD";
+ break;
default:
*ppName = (uchar*) "INVALID opcode";
break;
diff --git a/vmop.h b/vmop.h
index 70e166e3..804da5be 100644
--- a/vmop.h
+++ b/vmop.h
@@ -32,6 +32,7 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc(
*/
opcode_OR = ctok_OR,
opcode_AND = ctok_AND,
+ opcode_STRADD= ctok_STRADD,
opcode_PLUS = ctok_PLUS,
opcode_MINUS = ctok_MINUS,
opcode_TIMES = ctok_TIMES, /* "*" */