From b8455132707ab4e5ca86e320c5cd8f8b84d6fc34 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 28 Feb 2008 10:40:34 +0000 Subject: - wrote doc on how to use the expression engine - changed ABNF to fully support old property names - added case-insensitive comparison operations --- ctok.c | 6 +++- ctok_token.h | 4 ++- debug.c | 16 +++++------ doc/rscript_abnf.html | 6 ++-- doc/rsyslog_conf.html | 80 +++++++++++++++++++++++++++++++++++++++++++++++---- doc/status.html | 2 +- expr.c | 40 +------------------------- queue.c | 2 +- stringbuf.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ stringbuf.h | 2 ++ vm.c | 56 ++++++++++++++++++++++++++++++++++-- vmop.h | 30 ++++++++++--------- wtp.c | 1 - 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 @@ -RainerScript ABNF - - +RainerScript ABNF

RainerScript ABNF

This is the formal definition of RainerScript, as supported by @@ -23,7 +21,7 @@ and many other languages).

Below is the formal language definitionin ABNF (RFC 2234) format:

-
; all of this is a working document and may change! -- rgerhards, 2008-02-24

script := *stmt
stmt := (if_stmt / block / vardef / run_s / load_s)
vardef := "var" ["scope" = ("global" / "event")]
block := "begin" stmt "end"
load_s := "load" constraint ("module") modpath params ; load mod only if expr is true
run_s := "run" constraint ("input") name
constraint:= "if" expr ; constrains some one-time commands
modpath := expr
params := ["params" *1param *("," param) "endparams"]
param := paramname) "=" expr
paramname := [*(obqualifier ".") name]
modpath:= ; path to module
?line? := cfsysline / cfli
cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)
BOL := ; Begin of Line - implicitely set on file beginning and after each EOL
EOL := 0x0a ;LF
if_stmt := "if" expr "then"
old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!
facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" /
"mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" /
"local0" .. "local7" / "mark"
; The keyword security should not be used anymore
; mark is just internal
severity := TBD ; not really relevant in this context

; and now the actual expression
expr := e_and *("or" e_and)
e_and := e_cmp *("and" e_cmp)
e_cmp := val 0*1(cmp_op val)
val := term *(("+" / "-" / "&") term)
term := factor *(("*" / "/" / "%") factor)
factor := ["not"] ["-"] terminal
terminal := var / constant / function / ( "(" expr ")" )
function := name "(" *("," expr) ")"
var := "$" varname
varname := msgvar / sysvar
msgvar := name
sysvar := "$" name
name := alpha *(alnum)
constant := string / number
string := simpstr / tplstr ; tplstr will be implemented in next phase
simpstr := "'" *char "'" ; use your imagination for char ;)
tplstr := '"' template '"' ; not initially implemented
number := ["-"] 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal
cmp_op := "==" / "!=" / "<>" / "<" / ">" / "<=" / ">=" / "contains" / "startswith"
digit := %x30-39
alpha := "a" ... "z" # all letters
alnum :* alpha / digit / "_"
+
; all of this is a working document and may change! -- rgerhards, 2008-02-24

script := *stmt
stmt := (if_stmt / block / vardef / run_s / load_s)
vardef := "var" ["scope" = ("global" / "event")]
block := "begin" stmt "end"
load_s := "load" constraint ("module") modpath params ; load mod only if expr is true
run_s := "run" constraint ("input") name
constraint:= "if" expr ; constrains some one-time commands
modpath := expr
params := ["params" *1param *("," param) "endparams"]
param := paramname) "=" expr
paramname := [*(obqualifier ".") name]
modpath:= ; path to module
?line? := cfsysline / cfli
cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)
BOL := ; Begin of Line - implicitely set on file beginning and after each EOL
EOL := 0x0a ;LF
if_stmt := "if" expr "then"
old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!
facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" /
"mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" /
"local0" .. "local7" / "mark"
; The keyword security should not be used anymore
; mark is just internal
severity := TBD ; not really relevant in this context

