5
5
* requires strings to be able to handle embedded \0 characters.
6
6
* Please see syslogd.c for license information.
7
7
* All functions in this "class" start with rsCStr (rsyslog Counted String).
8
* This code is placed under the GPL.
9
8
* begun 2005-09-07 rgerhards
10
* Copyright (C) 2007 by Rainer Gerhards and Adiscon GmbH
12
* This file is part of rsyslog.
14
* Rsyslog is free software: you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation, either version 3 of the License, or
17
* (at your option) any later version.
19
* Rsyslog is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
27
* A copy of the GPL can be found in the file "COPYING" in this distribution.
11
29
#include "config.h"
15
33
#include <string.h>
17
35
#include <sys/types.h>
19
36
#include "rsyslog.h"
20
37
#include "stringbuf.h"
21
38
#include "srUtils.h"
24
43
/* ################################################################# *
25
44
* private members *
26
45
* ################################################################# */
30
51
/* ################################################################# *
32
53
* ################################################################# */
35
rsCStrObj *rsCStrConstruct(void)
56
rsRetVal rsCStrConstruct(cstr_t **ppThis)
39
if((pThis = (rsCStrObj*) calloc(1, sizeof(rsCStrObj))) == NULL)
61
ASSERT(ppThis != NULL);
63
if((pThis = (cstr_t*) calloc(1, sizeof(cstr_t))) == NULL)
64
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
42
66
rsSETOBJTYPE(pThis, OIDrsCStr);
43
67
pThis->pBuf = NULL;
45
69
pThis->iBufSize = 0;
46
70
pThis->iStrLen = 0;
47
71
pThis->iAllocIncrement = RS_STRINGBUF_ALLOC_INCREMENT;
52
79
/* construct from sz string
53
80
* rgerhards 2005-09-15
55
rsRetVal rsCStrConstructFromszStr(rsCStrObj **ppThis, uchar *sz)
82
rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz)
59
87
assert(ppThis != NULL);
61
if((pThis = rsCStrConstruct()) == NULL)
62
return RS_RET_OUT_OF_MEMORY;
89
CHKiRet(rsCStrConstruct(&pThis));
64
91
pThis->iBufSize = pThis->iStrLen = strlen((char*)(char *) sz);
65
92
if((pThis->pBuf = (uchar*) malloc(sizeof(uchar) * pThis->iStrLen)) == NULL) {
67
return RS_RET_OUT_OF_MEMORY;
94
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
70
97
/* we do NOT need to copy the \0! */
71
98
memcpy(pThis->pBuf, sz, pThis->iStrLen);
77
106
/* construct from CStr object. only the counted string is
78
107
* copied, not the szString.
79
108
* rgerhards 2005-10-18
81
rsRetVal rsCStrConstructFromCStr(rsCStrObj **ppThis, rsCStrObj *pFrom)
110
rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom)
85
115
assert(ppThis != NULL);
86
116
rsCHECKVALIDOBJECT(pFrom, OIDrsCStr);
88
if((pThis = rsCStrConstruct()) == NULL)
89
return RS_RET_OUT_OF_MEMORY;
118
CHKiRet(rsCStrConstruct(&pThis));
91
120
pThis->iBufSize = pThis->iStrLen = pFrom->iStrLen;
92
121
if((pThis->pBuf = (uchar*) malloc(sizeof(uchar) * pThis->iStrLen)) == NULL) {
94
return RS_RET_OUT_OF_MEMORY;
123
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
97
126
/* copy properties */
98
127
memcpy(pThis->pBuf, pFrom->pBuf, pThis->iStrLen);
105
void rsCStrDestruct(rsCStrObj *pThis)
135
void rsCStrDestruct(cstr_t **ppThis)
137
cstr_t *pThis = *ppThis;
107
139
/* rgerhards 2005-10-19: The free of pBuf was contained in conditional compilation.
108
140
* The code was only compiled if STRINGBUF_TRIM_ALLOCSIZE was set to 1. I honestly
109
141
* do not know why it was so, I think it was an artifact. Anyhow, I have changed this
110
142
* now. Should there any issue occur, this comment hopefully will shed some light
111
143
* on what happened. I re-verified, and this function has never before been called
112
144
* by anyone. So changing it can have no impact for obvious reasons...
146
* rgerhards, 2008-02-20: I changed the interface to the new calling conventions, where
147
* the destructor receives a pointer to the object, so that it can set it to NULL.
114
149
if(pThis->pBuf != NULL) {
115
150
free(pThis->pBuf);
122
157
RSFREEOBJ(pThis);
126
rsRetVal rsCStrAppendStrWithLen(rsCStrObj *pThis, uchar* psz, size_t iStrLen)
162
/* extend the string buffer if its size is insufficient.
163
* Param iMinNeeded is the minumum free space needed. If it is larger
164
* than the default alloc increment, space for at least this amount is
165
* allocated. In practice, a bit more is allocated because we envision that
166
* some more characters may be added after these.
167
* rgerhards, 2008-01-07
169
static rsRetVal rsCStrExtendBuf(cstr_t *pThis, size_t iMinNeeded)
175
/* first compute the new size needed */
176
if(iMinNeeded > pThis->iAllocIncrement) {
177
/* we allocate "n" iAllocIncrements. Usually, that should
178
* leave some room after the absolutely needed one. It also
179
* reduces memory fragmentation. Note that all of this are
180
* integer operations (very important to understand what is
181
* going on)! Parenthesis are for better readibility.
183
iNewSize = ((iMinNeeded / pThis->iAllocIncrement) + 1) * pThis->iAllocIncrement;
185
iNewSize = pThis->iBufSize + pThis->iAllocIncrement;
187
iNewSize += pThis->iBufSize; /* add current size */
189
/* and then allocate and copy over */
190
/* DEV debugging only: dbgprintf("extending string buffer, old %d, new %d\n", pThis->iBufSize, iNewSize); */
191
if((pNewBuf = (uchar*) malloc(iNewSize * sizeof(uchar))) == NULL)
192
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
193
memcpy(pNewBuf, pThis->pBuf, pThis->iBufSize);
194
pThis->iBufSize = iNewSize;
195
if(pThis->pBuf != NULL) {
198
pThis->pBuf = pNewBuf;
205
/* append a string of known length. In this case, we make sure we do at most
206
* one additional memory allocation.
207
* I optimized this function to use memcpy(), among others. Consider it a
208
* rewrite (which may be good to know in case of bugs) -- rgerhards, 2008-01-07
210
rsRetVal rsCStrAppendStrWithLen(cstr_t *pThis, uchar* psz, size_t iStrLen)
131
214
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
132
215
assert(psz != NULL);
134
/* we first check if the to-be-added string is larger than the
135
* alloc increment. If so, we temporarily increase the alloc
136
* increment to the length of the string. This will ensure that
137
* one string copy will be needed at most. As this is a very
138
* costly operation, it outweights the cost of the strlen((char*)) and
139
* related stuff - at least I think so.
140
* rgerhards 2005-09-22
142
/* We save the current alloc increment in any case, so we can just
143
* overwrite it below, this is faster than any if-construct.
145
iOldAllocInc = pThis->iAllocIncrement;
146
if(iStrLen > pThis->iAllocIncrement) {
147
pThis->iAllocIncrement = iStrLen;
217
/* does the string fit? */
218
if(pThis->iStrLen + iStrLen > pThis->iBufSize) {
219
CHKiRet(rsCStrExtendBuf(pThis, iStrLen)); /* need more memory! */
151
if((iRet = rsCStrAppendChar(pThis, *psz++)) != RS_RET_OK)
222
/* ok, now we always have sufficient continues memory to do a memcpy() */
223
memcpy(pThis->pBuf + pThis->iStrLen, psz, iStrLen);
224
pThis->iStrLen += iStrLen;
154
pThis->iAllocIncrement = iOldAllocInc; /* restore */
161
233
* need to change existing code.
162
234
* rgerhards, 2007-07-03
164
rsRetVal rsCStrAppendStr(rsCStrObj *pThis, uchar* psz)
166
return rsCStrAppendStrWithLen(pThis, psz, strlen((char*)(char*) psz));
170
rsRetVal rsCStrAppendInt(rsCStrObj *pThis, int i)
236
rsRetVal rsCStrAppendStr(cstr_t *pThis, uchar* psz)
238
return rsCStrAppendStrWithLen(pThis, psz, strlen((char*) psz));
242
/* append the contents of one cstr_t object to another
243
* rgerhards, 2008-02-25
245
rsRetVal rsCStrAppendCStr(cstr_t *pThis, cstr_t *pstrAppend)
247
return rsCStrAppendStrWithLen(pThis, pstrAppend->pBuf, pstrAppend->iStrLen);
251
rsRetVal rsCStrAppendInt(cstr_t *pThis, long i)
175
256
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
177
if((iRet = srUtilItoA((char*) szBuf, sizeof(szBuf), i)) != RS_RET_OK)
258
CHKiRet(srUtilItoA((char*) szBuf, sizeof(szBuf), i));
180
return rsCStrAppendStr(pThis, szBuf);
260
iRet = rsCStrAppendStr(pThis, szBuf);
184
rsRetVal rsCStrAppendChar(rsCStrObj *pThis, uchar c)
266
rsRetVal rsCStrAppendChar(cstr_t *pThis, uchar c)
188
270
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
190
if(pThis->iStrLen >= pThis->iBufSize)
191
{ /* need more memory! */
192
if((pNewBuf = (uchar*) malloc((pThis->iBufSize + pThis->iAllocIncrement) * sizeof(uchar))) == NULL)
193
return RS_RET_OUT_OF_MEMORY;
194
memcpy(pNewBuf, pThis->pBuf, pThis->iBufSize);
195
pThis->iBufSize += pThis->iAllocIncrement;
196
if(pThis->pBuf != NULL) {
199
pThis->pBuf = pNewBuf;
272
if(pThis->iStrLen >= pThis->iBufSize) {
273
CHKiRet(rsCStrExtendBuf(pThis, 1)); /* need more memory! */
202
276
/* ok, when we reach this, we have sufficient memory */
373
448
free(pThis->pBuf);
374
449
RSFREEOBJ(pThis);
380
rsRetVal rsCStrFinish(rsCStrObj __attribute__((unused)) *pThis)
382
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
384
# if STRINGBUF_TRIM_ALLOCSIZE == 1
385
/* in this mode, we need to trim the string. To do
455
#if STRINGBUF_TRIM_ALLOCSIZE == 1
456
/* Only in this mode, we need to trim the string. To do
386
457
* so, we must allocate a new buffer of the exact
387
458
* string size, and then copy the old one over.
388
* This new buffer is then to be returned.
390
if((pRetBuf = malloc((pThis->iBufSize) * sizeof(uchar))) == NULL)
461
* STRINGBUF_TRIM_ALLOCSIZE can, in theory, be used to trim
462
* memory buffers. This part of the code was inherited from
463
* liblogging (where it is used in a different context) but
464
* never put to use in rsyslog. The reason is that it is hardly
465
* imaginable where the extra performance cost is worth the save
466
* in memory alloc. Then Anders Blomdel rightfully pointed out that
467
* the code does not work at all - and nobody even know that it
468
* probably shouldn't. Rather than removing, I deciced to somewhat
469
* fix the code, so that this feature may be enabled if somebody
470
* really has a need for it. Be warned, however, that I NEVER
471
* tested the fix. So if you intend to use this feature, you must
472
* do full testing before you rely on it. -- rgerhards, 2008-02-12
474
rsRetVal rsCStrFinish(cstr_t __attribute__((unused)) *pThis)
478
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
480
if((pBuf = malloc((pThis->iStrLen) * sizeof(uchar))) == NULL)
391
481
{ /* OK, in this case we use the previous buffer. At least
396
486
{ /* got the new buffer, so let's use it */
398
memcpy(pBuf, pThis->pBuf, pThis->iBufPtr + 1);
487
memcpy(pBuf, pThis->pBuf, pThis->iStrLen);
399
488
pThis->pBuf = pBuf;
402
/* here, we need to do ... nothing ;)
408
void rsCStrSetAllocIncrement(rsCStrObj *pThis, int iNewIncrement)
493
#endif /* #if STRINGBUF_TRIM_ALLOCSIZE == 1 */
496
void rsCStrSetAllocIncrement(cstr_t *pThis, int iNewIncrement)
410
498
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
411
499
assert(iNewIncrement > 0);
508
/* check if a sz-type string start with a CStr object. This function
596
/* check if a sz-type string starts with a CStr object. This function
509
597
* is initially written to support the "startswith" property-filter
510
598
* comparison operation. Maybe it also has other needs.
599
* This functions is modelled after the strcmp() series, thus a
600
* return value of 0 indicates that the string starts with the
601
* sequence while -1 indicates it does not!
511
602
* rgerhards 2005-10-19
513
int rsCStrSzStrStartsWithCStr(rsCStrObj *pCS1, uchar *psz, size_t iLenSz)
604
int rsCStrSzStrStartsWithCStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
568
662
return -1; /* pCS1 is less then psz */
666
/* The same as rsCStrStartsWithSzStr(), but does a case-insensitive
667
* comparison. TODO: consolidate the two.
668
* rgerhards 2008-02-28
670
int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz)
674
rsCHECKVALIDOBJECT(pCS1, OIDrsCStr);
676
assert(iLenSz == strlen((char*)psz)); /* just make sure during debugging! */
677
if(pCS1->iStrLen >= iLenSz) {
678
/* we are using iLenSz below, because we need to check
679
* iLenSz characters at maximum (start with!)
682
return 0; /* yes, it starts with a zero-sized string ;) */
683
else { /* we now have something to compare, so let's do it... */
684
for(i = 0 ; i < iLenSz ; ++i) {
685
if(tolower(pCS1->pBuf[i]) != tolower(psz[i]))
686
return tolower(pCS1->pBuf[i]) - tolower(psz[i]);
688
/* if we arrive here, the string actually starts with psz */
693
return -1; /* pCS1 is less then psz */
571
696
/* check if a CStr object matches a regex.
572
697
* msamia@redhat.com 2007-07-12
573
698
* @return returns 0 if matched
574
699
* bug: doesn't work for CStr containing \0
575
700
* rgerhards, 2007-07-16: bug is no real bug, because rsyslogd ensures there
576
701
* never is a \0 *inside* a property string.
702
* Note that the function returns -1 if regexp functionality is not available.
703
* TODO: change calling interface! -- rgerhards, 2008-03-07
578
int rsCStrSzStrMatchRegex(rsCStrObj *pCS1, uchar *psz)
705
int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz)
581
regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0);
582
int iRet = regexec(&preq, (char*) psz, 0, NULL, 0);
712
if(objUse(regexp, LM_REGEXP_FILENAME) == RS_RET_OK) {
713
regexp.regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0);
714
ret = regexp.regexec(&preq, (char*) psz, 0, NULL, 0);
715
regexp.regfree(&preq);
717
ret = 1; /* simulate "not found" */
587
725
/* compare a rsCStr object with a classical sz string. This function
588
726
* is almost identical to rsCStrZsStrCmp(), but it also takes an offset
589
727
* to the CStr object from where the comparison is to start.
629
769
/* if we arrive here, the strings are equal */
634
775
return pCS1->iStrLen - iOffset - iLenSz;
781
/* Converts a string to a number. If the string dos not contain a number,
782
* RS_RET_NOT_A_NUMBER is returned and the contents of pNumber is undefined.
783
* If all goes well, pNumber contains the number that the string was converted
787
rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber)
794
ASSERT(pStr != NULL);
795
ASSERT(pNumber != NULL);
797
if(pStr->iStrLen == 0) {
798
/* can be converted to 0! (by convention) */
803
/* first skip whitespace (if present) */
804
for(i = 0 ; i < pStr->iStrLen && isspace(pStr->pBuf[i]) ; ++i) {
808
/* we have a string, so let's check its syntax */
809
if(pStr->pBuf[i] == '+') {
810
++i; /* skip that char */
812
} else if(pStr->pBuf[0] == '-') {
813
++i; /* skip that char */
819
/* TODO: octal? hex? */
821
while(i < pStr->iStrLen && isdigit(pStr->pBuf[i])) {
822
n = n * 10 + pStr->pBuf[i] * 10;
826
if(i < pStr->iStrLen) /* non-digits before end of string? */
827
ABORT_FINALIZE(RS_RET_NOT_A_NUMBER);
832
/* we got it, so return the number */
840
/* Converts a string to a boolen. First tries to convert to a number. If
841
* that succeeds, we are done (number is then used as boolean value). If
842
* that fails, we look if the string is "yes" or "true". If so, a value
843
* of 1 is returned. In all other cases, a value of 0 is returned. Please
844
* note that we do not have a specific boolean type, so we return a number.
846
* RS_RET_NOT_A_NUMBER is returned and the contents of pNumber is undefined.
847
* If all goes well, pNumber contains the number that the string was converted
851
rsCStrConvertToBool(cstr_t *pStr, number_t *pBool)
855
ASSERT(pStr != NULL);
856
ASSERT(pBool != NULL);
858
iRet = rsCStrConvertToNumber(pStr, pBool);
860
if(iRet != RS_RET_NOT_A_NUMBER) {
861
FINALIZE; /* in any case, we have nothing left to do */
864
/* TODO: maybe we can do better than strcasecmp ;) -- overhead! */
865
if(!strcasecmp((char*)rsCStrGetSzStr(pStr), "true")) {
867
} else if(!strcasecmp((char*)rsCStrGetSzStr(pStr), "yes")) {
959
/* This is the same as rsCStrLocateInSzStr(), but does a case-insensitve
961
* TODO: over time, consolidate the two.
962
* rgerhards, 2008-02-28
964
int rsCStrCaseInsensitiveLocateInSzStr(cstr_t *pThis, uchar *sz)
969
rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
972
if(pThis->iStrLen == 0)
975
/* compute the largest index where a match could occur - after all,
976
* the to-be-located string must be able to be present in the
977
* searched string (it needs its size ;)).
979
iMax = strlen((char*)sz) - pThis->iStrLen;
983
while(i <= iMax && !bFound) {
985
uchar *pComp = sz + i;
986
for(iCheck = 0 ; iCheck < pThis->iStrLen ; ++iCheck)
987
if(tolower(*(pComp + iCheck)) != tolower(*(pThis->pBuf + iCheck)))
989
if(iCheck == pThis->iStrLen)
990
bFound = 1; /* found! - else it wouldn't be equal */
992
++i; /* on to the next try */
995
return(bFound ? i : -1);
719
999
#if 0 /* read comment below why this is commented out. In short: for future use! */
720
1000
/* locate the first occurence of a standard sz string inside a rsCStr object.
721
1001
* Returns the offset (0-bound) of this first occurrence. If not found, -1 is