diff --git a/bstest.c b/bstest.c index 9060ef180820b1cc9fb91129c2bc09387ebf8825_YnN0ZXN0LmM=..0ed5f17443a8988ea51e12ea00d24ba96d963022_YnN0ZXN0LmM= 100644 --- a/bstest.c +++ b/bstest.c @@ -22,6 +22,15 @@ static bstring dumpOut[16]; static int rot = 0; +static int incorrectBstring (const struct tagbstring * b) { + if (NULL == b) return 1; + if (NULL == b->data) return 1; + if (b->slen < 0) return 1; + if (b->mlen > 0 && b->slen > b->mlen) return 1; + if (b->data[b->slen] != '\0') return 1; + return 0; +} + static char * dumpBstring (const struct tagbstring * b) { rot = (rot + 1) % (unsigned)16; if (dumpOut[rot] == NULL) { @@ -619,6 +628,52 @@ #define test7() test7x8 ("biseq", biseq, -1, 0, 0, 1) #define test8() test7x8 ("bstrcmp", bstrcmp, SHRT_MIN, -1, 1, 0) +static int test47_0 (const struct tagbstring* b, const unsigned char* blk, int len, int res) { +int rv, ret = 0; + + ret += (res != (rv = biseqblk (b, blk, len))); + printf (".\tbiseqblk (%s, %s) = %d\n", dumpBstring (b), dumpCstring (blk), rv); + if (ret) { + printf ("\t\tfailure(%d) = %d (res = %d)\n", __LINE__, ret, res); + } + return ret; +} + +static int test47 (void) { +int ret = 0; + + printf ("TEST: int biseqblk (const_bstring b, const void * blk, int len);\n"); + + /* tests with NULL */ + ret += test47_0 (NULL, NULL, 0, -1); + ret += test47_0 (&emptyBstring, NULL, 0, -1); + ret += test47_0 (NULL, emptyBstring.data, 0, -1); + ret += test47_0 (&shortBstring, NULL, shortBstring.slen, -1); + ret += test47_0 (NULL, shortBstring.data, 0, -1); + ret += test47_0 (&badBstring1, badBstring1.data, badBstring1.slen, -1); + ret += test47_0 (&badBstring2, badBstring2.data, badBstring2.slen, -1); + ret += test47_0 (&shortBstring, badBstring2.data, badBstring2.slen, -1); + ret += test47_0 (&badBstring2, shortBstring.data, shortBstring.slen, -1); + + /* normal operation tests on all sorts of subranges */ + ret += test47_0 (&emptyBstring, emptyBstring.data, emptyBstring.slen, 1); + ret += test47_0 (&shortBstring, emptyBstring.data, emptyBstring.slen, 0); + ret += test47_0 (&emptyBstring, shortBstring.data, shortBstring.slen, 0); + ret += test47_0 (&shortBstring, shortBstring.data, shortBstring.slen, 1); + + { + bstring b = bstrcpy (&shortBstring); + b->data[1]++; + ret += test47_0 (b, shortBstring.data, shortBstring.slen, 0); + bdestroy (b); + } + ret += test47_0 (&shortBstring, longBstring.data, longBstring.slen, 0); + ret += test47_0 (&longBstring, shortBstring.data, shortBstring.slen, 0); + + printf ("\t# failures: %d\n", ret); + return ret; +} + static int test9_0 (const_bstring b0, const_bstring b1, int n, int res) { int rv, ret = 0; @@ -1128,6 +1183,24 @@ return ret; } +static int test16_1 (void) { +bstring b0 = bfromStatic ("aaaaabbbbb"); +struct tagbstring b1; +int res, ret = 0; + + bmid2tbstr (b1, b0, 4, 4); + b0->slen = 6; + + printf (".\tbinsert (%s, 2, %s, '?') = ", dumpBstring (b0), dumpBstring (&b1)); + res = binsert (b0, 2, &b1, '?'); + printf ("%s (Alias test)\n", dumpBstring (b0)); + + ret += (res != 0); + ret += !biseqStatic(b0, "aaabbbaaab"); + + return ret; +} + static int test16 (void) { int ret = 0; printf ("TEST: int binsert (bstring b0, int pos, const_bstring b1, unsigned char fill);\n"); @@ -1154,6 +1227,10 @@ ret += test16_0 (&shortBstring, 2, &shortBstring, (unsigned char) '?', "bobogusgus"); ret += test16_0 (&shortBstring, 6, &shortBstring, (unsigned char) '?', "bogus?bogus"); ret += test16_0 (&shortBstring, 6, NULL, (unsigned char) '?', "bogus"); + + /* Alias testing */ + ret += test16_1 (); + printf ("\t# failures: %d\n", ret); return ret; } @@ -1537,6 +1614,7 @@ c = bjoin (l, &t); ret += !biseq (c, b); + ret += incorrectBstring (c); bdestroy (c); ret += 0 != bstrListDestroy (l); } else { @@ -1582,6 +1660,7 @@ c = bjoin (l, sc); ret += !biseq (c, b); + ret += incorrectBstring (c); bdestroy (c); ret += 0 != bstrListDestroy (l); } else { @@ -1600,6 +1679,7 @@ static int test21 (void) { struct tagbstring is = bsStatic ("is"); struct tagbstring ng = bsStatic ("ng"); +struct tagbstring commas = bsStatic (",,,,"); int ret = 0; printf ("TEST: struct bstrList * bsplit (const_bstring str, unsigned char splitChar);\n"); @@ -1614,6 +1694,7 @@ ret += test21_0 (&shortBstring, (char) 's', 2); ret += test21_0 (&shortBstring, (char) 'b', 2); ret += test21_0 (&longBstring, (char) 'o', 9); + ret += test21_0 (&commas, (char) ',', 5); printf ("TEST: struct bstrList * bsplitstr (bstring str, const_bstring splitStr);\n"); @@ -1669,6 +1750,7 @@ bdestroy (l->entry[0]); l->qty--; b = bjoin (l, &longBstring); + ret += incorrectBstring (b); bstrListDestroy (l); if (b->slen) { printf ("\t\tfailure(%d) ", __LINE__); @@ -2951,6 +3033,44 @@ return ret; } +static int test48_0 (const_bstring b, const unsigned char * blk, int len, int res) { +int rv, ret = 0; + + ret += (res != (rv = biseqcaselessblk (b, blk, len))); + printf (".\tbiseqcaselessblk (%s, %s, %d) = %d\n", dumpBstring (b), dumpCstring (blk), len, rv); + if (ret) { + printf ("\t\tfailure(%d) = %d (res = %d)\n", __LINE__, ret, res); + } + return ret; +} + +static int test48 (void) { +int ret = 0; +struct tagbstring t0 = bsStatic ("bOgUs"); +struct tagbstring t1 = bsStatic ("bOgUR"); +struct tagbstring t2 = bsStatic ("bOgUt"); + + printf ("TEST: int biseqcaselessblk (const_bstring b, const void * blk, int len);\n"); + + /* tests with NULL */ + ret += test48_0 (NULL, NULL, 0, BSTR_ERR); + ret += test48_0 (&emptyBstring, NULL, 0, BSTR_ERR); + ret += test48_0 (NULL, emptyBstring.data, 0, BSTR_ERR); + ret += test48_0 (&emptyBstring, badBstring1.data, emptyBstring.slen, BSTR_ERR); + ret += test48_0 (&badBstring1, emptyBstring.data, badBstring1.slen, BSTR_ERR); + ret += test48_0 (&shortBstring, badBstring2.data, badBstring2.slen, BSTR_ERR); + ret += test48_0 (&badBstring2, shortBstring.data, badBstring2.slen, BSTR_ERR); + + /* normal operation tests on all sorts of subranges */ + ret += test48_0 (&emptyBstring, emptyBstring.data, emptyBstring.slen, 1); + ret += test48_0 (&shortBstring, t0.data, t0.slen, 1); + ret += test48_0 (&shortBstring, t1.data, t1.slen, 0); + ret += test48_0 (&shortBstring, t2.data, t2.slen, 0); + + if (ret) printf ("\t# failures: %d\n", ret); + return ret; +} + struct emuFile { int ofs; bstring contents; @@ -3560,6 +3680,8 @@ ret += test44 (); ret += test45 (); ret += test46 (); + ret += test47 (); + ret += test48 (); printf ("# test failures: %d\n", ret); diff --git a/bstrlib.c b/bstrlib.c index 9060ef180820b1cc9fb91129c2bc09387ebf8825_YnN0cmxpYi5j..0ed5f17443a8988ea51e12ea00d24ba96d963022_YnN0cmxpYi5j 100644 --- a/bstrlib.c +++ b/bstrlib.c @@ -30,5 +30,12 @@ #endif #ifndef bstr__alloc +#if defined (BSTRLIB_TEST_CANARY) +void* bstr__alloc (size_t sz) { + char* p = (char *) malloc (sz); + memset (p, 'X', sz); + return p; +} +#else #define bstr__alloc(x) malloc (x) #endif @@ -33,5 +40,6 @@ #define bstr__alloc(x) malloc (x) #endif +#endif #ifndef bstr__free #define bstr__free(p) free (p) @@ -121,7 +129,9 @@ /* Since we failed, try allocating the tighest possible allocation */ - if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) { + len = olen; + x = (unsigned char *) bstr__realloc (b->data, (size_t) olen); + if (NULL == x) { return BSTR_ERR; } } @@ -139,7 +149,8 @@ goto reallocStrategy; } else { - if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen); + if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, + (size_t) b->slen); bstr__free (b->data); } } @@ -343,7 +354,8 @@ int len, d; bstring aux = (bstring) b1; - if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR; + if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) + return BSTR_ERR; d = b0->slen; len = b1->slen; @@ -376,7 +388,8 @@ if (b == NULL) return BSTR_ERR; d = b->slen; - if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR; + if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) + return BSTR_ERR; b->data[d] = (unsigned char) c; b->data[d + 1] = (unsigned char) '\0'; b->slen++; @@ -688,6 +701,33 @@ return - (int) (UCHAR_MAX + 1); } +/* int biseqcaselessblk (const_bstring b, const void * blk, int len) + * + * Compare content of b and the array of bytes in blk for length len for + * equality without differentiating between character case. If the content + * differs other than in case, 0 is returned, if, ignoring case, the content + * is the same, 1 is returned, if there is an error, -1 is returned. If the + * length of the strings are different, this function is O(1). '\0' + * characters are not treated in any special way. + */ +int biseqcaselessblk (const_bstring b, const void * blk, int len) { +int i; + + if (bdata (b) == NULL || b->slen < 0 || + blk == NULL || len < 0) return BSTR_ERR; + if (b->slen != len) return 0; + if (len == 0 || b->data == blk) return 1; + for (i=0; i < len; i++) { + if (b->data[i] != ((unsigned char*)blk)[i]) { + unsigned char c = (unsigned char) downcase (b->data[i]); + if (c != (unsigned char) downcase (((unsigned char*)blk)[i])) + return 0; + } + } + return 1; +} + + /* int biseqcaseless (const_bstring b0, const_bstring b1) * * Compare two strings for equality without differentiating between case. @@ -697,6 +737,7 @@ * termination characters are not treated in any special way. */ int biseqcaseless (const_bstring b0, const_bstring b1) { +#if 0 int i, n; if (bdata (b0) == NULL || b0->slen < 0 || @@ -710,6 +751,10 @@ } } return 1; +#else + if (NULL == b1) return BSTR_ERR; + return biseqcaselessblk (b0, b1->data, b1->slen); +#endif } /* int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) @@ -809,6 +854,22 @@ return BSTR_OK; } +/* int biseqblk (const_bstring b, const void * blk, int len) + * + * Compare the string b with the character block blk of length len. If the + * content differs, 0 is returned, if the content is the same, 1 is returned, + * if there is an error, -1 is returned. If the length of the strings are + * different, this function is O(1). '\0' characters are not treated in any + * special way. + */ +int biseqblk (const_bstring b, const void * blk, int len) { + if (len < 0 || b == NULL || blk == NULL || b->data == NULL || b->slen < 0) + return BSTR_ERR; + if (b->slen != len) return 0; + if (len == 0 || b->data == blk) return 1; + return !bstr__memcmp (b->data, blk, len); +} + /* int biseq (const_bstring b0, const_bstring b1) * * Compare the string b0 and b1. If the strings differ, 0 is returned, if @@ -859,5 +920,6 @@ */ int biseqcstr (const_bstring b, const char * s) { int i; - if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR; + if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) + return BSTR_ERR; for (i=0; i < b->slen; i++) { @@ -863,5 +925,6 @@ for (i=0; i < b->slen; i++) { - if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK; + if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) + return BSTR_OK; } return s[i] == '\0'; } @@ -880,7 +943,8 @@ */ int biseqcstrcaseless (const_bstring b, const char * s) { int i; - if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR; + if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) + return BSTR_ERR; for (i=0; i < b->slen; i++) { if (s[i] == '\0' || (b->data[i] != (unsigned char) s[i] && @@ -1237,7 +1301,8 @@ if (b2->slen == 0) return pos; /* Obvious alias case */ - if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK; + if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) + return BSTR_OK; i = pos; if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR; @@ -1273,8 +1338,10 @@ int bstrchrp (const_bstring b, int c, int pos) { unsigned char * p; - if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR; - p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos)); + if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) + return BSTR_ERR; + p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, + (b->slen - pos)); if (p) return (int) (p - b->data); return BSTR_ERR; } @@ -1287,7 +1354,8 @@ int bstrrchrp (const_bstring b, int c, int pos) { int i; - if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR; + if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) + return BSTR_ERR; for (i=pos; i >= 0; i--) { if (b->data[i] == (unsigned char) c) return i; } @@ -1301,6 +1369,7 @@ #define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY) struct charField { LONG_TYPE content[CFCLEN]; }; -#define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1)))) +#define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & \ + (((long)1) << ((c) & (LONG_BITS_QTY-1)))) #define setInCharField(cf,idx) { \ unsigned int c = (unsigned int) (idx); \ @@ -1305,6 +1374,7 @@ #define setInCharField(cf,idx) { \ unsigned int c = (unsigned int) (idx); \ - (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \ + (cf)->content[c >> LONG_LOG_BITS_QTY] |= \ + (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \ } #else @@ -1333,7 +1403,8 @@ } /* Inner engine for binchr */ -static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) { +static int binchrCF (const unsigned char * data, int len, int pos, + const struct charField * cf) { int i; for (i=pos; i < len; i++) { unsigned char c = (unsigned char) data[i]; @@ -1358,7 +1429,8 @@ } /* Inner engine for binchrr */ -static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) { +static int binchrrCF (const unsigned char * data, int pos, + const struct charField * cf) { int i; for (i=pos; i >= 0; i--) { unsigned int c = (unsigned int) data[i]; @@ -1434,7 +1506,8 @@ /* Aliasing case */ if (NULL != aux) { - if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) { + if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && + pd < (ptrdiff_t) b0->mlen) { if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR; } d += aux->slen; @@ -1450,7 +1523,8 @@ /* Fill in "fill" character as necessary */ if (pos > newlen) { - bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen)); + bstr__memset (b0->data + b0->slen, (int) fill, + (size_t) (pos - b0->slen)); newlen = pos; } @@ -1469,7 +1543,60 @@ return BSTR_OK; } -/* int binsert (bstring b1, int pos, bstring b2, unsigned char fill) +/* int binsertblk (bstring b, int pos, const void * blk, int len, + * unsigned char fill) + * + * Inserts the block of characters at blk with length len into b at position + * pos. If the position pos is past the end of b, then the character "fill" + * is appended as necessary to make up the gap between the end of b1 and pos. + * Unlike bsetstr, binsert does not allow b2 to be NULL. + */ +int binsertblk (bstring b, int pos, const void * blk, int len, + unsigned char fill) { +int d, l; +unsigned char* aux = (unsigned char*) blk; + + if (b == NULL || blk == NULL || pos < 0 || len < 0 || b->slen < 0 || + b->mlen <= 0 || b->mlen < b->slen) return BSTR_ERR; + + /* Compute the two possible end pointers */ + d = b->slen + len; + l = pos + len; + if ((d|l) < 0) return BSTR_ERR; /* Integer wrap around. */ + + /* Aliasing case */ + if (((size_t) ((unsigned char*) blk + len)) >= ((size_t) b->data) && + ((size_t) blk) < ((size_t) (b->data + b->mlen))) { + if (NULL == (aux = (unsigned char*) bstr__alloc (len))) + return BSTR_ERR; + bstr__memcpy (aux, blk, len); + } + + if (l > d) { + /* Inserting past the end of the string */ + if (balloc (b, l + 1) != BSTR_OK) { + if (aux != (unsigned char*) blk) bstr__free (aux); + return BSTR_ERR; + } + bstr__memset (b->data + b->slen, (int) fill, + (size_t) (pos - b->slen)); + b->slen = l; + } else { + /* Inserting in the middle of the string */ + if (balloc (b, d + 1) != BSTR_OK) { + if (aux != (unsigned char*) blk) bstr__free (aux); + return BSTR_ERR; + } + bBlockCopy (b->data + l, b->data + pos, d - l); + b->slen = d; + } + bBlockCopy (b->data + pos, aux, len); + b->data[b->slen] = (unsigned char) '\0'; + if (aux != (unsigned char*) blk) bstr__free (aux); + return BSTR_OK; +} + +/* int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) * * Inserts the string b2 into b1 at position pos. If the position pos is * past the end of b1, then the character "fill" is appended as necessary to @@ -1477,46 +1604,10 @@ * does not allow b2 to be NULL. */ int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) { -int d, l; -ptrdiff_t pd; -bstring aux = (bstring) b2; - - if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 || - b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR; - - /* Aliasing case */ - if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) { - if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR; - } - - /* Compute the two possible end pointers */ - d = b1->slen + aux->slen; - l = pos + aux->slen; - if ((d|l) < 0) return BSTR_ERR; - - if (l > d) { - /* Inserting past the end of the string */ - if (balloc (b1, l + 1) != BSTR_OK) { - if (aux != b2) bdestroy (aux); - return BSTR_ERR; - } - bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen)); - b1->slen = l; - } else { - /* Inserting in the middle of the string */ - if (balloc (b1, d + 1) != BSTR_OK) { - if (aux != b2) bdestroy (aux); - return BSTR_ERR; - } - bBlockCopy (b1->data + l, b1->data + pos, d - l); - b1->slen = d; - } - bBlockCopy (b1->data + pos, aux->data, aux->slen); - b1->data[b1->slen] = (unsigned char) '\0'; - if (aux != b2) bdestroy (aux); - return BSTR_OK; + if (NULL == b2 || (b2->mlen > 0 && b2->slen > b2->mlen)) return BSTR_ERR; + return binsertblk (b1, pos, b2->data, b2->slen, fill); } /* int breplace (bstring b1, int pos, int len, bstring b2, * unsigned char fill) * @@ -1518,9 +1609,9 @@ } /* int breplace (bstring b1, int pos, int len, bstring b2, * unsigned char fill) * - * Replace a section of a string from pos for a length len with the string b2. - * fill is used is pos > b1->slen. + * Replace a section of a string from pos for a length len with the string + * b2. fill is used is pos > b1->slen. */ int breplace (bstring b1, int pos, int len, const_bstring b2, @@ -1525,6 +1616,6 @@ */ int breplace (bstring b1, int pos, int len, const_bstring b2, - unsigned char fill) { + unsigned char fill) { int pl, ret; ptrdiff_t pd; bstring aux = (bstring) b2; @@ -1545,7 +1636,8 @@ } /* Aliasing case */ - if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) { + if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && + pd < (ptrdiff_t) b1->slen) { if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR; } @@ -1556,7 +1648,9 @@ } } - if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len)); + if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, + b1->data + pos + len, + b1->slen - (pos + len)); bstr__memcpy (b1->data + pos, aux->data, aux->slen); b1->slen += aux->slen - len; b1->data[b1->slen] = (unsigned char) '\0'; @@ -1575,6 +1669,8 @@ #define INITIAL_STATIC_FIND_INDEX_COUNT 32 -static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) { +static int findreplaceengine (bstring b, const_bstring find, + const_bstring repl, int pos, + instr_fnptr instr) { int i, ret, slen, mlen, delta, acc; int * d; @@ -1579,6 +1675,6 @@ int i, ret, slen, mlen, delta, acc; int * d; -int static_d[INITIAL_STATIC_FIND_INDEX_COUNT+1]; /* This +1 is unnecessary, but it shuts up LINT. */ +int static_d[INITIAL_STATIC_FIND_INDEX_COUNT+1]; /* This +1 is for LINT. */ ptrdiff_t pd; bstring auxf = (bstring) find; bstring auxr = (bstring) repl; @@ -1669,7 +1765,8 @@ mlen += mlen; sl = sizeof (int *) * mlen; if (static_d == d) d = NULL; /* static_d cannot be realloced */ - if (mlen <= 0 || sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) { + if (mlen <= 0 || sl < mlen || + NULL == (t = (int *) bstr__realloc (d, sl))) { ret = BSTR_ERR; goto done; } @@ -1720,7 +1817,8 @@ * Replace all occurrences of a find string with a replace string after a * given point in a bstring. */ -int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) { +int bfindreplace (bstring b, const_bstring find, const_bstring repl, + int pos) { return findreplaceengine (b, find, repl, pos, binstr); } @@ -1730,7 +1828,8 @@ * Replace all occurrences of a find string, ignoring case, with a replace * string after a given point in a bstring. */ -int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) { +int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, + int pos) { return findreplaceengine (b, find, repl, pos, binstrcaseless); } @@ -1925,7 +2024,8 @@ bstring bgets (bNgetc getcPtr, void * parm, char terminator) { bstring buff; - if (0 > bgetsa (buff = bfromcstr (""), getcPtr, parm, terminator) || 0 >= buff->slen) { + if (0 > bgetsa (buff = bfromcstr (""), getcPtr, parm, terminator) || + 0 >= buff->slen) { bdestroy (buff); buff = NULL; } @@ -1936,7 +2036,7 @@ bstring buff; /* Buffer for over-reads */ void * parm; /* The stream handle for core stream */ bNread readFnPtr; /* fread compatible fnptr for core stream */ - int isEOF; /* track file's EOF state */ + int isEOF; /* track file's EOF state */ int maxBuffSz; }; @@ -2035,7 +2135,8 @@ /* Perform direct in-place reads into the destination to allow for the minimum of data-copies */ for (;;) { - if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR; + if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) + return BSTR_ERR; b = (char *) (r->data + r->slen); l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm); if (l <= 0) { @@ -2104,7 +2205,8 @@ /* Perform direct in-place reads into the destination to allow for the minimum of data-copies */ for (;;) { - if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR; + if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) + return BSTR_ERR; b = (unsigned char *) (r->data + r->slen); l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm); if (l <= 0) { @@ -2156,7 +2258,8 @@ if (0 == l) { if (s->isEOF) return BSTR_ERR; if (r->mlen > n) { - l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm); + l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, + s->parm); if (0 >= l || l > n - r->slen) { s->isEOF = 1; return BSTR_ERR; @@ -2264,6 +2367,6 @@ return bassign (r, s->buff); } -/* bstring bjoin (const struct bstrList * bl, const_bstring sep); +/* bstring bjoinblk (const struct bstrList * bl, void * blk, int len); * * Join the entries of a bstrList into one bstring by sequentially @@ -2268,5 +2371,6 @@ * * Join the entries of a bstrList into one bstring by sequentially - * concatenating them with the sep string in between. If there is an error - * NULL is returned, otherwise a bstring with the correct result is returned. + * concatenating them with the content from blk for length len in between. + * If there is an error NULL is returned, otherwise a bstring with the + * correct result is returned. */ @@ -2272,3 +2376,3 @@ */ -bstring bjoin (const struct bstrList * bl, const_bstring sep) { +bstring bjoinblk (const struct bstrList * bl, const void * blk, int len) { bstring b; @@ -2274,4 +2378,5 @@ bstring b; +unsigned char * p; int i, c, v; if (bl == NULL || bl->qty < 0) return NULL; @@ -2275,7 +2380,8 @@ int i, c, v; if (bl == NULL || bl->qty < 0) return NULL; - if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL; + if (len < 0) return NULL; + if (len > 0 && blk == NULL) return NULL; if (bl->qty < 1) return bfromStatic (""); for (i = 0, c = 1; i < bl->qty; i++) { @@ -2285,6 +2391,4 @@ if (c < 0) return NULL; /* Wrap around ?? */ } - if (sep != NULL) c += (bl->qty - 1) * sep->slen; - b = (bstring) bstr__alloc (sizeof (struct tagbstring)); @@ -2290,7 +2394,36 @@ b = (bstring) bstr__alloc (sizeof (struct tagbstring)); - if (NULL == b) return NULL; /* Out of memory */ - b->data = (unsigned char *) bstr__alloc (c); - if (b->data == NULL) { - bstr__free (b); - return NULL; + if (len == 0) { + p = b->data = (unsigned char *) bstr__alloc (c); + if (p == NULL) { + bstr__free (b); + return NULL; + } + for (i = 0; i < bl->qty; i++) { + v = bl->entry[i]->slen; + bstr__memcpy (p, bl->entry[i]->data, v); + p += v; + } + } else { + v = (bl->qty - 1) * len; + if ((bl->qty > 512 || len > 127) && + v / len != bl->qty - 1) return NULL; /* Wrap around ?? */ + c += v; + if (c < v) return NULL; /* Wrap around ?? */ + p = b->data = (unsigned char *) bstr__alloc (c); + if (p == NULL) { + bstr__free (b); + return NULL; + } + v = bl->entry[0]->slen; + bstr__memcpy (p, bl->entry[0]->data, v); + p += v; + for (i = 1; i < bl->qty; i++) { + bstr__memcpy (p, blk, len); + p += len; + v = bl->entry[i]->slen; + if (v) { + bstr__memcpy (p, bl->entry[i]->data, v); + p += v; + } + } } @@ -2296,4 +2429,3 @@ } - b->mlen = c; b->slen = c-1; @@ -2298,16 +2430,6 @@ b->mlen = c; b->slen = c-1; - - for (i = 0, c = 0; i < bl->qty; i++) { - if (i > 0 && sep != NULL) { - bstr__memcpy (b->data + c, sep->data, sep->slen); - c += sep->slen; - } - v = bl->entry[i]->slen; - bstr__memcpy (b->data + c, bl->entry[i]->data, v); - c += v; - } - b->data[c] = (unsigned char) '\0'; + b->data[c-1] = (unsigned char) '\0'; return b; } @@ -2311,6 +2433,17 @@ return b; } +/* bstring bjoin (const struct bstrList * bl, const_bstring sep); + * + * Join the entries of a bstrList into one bstring by sequentially + * concatenating them with the sep string in between. If there is an error + * NULL is returned, otherwise a bstring with the correct result is returned. + */ +bstring bjoin (const struct bstrList * bl, const_bstring sep) { + if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL; + return bjoinblk (bl, sep->data, sep->slen); +} + #define BSSSC_BUFF_LEN (256) /* int bssplitscb (struct bStream * s, const_bstring splitStr, @@ -2314,7 +2447,8 @@ #define BSSSC_BUFF_LEN (256) /* int bssplitscb (struct bStream * s, const_bstring splitStr, - * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) + * int (* cb) (void * parm, int ofs, const_bstring entry), + * void * parm) * * Iterate the set of disjoint sequential substrings read from a stream * divided by any of the characters in splitStr. An empty splitStr causes @@ -2336,8 +2470,8 @@ bstring buff; int i, p, ret; - if (cb == NULL || s == NULL || s->readFnPtr == NULL - || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR; + if (cb == NULL || s == NULL || s->readFnPtr == NULL || + splitStr == NULL || splitStr->slen < 0) return BSTR_ERR; if (NULL == (buff = bfromcstr (""))) return BSTR_ERR; @@ -2380,7 +2514,8 @@ } /* int bssplitstrcb (struct bStream * s, const_bstring splitStr, - * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) + * int (* cb) (void * parm, int ofs, const_bstring entry), + * void * parm) * * Iterate the set of disjoint sequential substrings read from a stream * divided by the entire substring splitStr. An empty splitStr causes @@ -2446,7 +2581,8 @@ * Create a bstrList. */ struct bstrList * bstrListCreate (void) { -struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList)); +struct bstrList * sl = + (struct bstrList *) bstr__alloc (sizeof (struct bstrList)); if (sl) { sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring)); if (!sl->entry) { @@ -2462,7 +2598,8 @@ /* int bstrListDestroy (struct bstrList * sl) * - * Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate. + * Destroy a bstrList that has been created by bsplit, bsplits or + * bstrListCreate. */ int bstrListDestroy (struct bstrList * sl) { int i; @@ -2490,7 +2627,8 @@ bstring * l; int smsz; size_t nsz; - if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR; + if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || + sl->qty > sl->mlen) return BSTR_ERR; if (sl->mlen >= msz) return BSTR_OK; smsz = snapUpSize (msz); nsz = ((size_t) smsz) * sizeof (bstring); @@ -2515,7 +2653,8 @@ int bstrListAllocMin (struct bstrList * sl, int msz) { bstring * l; size_t nsz; - if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR; + if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || + sl->qty > sl->mlen) return BSTR_ERR; if (msz < sl->qty) msz = sl->qty; if (sl->mlen == msz) return BSTR_OK; nsz = ((size_t) msz) * sizeof (bstring); @@ -2638,7 +2777,8 @@ return bsplitcb (str, splitStr->data[0], pos, cb, parm); for (i=p=pos; i <= str->slen - splitStr->slen; i++) { - if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) { + if (0 == bstr__memcmp (splitStr->data, str->data + i, + splitStr->slen)) { if ((ret = cb (parm, p, i - p)) < 0) return ret; i += splitStr->slen; p = i; @@ -2664,7 +2804,8 @@ mlen += mlen; } - tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen); + tbl = (bstring *) bstr__realloc (g->bl->entry, + sizeof (bstring) * mlen); if (tbl == NULL) return BSTR_ERR; g->bl->entry = tbl; @@ -2979,7 +3120,7 @@ /* Did the operation complete successfully within bounds? */ - if (n >= (l = b->slen + (int) (strlen) ((const char *) b->data + b->slen))) { + if (n >= (l = b->slen + (int) (strlen) ((char *) b->data + b->slen))) { b->slen = l; return BSTR_OK; } diff --git a/bstrlib.h b/bstrlib.h index 9060ef180820b1cc9fb91129c2bc09387ebf8825_YnN0cmxpYi5o..0ed5f17443a8988ea51e12ea00d24ba96d963022_YnN0cmxpYi5o 100644 --- a/bstrlib.h +++ b/bstrlib.h @@ -66,6 +66,7 @@ extern int bcatcstr (bstring b, const char * s); extern int bcatblk (bstring b, const void * s, int len); extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill); +extern int binsertblk (bstring s1, int pos, const void * s2, int len, unsigned char fill); extern int binsertch (bstring s1, int pos, int len, unsigned char fill); extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill); extern int bdelete (bstring s1, int pos, int len); @@ -76,5 +77,6 @@ extern int bstricmp (const_bstring b0, const_bstring b1); extern int bstrnicmp (const_bstring b0, const_bstring b1, int n); extern int biseqcaseless (const_bstring b0, const_bstring b1); +extern int biseqcaselessblk (const_bstring b, const void * blk, int len); extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); extern int biseq (const_bstring b0, const_bstring b1); @@ -79,5 +81,6 @@ extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); extern int biseq (const_bstring b0, const_bstring b1); +extern int biseqblk (const_bstring b, const void * blk, int len); extern int bisstemeqblk (const_bstring b0, const void * blk, int len); extern int biseqcstr (const_bstring b, const char * s); extern int biseqcstrcaseless (const_bstring b, const char * s); @@ -113,6 +116,7 @@ extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr); extern struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr); extern bstring bjoin (const struct bstrList * bl, const_bstring sep); +extern bstring bjoinblk (const struct bstrList * bl, const void * s, int len); extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos, @@ -216,6 +220,11 @@ #define bcatStatic(b,s) ((bcatblk)((b), bsStaticBlkParms(s))) #define bfromStatic(s) ((blk2bstr)(bsStaticBlkParms(s))) #define bassignStatic(b,s) ((bassignblk)((b), bsStaticBlkParms(s))) +#define binsertStatic(b,p,s,f) ((binsertblk)((b), (p), bsStaticBlkParms(s), (f))) +#define bjoinStatic(b,s) ((bjoinblk)((b), bsStaticBlkParms(s))) +#define biseqStatic(b,s) ((biseqblk)((b), bsStaticBlkParms(s))) +#define bisstemeqStatic(b,s) ((bisstemeqblk)((b), bsStaticBlkParms(s))) +#define biseqcaselessStatic(b,s) ((biseqcaselessblk)((b), bsStaticBlkParms(s))) #define bisstemeqcaselessStatic(b,s) ((bisstemeqcaselessblk)((b), bsStaticBlkParms(s))) /* Reference building macros */ diff --git a/bstrlib.txt b/bstrlib.txt index 9060ef180820b1cc9fb91129c2bc09387ebf8825_YnN0cmxpYi50eHQ=..0ed5f17443a8988ea51e12ea00d24ba96d963022_YnN0cmxpYi50eHQ= 100644 --- a/bstrlib.txt +++ b/bstrlib.txt @@ -829,6 +829,17 @@ .......................................................................... + extern int biseqcaselessblk (const_bstring b, const void * blk, int len); + + Compare content of b and the array of bytes in blk for length len for + equality without differentiating between character case. If the content + differs other than in case, 0 is returned, if, ignoring case, the content + is the same, 1 is returned, if there is an error, -1 is returned. If the + length of the strings are different, this function is O(1). '\0' + termination characters are not treated in any special way. + + .......................................................................... + extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); Compare beginning of bstring b0 with a block of memory of length len @@ -839,6 +850,16 @@ .......................................................................... + int biseqblk (const_bstring b, const void * blk, int len) + + Compare the string b with the character block blk of length len. If the + content differs, 0 is returned, if the content is the same, 1 is returned, + if there is an error, -1 is returned. If the length of the strings are + different, this function is O(1). '\0' characters are not treated in + any special way. + + .......................................................................... + extern int biseqcstr (const_bstring b, const char *s); Compare the bstring b and char * bstring s. The C string s must be '\0' @@ -1083,6 +1104,16 @@ .......................................................................... + int binsertblk (bstring b, int pos, const void * blk, int len, + unsigned char fill) + + Inserts the block of characters at blk with length len into b at position + pos. If the position pos is past the end of b, then the character "fill" + is appended as necessary to make up the gap between the end of b1 and pos. + Unlike bsetstr, binsert does not allow b2 to be NULL. + + .......................................................................... + extern int binsertch (bstring s1, int pos, int len, unsigned char fill); Inserts the character fill repeatedly into s1 at position pos for a @@ -1338,6 +1369,15 @@ .......................................................................... + bstring bjoinblk (const struct bstrList * bl, void * blk, int len); + + Join the entries of a bstrList into one bstring by sequentially + concatenating them with the content from blk for length len in between. + If there is an error NULL is returned, otherwise a bstring with the + correct result is returned. + + .......................................................................... + extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, int (* cb) (void * parm, int ofs, int len), void * parm); @@ -1967,6 +2007,15 @@ .......................................................................... + int binsertStatic (bstring s1, int pos, " ... ", char fill); + + Inserts the string literal into s1 at position pos. If the position pos + is past the end of s1, then the character "fill" is appended as necessary + to make up the gap between the end of s1 and pos. The value BSTR_OK is + returned if the operation is successful, otherwise BSTR_ERR is returned. + + .......................................................................... + int bassignStatic (bstring b, " ... "); Assign the contents of a string literal to the bstring b. The string @@ -1974,7 +2023,37 @@ .......................................................................... + int biseqStatic (const_bstring b, " ... "); + + Compare the string b with the string literal. If the content differs, 0 + is returned, if the content is the same, 1 is returned, if there is an + error, -1 is returned. If the length of the strings are different, this + function is O(1). '\0' characters are not treated in any special way. + + .......................................................................... + + int biseqcaselessStatic (const_bstring b, " ... "); + + Compare content of b and the string literal for equality without + differentiating between character case. If the content differs other + than in case, 0 is returned, if, ignoring case, the content is the same, + 1 is returned, if there is an error, -1 is returned. If the length of + the strings are different, this function is O(1). '\0' characters are + not treated in any special way. + + .......................................................................... + + int bisstemeqStatic (bstring b, " ... "); + + Compare beginning of bstring b with a string literal for equality. If + the beginning of b differs from the memory block (or if b is too short), + 0 is returned, if the bstrings are the same, 1 is returned, if there is + an error, -1 is returned. The string literal parameter is enforced as + literal at compile time. + + .......................................................................... + int bisstemeqcaselessStatic (bstring b, " ... "); Compare beginning of bstring b with a string literal without differentiating between case for equality. If the beginning of b differs @@ -1977,11 +2056,11 @@ int bisstemeqcaselessStatic (bstring b, " ... "); Compare beginning of bstring b with a string literal without differentiating between case for equality. If the beginning of b differs - from the memory block other than in case (or if b0 is too short), 0 is + from the memory block other than in case (or if b is too short), 0 is returned, if the bstrings are the same, 1 is returned, if there is an error, -1 is returned. The string literal parameter is enforced as literal at compile time. .......................................................................... @@ -1982,9 +2061,18 @@ returned, if the bstrings are the same, 1 is returned, if there is an error, -1 is returned. The string literal parameter is enforced as literal at compile time. .......................................................................... + bstring bjoinStatic (const struct bstrList * bl, " ... "); + + Join the entries of a bstrList into one bstring by sequentially + concatenating them with the string literal in between. If there is an + error NULL is returned, otherwise a bstring with the correct result is + returned. See bstrListCreate() above for structure of struct bstrList. + + .......................................................................... + void bvformata (int& ret, bstring b, const char * format, lastarg); Append the bstring b with printf like formatting with the format control