; and now the actual expression
expr := e_and *("or" e_and)
e_and := e_cmp *("and" e_cmp)
e_cmp := val 0*1(cmp_op val)
val := term *(("+" / "-" / "&") term)
term := factor *(("*" / "/" / "%") factor)
factor := ["not"] ["-"] terminal
terminal := var / constant / function / ( "(" expr ")" )
function := name "(" *("," expr) ")"
var := "$" varname
varname := msgvar / sysvar
msgvar := name
sysvar := "$" name
name := alpha *(alnum)
constant := string / number
string := simpstr / tplstr ; tplstr will be implemented in next phase
simpstr := "'" *char "'" ; use your imagination for char ;)
tplstr := '"' template '"' ; not initially implemented
number := ["-"] 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal
cmp_op := "==" / "!=" / "<>" / "<" / ">" / "<=" / ">=" / "contains" / "contains_i" / "startswith" / "startswith_i"
digit := %x30-39
alpha := "a" ... "z" # all letters
alnum :* alpha / digit / "_" /"-" # "-" necessary to cover currently-existing message properties

Samples

Some samples of RainerScript:

define function IsLinux
begin
    if $environ contains "linux" then return true else return false
end

load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */
run if IsLinux() input 'klog'
load 'ommysql.so'

if $message contains "error" then
  action
    type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,
    action.dbname='events', action.dbuser='uid',
    [?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 @@ -rsyslog.conf file +rsyslog.conf file + +

rsyslog.conf configuration file

This document is currently being enhanced. Please @@ -36,7 +38,10 @@ SQLLite, Ingres, Oracle, mSQL)

  • imfile -  input module for text files
  • imudp - udp syslog message input
  • -
  • imtcp - input plugin for plain tcp syslog
  • imgssapi - input plugin for plain tcp and GSS-enable syslog
  • +
  • imtcp - input +plugin for plain tcp syslog
  • +
  • imgssapi - +input plugin for plain tcp and GSS-enable syslog
  • immark - support for mark messages
  • imklog - kernel logging
  • @@ -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.

    Filter Conditions

    -

    Rsyslog offers two different types "filter conditions":

    +

    Rsyslog offers four different types "filter conditions":

    Blocks

    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.
    -
    The priority is one of the following keywords, in ascending order: +
    +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.

    Expression-Based Filters

    -So far, please see expressions. +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.
    +
    +Expression based filters are indicated by the keyword "if" in column 1 +of a new line. They have this format:
    +
    +if expr then action-part-of-selector-line
    +
    +"If" and "then" are fixed keywords that mus be present. "expr" is a +(potentially quite complex) expression. So the expression documentation 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).
    +
    +A few quick samples:
    +
    + +*.* /var/log/file1 # the traditional way
    +if $msg contains 'error' /var/log/errlog # the expression-based way
    +
    +
    +Right now, you need to specify numerical values if you would like to +check for facilities and severity. These can be found in RFC 3164. +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:
    +
    + +if $syslogfacility-text == 'local0' and $msg +startswith 'DEVNAME' and ($msg contains 'error1' or $msg contains +'error0') then /var/log/somelog
    +
    +
    +Please note that the above must +all be on one line! And if you would like to store all +messages except those that contain "error1" or "error0", you just need +to add a "not":
    +
    + +if $syslogfacility-text == 'local0' and $msg +startswith 'DEVNAME' and not +($msg contains 'error1' or $msg contains +'error0') then /var/log/somelog
    +
    +
    If you would like to do case-insensitive comparisons, use +"contains_i" instead of "contains" and "startswith_i" instead of +"startswith".

    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).

    ACTIONS

    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.
    *.alert root,rgerhards

    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.
    +the terminals of the operator, i.e. of the users "root'' and +"rgerhards'' if they're logged in.


    *.* @finlandia
    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 @@ rsyslog status page

    rsyslog status page

    -

    This page reflects the status as of 2008-02-27.

    +

    This page reflects the status as of 2008-02-28.

    Current Releases

    development: 3.11.6 - 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); -- cgit