diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | doc/rainerscript.html | 14 | ||||
-rw-r--r-- | grammar/rainerscript.c | 65 |
3 files changed, 73 insertions, 9 deletions
@@ -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 { |