summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2013-02-10 12:42:25 +0100
committerRainer Gerhards <rgerhards@adiscon.com>2013-02-10 12:42:25 +0100
commit2da01aa019afdcacbed7cb08f41f72fc7482f0ab (patch)
tree251fc525bd92de82956243e5948f5c499f5323e3
parent0f051ac6fc85cb4be725eba0723c9aff7ec425d7 (diff)
downloadrsyslog-2da01aa019afdcacbed7cb08f41f72fc7482f0ab.tar.gz
rsyslog-2da01aa019afdcacbed7cb08f41f72fc7482f0ab.tar.bz2
rsyslog-2da01aa019afdcacbed7cb08f41f72fc7482f0ab.zip
field() function now supports a string as field delimiter
also done a bugfix: field() function did never return "***FIELD NOT FOUND***" instead it returned "***ERROR in field() FUNCTION***" in that case
-rw-r--r--ChangeLog3
-rw-r--r--doc/rainerscript.html14
-rw-r--r--grammar/rainerscript.c65
3 files changed, 73 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 3746d3f1..4944987c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,10 @@
---------------------------------------------------------------------------
Version 7.3.7 [devel] 2013-02-??
+- field() function now supports a string as field delimiter
- bugfix: mmjsonparse segfault if new-style config was used
- bugfix: script == comparison did not work properly on JSON objects
+- bugfix: field() function did never return "***FIELD NOT FOUND***"
+ instead it returned "***ERROR in field() FUNCTION***" in that case
---------------------------------------------------------------------------
Version 7.3.6 [devel] 2013-01-28
- greatly improved speed of large-array [N]EQ RainerScript comparisons
diff --git a/doc/rainerscript.html b/doc/rainerscript.html
index c9f00386..d76316ed 100644
--- a/doc/rainerscript.html
+++ b/doc/rainerscript.html
@@ -67,10 +67,20 @@ variable, if it exists. Returns an empty string if it does not exist.
<li>cnum(expr) - converts expr to a number (integer)
<li>re_match(expr, re) - returns 1, if expr matches re, 0 otherwise
<li>field(str, delim, matchnbr) - returns a field-based substring. str is the string
-to search, delim is the numerical ascii value of the field delimiter (so that
-non-printable characters can by specified) and matchnbr is the match to search
+to search, delim is the delimiter and matchnbr is the match to search
for (the first match starts at 1). This works similar as the field based
property-replacer option.
+Versions prior to 7.3.7 only support a single character as delimiter character.
+Starting with version 7.3.7, a full string can be used as delimiter. If a single
+character is being used as delimiter, delim is the numerical ascii value of the
+field delimiter character (so that non-printable characters can by specified). If a
+string is used as delmiter, a multi-character string (e.g. "#011") is to be
+specified. Samples:<br>
+set $!usr!field = field($msg, 32, 3); -- the third field, delimited by space<br>
+set $!usr!field = field($msg, "#011", 3); -- the third field, delmited by "#011"<br>
+Note that when a single character is specified as string [field($msg, ",", 3)] a
+string-based extraction is done, which is more performance intense than the
+equivalent single-character [field($msg, 44 ,3)] extraction.
<li>prifilt(constant) - mimics a traditional PRI-based filter (like "*.*" or
"mail.info"). The traditional filter string must be given as a <b>constant string</b>.
Dynamic string evaluation is not permitted (for performance reasons).
diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c
index 83ed7680..6dbdad63 100644
--- a/grammar/rainerscript.c
+++ b/grammar/rainerscript.c
@@ -1137,8 +1137,8 @@ var2CString(struct var *r, int *bMustFree)
return cstr;
}
-rsRetVal
-doExtractField(uchar *str, uchar delim, int matchnbr, uchar **resstr)
+static rsRetVal
+doExtractFieldByChar(uchar *str, uchar delim, int matchnbr, uchar **resstr)
{
int iCurrFld;
int iLen;
@@ -1175,8 +1175,51 @@ doExtractField(uchar *str, uchar delim, int matchnbr, uchar **resstr)
/* now copy */
memcpy(pBuf, pFld, iLen);
pBuf[iLen] = '\0'; /* terminate it */
- if(*(pFldEnd+1) != '\0')
- ++pFldEnd; /* OK, skip again over delimiter char */
+ *resstr = pBuf;
+ } else {
+ ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND);
+ }
+finalize_it:
+ RETiRet;
+}
+
+
+static rsRetVal
+doExtractFieldByStr(uchar *str, char *delim, rs_size_t lenDelim, int matchnbr, uchar **resstr)
+{
+ int iCurrFld;
+ int iLen;
+ uchar *pBuf;
+ uchar *pFld;
+ uchar *pFldEnd;
+ DEFiRet;
+
+ /* first, skip to the field in question */
+ iCurrFld = 1;
+ pFld = str;
+ while(pFld != NULL && iCurrFld < matchnbr) {
+ if((pFld = (uchar*) strstr((char*)pFld, delim)) != NULL) {
+ pFld += lenDelim;
+ ++iCurrFld;
+ }
+ }
+ dbgprintf("field() field requested %d, field found %d\n", matchnbr, iCurrFld);
+
+ if(iCurrFld == matchnbr) {
+ /* field found, now extract it */
+ /* first of all, we need to find the end */
+ pFldEnd = (uchar*) strstr((char*)pFld, delim);
+ if(pFldEnd == NULL) {
+ iLen = strlen((char*) pFld);
+ } else { /* found delmiter! Note that pFldEnd *is* already on
+ * the first delmi char, we don't need that. */
+ iLen = pFldEnd - pFld;
+ }
+ /* we got our end pointer, now do the copy */
+ CHKmalloc(pBuf = MALLOC((iLen + 1) * sizeof(char)));
+ /* now copy */
+ memcpy(pBuf, pFld, iLen);
+ pBuf[iLen] = '\0'; /* terminate it */
*resstr = pBuf;
} else {
ABORT_FINALIZE(RS_RET_FIELD_NOT_FOUND);
@@ -1289,13 +1332,21 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr)
cnfexprEval(func->expr[1], &r[1], usrptr);
cnfexprEval(func->expr[2], &r[2], usrptr);
str = (char*) var2CString(&r[0], &bMustFree);
- delim = var2Number(&r[1], NULL);
matchnbr = var2Number(&r[2], NULL);
- localRet = doExtractField((uchar*)str, (char) delim, matchnbr, &resStr);
+ if(r[1].datatype == 'S') {
+ char *delimstr;
+ delimstr = (char*) es_str2cstr(r[1].d.estr, NULL);
+ localRet = doExtractFieldByStr((uchar*)str, delimstr, es_strlen(r[1].d.estr),
+ matchnbr, &resStr);
+ free(delimstr);
+ } else {
+ delim = var2Number(&r[1], NULL);
+ localRet = doExtractFieldByChar((uchar*)str, (char) delim, matchnbr, &resStr);
+ }
if(localRet == RS_RET_OK) {
ret->d.estr = es_newStrFromCStr((char*)resStr, strlen((char*)resStr));
free(resStr);
- } else if(localRet == RS_RET_OK) {
+ } else if(localRet == RS_RET_FIELD_NOT_FOUND) {
ret->d.estr = es_newStrFromCStr("***FIELD NOT FOUND***",
sizeof("***FIELD NOT FOUND***")-1);
} else {