summaryrefslogtreecommitdiffstats
path: root/stringbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'stringbuf.c')
-rw-r--r--[-rwxr-xr-x]stringbuf.c507
1 files changed, 416 insertions, 91 deletions
diff --git a/stringbuf.c b/stringbuf.c
index 01467f4d..4254d5bd 100755..100644
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -5,8 +5,26 @@
* requires strings to be able to handle embedded \0 characters.
* Please see syslogd.c for license information.
* All functions in this "class" start with rsCStr (rsyslog Counted String).
- * This code is placed under the GPL.
* begun 2005-09-07 rgerhards
+ *
+ * Copyright (C) 2007 by Rainer Gerhards and Adiscon GmbH
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#include "config.h"
@@ -15,29 +33,35 @@
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
-#include <regex.h>
#include "rsyslog.h"
#include "stringbuf.h"
#include "srUtils.h"
+#include "regexp.h"
+#include "obj.h"
/* ################################################################# *
* private members *
* ################################################################# */
-
+/* static data */
+DEFobjCurrIf(obj)
+DEFobjCurrIf(regexp)
/* ################################################################# *
* public members *
* ################################################################# */
-rsCStrObj *rsCStrConstruct(void)
+rsRetVal rsCStrConstruct(cstr_t **ppThis)
{
- rsCStrObj *pThis;
+ DEFiRet;
+ cstr_t *pThis;
+
+ ASSERT(ppThis != NULL);
- if((pThis = (rsCStrObj*) calloc(1, sizeof(rsCStrObj))) == NULL)
- return NULL;
+ if((pThis = (cstr_t*) calloc(1, sizeof(cstr_t))) == NULL)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
rsSETOBJTYPE(pThis, OIDrsCStr);
pThis->pBuf = NULL;
@@ -45,71 +69,82 @@ rsCStrObj *rsCStrConstruct(void)
pThis->iBufSize = 0;
pThis->iStrLen = 0;
pThis->iAllocIncrement = RS_STRINGBUF_ALLOC_INCREMENT;
+ *ppThis = pThis;
- return pThis;
+finalize_it:
+ RETiRet;
}
+
/* construct from sz string
* rgerhards 2005-09-15
*/
-rsRetVal rsCStrConstructFromszStr(rsCStrObj **ppThis, uchar *sz)
+rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz)
{
- rsCStrObj *pThis;
+ DEFiRet;
+ cstr_t *pThis;
assert(ppThis != NULL);
- if((pThis = rsCStrConstruct()) == NULL)
- return RS_RET_OUT_OF_MEMORY;
+ CHKiRet(rsCStrConstruct(&pThis));
pThis->iBufSize = pThis->iStrLen = strlen((char*)(char *) sz);
if((pThis->pBuf = (uchar*) malloc(sizeof(uchar) * pThis->iStrLen)) == NULL) {
RSFREEOBJ(pThis);
- return RS_RET_OUT_OF_MEMORY;
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
}
/* we do NOT need to copy the \0! */
memcpy(pThis->pBuf, sz, pThis->iStrLen);
*ppThis = pThis;
- return RS_RET_OK;
+
+finalize_it:
+ RETiRet;
}
/* construct from CStr object. only the counted string is
* copied, not the szString.
* rgerhards 2005-10-18
*/
-rsRetVal rsCStrConstructFromCStr(rsCStrObj **ppThis, rsCStrObj *pFrom)
+rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom)
{
- rsCStrObj *pThis;
+ DEFiRet;
+ cstr_t *pThis;
assert(ppThis != NULL);
rsCHECKVALIDOBJECT(pFrom, OIDrsCStr);
- if((pThis = rsCStrConstruct()) == NULL)
- return RS_RET_OUT_OF_MEMORY;
+ CHKiRet(rsCStrConstruct(&pThis));
pThis->iBufSize = pThis->iStrLen = pFrom->iStrLen;
if((pThis->pBuf = (uchar*) malloc(sizeof(uchar) * pThis->iStrLen)) == NULL) {
RSFREEOBJ(pThis);
- return RS_RET_OUT_OF_MEMORY;
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
}
/* copy properties */
memcpy(pThis->pBuf, pFrom->pBuf, pThis->iStrLen);
*ppThis = pThis;
- return RS_RET_OK;
+finalize_it:
+ RETiRet;
}
-void rsCStrDestruct(rsCStrObj *pThis)
+void rsCStrDestruct(cstr_t **ppThis)
{
+ cstr_t *pThis = *ppThis;
+
/* rgerhards 2005-10-19: The free of pBuf was contained in conditional compilation.
* The code was only compiled if STRINGBUF_TRIM_ALLOCSIZE was set to 1. I honestly
* do not know why it was so, I think it was an artifact. Anyhow, I have changed this
* now. Should there any issue occur, this comment hopefully will shed some light
* on what happened. I re-verified, and this function has never before been called
* by anyone. So changing it can have no impact for obvious reasons...
+ *
+ * rgerhards, 2008-02-20: I changed the interface to the new calling conventions, where
+ * the destructor receives a pointer to the object, so that it can set it to NULL.
*/
if(pThis->pBuf != NULL) {
free(pThis->pBuf);
@@ -120,39 +155,76 @@ void rsCStrDestruct(rsCStrObj *pThis)
}
RSFREEOBJ(pThis);
+ *ppThis = NULL;
+}
+
+
+/* extend the string buffer if its size is insufficient.
+ * Param iMinNeeded is the minumum free space needed. If it is larger
+ * than the default alloc increment, space for at least this amount is
+ * allocated. In practice, a bit more is allocated because we envision that
+ * some more characters may be added after these.
+ * rgerhards, 2008-01-07
+ */
+static rsRetVal rsCStrExtendBuf(cstr_t *pThis, size_t iMinNeeded)
+{
+ DEFiRet;
+ uchar *pNewBuf;
+ size_t iNewSize;
+
+ /* first compute the new size needed */
+ if(iMinNeeded > pThis->iAllocIncrement) {
+ /* we allocate "n" iAllocIncrements. Usually, that should
+ * leave some room after the absolutely needed one. It also
+ * reduces memory fragmentation. Note that all of this are
+ * integer operations (very important to understand what is
+ * going on)! Parenthesis are for better readibility.
+ */
+ iNewSize = ((iMinNeeded / pThis->iAllocIncrement) + 1) * pThis->iAllocIncrement;
+ } else {
+ iNewSize = pThis->iBufSize + pThis->iAllocIncrement;
+ }
+ iNewSize += pThis->iBufSize; /* add current size */
+
+ /* and then allocate and copy over */
+ /* DEV debugging only: dbgprintf("extending string buffer, old %d, new %d\n", pThis->iBufSize, iNewSize); */
+ if((pNewBuf = (uchar*) malloc(iNewSize * sizeof(uchar))) == NULL)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ memcpy(pNewBuf, pThis->pBuf, pThis->iBufSize);
+ pThis->iBufSize = iNewSize;
+ if(pThis->pBuf != NULL) {
+ free(pThis->pBuf);
+ }
+ pThis->pBuf = pNewBuf;
+
+finalize_it:
+ RETiRet;
}
-rsRetVal rsCStrAppendStrWithLen(rsCStrObj *pThis, uchar* psz, size_t iStrLen)
+/* append a string of known length. In this case, we make sure we do at most
+ * one additional memory allocation.
+ * I optimized this function to use memcpy(), among others. Consider it a
+ * rewrite (which may be good to know in case of bugs) -- rgerhards, 2008-01-07
+ */
+rsRetVal rsCStrAppendStrWithLen(cstr_t *pThis, uchar* psz, size_t iStrLen)
{
- rsRetVal iRet;
- int iOldAllocInc;
+ DEFiRet;
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
assert(psz != NULL);
- /* we first check if the to-be-added string is larger than the
- * alloc increment. If so, we temporarily increase the alloc
- * increment to the length of the string. This will ensure that
- * one string copy will be needed at most. As this is a very
- * costly operation, it outweights the cost of the strlen((char*)) and
- * related stuff - at least I think so.
- * rgerhards 2005-09-22
- */
- /* We save the current alloc increment in any case, so we can just
- * overwrite it below, this is faster than any if-construct.
- */
- iOldAllocInc = pThis->iAllocIncrement;
- if(iStrLen > pThis->iAllocIncrement) {
- pThis->iAllocIncrement = iStrLen;
+ /* does the string fit? */
+ if(pThis->iStrLen + iStrLen > pThis->iBufSize) {
+ CHKiRet(rsCStrExtendBuf(pThis, iStrLen)); /* need more memory! */
}
- while(*psz)
- if((iRet = rsCStrAppendChar(pThis, *psz++)) != RS_RET_OK)
- return iRet;
+ /* ok, now we always have sufficient continues memory to do a memcpy() */
+ memcpy(pThis->pBuf + pThis->iStrLen, psz, iStrLen);
+ pThis->iStrLen += iStrLen;
- pThis->iAllocIncrement = iOldAllocInc; /* restore */
- return RS_RET_OK;
+finalize_it:
+ RETiRet;
}
@@ -161,42 +233,44 @@ rsRetVal rsCStrAppendStrWithLen(rsCStrObj *pThis, uchar* psz, size_t iStrLen)
* need to change existing code.
* rgerhards, 2007-07-03
*/
-rsRetVal rsCStrAppendStr(rsCStrObj *pThis, uchar* psz)
+rsRetVal rsCStrAppendStr(cstr_t *pThis, uchar* psz)
{
- return rsCStrAppendStrWithLen(pThis, psz, strlen((char*)(char*) psz));
+ return rsCStrAppendStrWithLen(pThis, psz, strlen((char*) psz));
}
-rsRetVal rsCStrAppendInt(rsCStrObj *pThis, int i)
+/* append the contents of one cstr_t object to another
+ * rgerhards, 2008-02-25
+ */
+rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend)
{
- rsRetVal iRet;
+ return rsCStrAppendStrWithLen(pThis, pstrAppend->pBuf, pstrAppend->iStrLen);
+}
+
+
+rsRetVal rsCStrAppendInt(cstr_t *pThis, long i)
+{
+ DEFiRet;
uchar szBuf[32];
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
- if((iRet = srUtilItoA((char*) szBuf, sizeof(szBuf), i)) != RS_RET_OK)
- return iRet;
+ CHKiRet(srUtilItoA((char*) szBuf, sizeof(szBuf), i));
- return rsCStrAppendStr(pThis, szBuf);
+ iRet = rsCStrAppendStr(pThis, szBuf);
+finalize_it:
+ RETiRet;
}
-rsRetVal rsCStrAppendChar(rsCStrObj *pThis, uchar c)
+rsRetVal rsCStrAppendChar(cstr_t *pThis, uchar c)
{
- uchar* pNewBuf;
+ DEFiRet;
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
- if(pThis->iStrLen >= pThis->iBufSize)
- { /* need more memory! */
- if((pNewBuf = (uchar*) malloc((pThis->iBufSize + pThis->iAllocIncrement) * sizeof(uchar))) == NULL)
- return RS_RET_OUT_OF_MEMORY;
- memcpy(pNewBuf, pThis->pBuf, pThis->iBufSize);
- pThis->iBufSize += pThis->iAllocIncrement;
- if(pThis->pBuf != NULL) {
- free(pThis->pBuf);
- }
- pThis->pBuf = pNewBuf;
+ if(pThis->iStrLen >= pThis->iBufSize) {
+ CHKiRet(rsCStrExtendBuf(pThis, 1)); /* need more memory! */
}
/* ok, when we reach this, we have sufficient memory */
@@ -208,7 +282,8 @@ rsRetVal rsCStrAppendChar(rsCStrObj *pThis, uchar c)
pThis->pszBuf = NULL;
}
- return RS_RET_OK;
+finalize_it:
+ RETiRet;
}
@@ -219,7 +294,7 @@ rsRetVal rsCStrAppendChar(rsCStrObj *pThis, uchar c)
* not modified by this function.
* rgerhards, 2005-10-18
*/
-rsRetVal rsCStrSetSzStr(rsCStrObj *pThis, uchar *pszNew)
+rsRetVal rsCStrSetSzStr(cstr_t *pThis, uchar *pszNew)
{
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
@@ -260,7 +335,7 @@ rsRetVal rsCStrSetSzStr(rsCStrObj *pThis, uchar *pszNew)
* WARNING: The returned pointer MUST NOT be freed, as it may be
* obtained from that constant memory pool (in case of NULL!)
*/
-uchar* rsCStrGetSzStrNoNULL(rsCStrObj *pThis)
+uchar* rsCStrGetSzStrNoNULL(cstr_t *pThis)
{
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
if(pThis->pBuf == NULL)
@@ -278,7 +353,7 @@ uchar* rsCStrGetSzStrNoNULL(rsCStrObj *pThis)
* rsCStrGetSzStrNoNULL() instead.
* rgerhards, 2005-09-15
*/
-uchar* rsCStrGetSzStr(rsCStrObj *pThis)
+uchar* rsCStrGetSzStr(cstr_t *pThis)
{
size_t i;
@@ -342,7 +417,7 @@ uchar* rsCStrGetSzStr(rsCStrObj *pThis)
* PLEASE NOTE: the caller must free the memory returned in ppSz in any case
* (except, of course, if it is NULL).
*/
-rsRetVal rsCStrConvSzStrAndDestruct(rsCStrObj *pThis, uchar **ppSz, int bRetNULL)
+rsRetVal rsCStrConvSzStrAndDestruct(cstr_t *pThis, uchar **ppSz, int bRetNULL)
{
DEFiRet;
uchar* pRetBuf;
@@ -373,17 +448,52 @@ finalize_it:
free(pThis->pBuf);
RSFREEOBJ(pThis);
- return(iRet);
+ RETiRet;
}
-rsRetVal rsCStrFinish(rsCStrObj __attribute__((unused)) *pThis)
+#if STRINGBUF_TRIM_ALLOCSIZE == 1
+ /* Only in this mode, we need to trim the string. To do
+ * so, we must allocate a new buffer of the exact
+ * string size, and then copy the old one over.
+ */
+ /* WARNING
+ * STRINGBUF_TRIM_ALLOCSIZE can, in theory, be used to trim
+ * memory buffers. This part of the code was inherited from
+ * liblogging (where it is used in a different context) but
+ * never put to use in rsyslog. The reason is that it is hardly
+ * imaginable where the extra performance cost is worth the save
+ * in memory alloc. Then Anders Blomdel rightfully pointed out that
+ * the code does not work at all - and nobody even know that it
+ * probably shouldn't. Rather than removing, I deciced to somewhat
+ * fix the code, so that this feature may be enabled if somebody
+ * really has a need for it. Be warned, however, that I NEVER
+ * tested the fix. So if you intend to use this feature, you must
+ * do full testing before you rely on it. -- rgerhards, 2008-02-12
+ */
+rsRetVal rsCStrFinish(cstr_t __attribute__((unused)) *pThis)
{
+ DEFiRet;
+ uchar* pBuf;
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
- return RS_RET_OK;
+
+ if((pBuf = malloc((pThis->iStrLen) * sizeof(uchar))) == NULL)
+ { /* OK, in this case we use the previous buffer. At least
+ * we have it ;)
+ */
+ }
+ else
+ { /* got the new buffer, so let's use it */
+ memcpy(pBuf, pThis->pBuf, pThis->iStrLen);
+ pThis->pBuf = pBuf;
+ }
+
+ RETiRet;
}
+#endif /* #if STRINGBUF_TRIM_ALLOCSIZE == 1 */
+
-void rsCStrSetAllocIncrement(rsCStrObj *pThis, int iNewIncrement)
+void rsCStrSetAllocIncrement(cstr_t *pThis, int iNewIncrement)
{
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
assert(iNewIncrement > 0);
@@ -399,7 +509,7 @@ void rsCStrSetAllocIncrement(rsCStrObj *pThis, int iNewIncrement)
* This is due to performance reasons.
*/
#ifndef NDEBUG
-int rsCStrLen(rsCStrObj *pThis)
+int rsCStrLen(cstr_t *pThis)
{
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
return(pThis->iStrLen);
@@ -409,7 +519,7 @@ int rsCStrLen(rsCStrObj *pThis)
/* Truncate characters from the end of the string.
* rgerhards 2005-09-15
*/
-rsRetVal rsCStrTruncate(rsCStrObj *pThis, size_t nTrunc)
+rsRetVal rsCStrTruncate(cstr_t *pThis, size_t nTrunc)
{
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
@@ -432,7 +542,7 @@ rsRetVal rsCStrTruncate(rsCStrObj *pThis, size_t nTrunc)
/* Trim trailing whitespace from a given string
*/
-rsRetVal rsCStrTrimTrailingWhiteSpace(rsCStrObj *pThis)
+rsRetVal rsCStrTrimTrailingWhiteSpace(cstr_t *pThis)
{
register int i;
register uchar *pC;
@@ -459,7 +569,7 @@ rsRetVal rsCStrTrimTrailingWhiteSpace(rsCStrObj *pThis)
* in equal-size strings.
* rgerhards, 2005-09-26
*/
-int rsCStrCStrCmp(rsCStrObj *pCS1, rsCStrObj *pCS2)
+int rsCStrCStrCmp(cstr_t *pCS1, cstr_t *pCS2)
{
rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
rsCHECKVALIDOBJECT(pCS2, OIDrsCStr);
@@ -483,12 +593,15 @@ int rsCStrCStrCmp(rsCStrObj *pCS1, rsCStrObj *pCS2)
}
-/* check if a sz-type string start with a CStr object. This function
+/* check if a sz-type string starts with a CStr object. This function
* is initially written to support the "startswith" property-filter
* comparison operation. Maybe it also has other needs.
+ * This functions is modelled after the strcmp() series, thus a
+ * return value of 0 indicates that the string starts with the
+ * sequence while -1 indicates it does not!
* rgerhards 2005-10-19
*/
-int rsCStrSzStrStartsWithCStr(rsCStrObj *pCS1, uchar *psz, size_t iLenSz)
+int rsCStrSzStrStartsWithCStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
{
register int i;
int iMax;
@@ -518,9 +631,12 @@ int rsCStrSzStrStartsWithCStr(rsCStrObj *pCS1, uchar *psz, size_t iLenSz)
/* check if a CStr object starts with a sz-type string.
+ * This functions is modelled after the strcmp() series, thus a
+ * return value of 0 indicates that the string starts with the
+ * sequence while -1 indicates it does not!
* rgerhards 2005-09-26
*/
-int rsCStrStartsWithSzStr(rsCStrObj *pCS1, uchar *psz, size_t iLenSz)
+int rsCStrStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
{
register size_t i;
@@ -546,22 +662,66 @@ int rsCStrStartsWithSzStr(rsCStrObj *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
* bug: doesn't work for CStr containing \0
* rgerhards, 2007-07-16: bug is no real bug, because rsyslogd ensures there
* never is a \0 *inside* a property string.
+ * Note that the function returns -1 if regexp functionality is not available.
+ * TODO: change calling interface! -- rgerhards, 2008-03-07
*/
-int rsCStrSzStrMatchRegex(rsCStrObj *pCS1, uchar *psz)
+int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz)
{
- regex_t preq;
- regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0);
- int iRet = regexec(&preq, (char*) psz, 0, NULL, 0);
- regfree(&preq);
- return iRet;
+ regex_t preq;
+ int ret;
+
+ BEGINfunc
+
+ if(objUse(regexp, LM_REGEXP_FILENAME) == RS_RET_OK) {
+ regexp.regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0);
+ ret = regexp.regexec(&preq, (char*) psz, 0, NULL, 0);
+ regexp.regfree(&preq);
+ } else {
+ ret = 1; /* simulate "not found" */
+ }
+
+ ENDfunc
+ return ret;
}
+
/* compare a rsCStr object with a classical sz string. This function
* is almost identical to rsCStrZsStrCmp(), but it also takes an offset
* to the CStr object from where the comparison is to start.
@@ -583,8 +743,9 @@ int rsCStrSzStrMatchRegex(rsCStrObj *pCS1, uchar *psz)
* program bug and will lead to unpredictable results and program aborts).
* rgerhards 2005-09-26
*/
-int rsCStrOffsetSzStrCmp(rsCStrObj *pCS1, size_t iOffset, uchar *psz, size_t iLenSz)
+int rsCStrOffsetSzStrCmp(cstr_t *pCS1, size_t iOffset, uchar *psz, size_t iLenSz)
{
+ BEGINfunc
rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
assert(iOffset < pCS1->iStrLen);
assert(psz != NULL);
@@ -593,9 +754,10 @@ int rsCStrOffsetSzStrCmp(rsCStrObj *pCS1, size_t iOffset, uchar *psz, size_t iLe
/* we are using iLenSz below, because the lengths
* are equal and iLenSz is faster to access
*/
- if(iLenSz == 0)
+ if(iLenSz == 0) {
return 0; /* zero-sized strings are equal ;) */
- else { /* we now have two non-empty strings of equal
+ ENDfunc
+ } else { /* we now have two non-empty strings of equal
* length, so we need to actually check if they
* are equal.
*/
@@ -606,10 +768,110 @@ int rsCStrOffsetSzStrCmp(rsCStrObj *pCS1, size_t iOffset, uchar *psz, size_t iLe
}
/* if we arrive here, the strings are equal */
return 0;
+ ENDfunc
}
}
- else
+ else {
return pCS1->iStrLen - iOffset - iLenSz;
+ ENDfunc
+ }
+}
+
+
+/* Converts a string to a number. If the string dos not contain a number,
+ * RS_RET_NOT_A_NUMBER is returned and the contents of pNumber is undefined.
+ * If all goes well, pNumber contains the number that the string was converted
+ * to.
+ */
+rsRetVal
+rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber)
+{
+ DEFiRet;
+ number_t n;
+ int bIsNegative;
+ size_t i;
+
+ ASSERT(pStr != NULL);
+ ASSERT(pNumber != NULL);
+
+ if(pStr->iStrLen == 0) {
+ /* can be converted to 0! (by convention) */
+ pNumber = 0;
+ FINALIZE;
+ }
+
+ /* first skip whitespace (if present) */
+ for(i = 0 ; i < pStr->iStrLen && isspace(pStr->pBuf[i]) ; ++i) {
+ /*DO NOTHING*/
+ }
+
+ /* we have a string, so let's check its syntax */
+ if(pStr->pBuf[i] == '+') {
+ ++i; /* skip that char */
+ bIsNegative = 0;
+ } else if(pStr->pBuf[0] == '-') {
+ ++i; /* skip that char */
+ bIsNegative = 1;
+ } else {
+ bIsNegative = 0;
+ }
+
+ /* TODO: octal? hex? */
+ n = 0;
+ while(i < pStr->iStrLen && isdigit(pStr->pBuf[i])) {
+ n = n * 10 + pStr->pBuf[i] * 10;
+ ++i;
+ }
+
+ if(i < pStr->iStrLen) /* non-digits before end of string? */
+ ABORT_FINALIZE(RS_RET_NOT_A_NUMBER);
+
+ if(bIsNegative)
+ n *= -1;
+
+ /* we got it, so return the number */
+ *pNumber = n;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* Converts a string to a boolen. First tries to convert to a number. If
+ * that succeeds, we are done (number is then used as boolean value). If
+ * that fails, we look if the string is "yes" or "true". If so, a value
+ * of 1 is returned. In all other cases, a value of 0 is returned. Please
+ * note that we do not have a specific boolean type, so we return a number.
+ * so, these are
+ * RS_RET_NOT_A_NUMBER is returned and the contents of pNumber is undefined.
+ * If all goes well, pNumber contains the number that the string was converted
+ * to.
+ */
+rsRetVal
+rsCStrConvertToBool(cstr_t *pStr, number_t *pBool)
+{
+ DEFiRet;
+
+ ASSERT(pStr != NULL);
+ ASSERT(pBool != NULL);
+
+ iRet = rsCStrConvertToNumber(pStr, pBool);
+
+ if(iRet != RS_RET_NOT_A_NUMBER) {
+ FINALIZE; /* in any case, we have nothing left to do */
+ }
+
+ /* TODO: maybe we can do better than strcasecmp ;) -- overhead! */
+ if(!strcasecmp((char*)rsCStrGetSzStr(pStr), "true")) {
+ *pBool = 1;
+ } else if(!strcasecmp((char*)rsCStrGetSzStr(pStr), "yes")) {
+ *pBool = 1;
+ } else {
+ *pBool = 0;
+ }
+
+finalize_it:
+ RETiRet;
}
@@ -626,7 +888,7 @@ int rsCStrOffsetSzStrCmp(rsCStrObj *pCS1, size_t iOffset, uchar *psz, size_t iLe
* The to sz string pointer must not be NULL!
* rgerhards 2005-09-26
*/
-int rsCStrSzStrCmp(rsCStrObj *pCS1, uchar *psz, size_t iLenSz)
+int rsCStrSzStrCmp(cstr_t *pCS1, uchar *psz, size_t iLenSz)
{
rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
assert(psz != NULL);
@@ -659,7 +921,7 @@ int rsCStrSzStrCmp(rsCStrObj *pCS1, uchar *psz, size_t iLenSz)
* returned. Both parameters MUST be given (NULL is not allowed).
* rgerhards 2005-09-19
*/
-int rsCStrLocateInSzStr(rsCStrObj *pThis, uchar *sz)
+int rsCStrLocateInSzStr(cstr_t *pThis, uchar *sz)
{
int i;
int iMax;
@@ -694,6 +956,46 @@ int rsCStrLocateInSzStr(rsCStrObj *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
@@ -704,7 +1006,7 @@ int rsCStrLocateInSzStr(rsCStrObj *pThis, uchar *sz)
* some time later. However, it is not fully tested, so start with testing
* it before you put it to first use).
*/
-int rsCStrLocateSzStr(rsCStrObj *pThis, uchar *sz)
+int rsCStrLocateSzStr(cstr_t *pThis, uchar *sz)
{
int iLenSz;
int i;
@@ -744,6 +1046,29 @@ int rsCStrLocateSzStr(rsCStrObj *pThis, uchar *sz)
#endif /* end comment out */
+/* our exit function. TODO: remove once converted to a class
+ * rgerhards, 2008-03-11
+ */
+rsRetVal strExit()
+{
+ DEFiRet;
+ objRelease(regexp, LM_REGEXP_FILENAME);
+ RETiRet;
+}
+
+
+/* our init function. TODO: remove once converted to a class
+ */
+rsRetVal strInit()
+{
+ DEFiRet;
+ CHKiRet(objGetObjInterface(&obj));
+
+finalize_it:
+ RETiRet;
+}
+
+
/*
* Local variables:
* c-indent-level: 8