summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-02-28 10:40:34 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2008-02-28 10:40:34 +0000
commitb8455132707ab4e5ca86e320c5cd8f8b84d6fc34 (patch)
treed5c86299463ca9d2f35bedaa52aef72a22ac14f3
parent8860335f57904501bfd72c1c5b65b0c83c7d1c1e (diff)
downloadrsyslog-b8455132707ab4e5ca86e320c5cd8f8b84d6fc34.tar.gz
rsyslog-b8455132707ab4e5ca86e320c5cd8f8b84d6fc34.tar.xz
rsyslog-b8455132707ab4e5ca86e320c5cd8f8b84d6fc34.zip
- wrote doc on how to use the expression engine
- changed ABNF to fully support old property names - added case-insensitive comparison operations
-rw-r--r--ctok.c6
-rw-r--r--ctok_token.h4
-rw-r--r--debug.c16
-rw-r--r--doc/rscript_abnf.html6
-rw-r--r--doc/rsyslog_conf.html80
-rw-r--r--doc/status.html2
-rw-r--r--expr.c40
-rw-r--r--queue.c2
-rwxr-xr-xstringbuf.c71
-rwxr-xr-xstringbuf.h2
-rw-r--r--vm.c56
-rw-r--r--vmop.h30
-rw-r--r--wtp.c1
13 files changed, 238 insertions, 78 deletions
diff --git a/ctok.c b/ctok.c
index a8057a99..b10001f2 100644
--- a/ctok.c
+++ b/ctok.c
@@ -155,7 +155,7 @@ ctokGetWordFromStream(ctok_t *pThis, uchar *pWordBuf, size_t lenWordBuf)
CHKiRet(ctokSkipWhitespaceFromStream(pThis));
CHKiRet(ctokGetCharFromStream(pThis, &c));
- while(isalnum(c) && lenWordBuf > 1) {
+ while((isalnum(c) || c == '_' || c == '-') && lenWordBuf > 1) {
*pWordBuf++ = c;
--lenWordBuf;
CHKiRet(ctokGetCharFromStream(pThis, &c));
@@ -503,8 +503,12 @@ ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken)
pToken->tok = ctok_NOT;
} else if(!strcasecmp((char*)szWord, "contains")) {
pToken->tok = ctok_CMP_CONTAINS;
+ } else if(!strcasecmp((char*)szWord, "contains_i")) {
+ pToken->tok = ctok_CMP_CONTAINSI;
} else if(!strcasecmp((char*)szWord, "startswith")) {
pToken->tok = ctok_CMP_STARTSWITH;
+ } else if(!strcasecmp((char*)szWord, "startswith_i")) {
+ pToken->tok = ctok_CMP_STARTSWITHI;
} else if(!strcasecmp((char*)szWord, "then")) {
pToken->tok = ctok_THEN;
} else {
diff --git a/ctok_token.h b/ctok_token.h
index c2b8aeba..63a00dd8 100644
--- a/ctok_token.h
+++ b/ctok_token.h
@@ -60,7 +60,9 @@ typedef struct {
ctok_CMP_LTEQ = 104,
ctok_CMP_CONTAINS = 105,
ctok_CMP_STARTSWITH = 106,
- ctok_CMP_GTEQ = 107, /* end compare operations */
+ ctok_CMP_CONTAINSI = 107,
+ ctok_CMP_STARTSWITHI = 108,
+ ctok_CMP_GTEQ = 109, /* end compare operations */
} tok;
var_t *pVar;
//cstr_t *pstrVal;
diff --git a/debug.c b/debug.c
index 74a5d9dd..b39a0205 100644
--- a/debug.c
+++ b/debug.c
@@ -930,11 +930,11 @@ int dbgEntrFunc(dbgFuncDB_t *pFuncDB, int line)
/* when we reach this point, we have a fully-initialized FuncDB! */
//if(bLogFuncFlow) /* quick debug hack... select the best for you! */
- //if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "vm.c")) /* quick debug hack... select the best for you! */
+ if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "vm.c")) /* quick debug hack... select the best for you! */
//if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "expr.c")) /* quick debug hack... select the best for you! */
- if(bLogFuncFlow && (!strcmp((char*)pFuncDB->file, "wti.c")
- ||!strcmp((char*)pFuncDB->file, "wtp.c")
- ||!strcmp((char*)pFuncDB->file, "queue.c"))) /* quick debug hack... select the best for you! */
+ //if(bLogFuncFlow && (!strcmp((char*)pFuncDB->file, "wti.c")
+ //||!strcmp((char*)pFuncDB->file, "wtp.c")
+ //||!strcmp((char*)pFuncDB->file, "queue.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",
@@ -964,11 +964,11 @@ void dbgExitFunc(dbgFuncDB_t *pFuncDB, int iStackPtrRestore)
dbgFuncDBPrintActiveMutexes(pFuncDB, "WARNING: mutex still owned by us as we exit function, mutex: ", pthread_self());
//if(bLogFuncFlow) /* quick debug hack... select the best for you! */
- //if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "vm.c")) /* quick debug hack... select the best for you! */
+ if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "vm.c")) /* quick debug hack... select the best for you! */
//if(bLogFuncFlow && !strcmp((char*)pFuncDB->file, "expr.c")) /* quick debug hack... select the best for you! */
- if(bLogFuncFlow && (!strcmp((char*)pFuncDB->file, "wti.c")
- ||!strcmp((char*)pFuncDB->file, "wtp.c")
- ||!strcmp((char*)pFuncDB->file, "queue.c"))) /* quick debug hack... select the best for you! */
+ //if(bLogFuncFlow && (!strcmp((char*)pFuncDB->file, "wti.c")
+ //||!strcmp((char*)pFuncDB->file, "wtp.c")
+ //||!strcmp((char*)pFuncDB->file, "queue.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/rscript_abnf.html b/doc/rscript_abnf.html
index 6ffd4c37..97de7284 100644
--- a/doc/rscript_abnf.html
+++ b/doc/rscript_abnf.html
@@ -1,8 +1,6 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
-<meta http-equiv="Content-Language" content="en"><title>RainerScript ABNF</title>
-
-</head>
+<meta http-equiv="Content-Language" content="en"><title>RainerScript ABNF</title></head>
<body>
<h1>RainerScript ABNF</h1>
<p>This is the formal definition of RainerScript, as supported by
@@ -23,7 +21,7 @@ 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 *(("+" / "-" / "&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>
+<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" / "contains_i" / "startswith" / "startswith_i"<br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_" /"-" # "-" necessary to cover currently-existing message properties<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
diff --git a/doc/rsyslog_conf.html b/doc/rsyslog_conf.html
index 60e2e7ac..9e67a8c1 100644
--- a/doc/rsyslog_conf.html
+++ b/doc/rsyslog_conf.html
@@ -1,5 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html><head><title>rsyslog.conf file</title></head>
+<html><head><title>rsyslog.conf file</title>
+
+</head>
<body>
<h1>rsyslog.conf configuration file</h1>
<p><b>This document is currently being enhanced. Please
@@ -36,7 +38,10 @@ SQLLite, Ingres, Oracle, mSQL)</li>
<li><a href="imfile.html">imfile</a>
-&nbsp; input module for text files</li>
<li>imudp - udp syslog message input</li>
-<li><a href="imtcp.html">imtcp</a> - input plugin for plain tcp syslog</li><li><a href="imgssapi.html">imgssapi</a> - input plugin for plain tcp and GSS-enable syslog</li>
+<li><a href="imtcp.html">imtcp</a> - input
+plugin for plain tcp syslog</li>
+<li><a href="imgssapi.html">imgssapi</a> -
+input plugin for plain tcp and GSS-enable syslog</li>
<li>immark - support for mark messages</li>
<li>imklog - kernel logging</li>
</ul>
@@ -371,10 +376,12 @@ been fixed to support files larger 2gb, but obviously only on file
systems and operating system versions that do so. So it can still make
sense to enforce a 2gb file size limit.</p>
<h2>Filter Conditions</h2>
-<p>Rsyslog offers two different types "filter conditions":</p>
+<p>Rsyslog offers four different types "filter conditions":</p>
<ul>
+<li>BSD-style blocks</li>
<li>"traditional" severity and facility based selectors</li>
<li>property-based filters</li>
+<li>expression-based filters</li>
</ul>
<h3>Blocks</h3>
<p>Rsyslogd supports BSD-style blocks inside rsyslog.conf. Each
@@ -424,7 +431,8 @@ not be used in applications. Anyway, you may want to specify and
redirect these messages here. The facility specifies the subsystem that
produced the message, i.e. all mail programs log with the mail facility
(LOG_MAIL) if they log using syslog.<br>
-<br>The priority is one of the following keywords, in ascending order:
+<br>
+The priority is one of the following keywords, in ascending order:
debug, info, notice, warning, warn (same as warning), err, error (same
as err), crit, alert, emerg, panic (same as emerg). The keywords error,
warn and panic are deprecated and should not be used anymore. The
@@ -560,7 +568,66 @@ it is possible to query facility and severity via property-based
filters, it is far more advisable to use classic selectors (see above)
for those cases.</p>
<h3>Expression-Based Filters</h3>
-So far, please see <a href="expression.h">expressions</a>.
+Expression based filters allow
+filtering on arbitrary complex expressions, which can include boolean,
+arithmetic and string operations. Expression filters will evolve into a
+full configuration scripting language. Unfortunately, their syntax will
+slightly change during that process. So if you use them now, you need
+to be prepared to change your configuration files some time later.
+However, we try to implement the scripting facility as soon as possible
+(also in respect to stage work needed). So the window of exposure is
+probably not too long.<br>
+<br>
+Expression based filters are indicated by the keyword "if" in column 1
+of a new line. They have this format:<br>
+<br>
+if expr then action-part-of-selector-line<br>
+<br>
+"If" and "then" are fixed keywords that mus be present. "expr" is a
+(potentially quite complex) expression. So the <a href="expression.h">expression documentation</a> for
+details. "action-part-of-selector-line" is an action, just as you know
+it (e.g. "/var/log/logfile" to write to that file).<br>
+<br>
+A few quick samples:<br>
+<br>
+<code>
+*.* /var/log/file1 # the traditional way<br>
+if $msg contains 'error' /var/log/errlog # the expression-based way<br>
+</code>
+<br>
+Right now, you need to specify numerical values if you would like to
+check for facilities and severity. These can be found in <a href="http://www.ietf.org/rfc/rfc3164.txt">RFC 3164</a>.
+If you don't like that, you can of course also use the textual property
+- just be sure to use the right one. As expression support is enhanced,
+this will change. For example, if you would like to filter on message
+that have facility local0, start with "DEVNAME" and have either
+"error1" or "error0" in their message content, you could use the
+following filter:<br>
+<br>
+<code>
+if $syslogfacility-text == 'local0' and $msg
+startswith 'DEVNAME' and ($msg contains 'error1' or $msg contains
+'error0') then /var/log/somelog<br>
+</code>
+<br>
+Please note that the above <span style="font-weight: bold;">must
+all be on one line</span>! And if you would like to store all
+messages except those that contain "error1" or "error0", you just need
+to add a "not":<br>
+<br>
+<code>
+if $syslogfacility-text == 'local0' and $msg
+startswith 'DEVNAME' and <span style="font-weight: bold;">not</span>
+($msg contains 'error1' or $msg contains
+'error0') then /var/log/somelog<br>
+</code>
+<br>If you would like to do case-insensitive comparisons, use
+"contains_i" instead of "contains" and "startswith_i" instead of
+"startswith".<br><br>Note that regular expressions are currently NOT
+supported in expression-based filters. These will be added later when
+function support is added to the expression engine (the reason is that
+regular expressions will be a separate loadable module, which requires
+some more prequisites before it can be implemented).<br>
<h2>ACTIONS</h2>
<p>The action field of a rule describes what to do with the
message. In general, message content is written to a kind of "logfile".
@@ -1012,7 +1079,8 @@ currently logged in users. This is the wall action.<br>
*.alert root,rgerhards<br>
<br>
This rule directs all messages with a priority of alert or higher to
-the terminals of the operator, i.e. of the users "root'' and "rgerhards'' if they're logged in.<br>
+the terminals of the operator, i.e. of the users "root'' and
+"rgerhards'' if they're logged in.<br>
<br>
<br>
*.* @finlandia<br>
diff --git a/doc/status.html b/doc/status.html
index 7f2d48f3..43c19a71 100644
--- a/doc/status.html
+++ b/doc/status.html
@@ -2,7 +2,7 @@
<html><head><title>rsyslog status page</title></head>
<body>
<h2>rsyslog status page</h2>
-<p>This page reflects the status as of 2008-02-27.</p>
+<p>This page reflects the status as of 2008-02-28.</p>
<h2>Current Releases</h2>
<p><b>development:</b> 3.11.6 -
<a href="http://www.rsyslog.com/Article183.phtml">change
diff --git a/expr.c b/expr.c
index 03ced285..ec96b187 100644
--- a/expr.c
+++ b/expr.c
@@ -326,6 +326,7 @@ finalize_it:
/* ------------------------------ actual expr object functions ------------------------------ */
/* Standard-Constructor
+ * rgerhards, 2008-02-09 (a rainy Tenerife return flight day ;))
*/
BEGINobjConstruct(expr) /* be sure to specify the object type also in END macro! */
ENDobjConstruct(expr)
@@ -352,45 +353,6 @@ CODESTARTobjDestruct(expr)
ENDobjDestruct(expr)
-/* evaluate an expression and store the result. pMsg is optional, but if
- * it is not given, no message-based variables can be accessed. The expression
- * must previously have been created.
- * rgerhards, 2008-02-09 (a rainy tenerife return flight day ;))
- */
-rsRetVal
-exprEval(expr_t *pThis, msg_t *pMsg)
-{
- DEFiRet;
-
- ISOBJ_TYPE_assert(pThis, expr);
- ISOBJ_TYPE_assert(pMsg, msg);
-
- RETiRet;
-}
-
-
-/* returns the expression result as a string. The string is read-only and valid
- * only as long as the expression exists and is not newly evaluated. If the caller
- * needs to access it for an extended period of time, it must copy it. This is a
- * performance optimization, as most expression results are expected to be used
- * only for a brief period. In such cases, it saves us the need to copy the string.
- * Also, it is assumed that most callers will hold their private expression. If it
- * is not shared, the caller can count on the string to remain stable as long as it
- * does not reevaluate the expression (via exprEval or other means) or destruct it.
- * rgerhards, 2008-02-09 (a rainy tenerife return flight day ;))
- */
-rsRetVal
-exprGetStr(expr_t *pThis, cstr_t **ppStr)
-{
- DEFiRet;
-
- ISOBJ_TYPE_assert(pThis, expr);
- ASSERT(ppStr != NULL);
-
- RETiRet;
-}
-
-
/* parse an expression object based on a given tokenizer
* rgerhards, 2008-02-19
*/
diff --git a/queue.c b/queue.c
index cd10a5df..1020dfcc 100644
--- a/queue.c
+++ b/queue.c
@@ -933,7 +933,7 @@ queueUngetObj(queue_t *pThis, obj_t *pUsr, int bLockMutex)
DEFVARS_mutexProtection;
ISOBJ_TYPE_assert(pThis, queue);
- ISOBJ_assert(pUsr);
+ ISOBJ_assert(pUsr); /* TODO: we aborted right at this place at least once -- race? 2008-02-28 */
dbgoprint((obj_t*) pThis, "ungetting user object %s\n", objGetName(pUsr));
BEGIN_MTX_PROTECTED_OPERATIONS(pThis->mut, bLockMutex);
diff --git a/stringbuf.c b/stringbuf.c
index a4f5a3ec..b95892ad 100755
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -659,6 +659,37 @@ int rsCStrStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
return -1; /* pCS1 is less then psz */
}
+
+/* The same as rsCStrStartsWithSzStr(), but does a case-insensitive
+ * comparison. TODO: consolidate the two.
+ * rgerhards 2008-02-28
+ */
+int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
+{
+ register size_t i;
+
+ rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
+ assert(psz != NULL);
+ assert(iLenSz == strlen((char*)psz)); /* just make sure during debugging! */
+ if(pCS1->iStrLen >= iLenSz) {
+ /* we are using iLenSz below, because we need to check
+ * iLenSz characters at maximum (start with!)
+ */
+ if(iLenSz == 0)
+ return 0; /* yes, it starts with a zero-sized string ;) */
+ else { /* we now have something to compare, so let's do it... */
+ for(i = 0 ; i < iLenSz ; ++i) {
+ if(tolower(pCS1->pBuf[i]) != tolower(psz[i]))
+ return tolower(pCS1->pBuf[i]) - tolower(psz[i]);
+ }
+ /* if we arrive here, the string actually starts with psz */
+ return 0;
+ }
+ }
+ else
+ return -1; /* pCS1 is less then psz */
+}
+
/* check if a CStr object matches a regex.
* msamia@redhat.com 2007-07-12
* @return returns 0 if matched
@@ -911,6 +942,46 @@ int rsCStrLocateInSzStr(cstr_t *pThis, uchar *sz)
}
+/* This is the same as rsCStrLocateInSzStr(), but does a case-insensitve
+ * comparison.
+ * TODO: over time, consolidate the two.
+ * rgerhards, 2008-02-28
+ */
+int rsCStrCaseInsensitiveLocateInSzStr(cstr_t *pThis, uchar *sz)
+{
+ int i;
+ int iMax;
+ int bFound;
+ rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
+ assert(sz != NULL);
+
+ if(pThis->iStrLen == 0)
+ return 0;
+
+ /* compute the largest index where a match could occur - after all,
+ * the to-be-located string must be able to be present in the
+ * searched string (it needs its size ;)).
+ */
+ iMax = strlen((char*)sz) - pThis->iStrLen;
+
+ bFound = 0;
+ i = 0;
+ while(i <= iMax && !bFound) {
+ size_t iCheck;
+ uchar *pComp = sz + i;
+ for(iCheck = 0 ; iCheck < pThis->iStrLen ; ++iCheck)
+ if(tolower(*(pComp + iCheck)) != tolower(*(pThis->pBuf + iCheck)))
+ break;
+ if(iCheck == pThis->iStrLen)
+ bFound = 1; /* found! - else it wouldn't be equal */
+ else
+ ++i; /* on to the next try */
+ }
+
+ return(bFound ? i : -1);
+}
+
+
#if 0 /* read comment below why this is commented out. In short: for future use! */
/* locate the first occurence of a standard sz string inside a rsCStr object.
* Returns the offset (0-bound) of this first occurrence. If not found, -1 is
diff --git a/stringbuf.h b/stringbuf.h
index c3db2486..6b5826ff 100755
--- a/stringbuf.h
+++ b/stringbuf.h
@@ -135,7 +135,9 @@ int rsCStrSzStrCmp(cstr_t *pCS1, uchar *psz, size_t iLenSz);
int rsCStrOffsetSzStrCmp(cstr_t *pCS1, size_t iOffset, uchar *psz, size_t iLenSz);
int rsCStrLocateSzStr(cstr_t *pCStr, uchar *sz);
int rsCStrLocateInSzStr(cstr_t *pThis, uchar *sz);
+int rsCStrCaseInsensitiveLocateInSzStr(cstr_t *pThis, uchar *sz);
int rsCStrStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
+int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
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);
diff --git a/vm.c b/vm.c
index 49342035..ab919e17 100644
--- a/vm.c
+++ b/vm.c
@@ -109,6 +109,8 @@ BEGINop(name) \
number_t bRes; \
CODESTARTop(name) \
CHKiRet(vmstk.Pop2CommOp(pThis->pStk, &operand1, &operand2)); \
+var.DebugPrint(operand1); \
+var.DebugPrint(operand2); \
/* data types are equal (so we look only at operand1), but we must \
* check which type we have to deal with... \
*/ \
@@ -189,36 +191,84 @@ ENDCMPOP(CMP_GTEQ)
BEGINop(CMP_CONTAINS) /* remember to set the instruction also in the ENDop macro! */
var_t *operand1;
var_t *operand2;
- int bRes;
+ number_t bRes;
CODESTARTop(CMP_CONTAINS)
/* operand2 is on top of stack, so needs to be popped first */
vmstk.PopString(pThis->pStk, &operand2);
vmstk.PopString(pThis->pStk, &operand1);
+var.DebugPrint(operand1); \
+var.DebugPrint(operand2); \
/* TODO: extend cstr class so that it supports location of cstr inside cstr */
bRes = (rsCStrLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1;
/* we have a result, so let's push it */
+RUNLOG_VAR("%lld", bRes); \
PUSHRESULTop(operand1, bRes);
var.Destruct(&operand2); /* no longer needed */
ENDop(CMP_CONTAINS)
+
+BEGINop(CMP_CONTAINSI) /* remember to set the instruction also in the ENDop macro! */
+ var_t *operand1;
+ var_t *operand2;
+ number_t bRes;
+CODESTARTop(CMP_CONTAINSI)
+ /* operand2 is on top of stack, so needs to be popped first */
+ vmstk.PopString(pThis->pStk, &operand2);
+ vmstk.PopString(pThis->pStk, &operand1);
+var.DebugPrint(operand1); \
+var.DebugPrint(operand2); \
+ /* TODO: extend cstr class so that it supports location of cstr inside cstr */
+ bRes = (rsCStrCaseInsensitiveLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1;
+
+ /* we have a result, so let's push it */
+RUNLOG_VAR("%lld", bRes); \
+ PUSHRESULTop(operand1, bRes);
+ var.Destruct(&operand2); /* no longer needed */
+ENDop(CMP_CONTAINSI)
+
+
BEGINop(CMP_STARTSWITH) /* remember to set the instruction also in the ENDop macro! */
var_t *operand1;
var_t *operand2;
- int bRes;
+ number_t bRes;
CODESTARTop(CMP_STARTSWITH)
/* operand2 is on top of stack, so needs to be popped first */
vmstk.PopString(pThis->pStk, &operand2);
vmstk.PopString(pThis->pStk, &operand1);
+var.DebugPrint(operand1); \
+var.DebugPrint(operand2); \
/* TODO: extend cstr class so that it supports location of cstr inside cstr */
bRes = (rsCStrStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr),
rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0;
/* we have a result, so let's push it */
+RUNLOG_VAR("%lld", bRes); \
PUSHRESULTop(operand1, bRes);
var.Destruct(&operand2); /* no longer needed */
ENDop(CMP_STARTSWITH)
+
+BEGINop(CMP_STARTSWITHI) /* remember to set the instruction also in the ENDop macro! */
+ var_t *operand1;
+ var_t *operand2;
+ number_t bRes;
+CODESTARTop(CMP_STARTSWITHI)
+ /* operand2 is on top of stack, so needs to be popped first */
+ vmstk.PopString(pThis->pStk, &operand2);
+ vmstk.PopString(pThis->pStk, &operand1);
+var.DebugPrint(operand1); \
+var.DebugPrint(operand2); \
+ /* TODO: extend cstr class so that it supports location of cstr inside cstr */
+ bRes = (rsCStrCaseInsensitveStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr),
+ rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0;
+
+ /* we have a result, so let's push it */
+RUNLOG_VAR("%lld", bRes); \
+ PUSHRESULTop(operand1, bRes);
+ var.Destruct(&operand2); /* no longer needed */
+ENDop(CMP_STARTSWITHI)
+
/* end comare operations that work on strings, only */
BEGINop(STRADD) /* remember to set the instruction also in the ENDop macro! */
@@ -358,7 +408,9 @@ execProg(vm_t *pThis, vmprg_t *pProg)
doOP(CMP_LTEQ);
doOP(CMP_GTEQ);
doOP(CMP_CONTAINS);
+ doOP(CMP_CONTAINSI);
doOP(CMP_STARTSWITH);
+ doOP(CMP_STARTSWITHI);
doOP(NOT);
doOP(PUSHCONSTANT);
doOP(PUSHMSGVAR);
diff --git a/vmop.h b/vmop.h
index 804da5be..9b3c35be 100644
--- a/vmop.h
+++ b/vmop.h
@@ -39,21 +39,23 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc(
opcode_DIV = ctok_DIV,
opcode_MOD = ctok_MOD,
opcode_NOT = ctok_NOT,
- opcode_CMP_EQ = ctok_CMP_EQ, /* all compare operations must be in a row */
- opcode_CMP_NEQ = ctok_CMP_NEQ,
- opcode_CMP_LT = ctok_CMP_LT,
- opcode_CMP_GT = ctok_CMP_GT,
- opcode_CMP_LTEQ = ctok_CMP_LTEQ,
- opcode_CMP_CONTAINS = ctok_CMP_CONTAINS,
- opcode_CMP_STARTSWITH = ctok_CMP_STARTSWITH,
- opcode_CMP_GTEQ = ctok_CMP_GTEQ, /* end compare operations */
+ opcode_CMP_EQ = ctok_CMP_EQ, /* all compare operations must be in a row */
+ opcode_CMP_NEQ = ctok_CMP_NEQ,
+ opcode_CMP_LT = ctok_CMP_LT,
+ opcode_CMP_GT = ctok_CMP_GT,
+ opcode_CMP_LTEQ = ctok_CMP_LTEQ,
+ opcode_CMP_CONTAINS = ctok_CMP_CONTAINS,
+ opcode_CMP_STARTSWITH = ctok_CMP_STARTSWITH,
+ opcode_CMP_CONTAINSI = ctok_CMP_CONTAINSI,
+ opcode_CMP_STARTSWITHI = ctok_CMP_STARTSWITHI,
+ opcode_CMP_GTEQ = ctok_CMP_GTEQ, /* end compare operations */
/* here we start our own codes */
- opcode_POP = 1000, /* requires var operand to receive result */
- opcode_PUSHSYSVAR = 1001, /* requires var operand */
- opcode_PUSHMSGVAR = 1002, /* requires var operand */
- opcode_PUSHCONSTANT = 1003, /* requires var operand */
- opcode_UNARY_MINUS = 1010,
- opcode_END_PROG = 1011
+ opcode_POP = 1000, /* requires var operand to receive result */
+ opcode_PUSHSYSVAR = 1001, /* requires var operand */
+ opcode_PUSHMSGVAR = 1002, /* requires var operand */
+ opcode_PUSHCONSTANT = 1003, /* requires var operand */
+ opcode_UNARY_MINUS = 1010,
+ opcode_END_PROG = 1011
} opcode_t;
diff --git a/wtp.c b/wtp.c
index 7e920631..c68a1e92 100644
--- a/wtp.c
+++ b/wtp.c
@@ -464,7 +464,6 @@ wtpStartWrkr(wtp_t *pThis, int bLockMutex)
}
}
-dbgprintf("%s: after thrd search: i %d, max %d\n", wtpGetDbgHdr(pThis), i, pThis->iNumWorkerThreads);
if(i == pThis->iNumWorkerThreads)
ABORT_FINALIZE(RS_RET_NO_MORE_THREADS);