Annotation of embedaddon/coova-chilli/bstring/bstrlib.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * This source file is part of the bstring string library.  This code was
                      3:  * written by Paul Hsieh in 2002-2007, and is covered by the BSD open source 
                      4:  * license. Refer to the accompanying documentation for details on usage and 
                      5:  * license.
                      6:  */
                      7: 
                      8: /*
                      9:  * bstrlib.c
                     10:  *
                     11:  * This file is the core module for implementing the bstring functions.
                     12:  */
                     13: 
                     14: #include <stdio.h>
                     15: #include <stddef.h>
                     16: #include <stdarg.h>
                     17: #include <stdlib.h>
                     18: #include <string.h>
                     19: #include <ctype.h>
                     20: #include "bstrlib.h"
                     21: 
                     22: /* Optionally include a mechanism for debugging memory */
                     23: 
                     24: #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
                     25: #include "memdbg.h"
                     26: #endif
                     27: 
                     28: #ifndef bstr__alloc
                     29: #define bstr__alloc(x) malloc (x)
                     30: #endif
                     31: 
                     32: #ifndef bstr__free
                     33: #define bstr__free(p) free (p)
                     34: #endif
                     35: 
                     36: #ifndef bstr__realloc
                     37: #define bstr__realloc(p,x) realloc ((p), (x))
                     38: #endif
                     39: 
                     40: #ifndef bstr__memcpy
                     41: #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
                     42: #endif
                     43: 
                     44: #ifndef bstr__memmove
                     45: #define bstr__memmove(d,s,l) memmove ((d), (s), (l))
                     46: #endif
                     47: 
                     48: #ifndef bstr__memset
                     49: #define bstr__memset(d,c,l) memset ((d), (c), (l))
                     50: #endif
                     51: 
                     52: #ifndef bstr__memcmp
                     53: #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
                     54: #endif
                     55: 
                     56: #ifndef bstr__memchr
                     57: #define bstr__memchr(s,c,l) memchr ((s), (c), (l))
                     58: #endif
                     59: 
                     60: /* Just a length safe wrapper for memmove. */
                     61: 
                     62: #define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); }
                     63: 
                     64: /* Compute the snapped size for a given requested size.  By snapping to powers
                     65:    of 2 like this, repeated reallocations are avoided. */
                     66: static int snapUpSize (int i) {
                     67:        if (i < 8) {
                     68:                i = 8;
                     69:        } else {
                     70:                unsigned int j;
                     71:                j = (unsigned int) i;
                     72: 
                     73:                j |= (j >>  1);
                     74:                j |= (j >>  2);
                     75:                j |= (j >>  4);
                     76:                j |= (j >>  8);         /* Ok, since int >= 16 bits */
                     77: #if (UINT_MAX != 0xffff)
                     78:                j |= (j >> 16);         /* For 32 bit int systems */
                     79: #if (UINT_MAX > 0xffffffffUL)
                     80:                j |= (j >> 32);         /* For 64 bit int systems */
                     81: #endif
                     82: #endif
                     83:                /* Least power of two greater than i */
                     84:                j++;
                     85:                if ((int) j >= i) i = (int) j;
                     86:        }
                     87:        return i;
                     88: }
                     89: 
                     90: /*  int balloc (bstring b, int len)
                     91:  *
                     92:  *  Increase the size of the memory backing the bstring b to at least len.
                     93:  */
                     94: int balloc (bstring b, int olen) {
                     95:        int len;
                     96:        if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 || 
                     97:            b->mlen < b->slen || olen <= 0) {
                     98:                return BSTR_ERR;
                     99:        }
                    100: 
                    101:        if (olen >= b->mlen) {
                    102:                unsigned char * x;
                    103: 
                    104:                if ((len = snapUpSize (olen)) <= b->mlen) return BSTR_OK;
                    105: 
                    106:                /* Assume probability of a non-moving realloc is 0.125 */
                    107:                if (7 * b->mlen < 8 * b->slen) {
                    108: 
                    109:                        /* If slen is close to mlen in size then use realloc to reduce
                    110:                           the memory defragmentation */
                    111: 
                    112:                        reallocStrategy:;
                    113: 
                    114:                        x = (unsigned char *) bstr__realloc (b->data, (size_t) len);
                    115:                        if (x == NULL) {
                    116: 
                    117:                                /* Since we failed, try allocating the tighest possible 
                    118:                                   allocation */
                    119: 
                    120:                                if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) {
                    121:                                        return BSTR_ERR;
                    122:                                }
                    123:                        }
                    124:                } else {
                    125: 
                    126:                        /* If slen is not close to mlen then avoid the penalty of copying
                    127:                           the extra bytes that are allocated, but not considered part of
                    128:                           the string */
                    129: 
                    130:                        if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) {
                    131: 
                    132:                                /* Perhaps there is no available memory for the two 
                    133:                                   allocations to be in memory at once */
                    134: 
                    135:                                goto reallocStrategy;
                    136: 
                    137:                        } else {
                    138:                                if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen);
                    139:                                bstr__free (b->data);
                    140:                        }
                    141:                }
                    142:                b->data = x;
                    143:                b->mlen = len;
                    144:                b->data[b->slen] = (unsigned char) '\0';
                    145:        }
                    146: 
                    147:        return BSTR_OK;
                    148: }
                    149: 
                    150: /*  int ballocmin (bstring b, int len)
                    151:  *
                    152:  *  Set the size of the memory backing the bstring b to len or b->slen+1,
                    153:  *  whichever is larger.  Note that repeated use of this function can degrade
                    154:  *  performance.
                    155:  */
                    156: int ballocmin (bstring b, int len) {
                    157:        unsigned char * s;
                    158: 
                    159:        if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 || 
                    160:            b->mlen < b->slen || len <= 0) {
                    161:                return BSTR_ERR;
                    162:        }
                    163: 
                    164:        if (len < b->slen + 1) len = b->slen + 1;
                    165: 
                    166:        if (len != b->mlen) {
                    167:                s = (unsigned char *) bstr__realloc (b->data, (size_t) len);
                    168:                if (NULL == s) return BSTR_ERR;
                    169:                s[b->slen] = (unsigned char) '\0';
                    170:                b->data = s;
                    171:                b->mlen = len;
                    172:        }
                    173: 
                    174:        return BSTR_OK;
                    175: }
                    176: 
                    177: /*  bstring bfromcstr (const char * str)
                    178:  *
                    179:  *  Create a bstring which contains the contents of the '\0' terminated char *
                    180:  *  buffer str.
                    181:  */
                    182: bstring bfromcstr (const char * str) {
                    183: bstring b;
                    184: int i;
                    185: size_t j;
                    186: 
                    187:        if (str == NULL) return NULL;
                    188:        j = (strlen) (str);
                    189:        i = snapUpSize ((int) (j + (2 - (j != 0))));
                    190:        if (i <= (int) j) return NULL;
                    191: 
                    192:        b = (bstring) bstr__alloc (sizeof (struct tagbstring));
                    193:        if (NULL == b) return NULL;
                    194:        b->slen = (int) j;
                    195:        if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
                    196:                bstr__free (b);
                    197:                return NULL;
                    198:        }
                    199: 
                    200:        bstr__memcpy (b->data, str, j+1);
                    201:        return b;
                    202: }
                    203: 
                    204: /*  bstring bfromcstralloc (int mlen, const char * str)
                    205:  *
                    206:  *  Create a bstring which contains the contents of the '\0' terminated char *
                    207:  *  buffer str.  The memory buffer backing the string is at least len 
                    208:  *  characters in length.
                    209:  */
                    210: bstring bfromcstralloc (int mlen, const char * str) {
                    211: bstring b;
                    212: int i;
                    213: size_t j;
                    214: 
                    215:        if (str == NULL) return NULL;
                    216:        j = (strlen) (str);
                    217:        i = snapUpSize ((int) (j + (2 - (j != 0))));
                    218:        if (i <= (int) j) return NULL;
                    219: 
                    220:        b = (bstring) bstr__alloc (sizeof (struct tagbstring));
                    221:        if (b == NULL) return NULL;
                    222:        b->slen = (int) j;
                    223:        if (i < mlen) i = mlen;
                    224: 
                    225:        if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
                    226:                bstr__free (b);
                    227:                return NULL;
                    228:        }
                    229: 
                    230:        bstr__memcpy (b->data, str, j+1);
                    231:        return b;
                    232: }
                    233: 
                    234: /*  bstring blk2bstr (const void * blk, int len)
                    235:  *
                    236:  *  Create a bstring which contains the content of the block blk of length 
                    237:  *  len.
                    238:  */
                    239: bstring blk2bstr (const void * blk, int len) {
                    240: bstring b;
                    241: int i;
                    242: 
                    243:        if (blk == NULL || len < 0) return NULL;
                    244:        b = (bstring) bstr__alloc (sizeof (struct tagbstring));
                    245:        if (b == NULL) return NULL;
                    246:        b->slen = len;
                    247: 
                    248:        i = len + (2 - (len != 0));
                    249:        i = snapUpSize (i);
                    250: 
                    251:        b->mlen = i;
                    252: 
                    253:        b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen);
                    254:        if (b->data == NULL) {
                    255:                bstr__free (b);
                    256:                return NULL;
                    257:        }
                    258: 
                    259:        if (len > 0) bstr__memcpy (b->data, blk, (size_t) len);
                    260:        b->data[len] = (unsigned char) '\0';
                    261: 
                    262:        return b;
                    263: }
                    264: 
                    265: /*  char * bstr2cstr (const_bstring s, char z)
                    266:  *
                    267:  *  Create a '\0' terminated char * buffer which is equal to the contents of 
                    268:  *  the bstring s, except that any contained '\0' characters are converted 
                    269:  *  to the character in z. This returned value should be freed with a 
                    270:  *  bcstrfree () call, by the calling application.
                    271:  */
                    272: char * bstr2cstr (const_bstring b, char z) {
                    273: int i, l;
                    274: char * r;
                    275: 
                    276:        if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
                    277:        l = b->slen;
                    278:        r = (char *) bstr__alloc ((size_t) (l + 1));
                    279:        if (r == NULL) return r;
                    280: 
                    281:        for (i=0; i < l; i ++) {
                    282:                r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i]));
                    283:        }
                    284: 
                    285:        r[l] = (unsigned char) '\0';
                    286: 
                    287:        return r;
                    288: }
                    289: 
                    290: /*  int bcstrfree (char * s)
                    291:  *
                    292:  *  Frees a C-string generated by bstr2cstr ().  This is normally unnecessary
                    293:  *  since it just wraps a call to bstr__free (), however, if bstr__alloc () 
                    294:  *  and bstr__free () have been redefined as a macros within the bstrlib 
                    295:  *  module (via defining them in memdbg.h after defining 
                    296:  *  BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std 
                    297:  *  library functions, then this allows a correct way of freeing the memory 
                    298:  *  that allows higher level code to be independent from these macro 
                    299:  *  redefinitions.
                    300:  */
                    301: int bcstrfree (char * s) {
                    302:        if (s) {
                    303:                bstr__free (s);
                    304:                return BSTR_OK;
                    305:        }
                    306:        return BSTR_ERR;
                    307: }
                    308: 
                    309: /*  int bconcat (bstring b0, const_bstring b1)
                    310:  *
                    311:  *  Concatenate the bstring b1 to the bstring b0.
                    312:  */
                    313: int bconcat (bstring b0, const_bstring b1) {
                    314: int len, d;
                    315: bstring aux = (bstring) b1;
                    316: 
                    317:        if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR;
                    318: 
                    319:        d = b0->slen;
                    320:        len = b1->slen;
                    321:        if ((d | (b0->mlen - d) | len) < 0) return BSTR_ERR;
                    322: 
                    323:        if (b0->mlen <= d + len + 1) {
                    324:                ptrdiff_t pd;
                    325:                if (0 <= (pd = b1->data - b0->data) && pd < b0->mlen) {
                    326:                        if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
                    327:                }
                    328:                if (balloc (b0, d + len + 1) != BSTR_OK) {
                    329:                        if (aux != b1) bdestroy (aux);
                    330:                        return BSTR_ERR;
                    331:                }
                    332:        }
                    333: 
                    334:        bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len);
                    335:        b0->data[d + len] = (unsigned char) '\0';
                    336:        b0->slen += len;
                    337:        if (aux != b1) bdestroy (aux);
                    338:        return BSTR_OK;
                    339: }
                    340: 
                    341: /*  int bconchar (bstring b, char c)
                    342:  *
                    343:  *  Concatenate the single character c to the bstring b.
                    344:  */
                    345: int bconchar (bstring b, char c) {
                    346: int d;
                    347: 
                    348:        if (b == NULL) return BSTR_ERR;
                    349:        d = b->slen;
                    350:        if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
                    351:        b->data[d] = (unsigned char) c;
                    352:        b->data[d + 1] = (unsigned char) '\0';
                    353:        b->slen++;
                    354:        return BSTR_OK;
                    355: }
                    356: 
                    357: /*  int bcatcstr (bstring b, const char * s)
                    358:  *
                    359:  *  Concatenate a char * string to a bstring.
                    360:  */
                    361: int bcatcstr (bstring b, const char * s) {
                    362: char * d;
                    363: int i, l;
                    364: 
                    365:        if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
                    366:         || b->mlen <= 0 || s == NULL) return BSTR_ERR;
                    367: 
                    368:        /* Optimistically concatenate directly */
                    369:        l = b->mlen - b->slen;
                    370:        d = (char *) &b->data[b->slen];
                    371:        for (i=0; i < l; i++) {
                    372:                if ((*d++ = *s++) == '\0') {
                    373:                        b->slen += i;
                    374:                        return BSTR_OK;
                    375:                }
                    376:        }
                    377:        b->slen += i;
                    378: 
                    379:        /* Need to explicitely resize and concatenate tail */
                    380:        return bcatblk (b, (const void *) s, (int) strlen (s));
                    381: }
                    382: 
                    383: /*  int bcatblk (bstring b, const void * s, int len)
                    384:  *
                    385:  *  Concatenate a fixed length buffer to a bstring.
                    386:  */
                    387: int bcatblk (bstring b, const void * s, int len) {
                    388: int nl;
                    389: 
                    390:        if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
                    391:         || b->mlen <= 0 || s == NULL || len < 0) return BSTR_ERR;
                    392: 
                    393:        if (0 > (nl = b->slen + len)) return BSTR_ERR; /* Overflow? */
                    394:        if (b->mlen <= nl && 0 > balloc (b, nl + 1)) return BSTR_ERR;
                    395: 
                    396:        bBlockCopy (&b->data[b->slen], s, (size_t) len);
                    397:        b->slen = nl;
                    398:        b->data[nl] = (unsigned char) '\0';
                    399:        return BSTR_OK;
                    400: }
                    401: 
                    402: /*  bstring bstrcpy (const_bstring b)
                    403:  *
                    404:  *  Create a copy of the bstring b.
                    405:  */
                    406: bstring bstrcpy (const_bstring b) {
                    407: bstring b0;
                    408: int i,j;
                    409: 
                    410:        /* Attempted to copy an invalid string? */
                    411:        if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
                    412: 
                    413:        b0 = (bstring) bstr__alloc (sizeof (struct tagbstring));
                    414:        if (b0 == NULL) {
                    415:                /* Unable to allocate memory for string header */
                    416:                return NULL;
                    417:        }
                    418: 
                    419:        i = b->slen;
                    420:        j = snapUpSize (i + 1);
                    421: 
                    422:        b0->data = (unsigned char *) bstr__alloc (j);
                    423:        if (b0->data == NULL) {
                    424:                j = i + 1;
                    425:                b0->data = (unsigned char *) bstr__alloc (j);
                    426:                if (b0->data == NULL) {
                    427:                        /* Unable to allocate memory for string data */
                    428:                        bstr__free (b0);
                    429:                        return NULL;
                    430:                }
                    431:        }
                    432: 
                    433:        b0->mlen = j;
                    434:        b0->slen = i;
                    435: 
                    436:        if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i);
                    437:        b0->data[b0->slen] = (unsigned char) '\0';
                    438: 
                    439:        return b0;
                    440: }
                    441: 
                    442: /*  int bassign (bstring a, const_bstring b)
                    443:  *
                    444:  *  Overwrite the string a with the contents of string b.
                    445:  */
                    446: int bassign (bstring a, const_bstring b) {
                    447:        if (b == NULL || b->data == NULL || b->slen < 0)
                    448:                return BSTR_ERR;
                    449:        if (b->slen != 0) {
                    450:                if (balloc (a, b->slen) != BSTR_OK) return BSTR_ERR;
                    451:                bstr__memmove (a->data, b->data, b->slen);
                    452:        } else {
                    453:                if (a == NULL || a->data == NULL || a->mlen < a->slen || 
                    454:                    a->slen < 0 || a->mlen == 0) 
                    455:                        return BSTR_ERR;
                    456:        }
                    457:        a->data[b->slen] = (unsigned char) '\0';
                    458:        a->slen = b->slen;
                    459:        return BSTR_OK;
                    460: }
                    461: 
                    462: /*  int bassignmidstr (bstring a, const_bstring b, int left, int len)
                    463:  *
                    464:  *  Overwrite the string a with the middle of contents of string b 
                    465:  *  starting from position left and running for a length len.  left and 
                    466:  *  len are clamped to the ends of b as with the function bmidstr.
                    467:  */
                    468: int bassignmidstr (bstring a, const_bstring b, int left, int len) {
                    469:        if (b == NULL || b->data == NULL || b->slen < 0)
                    470:                return BSTR_ERR;
                    471: 
                    472:        if (left < 0) {
                    473:                len += left;
                    474:                left = 0;
                    475:        }
                    476: 
                    477:        if (len > b->slen - left) len = b->slen - left;
                    478: 
                    479:        if (a == NULL || a->data == NULL || a->mlen < a->slen ||
                    480:            a->slen < 0 || a->mlen == 0)
                    481:                return BSTR_ERR;
                    482: 
                    483:        if (len > 0) {
                    484:                if (balloc (a, len) != BSTR_OK) return BSTR_ERR;
                    485:                bstr__memmove (a->data, b->data + left, len);
                    486:                a->slen = len;
                    487:        } else {
                    488:                a->slen = 0;
                    489:        }
                    490:        a->data[a->slen] = (unsigned char) '\0';
                    491:        return BSTR_OK;
                    492: }
                    493: 
                    494: /*  int bassigncstr (bstring a, const char * str)
                    495:  *
                    496:  *  Overwrite the string a with the contents of char * string str.  Note that 
                    497:  *  the bstring a must be a well defined and writable bstring.  If an error 
                    498:  *  occurs BSTR_ERR is returned however a may be partially overwritten.
                    499:  */
                    500: int bassigncstr (bstring a, const char * str) {
                    501: int i;
                    502: size_t len;
                    503:        if (a == NULL || a->data == NULL || a->mlen < a->slen ||
                    504:            a->slen < 0 || a->mlen == 0 || NULL == str) 
                    505:                return BSTR_ERR;
                    506: 
                    507:        for (i=0; i < a->mlen; i++) {
                    508:                if ('\0' == (a->data[i] = str[i])) {
                    509:                        a->slen = i;
                    510:                        return BSTR_OK;
                    511:                }
                    512:        }
                    513: 
                    514:        a->slen = i;
                    515:        len = strlen (str + i);
                    516:        if (len > INT_MAX || i + len + 1 > INT_MAX ||
                    517:            0 > balloc (a, (int) (i + len + 1))) return BSTR_ERR;
                    518:        bBlockCopy (a->data + i, str + i, (size_t) len + 1);
                    519:        a->slen += (int) len;
                    520:        return BSTR_OK;
                    521: }
                    522: 
                    523: /*  int bassignblk (bstring a, const void * s, int len)
                    524:  *
                    525:  *  Overwrite the string a with the contents of the block (s, len).  Note that 
                    526:  *  the bstring a must be a well defined and writable bstring.  If an error 
                    527:  *  occurs BSTR_ERR is returned and a is not overwritten.
                    528:  */
                    529: int bassignblk (bstring a, const void * s, int len) {
                    530:        if (a == NULL || a->data == NULL || a->mlen < a->slen ||
                    531:            a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1) 
                    532:                return BSTR_ERR;
                    533:        if (len + 1 > a->mlen && 0 > balloc (a, len + 1)) return BSTR_ERR;
                    534:        bBlockCopy (a->data, s, (size_t) len);
                    535:        a->data[len] = (unsigned char) '\0';
                    536:        a->slen = len;
                    537:        return BSTR_OK;
                    538: }
                    539: 
                    540: /*  int btrunc (bstring b, int n)
                    541:  *
                    542:  *  Truncate the bstring to at most n characters.
                    543:  */
                    544: int btrunc (bstring b, int n) {
                    545:        if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen ||
                    546:            b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
                    547:        if (b->slen > n) {
                    548:                b->slen = n;
                    549:                b->data[n] = (unsigned char) '\0';
                    550:        }
                    551:        return BSTR_OK;
                    552: }
                    553: 
                    554: #define   upcase(c) (toupper ((unsigned char) c))
                    555: #define downcase(c) (tolower ((unsigned char) c))
                    556: #define   wspace(c) (isspace ((unsigned char) c))
                    557: 
                    558: /*  int btoupper (bstring b)
                    559:  *
                    560:  *  Convert contents of bstring to upper case.
                    561:  */
                    562: int btoupper (bstring b) {
                    563: int i, len;
                    564:        if (b == NULL || b->data == NULL || b->mlen < b->slen ||
                    565:            b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
                    566:        for (i=0, len = b->slen; i < len; i++) {
                    567:                b->data[i] = (unsigned char) upcase (b->data[i]);
                    568:        }
                    569:        return BSTR_OK;
                    570: }
                    571: 
                    572: /*  int btolower (bstring b)
                    573:  *
                    574:  *  Convert contents of bstring to lower case.
                    575:  */
                    576: int btolower (bstring b) {
                    577: int i, len;
                    578:        if (b == NULL || b->data == NULL || b->mlen < b->slen ||
                    579:            b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
                    580:        for (i=0, len = b->slen; i < len; i++) {
                    581:                b->data[i] = (unsigned char) downcase (b->data[i]);
                    582:        }
                    583:        return BSTR_OK;
                    584: }
                    585: 
                    586: /*  int bstricmp (const_bstring b0, const_bstring b1)
                    587:  *
                    588:  *  Compare two strings without differentiating between case.  The return 
                    589:  *  value is the difference of the values of the characters where the two 
                    590:  *  strings first differ after lower case transformation, otherwise 0 is 
                    591:  *  returned indicating that the strings are equal.  If the lengths are 
                    592:  *  different, then a difference from 0 is given, but if the first extra 
                    593:  *  character is '\0', then it is taken to be the value UCHAR_MAX+1.
                    594:  */
                    595: int bstricmp (const_bstring b0, const_bstring b1) {
                    596: int i, v, n;
                    597: 
                    598:        if (bdata (b0) == NULL || b0->slen < 0 || 
                    599:            bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN;
                    600:        if ((n = b0->slen) > b1->slen) n = b1->slen;
                    601:        else if (b0->slen == b1->slen && b0->data == b1->data) return BSTR_OK;
                    602: 
                    603:        for (i = 0; i < n; i ++) {
                    604:                v  = (char) downcase (b0->data[i])
                    605:                   - (char) downcase (b1->data[i]);
                    606:                if (0 != v) return v;
                    607:        }
                    608: 
                    609:        if (b0->slen > n) {
                    610:                v = (char) downcase (b0->data[n]);
                    611:                if (v) return v;
                    612:                return UCHAR_MAX + 1;
                    613:        }
                    614:        if (b1->slen > n) {
                    615:                v = - (char) downcase (b1->data[n]);
                    616:                if (v) return v;
                    617:                return - (int) (UCHAR_MAX + 1);
                    618:        }
                    619:        return BSTR_OK;
                    620: }
                    621: 
                    622: /*  int bstrnicmp (const_bstring b0, const_bstring b1, int n)
                    623:  *
                    624:  *  Compare two strings without differentiating between case for at most n
                    625:  *  characters.  If the position where the two strings first differ is
                    626:  *  before the nth position, the return value is the difference of the values
                    627:  *  of the characters, otherwise 0 is returned.  If the lengths are different
                    628:  *  and less than n characters, then a difference from 0 is given, but if the 
                    629:  *  first extra character is '\0', then it is taken to be the value 
                    630:  *  UCHAR_MAX+1.
                    631:  */
                    632: int bstrnicmp (const_bstring b0, const_bstring b1, int n) {
                    633: int i, v, m;
                    634: 
                    635:        if (bdata (b0) == NULL || b0->slen < 0 || 
                    636:            bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN;
                    637:        m = n;
                    638:        if (m > b0->slen) m = b0->slen;
                    639:        if (m > b1->slen) m = b1->slen;
                    640: 
                    641:        if (b0->data != b1->data) {
                    642:                for (i = 0; i < m; i ++) {
                    643:                        v  = (char) downcase (b0->data[i]);
                    644:                        v -= (char) downcase (b1->data[i]);
                    645:                        if (v != 0) return b0->data[i] - b1->data[i];
                    646:                }
                    647:        }
                    648: 
                    649:        if (n == m || b0->slen == b1->slen) return BSTR_OK;
                    650: 
                    651:        if (b0->slen > m) {
                    652:                v = (char) downcase (b0->data[m]);
                    653:                if (v) return v;
                    654:                return UCHAR_MAX + 1;
                    655:        }
                    656: 
                    657:        v = - (char) downcase (b1->data[m]);
                    658:        if (v) return v;
                    659:        return - (int) (UCHAR_MAX + 1);
                    660: }
                    661: 
                    662: /*  int biseqcaseless (const_bstring b0, const_bstring b1)
                    663:  *
                    664:  *  Compare two strings for equality without differentiating between case.  
                    665:  *  If the strings differ other than in case, 0 is returned, if the strings 
                    666:  *  are the same, 1 is returned, if there is an error, -1 is returned.  If 
                    667:  *  the length of the strings are different, this function is O(1).  '\0' 
                    668:  *  termination characters are not treated in any special way.
                    669:  */
                    670: int biseqcaseless (const_bstring b0, const_bstring b1) {
                    671: int i, n;
                    672: 
                    673:        if (bdata (b0) == NULL || b0->slen < 0 || 
                    674:            bdata (b1) == NULL || b1->slen < 0) return BSTR_ERR;
                    675:        if (b0->slen != b1->slen) return BSTR_OK;
                    676:        if (b0->data == b1->data || b0->slen == 0) return 1;
                    677:        for (i=0, n=b0->slen; i < n; i++) {
                    678:                if (b0->data[i] != b1->data[i]) {
                    679:                        unsigned char c = (unsigned char) downcase (b0->data[i]);
                    680:                        if (c != (unsigned char) downcase (b1->data[i])) return 0;
                    681:                }
                    682:        }
                    683:        return 1;
                    684: }
                    685: 
                    686: /*  int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len)
                    687:  *
                    688:  *  Compare beginning of string b0 with a block of memory of length len 
                    689:  *  without differentiating between case for equality.  If the beginning of b0
                    690:  *  differs from the memory block other than in case (or if b0 is too short), 
                    691:  *  0 is returned, if the strings are the same, 1 is returned, if there is an 
                    692:  *  error, -1 is returned.  '\0' characters are not treated in any special 
                    693:  *  way.
                    694:  */
                    695: int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) {
                    696: int i;
                    697: 
                    698:        if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
                    699:                return BSTR_ERR;
                    700:        if (b0->slen < len) return BSTR_OK;
                    701:        if (b0->data == (const unsigned char *) blk || len == 0) return 1;
                    702: 
                    703:        for (i = 0; i < len; i ++) {
                    704:                if (b0->data[i] != ((const unsigned char *) blk)[i]) {
                    705:                        if (downcase (b0->data[i]) != 
                    706:                            downcase (((const unsigned char *) blk)[i])) return 0;
                    707:                }
                    708:        }
                    709:        return 1;
                    710: }
                    711: 
                    712: /*
                    713:  * int bltrimws (bstring b)
                    714:  *
                    715:  * Delete whitespace contiguous from the left end of the string.
                    716:  */
                    717: int bltrimws (bstring b) {
                    718: int i, len;
                    719: 
                    720:        if (b == NULL || b->data == NULL || b->mlen < b->slen ||
                    721:            b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
                    722: 
                    723:        for (len = b->slen, i = 0; i < len; i++) {
                    724:                if (!wspace (b->data[i])) {
                    725:                        return bdelete (b, 0, i);
                    726:                }
                    727:        }
                    728: 
                    729:        b->data[0] = (unsigned char) '\0';
                    730:        b->slen = 0;
                    731:        return BSTR_OK;
                    732: }
                    733: 
                    734: /*
                    735:  * int brtrimws (bstring b)
                    736:  *
                    737:  * Delete whitespace contiguous from the right end of the string.
                    738:  */
                    739: int brtrimws (bstring b) {
                    740: int i;
                    741: 
                    742:        if (b == NULL || b->data == NULL || b->mlen < b->slen ||
                    743:            b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
                    744: 
                    745:        for (i = b->slen - 1; i >= 0; i--) {
                    746:                if (!wspace (b->data[i])) {
                    747:                        if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
                    748:                        b->slen = i + 1;
                    749:                        return BSTR_OK;
                    750:                }
                    751:        }
                    752: 
                    753:        b->data[0] = (unsigned char) '\0';
                    754:        b->slen = 0;
                    755:        return BSTR_OK;
                    756: }
                    757: 
                    758: /*
                    759:  * int btrimws (bstring b)
                    760:  *
                    761:  * Delete whitespace contiguous from both ends of the string.
                    762:  */
                    763: int btrimws (bstring b) {
                    764: int i, j;
                    765: 
                    766:        if (b == NULL || b->data == NULL || b->mlen < b->slen ||
                    767:            b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
                    768: 
                    769:        for (i = b->slen - 1; i >= 0; i--) {
                    770:                if (!wspace (b->data[i])) {
                    771:                        if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
                    772:                        b->slen = i + 1;
                    773:                        for (j = 0; wspace (b->data[j]); j++) {}
                    774:                        return bdelete (b, 0, j);
                    775:                }
                    776:        }
                    777: 
                    778:        b->data[0] = (unsigned char) '\0';
                    779:        b->slen = 0;
                    780:        return BSTR_OK;
                    781: }
                    782: 
                    783: /*  int biseq (const_bstring b0, const_bstring b1)
                    784:  *
                    785:  *  Compare the string b0 and b1.  If the strings differ, 0 is returned, if 
                    786:  *  the strings are the same, 1 is returned, if there is an error, -1 is 
                    787:  *  returned.  If the length of the strings are different, this function is
                    788:  *  O(1).  '\0' termination characters are not treated in any special way.
                    789:  */
                    790: int biseq (const_bstring b0, const_bstring b1) {
                    791:        if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
                    792:                b0->slen < 0 || b1->slen < 0) return BSTR_ERR;
                    793:        if (b0->slen != b1->slen) return BSTR_OK;
                    794:        if (b0->data == b1->data || b0->slen == 0) return 1;
                    795:        return !bstr__memcmp (b0->data, b1->data, b0->slen);
                    796: }
                    797: 
                    798: /*  int bisstemeqblk (const_bstring b0, const void * blk, int len)
                    799:  *
                    800:  *  Compare beginning of string b0 with a block of memory of length len for 
                    801:  *  equality.  If the beginning of b0 differs from the memory block (or if b0 
                    802:  *  is too short), 0 is returned, if the strings are the same, 1 is returned, 
                    803:  *  if there is an error, -1 is returned.  '\0' characters are not treated in 
                    804:  *  any special way.
                    805:  */
                    806: int bisstemeqblk (const_bstring b0, const void * blk, int len) {
                    807: int i;
                    808: 
                    809:        if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
                    810:                return BSTR_ERR;
                    811:        if (b0->slen < len) return BSTR_OK;
                    812:        if (b0->data == (const unsigned char *) blk || len == 0) return 1;
                    813: 
                    814:        for (i = 0; i < len; i ++) {
                    815:                if (b0->data[i] != ((const unsigned char *) blk)[i]) return BSTR_OK;
                    816:        }
                    817:        return 1;
                    818: }
                    819: 
                    820: /*  int biseqcstr (const_bstring b, const char *s)
                    821:  *
                    822:  *  Compare the bstring b and char * string s.  The C string s must be '\0' 
                    823:  *  terminated at exactly the length of the bstring b, and the contents 
                    824:  *  between the two must be identical with the bstring b with no '\0' 
                    825:  *  characters for the two contents to be considered equal.  This is 
                    826:  *  equivalent to the condition that their current contents will be always be 
                    827:  *  equal when comparing them in the same format after converting one or the 
                    828:  *  other.  If the strings are equal 1 is returned, if they are unequal 0 is 
                    829:  *  returned and if there is a detectable error BSTR_ERR is returned.
                    830:  */
                    831: int biseqcstr (const_bstring b, const char * s) {
                    832: int i;
                    833:        if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
                    834:        for (i=0; i < b->slen; i++) {
                    835:                if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK;
                    836:        }
                    837:        return s[i] == '\0';
                    838: }
                    839: 
                    840: /*  int biseqcstrcaseless (const_bstring b, const char *s)
                    841:  *
                    842:  *  Compare the bstring b and char * string s.  The C string s must be '\0' 
                    843:  *  terminated at exactly the length of the bstring b, and the contents 
                    844:  *  between the two must be identical except for case with the bstring b with 
                    845:  *  no '\0' characters for the two contents to be considered equal.  This is 
                    846:  *  equivalent to the condition that their current contents will be always be 
                    847:  *  equal ignoring case when comparing them in the same format after 
                    848:  *  converting one or the other.  If the strings are equal, except for case, 
                    849:  *  1 is returned, if they are unequal regardless of case 0 is returned and 
                    850:  *  if there is a detectable error BSTR_ERR is returned.
                    851:  */
                    852: int biseqcstrcaseless (const_bstring b, const char * s) {
                    853: int i;
                    854:        if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
                    855:        for (i=0; i < b->slen; i++) {
                    856:                if (s[i] == '\0' || 
                    857:                    (b->data[i] != (unsigned char) s[i] && 
                    858:                     downcase (b->data[i]) != (unsigned char) downcase (s[i])))
                    859:                        return BSTR_OK;
                    860:        }
                    861:        return s[i] == '\0';
                    862: }
                    863: 
                    864: /*  int bstrcmp (const_bstring b0, const_bstring b1)
                    865:  *
                    866:  *  Compare the string b0 and b1.  If there is an error, SHRT_MIN is returned, 
                    867:  *  otherwise a value less than or greater than zero, indicating that the 
                    868:  *  string pointed to by b0 is lexicographically less than or greater than 
                    869:  *  the string pointed to by b1 is returned.  If the the string lengths are 
                    870:  *  unequal but the characters up until the length of the shorter are equal 
                    871:  *  then a value less than, or greater than zero, indicating that the string 
                    872:  *  pointed to by b0 is shorter or longer than the string pointed to by b1 is 
                    873:  *  returned.  0 is returned if and only if the two strings are the same.  If 
                    874:  *  the length of the strings are different, this function is O(n).  Like its
                    875:  *  standard C library counter part strcmp, the comparison does not proceed 
                    876:  *  past any '\0' termination characters encountered.
                    877:  */
                    878: int bstrcmp (const_bstring b0, const_bstring b1) {
                    879: int i, v, n;
                    880: 
                    881:        if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
                    882:                b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
                    883:        n = b0->slen; if (n > b1->slen) n = b1->slen;
                    884:        if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0))
                    885:                return BSTR_OK;
                    886: 
                    887:        for (i = 0; i < n; i ++) {
                    888:                v = ((char) b0->data[i]) - ((char) b1->data[i]);
                    889:                if (v != 0) return v;
                    890:                if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
                    891:        }
                    892: 
                    893:        if (b0->slen > n) return 1;
                    894:        if (b1->slen > n) return -1;
                    895:        return BSTR_OK;
                    896: }
                    897: 
                    898: /*  int bstrncmp (const_bstring b0, const_bstring b1, int n)
                    899:  *
                    900:  *  Compare the string b0 and b1 for at most n characters.  If there is an 
                    901:  *  error, SHRT_MIN is returned, otherwise a value is returned as if b0 and 
                    902:  *  b1 were first truncated to at most n characters then bstrcmp was called
                    903:  *  with these new strings are paremeters.  If the length of the strings are 
                    904:  *  different, this function is O(n).  Like its standard C library counter 
                    905:  *  part strcmp, the comparison does not proceed past any '\0' termination 
                    906:  *  characters encountered.
                    907:  */
                    908: int bstrncmp (const_bstring b0, const_bstring b1, int n) {
                    909: int i, v, m;
                    910: 
                    911:        if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
                    912:                b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
                    913:        m = n;
                    914:        if (m > b0->slen) m = b0->slen;
                    915:        if (m > b1->slen) m = b1->slen;
                    916: 
                    917:        if (b0->data != b1->data) {
                    918:                for (i = 0; i < m; i ++) {
                    919:                        v = ((char) b0->data[i]) - ((char) b1->data[i]);
                    920:                        if (v != 0) return v;
                    921:                        if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
                    922:                }
                    923:        }
                    924: 
                    925:        if (n == m || b0->slen == b1->slen) return BSTR_OK;
                    926: 
                    927:        if (b0->slen > m) return 1;
                    928:        return -1;
                    929: }
                    930: 
                    931: /*  bstring bmidstr (const_bstring b, int left, int len)
                    932:  *
                    933:  *  Create a bstring which is the substring of b starting from position left
                    934:  *  and running for a length len (clamped by the end of the bstring b.)  If
                    935:  *  b is detectably invalid, then NULL is returned.  The section described 
                    936:  *  by (left, len) is clamped to the boundaries of b.
                    937:  */
                    938: bstring bmidstr (const_bstring b, int left, int len) {
                    939: 
                    940:        if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
                    941: 
                    942:        if (left < 0) {
                    943:                len += left;
                    944:                left = 0;
                    945:        }
                    946: 
                    947:        if (len > b->slen - left) len = b->slen - left;
                    948: 
                    949:        if (len <= 0) return bfromcstr ("");
                    950:        return blk2bstr (b->data + left, len);
                    951: }
                    952: 
                    953: /*  int bdelete (bstring b, int pos, int len)
                    954:  *
                    955:  *  Removes characters from pos to pos+len-1 inclusive and shifts the tail of 
                    956:  *  the bstring starting from pos+len to pos.  len must be positive for this 
                    957:  *  call to have any effect.  The section of the string described by (pos, 
                    958:  *  len) is clamped to boundaries of the bstring b.
                    959:  */
                    960: int bdelete (bstring b, int pos, int len) {
                    961:        /* Clamp to left side of bstring */
                    962:        if (pos < 0) {
                    963:                len += pos;
                    964:                pos = 0;
                    965:        }
                    966: 
                    967:        if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 || 
                    968:            b->mlen < b->slen || b->mlen <= 0) 
                    969:                return BSTR_ERR;
                    970:        if (len > 0 && pos < b->slen) {
                    971:                if (pos + len >= b->slen) {
                    972:                        b->slen = pos;
                    973:                } else {
                    974:                        bBlockCopy ((char *) (b->data + pos),
                    975:                                    (char *) (b->data + pos + len), 
                    976:                                    b->slen - (pos+len));
                    977:                        b->slen -= len;
                    978:                }
                    979:                b->data[b->slen] = (unsigned char) '\0';
                    980:        }
                    981:        return BSTR_OK;
                    982: }
                    983: 
                    984: /*  int bdestroy (bstring b)
                    985:  *
                    986:  *  Free up the bstring.  Note that if b is detectably invalid or not writable
                    987:  *  then no action is performed and BSTR_ERR is returned.  Like a freed memory
                    988:  *  allocation, dereferences, writes or any other action on b after it has 
                    989:  *  been bdestroyed is undefined.
                    990:  */
                    991: int bdestroy (bstring b) {
                    992:        if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen ||
                    993:            b->data == NULL)
                    994:                return BSTR_ERR;
                    995: 
                    996:        bstr__free (b->data);
                    997: 
                    998:        /* In case there is any stale usage, there is one more chance to 
                    999:           notice this error. */
                   1000: 
                   1001:        b->slen = -1;
                   1002:        b->mlen = -__LINE__;
                   1003:        b->data = NULL;
                   1004: 
                   1005:        bstr__free (b);
                   1006:        return BSTR_OK;
                   1007: }
                   1008: 
                   1009: /*  int binstr (const_bstring b1, int pos, const_bstring b2)
                   1010:  *
                   1011:  *  Search for the bstring b2 in b1 starting from position pos, and searching 
                   1012:  *  forward.  If it is found then return with the first position where it is 
                   1013:  *  found, otherwise return BSTR_ERR.  Note that this is just a brute force 
                   1014:  *  string searcher that does not attempt clever things like the Boyer-Moore 
                   1015:  *  search algorithm.  Because of this there are many degenerate cases where 
                   1016:  *  this can take much longer than it needs to.
                   1017:  */
                   1018: int binstr (const_bstring b1, int pos, const_bstring b2) {
                   1019: int j, ii, ll, lf;
                   1020: unsigned char * d0;
                   1021: unsigned char c0;
                   1022: register unsigned char * d1;
                   1023: register unsigned char c1;
                   1024: register int i;
                   1025: 
                   1026:        if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
                   1027:            b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
                   1028:        if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
                   1029:        if (b1->slen < pos || pos < 0) return BSTR_ERR;
                   1030:        if (b2->slen == 0) return pos;
                   1031: 
                   1032:        /* No space to find such a string? */
                   1033:        if ((lf = b1->slen - b2->slen + 1) <= pos) return BSTR_ERR;
                   1034: 
                   1035:        /* An obvious alias case */
                   1036:        if (b1->data == b2->data && pos == 0) return 0;
                   1037: 
                   1038:        i = pos;
                   1039: 
                   1040:        d0 = b2->data;
                   1041:        d1 = b1->data;
                   1042:        ll = b2->slen;
                   1043: 
                   1044:        /* Peel off the b2->slen == 1 case */
                   1045:        c0 = d0[0];
                   1046:        if (1 == ll) {
                   1047:                for (;i < lf; i++) if (c0 == d1[i]) return i;
                   1048:                return BSTR_ERR;
                   1049:        }
                   1050: 
                   1051:        c1 = c0;
                   1052:        j = 0;
                   1053:        lf = b1->slen - 1;
                   1054: 
                   1055:        ii = -1;
                   1056:        if (i < lf) do {
                   1057:                /* Unrolled current character test */
                   1058:                if (c1 != d1[i]) {
                   1059:                        if (c1 != d1[1+i]) {
                   1060:                                i += 2;
                   1061:                                continue;
                   1062:                        }
                   1063:                        i++;
                   1064:                }
                   1065: 
                   1066:                /* Take note if this is the start of a potential match */
                   1067:                if (0 == j) ii = i;
                   1068: 
                   1069:                /* Shift the test character down by one */
                   1070:                j++;
                   1071:                i++;
                   1072: 
                   1073:                /* If this isn't past the last character continue */
                   1074:                if (j < ll) {
                   1075:                        c1 = d0[j];
                   1076:                        continue;
                   1077:                }
                   1078: 
                   1079:                N0:;
                   1080: 
                   1081:                /* If no characters mismatched, then we matched */
                   1082:                if (i == ii+j) return ii;
                   1083: 
                   1084:                /* Shift back to the beginning */
                   1085:                i -= j;
                   1086:                j  = 0;
                   1087:                c1 = c0;
                   1088:        } while (i < lf);
                   1089: 
                   1090:        /* Deal with last case if unrolling caused a misalignment */
                   1091:        if (i == lf && ll == j+1 && c1 == d1[i]) goto N0;
                   1092: 
                   1093:        return BSTR_ERR;
                   1094: }
                   1095: 
                   1096: /*  int binstrr (const_bstring b1, int pos, const_bstring b2)
                   1097:  *
                   1098:  *  Search for the bstring b2 in b1 starting from position pos, and searching 
                   1099:  *  backward.  If it is found then return with the first position where it is 
                   1100:  *  found, otherwise return BSTR_ERR.  Note that this is just a brute force 
                   1101:  *  string searcher that does not attempt clever things like the Boyer-Moore 
                   1102:  *  search algorithm.  Because of this there are many degenerate cases where 
                   1103:  *  this can take much longer than it needs to.
                   1104:  */
                   1105: int binstrr (const_bstring b1, int pos, const_bstring b2) {
                   1106: int j, i, l;
                   1107: unsigned char * d0, * d1;
                   1108: 
                   1109:        if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
                   1110:            b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
                   1111:        if (b1->slen == pos && b2->slen == 0) return pos;
                   1112:        if (b1->slen < pos || pos < 0) return BSTR_ERR;
                   1113:        if (b2->slen == 0) return pos;
                   1114: 
                   1115:        /* Obvious alias case */
                   1116:        if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0;
                   1117: 
                   1118:        i = pos;
                   1119:        if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
                   1120: 
                   1121:        /* If no space to find such a string then snap back */
                   1122:        if (l + 1 <= i) i = l;
                   1123:        j = 0;
                   1124: 
                   1125:        d0 = b2->data;
                   1126:        d1 = b1->data;
                   1127:        l  = b2->slen;
                   1128: 
                   1129:        for (;;) {
                   1130:                if (d0[j] == d1[i + j]) {
                   1131:                        j ++;
                   1132:                        if (j >= l) return i;
                   1133:                } else {
                   1134:                        i --;
                   1135:                        if (i < 0) break;
                   1136:                        j=0;
                   1137:                }
                   1138:        }
                   1139: 
                   1140:        return BSTR_ERR;
                   1141: }
                   1142: 
                   1143: /*  int binstrcaseless (const_bstring b1, int pos, const_bstring b2)
                   1144:  *
                   1145:  *  Search for the bstring b2 in b1 starting from position pos, and searching 
                   1146:  *  forward but without regard to case.  If it is found then return with the 
                   1147:  *  first position where it is found, otherwise return BSTR_ERR.  Note that 
                   1148:  *  this is just a brute force string searcher that does not attempt clever 
                   1149:  *  things like the Boyer-Moore search algorithm.  Because of this there are 
                   1150:  *  many degenerate cases where this can take much longer than it needs to.
                   1151:  */
                   1152: int binstrcaseless (const_bstring b1, int pos, const_bstring b2) {
                   1153: int j, i, l, ll;
                   1154: unsigned char * d0, * d1;
                   1155: 
                   1156:        if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
                   1157:            b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
                   1158:        if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
                   1159:        if (b1->slen < pos || pos < 0) return BSTR_ERR;
                   1160:        if (b2->slen == 0) return pos;
                   1161: 
                   1162:        l = b1->slen - b2->slen + 1;
                   1163: 
                   1164:        /* No space to find such a string? */
                   1165:        if (l <= pos) return BSTR_ERR;
                   1166: 
                   1167:        /* An obvious alias case */
                   1168:        if (b1->data == b2->data && pos == 0) return BSTR_OK;
                   1169: 
                   1170:        i = pos;
                   1171:        j = 0;
                   1172: 
                   1173:        d0 = b2->data;
                   1174:        d1 = b1->data;
                   1175:        ll = b2->slen;
                   1176: 
                   1177:        for (;;) {
                   1178:                if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
                   1179:                        j ++;
                   1180:                        if (j >= ll) return i;
                   1181:                } else {
                   1182:                        i ++;
                   1183:                        if (i >= l) break;
                   1184:                        j=0;
                   1185:                }
                   1186:        }
                   1187: 
                   1188:        return BSTR_ERR;
                   1189: }
                   1190: 
                   1191: /*  int binstrrcaseless (const_bstring b1, int pos, const_bstring b2)
                   1192:  *
                   1193:  *  Search for the bstring b2 in b1 starting from position pos, and searching 
                   1194:  *  backward but without regard to case.  If it is found then return with the 
                   1195:  *  first position where it is found, otherwise return BSTR_ERR.  Note that 
                   1196:  *  this is just a brute force string searcher that does not attempt clever 
                   1197:  *  things like the Boyer-Moore search algorithm.  Because of this there are 
                   1198:  *  many degenerate cases where this can take much longer than it needs to.
                   1199:  */
                   1200: int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) {
                   1201: int j, i, l;
                   1202: unsigned char * d0, * d1;
                   1203: 
                   1204:        if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
                   1205:            b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
                   1206:        if (b1->slen == pos && b2->slen == 0) return pos;
                   1207:        if (b1->slen < pos || pos < 0) return BSTR_ERR;
                   1208:        if (b2->slen == 0) return pos;
                   1209: 
                   1210:        /* Obvious alias case */
                   1211:        if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK;
                   1212: 
                   1213:        i = pos;
                   1214:        if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
                   1215: 
                   1216:        /* If no space to find such a string then snap back */
                   1217:        if (l + 1 <= i) i = l;
                   1218:        j = 0;
                   1219: 
                   1220:        d0 = b2->data;
                   1221:        d1 = b1->data;
                   1222:        l  = b2->slen;
                   1223: 
                   1224:        for (;;) {
                   1225:                if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
                   1226:                        j ++;
                   1227:                        if (j >= l) return i;
                   1228:                } else {
                   1229:                        i --;
                   1230:                        if (i < 0) break;
                   1231:                        j=0;
                   1232:                }
                   1233:        }
                   1234: 
                   1235:        return BSTR_ERR;
                   1236: }
                   1237: 
                   1238: 
                   1239: /*  int bstrchrp (const_bstring b, int c, int pos)
                   1240:  *
                   1241:  *  Search for the character c in b forwards from the position pos 
                   1242:  *  (inclusive).
                   1243:  */
                   1244: int bstrchrp (const_bstring b, int c, int pos) {
                   1245: unsigned char * p;
                   1246: 
                   1247:        if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
                   1248:        p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos));
                   1249:        if (p) return (int) (p - b->data);
                   1250:        return BSTR_ERR;
                   1251: }
                   1252: 
                   1253: /*  int bstrrchrp (const_bstring b, int c, int pos)
                   1254:  *
                   1255:  *  Search for the character c in b backwards from the position pos in string 
                   1256:  *  (inclusive).
                   1257:  */
                   1258: int bstrrchrp (const_bstring b, int c, int pos) {
                   1259: int i;
                   1260:  
                   1261:        if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
                   1262:        for (i=pos; i >= 0; i--) {
                   1263:                if (b->data[i] == (unsigned char) c) return i;
                   1264:        }
                   1265:        return BSTR_ERR;
                   1266: }
                   1267: 
                   1268: #if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF)
                   1269: #define LONG_LOG_BITS_QTY (3)
                   1270: #define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY)
                   1271: #define LONG_TYPE unsigned char
                   1272: 
                   1273: #define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY)
                   1274: struct charField { LONG_TYPE content[CFCLEN]; };
                   1275: #define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1))))
                   1276: #define setInCharField(cf,idx) { \
                   1277:        unsigned int c = (unsigned int) (idx); \
                   1278:        (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \
                   1279: }
                   1280: 
                   1281: #else
                   1282: 
                   1283: #define CFCLEN (1 << CHAR_BIT)
                   1284: struct charField { unsigned char content[CFCLEN]; };
                   1285: #define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)])
                   1286: #define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0
                   1287: 
                   1288: #endif
                   1289: 
                   1290: /* Convert a bstring to charField */
                   1291: static int buildCharField (struct charField * cf, const_bstring b) {
                   1292: int i;
                   1293:        if (b == NULL || b->data == NULL || b->slen <= 0) return BSTR_ERR;
                   1294:        memset ((void *) cf->content, 0, sizeof (struct charField));
                   1295:        for (i=0; i < b->slen; i++) {
                   1296:                setInCharField (cf, b->data[i]);
                   1297:        }
                   1298:        return BSTR_OK;
                   1299: }
                   1300: 
                   1301: static void invertCharField (struct charField * cf) {
                   1302: int i;
                   1303:        for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i];
                   1304: }
                   1305: 
                   1306: /* Inner engine for binchr */
                   1307: static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) {
                   1308: int i;
                   1309:        for (i=pos; i < len; i++) {
                   1310:                unsigned char c = (unsigned char) data[i];
                   1311:                if (testInCharField (cf, c)) return i;
                   1312:        }
                   1313:        return BSTR_ERR;
                   1314: }
                   1315: 
                   1316: /*  int binchr (const_bstring b0, int pos, const_bstring b1);
                   1317:  *
                   1318:  *  Search for the first position in b0 starting from pos or after, in which 
                   1319:  *  one of the characters in b1 is found and return it.  If such a position 
                   1320:  *  does not exist in b0, then BSTR_ERR is returned.
                   1321:  */
                   1322: int binchr (const_bstring b0, int pos, const_bstring b1) {
                   1323: struct charField chrs;
                   1324:        if (pos < 0 || b0 == NULL || b0->data == NULL ||
                   1325:            b0->slen <= pos) return BSTR_ERR;
                   1326:        if (1 == b1->slen) return bstrchrp (b0, b1->data[0], pos);
                   1327:        if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
                   1328:        return binchrCF (b0->data, b0->slen, pos, &chrs);
                   1329: }
                   1330: 
                   1331: /* Inner engine for binchrr */
                   1332: static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) {
                   1333: int i;
                   1334:        for (i=pos; i >= 0; i--) {
                   1335:                unsigned int c = (unsigned int) data[i];
                   1336:                if (testInCharField (cf, c)) return i;
                   1337:        }
                   1338:        return BSTR_ERR;
                   1339: }
                   1340: 
                   1341: /*  int binchrr (const_bstring b0, int pos, const_bstring b1);
                   1342:  *
                   1343:  *  Search for the last position in b0 no greater than pos, in which one of 
                   1344:  *  the characters in b1 is found and return it.  If such a position does not 
                   1345:  *  exist in b0, then BSTR_ERR is returned.
                   1346:  */
                   1347: int binchrr (const_bstring b0, int pos, const_bstring b1) {
                   1348: struct charField chrs;
                   1349:        if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL ||
                   1350:            b0->slen < pos) return BSTR_ERR;
                   1351:        if (pos == b0->slen) pos--;
                   1352:        if (1 == b1->slen) return bstrrchrp (b0, b1->data[0], pos);
                   1353:        if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
                   1354:        return binchrrCF (b0->data, pos, &chrs);
                   1355: }
                   1356: 
                   1357: /*  int bninchr (const_bstring b0, int pos, const_bstring b1);
                   1358:  *
                   1359:  *  Search for the first position in b0 starting from pos or after, in which 
                   1360:  *  none of the characters in b1 is found and return it.  If such a position 
                   1361:  *  does not exist in b0, then BSTR_ERR is returned.
                   1362:  */
                   1363: int bninchr (const_bstring b0, int pos, const_bstring b1) {
                   1364: struct charField chrs;
                   1365:        if (pos < 0 || b0 == NULL || b0->data == NULL || 
                   1366:            b0->slen <= pos) return BSTR_ERR;
                   1367:        if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
                   1368:        invertCharField (&chrs);
                   1369:        return binchrCF (b0->data, b0->slen, pos, &chrs);
                   1370: }
                   1371: 
                   1372: /*  int bninchrr (const_bstring b0, int pos, const_bstring b1);
                   1373:  *
                   1374:  *  Search for the last position in b0 no greater than pos, in which none of 
                   1375:  *  the characters in b1 is found and return it.  If such a position does not 
                   1376:  *  exist in b0, then BSTR_ERR is returned.
                   1377:  */
                   1378: int bninchrr (const_bstring b0, int pos, const_bstring b1) {
                   1379: struct charField chrs;
                   1380:        if (pos < 0 || b0 == NULL || b0->data == NULL || 
                   1381:            b0->slen < pos) return BSTR_ERR;
                   1382:        if (pos == b0->slen) pos--;
                   1383:        if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
                   1384:        invertCharField (&chrs);
                   1385:        return binchrrCF (b0->data, pos, &chrs);
                   1386: }
                   1387: 
                   1388: /*  int bsetstr (bstring b0, int pos, bstring b1, unsigned char fill)
                   1389:  *
                   1390:  *  Overwrite the string b0 starting at position pos with the string b1. If 
                   1391:  *  the position pos is past the end of b0, then the character "fill" is 
                   1392:  *  appended as necessary to make up the gap between the end of b0 and pos.
                   1393:  *  If b1 is NULL, it behaves as if it were a 0-length string.
                   1394:  */
                   1395: int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) {
                   1396: int d, newlen;
                   1397: ptrdiff_t pd;
                   1398: bstring aux = (bstring) b1;
                   1399: 
                   1400:        if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data || 
                   1401:            b0->mlen < b0->slen || b0->mlen <= 0) return BSTR_ERR;
                   1402:        if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return BSTR_ERR;
                   1403: 
                   1404:        d = pos;
                   1405: 
                   1406:        /* Aliasing case */
                   1407:        if (NULL != aux) {
                   1408:                if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) {
                   1409:                        if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
                   1410:                }
                   1411:                d += aux->slen;
                   1412:        }
                   1413: 
                   1414:        /* Increase memory size if necessary */
                   1415:        if (balloc (b0, d + 1) != BSTR_OK) {
                   1416:                if (aux != b1) bdestroy (aux);
                   1417:                return BSTR_ERR;
                   1418:        }
                   1419: 
                   1420:        newlen = b0->slen;
                   1421: 
                   1422:        /* Fill in "fill" character as necessary */
                   1423:        if (pos > newlen) {
                   1424:                bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen));
                   1425:                newlen = pos;
                   1426:        }
                   1427: 
                   1428:        /* Copy b1 to position pos in b0. */
                   1429:        if (aux != NULL) {
                   1430:                bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen);
                   1431:                if (aux != b1) bdestroy (aux);
                   1432:        }
                   1433: 
                   1434:        /* Indicate the potentially increased size of b0 */
                   1435:        if (d > newlen) newlen = d;
                   1436: 
                   1437:        b0->slen = newlen;
                   1438:        b0->data[newlen] = (unsigned char) '\0';
                   1439: 
                   1440:        return BSTR_OK;
                   1441: }
                   1442: 
                   1443: /*  int binsert (bstring b1, int pos, bstring b2, unsigned char fill)
                   1444:  *
                   1445:  *  Inserts the string b2 into b1 at position pos.  If the position pos is 
                   1446:  *  past the end of b1, then the character "fill" is appended as necessary to 
                   1447:  *  make up the gap between the end of b1 and pos.  Unlike bsetstr, binsert
                   1448:  *  does not allow b2 to be NULL.
                   1449:  */
                   1450: int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) {
                   1451: int d, l;
                   1452: ptrdiff_t pd;
                   1453: bstring aux = (bstring) b2;
                   1454: 
                   1455:        if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 || 
                   1456:            b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR;
                   1457: 
                   1458:        /* Aliasing case */
                   1459:        if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) {
                   1460:                if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
                   1461:        }
                   1462: 
                   1463:        /* Compute the two possible end pointers */
                   1464:        d = b1->slen + aux->slen;
                   1465:        l = pos + aux->slen;
                   1466:        if ((d|l) < 0) return BSTR_ERR;
                   1467: 
                   1468:        if (l > d) {
                   1469:                /* Inserting past the end of the string */
                   1470:                if (balloc (b1, l + 1) != BSTR_OK) {
                   1471:                        if (aux != b2) bdestroy (aux);
                   1472:                        return BSTR_ERR;
                   1473:                }
                   1474:                bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen));
                   1475:                b1->slen = l;
                   1476:        } else {
                   1477:                /* Inserting in the middle of the string */
                   1478:                if (balloc (b1, d + 1) != BSTR_OK) {
                   1479:                        if (aux != b2) bdestroy (aux);
                   1480:                        return BSTR_ERR;
                   1481:                }
                   1482:                bBlockCopy (b1->data + l, b1->data + pos, d - l);
                   1483:                b1->slen = d;
                   1484:        }
                   1485:        bBlockCopy (b1->data + pos, aux->data, aux->slen);
                   1486:        b1->data[b1->slen] = (unsigned char) '\0';
                   1487:        if (aux != b2) bdestroy (aux);
                   1488:        return BSTR_OK;
                   1489: }
                   1490: 
                   1491: /*  int breplace (bstring b1, int pos, int len, bstring b2, 
                   1492:  *                unsigned char fill)
                   1493:  *
                   1494:  *  Replace a section of a string from pos for a length len with the string b2.
                   1495:  *  fill is used is pos > b1->slen.
                   1496:  */
                   1497: int breplace (bstring b1, int pos, int len, const_bstring b2, 
                   1498:                          unsigned char fill) {
                   1499: int pl, ret;
                   1500: ptrdiff_t pd;
                   1501: bstring aux = (bstring) b2;
                   1502: 
                   1503:        if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL || 
                   1504:            b2 == NULL || b1->data == NULL || b2->data == NULL || 
                   1505:            b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen ||
                   1506:            b1->mlen <= 0) return BSTR_ERR;
                   1507: 
                   1508:        /* Straddles the end? */
                   1509:        if (pl >= b1->slen) {
                   1510:                if ((ret = bsetstr (b1, pos, b2, fill)) < 0) return ret;
                   1511:                if (pos + b2->slen < b1->slen) {
                   1512:                        b1->slen = pos + b2->slen;
                   1513:                        b1->data[b1->slen] = (unsigned char) '\0';
                   1514:                }
                   1515:                return ret;
                   1516:        }
                   1517: 
                   1518:        /* Aliasing case */
                   1519:        if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) {
                   1520:                if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
                   1521:        }
                   1522: 
                   1523:        if (aux->slen > len) {
                   1524:                if (balloc (b1, b1->slen + aux->slen - len) != BSTR_OK) {
                   1525:                        if (aux != b2) bdestroy (aux);
                   1526:                        return BSTR_ERR;
                   1527:                }
                   1528:        }
                   1529: 
                   1530:        if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len));
                   1531:        bstr__memcpy (b1->data + pos, aux->data, aux->slen);
                   1532:        b1->slen += aux->slen - len;
                   1533:        b1->data[b1->slen] = (unsigned char) '\0';
                   1534:        if (aux != b2) bdestroy (aux);
                   1535:        return BSTR_OK;
                   1536: }
                   1537: 
                   1538: /*  int bfindreplace (bstring b, const_bstring find, const_bstring repl, 
                   1539:  *                    int pos)
                   1540:  *
                   1541:  *  Replace all occurrences of a find string with a replace string after a
                   1542:  *  given point in a bstring.
                   1543:  */
                   1544: 
                   1545: typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2);
                   1546: 
                   1547: static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) {
                   1548: int i, ret, slen, mlen, delta, acc;
                   1549: int * d;
                   1550: int static_d[32];
                   1551: ptrdiff_t pd;
                   1552: bstring auxf = (bstring) find;
                   1553: bstring auxr = (bstring) repl;
                   1554: 
                   1555:        if (b == NULL || b->data == NULL || find == NULL ||
                   1556:            find->data == NULL || repl == NULL || repl->data == NULL || 
                   1557:            pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen || 
                   1558:            b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return BSTR_ERR;
                   1559:        if (pos > b->slen - find->slen) return BSTR_OK;
                   1560: 
                   1561:        /* Alias with find string */
                   1562:        pd = (ptrdiff_t) (find->data - b->data);
                   1563:        if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) {
                   1564:                if (NULL == (auxf = bstrcpy (find))) return BSTR_ERR;
                   1565:        }
                   1566: 
                   1567:        /* Alias with repl string */
                   1568:        pd = (ptrdiff_t) (repl->data - b->data);
                   1569:        if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) {
                   1570:                if (NULL == (auxr = bstrcpy (repl))) {
                   1571:                        if (auxf != find) bdestroy (auxf);
                   1572:                        return BSTR_ERR;
                   1573:                }
                   1574:        }
                   1575: 
                   1576:        delta = auxf->slen - auxr->slen;
                   1577: 
                   1578:        /* in-place replacement since find and replace strings are of equal 
                   1579:           length */
                   1580:        if (delta == 0) {
                   1581:                while ((pos = instr (b, pos, auxf)) >= 0) {
                   1582:                        bstr__memcpy (b->data + pos, auxr->data, auxr->slen);
                   1583:                        pos += auxf->slen;
                   1584:                }
                   1585:                if (auxf != find) bdestroy (auxf);
                   1586:                if (auxr != repl) bdestroy (auxr);
                   1587:                return BSTR_OK;
                   1588:        }
                   1589: 
                   1590:        /* shrinking replacement since auxf->slen > auxr->slen */
                   1591:        if (delta > 0) {
                   1592:                acc = 0;
                   1593: 
                   1594:                while ((i = instr (b, pos, auxf)) >= 0) {
                   1595:                        if (acc && i > pos)
                   1596:                                bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
                   1597:                        if (auxr->slen)
                   1598:                                bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen);
                   1599:                        acc += delta;
                   1600:                        pos = i + auxf->slen;
                   1601:                }
                   1602: 
                   1603:                if (acc) {
                   1604:                        i = b->slen;
                   1605:                        if (i > pos)
                   1606:                                bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
                   1607:                        b->slen -= acc;
                   1608:                        b->data[b->slen] = (unsigned char) '\0';
                   1609:                }
                   1610: 
                   1611:                if (auxf != find) bdestroy (auxf);
                   1612:                if (auxr != repl) bdestroy (auxr);
                   1613:                return BSTR_OK;
                   1614:        }
                   1615: 
                   1616:        /* expanding replacement since find->slen < repl->slen.  Its a lot 
                   1617:           more complicated. */
                   1618: 
                   1619:        mlen = 32;
                   1620:        d = (int *) static_d; /* Avoid malloc for trivial cases */
                   1621:        acc = slen = 0;
                   1622: 
                   1623:        while ((pos = instr (b, pos, auxf)) >= 0) {
                   1624:                if (slen + 1 >= mlen) {
                   1625:                        int sl;
                   1626:                        int * t;
                   1627:                        mlen += mlen;
                   1628:                        sl = sizeof (int *) * mlen;
                   1629:                        if (static_d == d) d = NULL;
                   1630:                        if (sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) {
                   1631:                                ret = BSTR_ERR;
                   1632:                                goto done;
                   1633:                        }
                   1634:                        if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d));
                   1635:                        d = t;
                   1636:                }
                   1637:                d[slen] = pos;
                   1638:                slen++;
                   1639:                acc -= delta;
                   1640:                pos += auxf->slen;
                   1641:                if (pos < 0 || acc < 0) {
                   1642:                        ret = BSTR_ERR;
                   1643:                        goto done;
                   1644:                }
                   1645:        }
                   1646:        d[slen] = b->slen;
                   1647: 
                   1648:        if (BSTR_OK == (ret = balloc (b, b->slen + acc + 1))) {
                   1649:                b->slen += acc;
                   1650:                for (i = slen-1; i >= 0; i--) {
                   1651:                        int s, l;
                   1652:                        s = d[i] + auxf->slen;
                   1653:                        l = d[i+1] - s;
                   1654:                        if (l) {
                   1655:                                bstr__memmove (b->data + s + acc, b->data + s, l);
                   1656:                        }
                   1657:                        if (auxr->slen) {
                   1658:                                bstr__memmove (b->data + s + acc - auxr->slen, 
                   1659:                                         auxr->data, auxr->slen);
                   1660:                        }
                   1661:                        acc += delta;           
                   1662:                }
                   1663:                b->data[b->slen] = (unsigned char) '\0';
                   1664:        }
                   1665: 
                   1666:        done:;
                   1667:        if (static_d == d) d = NULL;
                   1668:        bstr__free (d);
                   1669:        if (auxf != find) bdestroy (auxf);
                   1670:        if (auxr != repl) bdestroy (auxr);
                   1671:        return ret;
                   1672: }
                   1673: 
                   1674: /*  int bfindreplace (bstring b, const_bstring find, const_bstring repl, 
                   1675:  *                    int pos)
                   1676:  *
                   1677:  *  Replace all occurrences of a find string with a replace string after a
                   1678:  *  given point in a bstring.
                   1679:  */
                   1680: int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) {
                   1681:        return findreplaceengine (b, find, repl, pos, binstr);
                   1682: }
                   1683: 
                   1684: /*  int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, 
                   1685:  *                    int pos)
                   1686:  *
                   1687:  *  Replace all occurrences of a find string, ignoring case, with a replace 
                   1688:  *  string after a given point in a bstring.
                   1689:  */
                   1690: int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) {
                   1691:        return findreplaceengine (b, find, repl, pos, binstrcaseless);
                   1692: }
                   1693: 
                   1694: /*  int binsertch (bstring b, int pos, int len, unsigned char fill)
                   1695:  *
                   1696:  *  Inserts the character fill repeatedly into b at position pos for a 
                   1697:  *  length len.  If the position pos is past the end of b, then the 
                   1698:  *  character "fill" is appended as necessary to make up the gap between the 
                   1699:  *  end of b and the position pos + len.
                   1700:  */
                   1701: int binsertch (bstring b, int pos, int len, unsigned char fill) {
                   1702: int d, l, i;
                   1703: 
                   1704:        if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen ||
                   1705:            b->mlen <= 0 || len < 0) return BSTR_ERR;
                   1706: 
                   1707:        /* Compute the two possible end pointers */
                   1708:        d = b->slen + len;
                   1709:        l = pos + len;
                   1710:        if ((d|l) < 0) return BSTR_ERR;
                   1711: 
                   1712:        if (l > d) {
                   1713:                /* Inserting past the end of the string */
                   1714:                if (balloc (b, l + 1) != BSTR_OK) return BSTR_ERR;
                   1715:                pos = b->slen;
                   1716:                b->slen = l;
                   1717:        } else {
                   1718:                /* Inserting in the middle of the string */
                   1719:                if (balloc (b, d + 1) != BSTR_OK) return BSTR_ERR;
                   1720:                for (i = d - 1; i >= l; i--) {
                   1721:                        b->data[i] = b->data[i - len];
                   1722:                }
                   1723:                b->slen = d;
                   1724:        }
                   1725: 
                   1726:        for (i=pos; i < l; i++) b->data[i] = fill;
                   1727:        b->data[b->slen] = (unsigned char) '\0';
                   1728:        return BSTR_OK;
                   1729: }
                   1730: 
                   1731: /*  int bpattern (bstring b, int len)
                   1732:  *
                   1733:  *  Replicate the bstring, b in place, end to end repeatedly until it 
                   1734:  *  surpasses len characters, then chop the result to exactly len characters. 
                   1735:  *  This function operates in-place.  The function will return with BSTR_ERR 
                   1736:  *  if b is NULL or of length 0, otherwise BSTR_OK is returned.
                   1737:  */
                   1738: int bpattern (bstring b, int len) {
                   1739: int i, d;
                   1740: 
                   1741:        d = blength (b);
                   1742:        if (d <= 0 || len < 0 || balloc (b, len + 1) != BSTR_OK) return BSTR_ERR;
                   1743:        if (len > 0) {
                   1744:                if (d == 1) return bsetstr (b, len, NULL, b->data[0]);
                   1745:                for (i = d; i < len; i++) b->data[i] = b->data[i - d];
                   1746:        }
                   1747:        b->data[len] = (unsigned char) '\0';
                   1748:        b->slen = len;
                   1749:        return BSTR_OK;
                   1750: }
                   1751: 
                   1752: #define BS_BUFF_SZ (1024)
                   1753: 
                   1754: /*  int breada (bstring b, bNread readPtr, void * parm)
                   1755:  *
                   1756:  *  Use a finite buffer fread-like function readPtr to concatenate to the 
                   1757:  *  bstring b the entire contents of file-like source data in a roughly 
                   1758:  *  efficient way.
                   1759:  */
                   1760: int breada (bstring b, bNread readPtr, void * parm) {
                   1761: int i, l, n;
                   1762: 
                   1763:        if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
                   1764:            b->mlen <= 0 || readPtr == NULL) return BSTR_ERR;
                   1765: 
                   1766:        i = b->slen;
                   1767:        for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) {
                   1768:                if (BSTR_OK != balloc (b, n + 1)) return BSTR_ERR;
                   1769:                l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm);
                   1770:                i += l;
                   1771:                b->slen = i;
                   1772:                if (i < n) break;
                   1773:        }
                   1774: 
                   1775:        b->data[i] = (unsigned char) '\0';
                   1776:        return BSTR_OK;
                   1777: }
                   1778: 
                   1779: /*  bstring bread (bNread readPtr, void * parm)
                   1780:  *
                   1781:  *  Use a finite buffer fread-like function readPtr to create a bstring 
                   1782:  *  filled with the entire contents of file-like source data in a roughly 
                   1783:  *  efficient way.
                   1784:  */
                   1785: bstring bread (bNread readPtr, void * parm) {
                   1786: int ret;
                   1787: bstring buff;
                   1788: 
                   1789:        if (readPtr == NULL) return NULL;
                   1790:        buff = bfromcstr ("");
                   1791:        if (buff == NULL) return NULL;
                   1792:        ret = breada (buff, readPtr, parm);
                   1793:        if (ret < 0) {
                   1794:                bdestroy (buff);
                   1795:                return NULL;
                   1796:        }
                   1797:        return buff;
                   1798: }
                   1799: 
                   1800: /*  int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator)
                   1801:  *
                   1802:  *  Use an fgetc-like single character stream reading function (getcPtr) to 
                   1803:  *  obtain a sequence of characters which are concatenated to the end of the
                   1804:  *  bstring b.  The stream read is terminated by the passed in terminator 
                   1805:  *  parameter.
                   1806:  *
                   1807:  *  If getcPtr returns with a negative number, or the terminator character 
                   1808:  *  (which is appended) is read, then the stream reading is halted and the 
                   1809:  *  function returns with a partial result in b.  If there is an empty partial
                   1810:  *  result, 1 is returned.  If no characters are read, or there is some other 
                   1811:  *  detectable error, BSTR_ERR is returned.
                   1812:  */
                   1813: int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) {
                   1814: int c, d, e;
                   1815: 
                   1816:        if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
                   1817:            b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
                   1818:        d = 0;
                   1819:        e = b->mlen - 2;
                   1820: 
                   1821:        while ((c = getcPtr (parm)) >= 0) {
                   1822:                if (d > e) {
                   1823:                        b->slen = d;
                   1824:                        if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
                   1825:                        e = b->mlen - 2;
                   1826:                }
                   1827:                b->data[d] = (unsigned char) c;
                   1828:                d++;
                   1829:                if (c == terminator) break;
                   1830:        }
                   1831: 
                   1832:        b->data[d] = (unsigned char) '\0';
                   1833:        b->slen = d;
                   1834: 
                   1835:        return d == 0 && c < 0;
                   1836: }
                   1837: 
                   1838: /*  int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator)
                   1839:  *
                   1840:  *  Use an fgetc-like single character stream reading function (getcPtr) to 
                   1841:  *  obtain a sequence of characters which are concatenated to the end of the
                   1842:  *  bstring b.  The stream read is terminated by the passed in terminator 
                   1843:  *  parameter.
                   1844:  *
                   1845:  *  If getcPtr returns with a negative number, or the terminator character 
                   1846:  *  (which is appended) is read, then the stream reading is halted and the 
                   1847:  *  function returns with a partial result concatentated to b.  If there is 
                   1848:  *  an empty partial result, 1 is returned.  If no characters are read, or 
                   1849:  *  there is some other detectable error, BSTR_ERR is returned.
                   1850:  */
                   1851: int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) {
                   1852: int c, d, e;
                   1853: 
                   1854:        if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
                   1855:            b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
                   1856:        d = b->slen;
                   1857:        e = b->mlen - 2;
                   1858: 
                   1859:        while ((c = getcPtr (parm)) >= 0) {
                   1860:                if (d > e) {
                   1861:                        b->slen = d;
                   1862:                        if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
                   1863:                        e = b->mlen - 2;
                   1864:                }
                   1865:                b->data[d] = (unsigned char) c;
                   1866:                d++;
                   1867:                if (c == terminator) break;
                   1868:        }
                   1869: 
                   1870:        b->data[d] = (unsigned char) '\0';
                   1871:        b->slen = d;
                   1872: 
                   1873:        return d == 0 && c < 0;
                   1874: }
                   1875: 
                   1876: /*  bstring bgets (bNgetc getcPtr, void * parm, char terminator)
                   1877:  *
                   1878:  *  Use an fgetc-like single character stream reading function (getcPtr) to 
                   1879:  *  obtain a sequence of characters which are concatenated into a bstring.  
                   1880:  *  The stream read is terminated by the passed in terminator function.
                   1881:  *
                   1882:  *  If getcPtr returns with a negative number, or the terminator character 
                   1883:  *  (which is appended) is read, then the stream reading is halted and the 
                   1884:  *  result obtained thus far is returned.  If no characters are read, or 
                   1885:  *  there is some other detectable error, NULL is returned.
                   1886:  */
                   1887: bstring bgets (bNgetc getcPtr, void * parm, char terminator) {
                   1888: int ret;
                   1889: bstring buff;
                   1890: 
                   1891:        if (NULL == getcPtr || NULL == (buff = bfromcstr (""))) return NULL;
                   1892: 
                   1893:        ret = bgetsa (buff, getcPtr, parm, terminator);
                   1894:        if (ret < 0 || buff->slen <= 0) {
                   1895:                bdestroy (buff);
                   1896:                buff = NULL;
                   1897:        }
                   1898:        return buff;
                   1899: }
                   1900: 
                   1901: struct bStream {
                   1902:        bstring buff;           /* Buffer for over-reads */
                   1903:        void * parm;            /* The stream handle for core stream */
                   1904:        bNread readFnPtr;       /* fread compatible fnptr for core stream */
                   1905:        int isEOF;              /* track file's EOF state */
                   1906:        int maxBuffSz;
                   1907: };
                   1908: 
                   1909: /*  struct bStream * bsopen (bNread readPtr, void * parm)
                   1910:  *
                   1911:  *  Wrap a given open stream (described by a fread compatible function 
                   1912:  *  pointer and stream handle) into an open bStream suitable for the bstring 
                   1913:  *  library streaming functions.
                   1914:  */
                   1915: struct bStream * bsopen (bNread readPtr, void * parm) {
                   1916: struct bStream * s;
                   1917: 
                   1918:        if (readPtr == NULL) return NULL;
                   1919:        s = (struct bStream *) bstr__alloc (sizeof (struct bStream));
                   1920:        if (s == NULL) return NULL;
                   1921:        s->parm = parm;
                   1922:        s->buff = bfromcstr ("");
                   1923:        s->readFnPtr = readPtr;
                   1924:        s->maxBuffSz = BS_BUFF_SZ;
                   1925:        s->isEOF = 0;
                   1926:        return s;
                   1927: }
                   1928: 
                   1929: /*  int bsbufflength (struct bStream * s, int sz)
                   1930:  *
                   1931:  *  Set the length of the buffer used by the bStream.  If sz is zero, the 
                   1932:  *  length is not set.  This function returns with the previous length.
                   1933:  */
                   1934: int bsbufflength (struct bStream * s, int sz) {
                   1935: int oldSz;
                   1936:        if (s == NULL || sz < 0) return BSTR_ERR;
                   1937:        oldSz = s->maxBuffSz;
                   1938:        if (sz > 0) s->maxBuffSz = sz;
                   1939:        return oldSz;
                   1940: }
                   1941: 
                   1942: int bseof (const struct bStream * s) {
                   1943:        if (s == NULL || s->readFnPtr == NULL) return BSTR_ERR;
                   1944:        return s->isEOF && (s->buff->slen == 0);
                   1945: }
                   1946: 
                   1947: /*  void * bsclose (struct bStream * s)
                   1948:  *
                   1949:  *  Close the bStream, and return the handle to the stream that was originally
                   1950:  *  used to open the given stream.
                   1951:  */
                   1952: void * bsclose (struct bStream * s) {
                   1953: void * parm;
                   1954:        if (s == NULL) return NULL;
                   1955:        s->readFnPtr = NULL;
                   1956:        if (s->buff) bdestroy (s->buff);
                   1957:        s->buff = NULL;
                   1958:        parm = s->parm;
                   1959:        s->parm = NULL;
                   1960:        s->isEOF = 1;
                   1961:        bstr__free (s);
                   1962:        return parm;
                   1963: }
                   1964: 
                   1965: /*  int bsreadlna (bstring r, struct bStream * s, char terminator)
                   1966:  *
                   1967:  *  Read a bstring terminated by the terminator character or the end of the
                   1968:  *  stream from the bStream (s) and return it into the parameter r.  This 
                   1969:  *  function may read additional characters from the core stream that are not 
                   1970:  *  returned, but will be retained for subsequent read operations.
                   1971:  */
                   1972: int bsreadlna (bstring r, struct bStream * s, char terminator) {
                   1973: int i, l, ret, rlo;
                   1974: char * b;
                   1975: struct tagbstring x;
                   1976: 
                   1977:        if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 ||
                   1978:            r->slen < 0 || r->mlen < r->slen) return BSTR_ERR;
                   1979:        l = s->buff->slen;
                   1980:        if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
                   1981:        b = (char *) s->buff->data;
                   1982:        x.data = (unsigned char *) b;
                   1983: 
                   1984:        /* First check if the current buffer holds the terminator */
                   1985:        b[l] = terminator; /* Set sentinel */
                   1986:        for (i=0; b[i] != terminator; i++) ;
                   1987:        if (i < l) {
                   1988:                x.slen = i + 1;
                   1989:                ret = bconcat (r, &x);
                   1990:                s->buff->slen = l;
                   1991:                if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
                   1992:                return BSTR_OK;
                   1993:        }
                   1994: 
                   1995:        rlo = r->slen;
                   1996: 
                   1997:        /* If not then just concatenate the entire buffer to the output */
                   1998:        x.slen = l;
                   1999:        if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
                   2000: 
                   2001:        /* Perform direct in-place reads into the destination to allow for
                   2002:           the minimum of data-copies */
                   2003:        for (;;) {
                   2004:                if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
                   2005:                b = (char *) (r->data + r->slen);
                   2006:                l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
                   2007:                if (l <= 0) {
                   2008:                        r->data[r->slen] = (unsigned char) '\0';
                   2009:                        s->buff->slen = 0;
                   2010:                        s->isEOF = 1;
                   2011:                        /* If nothing was read return with an error message */
                   2012:                        return BSTR_ERR & -(r->slen == rlo);
                   2013:                }
                   2014:                b[l] = terminator; /* Set sentinel */
                   2015:                for (i=0; b[i] != terminator; i++) ;
                   2016:                if (i < l) break;
                   2017:                r->slen += l;
                   2018:        }
                   2019: 
                   2020:        /* Terminator found, push over-read back to buffer */
                   2021:        i++;
                   2022:        r->slen += i;
                   2023:        s->buff->slen = l - i;
                   2024:        bstr__memcpy (s->buff->data, b + i, l - i);
                   2025:        r->data[r->slen] = (unsigned char) '\0';
                   2026:        return BSTR_OK;
                   2027: }
                   2028: 
                   2029: /*  int bsreadlnsa (bstring r, struct bStream * s, bstring term)
                   2030:  *
                   2031:  *  Read a bstring terminated by any character in the term string or the end 
                   2032:  *  of the stream from the bStream (s) and return it into the parameter r.  
                   2033:  *  This function may read additional characters from the core stream that 
                   2034:  *  are not returned, but will be retained for subsequent read operations.
                   2035:  */
                   2036: int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) {
                   2037: int i, l, ret, rlo;
                   2038: unsigned char * b;
                   2039: struct tagbstring x;
                   2040: struct charField cf;
                   2041: 
                   2042:        if (s == NULL || s->buff == NULL || r == NULL || term == NULL ||
                   2043:            term->data == NULL || r->mlen <= 0 || r->slen < 0 ||
                   2044:            r->mlen < r->slen) return BSTR_ERR;
                   2045:        if (term->slen == 1) return bsreadlna (r, s, term->data[0]);
                   2046:        if (term->slen < 1 || buildCharField (&cf, term)) return BSTR_ERR;
                   2047: 
                   2048:        l = s->buff->slen;
                   2049:        if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
                   2050:        b = (unsigned char *) s->buff->data;
                   2051:        x.data = b;
                   2052: 
                   2053:        /* First check if the current buffer holds the terminator */
                   2054:        b[l] = term->data[0]; /* Set sentinel */
                   2055:        for (i=0; !testInCharField (&cf, b[i]); i++) ;
                   2056:        if (i < l) {
                   2057:                x.slen = i + 1;
                   2058:                ret = bconcat (r, &x);
                   2059:                s->buff->slen = l;
                   2060:                if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
                   2061:                return BSTR_OK;
                   2062:        }
                   2063: 
                   2064:        rlo = r->slen;
                   2065: 
                   2066:        /* If not then just concatenate the entire buffer to the output */
                   2067:        x.slen = l;
                   2068:        if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
                   2069: 
                   2070:        /* Perform direct in-place reads into the destination to allow for
                   2071:           the minimum of data-copies */
                   2072:        for (;;) {
                   2073:                if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
                   2074:                b = (unsigned char *) (r->data + r->slen);
                   2075:                l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
                   2076:                if (l <= 0) {
                   2077:                        r->data[r->slen] = (unsigned char) '\0';
                   2078:                        s->buff->slen = 0;
                   2079:                        s->isEOF = 1;
                   2080:                        /* If nothing was read return with an error message */
                   2081:                        return BSTR_ERR & -(r->slen == rlo);
                   2082:                }
                   2083: 
                   2084:                b[l] = term->data[0]; /* Set sentinel */
                   2085:                for (i=0; !testInCharField (&cf, b[i]); i++) ;
                   2086:                if (i < l) break;
                   2087:                r->slen += l;
                   2088:        }
                   2089: 
                   2090:        /* Terminator found, push over-read back to buffer */
                   2091:        i++;
                   2092:        r->slen += i;
                   2093:        s->buff->slen = l - i;
                   2094:        bstr__memcpy (s->buff->data, b + i, l - i);
                   2095:        r->data[r->slen] = (unsigned char) '\0';
                   2096:        return BSTR_OK;
                   2097: }
                   2098: 
                   2099: /*  int bsreada (bstring r, struct bStream * s, int n)
                   2100:  *
                   2101:  *  Read a bstring of length n (or, if it is fewer, as many bytes as is 
                   2102:  *  remaining) from the bStream.  This function may read additional 
                   2103:  *  characters from the core stream that are not returned, but will be 
                   2104:  *  retained for subsequent read operations.  This function will not read
                   2105:  *  additional characters from the core stream beyond virtual stream pointer.
                   2106:  */
                   2107: int bsreada (bstring r, struct bStream * s, int n) {
                   2108: int l, ret, orslen;
                   2109: char * b;
                   2110: struct tagbstring x;
                   2111: 
                   2112:        if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
                   2113:         || r->slen < 0 || r->mlen < r->slen || n <= 0) return BSTR_ERR;
                   2114: 
                   2115:        n += r->slen;
                   2116:        if (n <= 0) return BSTR_ERR;
                   2117: 
                   2118:        l = s->buff->slen;
                   2119: 
                   2120:        orslen = r->slen;
                   2121: 
                   2122:        if (0 == l) {
                   2123:                if (s->isEOF) return BSTR_ERR;
                   2124:                if (r->mlen > n) {
                   2125:                        l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm);
                   2126:                        if (0 >= l || l > n - r->slen) {
                   2127:                                s->isEOF = 1;
                   2128:                                return BSTR_ERR;
                   2129:                        }
                   2130:                        r->slen += l;
                   2131:                        r->data[r->slen] = (unsigned char) '\0';
                   2132:                        return 0;
                   2133:                }
                   2134:        }
                   2135: 
                   2136:        if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
                   2137:        b = (char *) s->buff->data;
                   2138:        x.data = (unsigned char *) b;
                   2139: 
                   2140:        do {
                   2141:                if (l + r->slen >= n) {
                   2142:                        x.slen = n - r->slen;
                   2143:                        ret = bconcat (r, &x);
                   2144:                        s->buff->slen = l;
                   2145:                        if (BSTR_OK == ret) bdelete (s->buff, 0, x.slen);
                   2146:                        return BSTR_ERR & -(r->slen == orslen);
                   2147:                }
                   2148: 
                   2149:                x.slen = l;
                   2150:                if (BSTR_OK != bconcat (r, &x)) break;
                   2151: 
                   2152:                l = n - r->slen;
                   2153:                if (l > s->maxBuffSz) l = s->maxBuffSz;
                   2154: 
                   2155:                l = (int) s->readFnPtr (b, 1, l, s->parm);
                   2156: 
                   2157:        } while (l > 0);
                   2158:        if (l < 0) l = 0;
                   2159:        if (l == 0) s->isEOF = 1;
                   2160:        s->buff->slen = l;
                   2161:        return BSTR_ERR & -(r->slen == orslen);
                   2162: }
                   2163: 
                   2164: /*  int bsreadln (bstring r, struct bStream * s, char terminator)
                   2165:  *
                   2166:  *  Read a bstring terminated by the terminator character or the end of the
                   2167:  *  stream from the bStream (s) and return it into the parameter r.  This 
                   2168:  *  function may read additional characters from the core stream that are not 
                   2169:  *  returned, but will be retained for subsequent read operations.
                   2170:  */
                   2171: int bsreadln (bstring r, struct bStream * s, char terminator) {
                   2172:        if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0)
                   2173:                return BSTR_ERR;
                   2174:        if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
                   2175:        r->slen = 0;
                   2176:        return bsreadlna (r, s, terminator);
                   2177: }
                   2178: 
                   2179: /*  int bsreadlns (bstring r, struct bStream * s, bstring term)
                   2180:  *
                   2181:  *  Read a bstring terminated by any character in the term string or the end 
                   2182:  *  of the stream from the bStream (s) and return it into the parameter r.  
                   2183:  *  This function may read additional characters from the core stream that 
                   2184:  *  are not returned, but will be retained for subsequent read operations.
                   2185:  */
                   2186: int bsreadlns (bstring r, struct bStream * s, const_bstring term) {
                   2187:        if (s == NULL || s->buff == NULL || r == NULL || term == NULL 
                   2188:         || term->data == NULL || r->mlen <= 0) return BSTR_ERR;
                   2189:        if (term->slen == 1) return bsreadln (r, s, term->data[0]);
                   2190:        if (term->slen < 1) return BSTR_ERR;
                   2191:        if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
                   2192:        r->slen = 0;
                   2193:        return bsreadlnsa (r, s, term);
                   2194: }
                   2195: 
                   2196: /*  int bsread (bstring r, struct bStream * s, int n)
                   2197:  *
                   2198:  *  Read a bstring of length n (or, if it is fewer, as many bytes as is 
                   2199:  *  remaining) from the bStream.  This function may read additional 
                   2200:  *  characters from the core stream that are not returned, but will be 
                   2201:  *  retained for subsequent read operations.  This function will not read
                   2202:  *  additional characters from the core stream beyond virtual stream pointer.
                   2203:  */
                   2204: int bsread (bstring r, struct bStream * s, int n) {
                   2205:        if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
                   2206:         || n <= 0) return BSTR_ERR;
                   2207:        if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
                   2208:        r->slen = 0;
                   2209:        return bsreada (r, s, n);
                   2210: }
                   2211: 
                   2212: /*  int bsunread (struct bStream * s, const_bstring b)
                   2213:  *
                   2214:  *  Insert a bstring into the bStream at the current position.  These 
                   2215:  *  characters will be read prior to those that actually come from the core 
                   2216:  *  stream.
                   2217:  */
                   2218: int bsunread (struct bStream * s, const_bstring b) {
                   2219:        if (s == NULL || s->buff == NULL) return BSTR_ERR;
                   2220:        return binsert (s->buff, 0, b, (unsigned char) '?');
                   2221: }
                   2222: 
                   2223: /*  int bspeek (bstring r, const struct bStream * s)
                   2224:  *
                   2225:  *  Return the currently buffered characters from the bStream that will be 
                   2226:  *  read prior to reads from the core stream.
                   2227:  */
                   2228: int bspeek (bstring r, const struct bStream * s) {
                   2229:        if (s == NULL || s->buff == NULL) return BSTR_ERR;
                   2230:        return bassign (r, s->buff);
                   2231: }
                   2232: 
                   2233: /*  bstring bjoin (const struct bstrList * bl, const_bstring sep);
                   2234:  *
                   2235:  *  Join the entries of a bstrList into one bstring by sequentially 
                   2236:  *  concatenating them with the sep string in between.  If there is an error 
                   2237:  *  NULL is returned, otherwise a bstring with the correct result is returned.
                   2238:  */
                   2239: bstring bjoin (const struct bstrList * bl, const_bstring sep) {
                   2240: bstring b;
                   2241: int i, c, v;
                   2242: 
                   2243:        if (bl == NULL || bl->qty < 0) return NULL;
                   2244:        if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL;
                   2245: 
                   2246:        for (i = 0, c = 1; i < bl->qty; i++) {
                   2247:                v = bl->entry[i]->slen;
                   2248:                if (v < 0) return NULL; /* Invalid input */
                   2249:                c += v;
                   2250:                if (c < 0) return NULL; /* Wrap around ?? */
                   2251:        }
                   2252: 
                   2253:        if (sep != NULL) c += (bl->qty - 1) * sep->slen;
                   2254: 
                   2255:        b = (bstring) bstr__alloc (sizeof (struct tagbstring));
                   2256:        if (NULL == b) return NULL; /* Out of memory */
                   2257:        b->data = (unsigned char *) bstr__alloc (c);
                   2258:        if (b->data == NULL) {
                   2259:                bstr__free (b);
                   2260:                return NULL;
                   2261:        }
                   2262: 
                   2263:        b->mlen = c;
                   2264:        b->slen = c-1;
                   2265: 
                   2266:        for (i = 0, c = 0; i < bl->qty; i++) {
                   2267:                if (i > 0 && sep != NULL) {
                   2268:                        bstr__memcpy (b->data + c, sep->data, sep->slen);
                   2269:                        c += sep->slen;
                   2270:                }
                   2271:                v = bl->entry[i]->slen;
                   2272:                bstr__memcpy (b->data + c, bl->entry[i]->data, v);
                   2273:                c += v;
                   2274:        }
                   2275:        b->data[c] = (unsigned char) '\0';
                   2276:        return b;
                   2277: }
                   2278: 
                   2279: #define BSSSC_BUFF_LEN (256)
                   2280: 
                   2281: /*  int bssplitscb (struct bStream * s, const_bstring splitStr, 
                   2282:  *     int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
                   2283:  *
                   2284:  *  Iterate the set of disjoint sequential substrings read from a stream 
                   2285:  *  divided by any of the characters in splitStr.  An empty splitStr causes 
                   2286:  *  the whole stream to be iterated once.
                   2287:  *
                   2288:  *  Note: At the point of calling the cb function, the bStream pointer is 
                   2289:  *  pointed exactly at the position right after having read the split 
                   2290:  *  character.  The cb function can act on the stream by causing the bStream
                   2291:  *  pointer to move, and bssplitscb will continue by starting the next split
                   2292:  *  at the position of the pointer after the return from cb.
                   2293:  *
                   2294:  *  However, if the cb causes the bStream s to be destroyed then the cb must
                   2295:  *  return with a negative value, otherwise bssplitscb will continue in an 
                   2296:  *  undefined manner.
                   2297:  */
                   2298: int bssplitscb (struct bStream * s, const_bstring splitStr, 
                   2299:        int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
                   2300: struct charField chrs;
                   2301: bstring buff;
                   2302: int i, p, ret;
                   2303: 
                   2304:        if (cb == NULL || s == NULL || s->readFnPtr == NULL 
                   2305:         || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
                   2306: 
                   2307:        if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
                   2308: 
                   2309:        if (splitStr->slen == 0) {
                   2310:                while (bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ;
                   2311:                if ((ret = cb (parm, 0, buff)) > 0) 
                   2312:                        ret = 0;
                   2313:        } else {
                   2314:                buildCharField (&chrs, splitStr);
                   2315:                ret = p = i = 0;
                   2316:                for (;;) {
                   2317:                        if (i >= buff->slen) {
                   2318:                                bsreada (buff, s, BSSSC_BUFF_LEN);
                   2319:                                if (i >= buff->slen) {
                   2320:                                        if (0 < (ret = cb (parm, p, buff))) ret = 0;
                   2321:                                        break;
                   2322:                                }
                   2323:                        }
                   2324:                        if (testInCharField (&chrs, buff->data[i])) {
                   2325:                                struct tagbstring t;
                   2326:                                unsigned char c;
                   2327: 
                   2328:                                blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1));
                   2329:                                if ((ret = bsunread (s, &t)) < 0) break;
                   2330:                                buff->slen = i;
                   2331:                                c = buff->data[i];
                   2332:                                buff->data[i] = (unsigned char) '\0';
                   2333:                                if ((ret = cb (parm, p, buff)) < 0) break;
                   2334:                                buff->data[i] = c;
                   2335:                                buff->slen = 0;
                   2336:                                p += i + 1;
                   2337:                                i = -1;
                   2338:                        }
                   2339:                        i++;
                   2340:                }
                   2341:        }
                   2342: 
                   2343:        bdestroy (buff);
                   2344:        return ret;
                   2345: }
                   2346: 
                   2347: /*  int bssplitstrcb (struct bStream * s, const_bstring splitStr, 
                   2348:  *     int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
                   2349:  *
                   2350:  *  Iterate the set of disjoint sequential substrings read from a stream 
                   2351:  *  divided by the entire substring splitStr.  An empty splitStr causes 
                   2352:  *  each character of the stream to be iterated.
                   2353:  *
                   2354:  *  Note: At the point of calling the cb function, the bStream pointer is 
                   2355:  *  pointed exactly at the position right after having read the split 
                   2356:  *  character.  The cb function can act on the stream by causing the bStream
                   2357:  *  pointer to move, and bssplitscb will continue by starting the next split
                   2358:  *  at the position of the pointer after the return from cb.
                   2359:  *
                   2360:  *  However, if the cb causes the bStream s to be destroyed then the cb must
                   2361:  *  return with a negative value, otherwise bssplitscb will continue in an 
                   2362:  *  undefined manner.
                   2363:  */
                   2364: int bssplitstrcb (struct bStream * s, const_bstring splitStr, 
                   2365:        int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
                   2366: bstring buff;
                   2367: int i, p, ret;
                   2368: 
                   2369:        if (cb == NULL || s == NULL || s->readFnPtr == NULL 
                   2370:         || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
                   2371: 
                   2372:        if (splitStr->slen == 1) return bssplitscb (s, splitStr, cb, parm);
                   2373: 
                   2374:        if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
                   2375: 
                   2376:        if (splitStr->slen == 0) {
                   2377:                for (i=0; bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) {
                   2378:                        if ((ret = cb (parm, 0, buff)) < 0) {
                   2379:                                bdestroy (buff);
                   2380:                                return ret;
                   2381:                        }
                   2382:                        buff->slen = 0;
                   2383:                }
                   2384:                return BSTR_OK;
                   2385:        } else {
                   2386:                ret = p = i = 0;
                   2387:                for (i=p=0;;) {
                   2388:                        if ((ret = binstr (buff, 0, splitStr)) >= 0) {
                   2389:                                struct tagbstring t;
                   2390:                                blk2tbstr (t, buff->data, ret);
                   2391:                                i = ret + splitStr->slen;
                   2392:                                if ((ret = cb (parm, p, &t)) < 0) break;
                   2393:                                p += i;
                   2394:                                bdelete (buff, 0, i);
                   2395:                        } else {
                   2396:                                bsreada (buff, s, BSSSC_BUFF_LEN);
                   2397:                                if (bseof (s)) {
                   2398:                                        if ((ret = cb (parm, p, buff)) > 0) ret = 0;
                   2399:                                        break;
                   2400:                                }
                   2401:                        }
                   2402:                }
                   2403:        }
                   2404: 
                   2405:        bdestroy (buff);
                   2406:        return ret;
                   2407: }
                   2408: 
                   2409: /*  int bstrListCreate (void)
                   2410:  *
                   2411:  *  Create a bstrList.
                   2412:  */
                   2413: struct bstrList * bstrListCreate (void) {
                   2414: struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
                   2415:        if (sl) {
                   2416:                sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring));
                   2417:                if (!sl->entry) {
                   2418:                        bstr__free (sl);
                   2419:                        sl = NULL;
                   2420:                } else {
                   2421:                        sl->qty = 0;
                   2422:                        sl->mlen = 1;
                   2423:                }
                   2424:        }
                   2425:        return sl;
                   2426: }
                   2427: 
                   2428: /*  int bstrListDestroy (struct bstrList * sl)
                   2429:  *
                   2430:  *  Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate.
                   2431:  */
                   2432: int bstrListDestroy (struct bstrList * sl) {
                   2433: int i;
                   2434:        if (sl == NULL || sl->qty < 0) return BSTR_ERR;
                   2435:        for (i=0; i < sl->qty; i++) {
                   2436:                if (sl->entry[i]) {
                   2437:                        bdestroy (sl->entry[i]);
                   2438:                        sl->entry[i] = NULL;
                   2439:                }
                   2440:        }
                   2441:        sl->qty  = -1;
                   2442:        sl->mlen = -1;
                   2443:        bstr__free (sl->entry);
                   2444:        sl->entry = NULL;
                   2445:        bstr__free (sl);
                   2446:        return BSTR_OK;
                   2447: }
                   2448: 
                   2449: /*  int bstrListAlloc (struct bstrList * sl, int msz)
                   2450:  *
                   2451:  *  Ensure that there is memory for at least msz number of entries for the
                   2452:  *  list.
                   2453:  */
                   2454: int bstrListAlloc (struct bstrList * sl, int msz) {
                   2455: bstring * l;
                   2456: int smsz;
                   2457: size_t nsz;
                   2458:        if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
                   2459:        if (sl->mlen >= msz) return BSTR_OK;
                   2460:        smsz = snapUpSize (msz);
                   2461:        nsz = ((size_t) smsz) * sizeof (bstring);
                   2462:        if (nsz < (size_t) smsz) return BSTR_ERR;
                   2463:        l = bstr__realloc (sl->entry, nsz);
                   2464:        if (!l) {
                   2465:                smsz = msz;
                   2466:                nsz = ((size_t) smsz) * sizeof (bstring);
                   2467:                l = bstr__realloc (sl->entry, nsz);
                   2468:                if (!l) return BSTR_ERR;
                   2469:        }
                   2470:        sl->mlen = smsz;
                   2471:        sl->entry = l;
                   2472:        return BSTR_OK;
                   2473: }
                   2474: 
                   2475: /*  int bstrListAllocMin (struct bstrList * sl, int msz)
                   2476:  *
                   2477:  *  Try to allocate the minimum amount of memory for the list to include at
                   2478:  *  least msz entries or sl->qty whichever is greater.
                   2479:  */
                   2480: int bstrListAllocMin (struct bstrList * sl, int msz) {
                   2481: bstring * l;
                   2482: size_t nsz;
                   2483:        if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
                   2484:        if (msz < sl->qty) msz = sl->qty;
                   2485:        if (sl->mlen == msz) return BSTR_OK;
                   2486:        nsz = ((size_t) msz) * sizeof (bstring);
                   2487:        if (nsz < (size_t) msz) return BSTR_ERR;
                   2488:        l = bstr__realloc (sl->entry, nsz);
                   2489:        if (!l) return BSTR_ERR;
                   2490:        sl->mlen = msz;
                   2491:        sl->entry = l;
                   2492:        return BSTR_OK;
                   2493: }
                   2494: 
                   2495: /*  int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
                   2496:  *     int (* cb) (void * parm, int ofs, int len), void * parm)
                   2497:  *
                   2498:  *  Iterate the set of disjoint sequential substrings over str divided by the
                   2499:  *  character in splitChar.
                   2500:  *
                   2501:  *  Note: Non-destructive modification of str from within the cb function 
                   2502:  *  while performing this split is not undefined.  bsplitcb behaves in 
                   2503:  *  sequential lock step with calls to cb.  I.e., after returning from a cb 
                   2504:  *  that return a non-negative integer, bsplitcb continues from the position 
                   2505:  *  1 character after the last detected split character and it will halt 
                   2506:  *  immediately if the length of str falls below this point.  However, if the 
                   2507:  *  cb function destroys str, then it *must* return with a negative value, 
                   2508:  *  otherwise bsplitcb will continue in an undefined manner.
                   2509:  */
                   2510: int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
                   2511:        int (* cb) (void * parm, int ofs, int len), void * parm) {
                   2512: int i, p, ret;
                   2513: 
                   2514:        if (cb == NULL || str == NULL || pos < 0 || pos > str->slen) 
                   2515:                return BSTR_ERR;
                   2516: 
                   2517:        p = pos;
                   2518:        do {
                   2519:                for (i=p; i < str->slen; i++) {
                   2520:                        if (str->data[i] == splitChar) break;
                   2521:                }
                   2522:                if ((ret = cb (parm, p, i - p)) < 0) return ret;
                   2523:                p = i + 1;
                   2524:        } while (p <= str->slen);
                   2525:        return BSTR_OK;
                   2526: }
                   2527: 
                   2528: /*  int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
                   2529:  *     int (* cb) (void * parm, int ofs, int len), void * parm)
                   2530:  *
                   2531:  *  Iterate the set of disjoint sequential substrings over str divided by any 
                   2532:  *  of the characters in splitStr.  An empty splitStr causes the whole str to
                   2533:  *  be iterated once.
                   2534:  *
                   2535:  *  Note: Non-destructive modification of str from within the cb function 
                   2536:  *  while performing this split is not undefined.  bsplitscb behaves in 
                   2537:  *  sequential lock step with calls to cb.  I.e., after returning from a cb 
                   2538:  *  that return a non-negative integer, bsplitscb continues from the position 
                   2539:  *  1 character after the last detected split character and it will halt 
                   2540:  *  immediately if the length of str falls below this point.  However, if the 
                   2541:  *  cb function destroys str, then it *must* return with a negative value, 
                   2542:  *  otherwise bsplitscb will continue in an undefined manner.
                   2543:  */
                   2544: int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
                   2545:        int (* cb) (void * parm, int ofs, int len), void * parm) {
                   2546: struct charField chrs;
                   2547: int i, p, ret;
                   2548: 
                   2549:        if (cb == NULL || str == NULL || pos < 0 || pos > str->slen 
                   2550:         || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
                   2551:        if (splitStr->slen == 0) {
                   2552:                if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0;
                   2553:                return ret;
                   2554:        }
                   2555: 
                   2556:        if (splitStr->slen == 1) 
                   2557:                return bsplitcb (str, splitStr->data[0], pos, cb, parm);
                   2558: 
                   2559:        buildCharField (&chrs, splitStr);
                   2560: 
                   2561:        p = pos;
                   2562:        do {
                   2563:                for (i=p; i < str->slen; i++) {
                   2564:                        if (testInCharField (&chrs, str->data[i])) break;
                   2565:                }
                   2566:                if ((ret = cb (parm, p, i - p)) < 0) return ret;
                   2567:                p = i + 1;
                   2568:        } while (p <= str->slen);
                   2569:        return BSTR_OK;
                   2570: }
                   2571: 
                   2572: /*  int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
                   2573:  *     int (* cb) (void * parm, int ofs, int len), void * parm)
                   2574:  *
                   2575:  *  Iterate the set of disjoint sequential substrings over str divided by the 
                   2576:  *  substring splitStr.  An empty splitStr causes the whole str to be 
                   2577:  *  iterated once.
                   2578:  *
                   2579:  *  Note: Non-destructive modification of str from within the cb function 
                   2580:  *  while performing this split is not undefined.  bsplitstrcb behaves in 
                   2581:  *  sequential lock step with calls to cb.  I.e., after returning from a cb 
                   2582:  *  that return a non-negative integer, bsplitscb continues from the position 
                   2583:  *  1 character after the last detected split character and it will halt 
                   2584:  *  immediately if the length of str falls below this point.  However, if the 
                   2585:  *  cb function destroys str, then it *must* return with a negative value, 
                   2586:  *  otherwise bsplitscb will continue in an undefined manner.
                   2587:  */
                   2588: int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
                   2589:        int (* cb) (void * parm, int ofs, int len), void * parm) {
                   2590: int i, p, ret;
                   2591: 
                   2592:        if (cb == NULL || str == NULL || pos < 0 || pos > str->slen 
                   2593:         || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
                   2594: 
                   2595:        if (0 == splitStr->slen) {
                   2596:                for (i=pos; i < str->slen; i++) {
                   2597:                        if ((ret = cb (parm, i, 1)) < 0) return ret;
                   2598:                }
                   2599:                return BSTR_OK;
                   2600:        }
                   2601: 
                   2602:        if (splitStr->slen == 1) 
                   2603:                return bsplitcb (str, splitStr->data[0], pos, cb, parm);
                   2604: 
                   2605:        for (i=p=pos; i <= str->slen - splitStr->slen; i++) {
                   2606:                if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) {
                   2607:                        if ((ret = cb (parm, p, i - p)) < 0) return ret;
                   2608:                        i += splitStr->slen;
                   2609:                        p = i;
                   2610:                }
                   2611:        }
                   2612:        if ((ret = cb (parm, p, str->slen - p)) < 0) return ret;
                   2613:        return BSTR_OK;
                   2614: }
                   2615: 
                   2616: struct genBstrList {
                   2617:        bstring b;
                   2618:        struct bstrList * bl;
                   2619: };
                   2620: 
                   2621: static int bscb (void * parm, int ofs, int len) {
                   2622: struct genBstrList * g = (struct genBstrList *) parm;
                   2623:        if (g->bl->qty >= g->bl->mlen) {
                   2624:                int mlen = g->bl->mlen * 2;
                   2625:                bstring * tbl;
                   2626: 
                   2627:                while (g->bl->qty >= mlen) {
                   2628:                        if (mlen < g->bl->mlen) return BSTR_ERR;
                   2629:                        mlen += mlen;
                   2630:                }
                   2631: 
                   2632:                tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen);
                   2633:                if (tbl == NULL) return BSTR_ERR;
                   2634: 
                   2635:                g->bl->entry = tbl;
                   2636:                g->bl->mlen = mlen;
                   2637:        }
                   2638: 
                   2639:        g->bl->entry[g->bl->qty] = bmidstr (g->b, ofs, len);
                   2640:        g->bl->qty++;
                   2641:        return BSTR_OK;
                   2642: }
                   2643: 
                   2644: /*  struct bstrList * bsplit (const_bstring str, unsigned char splitChar)
                   2645:  *
                   2646:  *  Create an array of sequential substrings from str divided by the character
                   2647:  *  splitChar.  
                   2648:  */
                   2649: struct bstrList * bsplit (const_bstring str, unsigned char splitChar) {
                   2650: struct genBstrList g;
                   2651: 
                   2652:        if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
                   2653: 
                   2654:        g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
                   2655:        if (g.bl == NULL) return NULL;
                   2656:        g.bl->mlen = 4;
                   2657:        g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
                   2658:        if (NULL == g.bl->entry) {
                   2659:                bstr__free (g.bl);
                   2660:                return NULL;
                   2661:        }
                   2662: 
                   2663:        g.b = (bstring) str;
                   2664:        g.bl->qty = 0;
                   2665:        if (bsplitcb (str, splitChar, 0, bscb, &g) < 0) {
                   2666:                bstrListDestroy (g.bl);
                   2667:                return NULL;
                   2668:        }
                   2669:        return g.bl;
                   2670: }
                   2671: 
                   2672: /*  struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr)
                   2673:  *
                   2674:  *  Create an array of sequential substrings from str divided by the entire
                   2675:  *  substring splitStr.
                   2676:  */
                   2677: struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) {
                   2678: struct genBstrList g;
                   2679: 
                   2680:        if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
                   2681: 
                   2682:        g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
                   2683:        if (g.bl == NULL) return NULL;
                   2684:        g.bl->mlen = 4;
                   2685:        g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
                   2686:        if (NULL == g.bl->entry) {
                   2687:                bstr__free (g.bl);
                   2688:                return NULL;
                   2689:        }
                   2690: 
                   2691:        g.b = (bstring) str;
                   2692:        g.bl->qty = 0;
                   2693:        if (bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) {
                   2694:                bstrListDestroy (g.bl);
                   2695:                return NULL;
                   2696:        }
                   2697:        return g.bl;
                   2698: }
                   2699: 
                   2700: /*  struct bstrList * bsplits (const_bstring str, bstring splitStr)
                   2701:  *
                   2702:  *  Create an array of sequential substrings from str divided by any of the 
                   2703:  *  characters in splitStr.  An empty splitStr causes a single entry bstrList
                   2704:  *  containing a copy of str to be returned.
                   2705:  */
                   2706: struct bstrList * bsplits (const_bstring str, const_bstring splitStr) {
                   2707: struct genBstrList g;
                   2708: 
                   2709:        if (     str == NULL ||      str->slen < 0 ||      str->data == NULL ||
                   2710:            splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL)
                   2711:                return NULL;
                   2712: 
                   2713:        g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
                   2714:        if (g.bl == NULL) return NULL;
                   2715:        g.bl->mlen = 4;
                   2716:        g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
                   2717:        if (NULL == g.bl->entry) {
                   2718:                bstr__free (g.bl);
                   2719:                return NULL;
                   2720:        }
                   2721:        g.b = (bstring) str;
                   2722:        g.bl->qty = 0;
                   2723: 
                   2724:        if (bsplitscb (str, splitStr, 0, bscb, &g) < 0) {
                   2725:                bstrListDestroy (g.bl);
                   2726:                return NULL;
                   2727:        }
                   2728:        return g.bl;
                   2729: }
                   2730: 
                   2731: #if defined (__TURBOC__) && !defined (__BORLANDC__)
                   2732: # ifndef BSTRLIB_NOVSNP
                   2733: #  define BSTRLIB_NOVSNP
                   2734: # endif
                   2735: #endif
                   2736: 
                   2737: /* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */
                   2738: #if defined(__WATCOMC__) || defined(_MSC_VER)
                   2739: #define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);}
                   2740: #else
                   2741: #ifdef BSTRLIB_NOVSNP
                   2742: /* This is just a hack.  If you are using a system without a vsnprintf, it is 
                   2743:    not recommended that bformat be used at all. */
                   2744: #define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;}
                   2745: #define START_VSNBUFF (256)
                   2746: #else
                   2747: 
                   2748: #ifdef __GNUC__
                   2749: /* Something is making gcc complain about this prototype not being here, so 
                   2750:    I've just gone ahead and put it in.
                   2751: extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg);
                   2752:  */
                   2753: #endif
                   2754: 
                   2755: #define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);}
                   2756: #endif
                   2757: #endif
                   2758: 
                   2759: #if !defined (BSTRLIB_NOVSNP)
                   2760: 
                   2761: #ifndef START_VSNBUFF
                   2762: #define START_VSNBUFF (16)
                   2763: #endif
                   2764: 
                   2765: /* On IRIX vsnprintf returns n-1 when the operation would overflow the target 
                   2766:    buffer, WATCOM and MSVC both return -1, while C99 requires that the 
                   2767:    returned value be exactly what the length would be if the buffer would be
                   2768:    large enough.  This leads to the idea that if the return value is larger 
                   2769:    than n, then changing n to the return value will reduce the number of
                   2770:    iterations required. */
                   2771: 
                   2772: /*  int bformata (bstring b, const char * fmt, ...)
                   2773:  *
                   2774:  *  After the first parameter, it takes the same parameters as printf (), but 
                   2775:  *  rather than outputting results to stdio, it appends the results to 
                   2776:  *  a bstring which contains what would have been output. Note that if there 
                   2777:  *  is an early generation of a '\0' character, the bstring will be truncated 
                   2778:  *  to this end point.
                   2779:  */
                   2780: int bformata (bstring b, const char * fmt, ...) {
                   2781: va_list arglist;
                   2782: bstring buff;
                   2783: int n, r;
                   2784: 
                   2785:        if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 
                   2786:         || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
                   2787: 
                   2788:        /* Since the length is not determinable beforehand, a search is
                   2789:           performed using the truncating "vsnprintf" call (to avoid buffer
                   2790:           overflows) on increasing potential sizes for the output result. */
                   2791: 
                   2792:        if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
                   2793:        if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
                   2794:                n = 1;
                   2795:                if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
                   2796:        }
                   2797: 
                   2798:        for (;;) {
                   2799:                va_start (arglist, fmt);
                   2800:                exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
                   2801:                va_end (arglist);
                   2802: 
                   2803:                buff->data[n] = (unsigned char) '\0';
                   2804:                buff->slen = (int) (strlen) ((char *) buff->data);
                   2805: 
                   2806:                if (buff->slen < n) break;
                   2807: 
                   2808:                if (r > n) n = r; else n += n;
                   2809: 
                   2810:                if (BSTR_OK != balloc (buff, n + 2)) {
                   2811:                        bdestroy (buff);
                   2812:                        return BSTR_ERR;
                   2813:                }
                   2814:        }
                   2815: 
                   2816:        r = bconcat (b, buff);
                   2817:        bdestroy (buff);
                   2818:        return r;
                   2819: }
                   2820: 
                   2821: /*  int bassignformat (bstring b, const char * fmt, ...)
                   2822:  *
                   2823:  *  After the first parameter, it takes the same parameters as printf (), but 
                   2824:  *  rather than outputting results to stdio, it outputs the results to 
                   2825:  *  the bstring parameter b. Note that if there is an early generation of a 
                   2826:  *  '\0' character, the bstring will be truncated to this end point.
                   2827:  */
                   2828: int bassignformat (bstring b, const char * fmt, ...) {
                   2829: va_list arglist;
                   2830: bstring buff;
                   2831: int n, r;
                   2832: 
                   2833:        if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0 
                   2834:         || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
                   2835: 
                   2836:        /* Since the length is not determinable beforehand, a search is
                   2837:           performed using the truncating "vsnprintf" call (to avoid buffer
                   2838:           overflows) on increasing potential sizes for the output result. */
                   2839: 
                   2840:        if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
                   2841:        if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
                   2842:                n = 1;
                   2843:                if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
                   2844:        }
                   2845: 
                   2846:        for (;;) {
                   2847:                va_start (arglist, fmt);
                   2848:                exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
                   2849:                va_end (arglist);
                   2850: 
                   2851:                buff->data[n] = (unsigned char) '\0';
                   2852:                buff->slen = (int) (strlen) ((char *) buff->data);
                   2853: 
                   2854:                if (buff->slen < n) break;
                   2855: 
                   2856:                if (r > n) n = r; else n += n;
                   2857: 
                   2858:                if (BSTR_OK != balloc (buff, n + 2)) {
                   2859:                        bdestroy (buff);
                   2860:                        return BSTR_ERR;
                   2861:                }
                   2862:        }
                   2863: 
                   2864:        r = bassign (b, buff);
                   2865:        bdestroy (buff);
                   2866:        return r;
                   2867: }
                   2868: 
                   2869: /*  bstring bformat (const char * fmt, ...)
                   2870:  *
                   2871:  *  Takes the same parameters as printf (), but rather than outputting results
                   2872:  *  to stdio, it forms a bstring which contains what would have been output.
                   2873:  *  Note that if there is an early generation of a '\0' character, the 
                   2874:  *  bstring will be truncated to this end point.
                   2875:  */
                   2876: bstring bformat (const char * fmt, ...) {
                   2877: va_list arglist;
                   2878: bstring buff;
                   2879: int n, r;
                   2880: 
                   2881:        if (fmt == NULL) return NULL;
                   2882: 
                   2883:        /* Since the length is not determinable beforehand, a search is
                   2884:           performed using the truncating "vsnprintf" call (to avoid buffer
                   2885:           overflows) on increasing potential sizes for the output result. */
                   2886: 
                   2887:        if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
                   2888:        if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
                   2889:                n = 1;
                   2890:                if (NULL == (buff = bfromcstralloc (n + 2, ""))) return NULL;
                   2891:        }
                   2892: 
                   2893:        for (;;) {
                   2894:                va_start (arglist, fmt);
                   2895:                exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
                   2896:                va_end (arglist);
                   2897: 
                   2898:                buff->data[n] = (unsigned char) '\0';
                   2899:                buff->slen = (int) (strlen) ((char *) buff->data);
                   2900: 
                   2901:                if (buff->slen < n) break;
                   2902: 
                   2903:                if (r > n) n = r; else n += n;
                   2904: 
                   2905:                if (BSTR_OK != balloc (buff, n + 2)) {
                   2906:                        bdestroy (buff);
                   2907:                        return NULL;
                   2908:                }
                   2909:        }
                   2910: 
                   2911:        return buff;
                   2912: }
                   2913: 
                   2914: /*  int bvcformata (bstring b, int count, const char * fmt, va_list arglist)
                   2915:  *
                   2916:  *  The bvcformata function formats data under control of the format control 
                   2917:  *  string fmt and attempts to append the result to b.  The fmt parameter is 
                   2918:  *  the same as that of the printf function.  The variable argument list is 
                   2919:  *  replaced with arglist, which has been initialized by the va_start macro.
                   2920:  *  The size of the output is upper bounded by count.  If the required output
                   2921:  *  exceeds count, the string b is not augmented with any contents and a value
                   2922:  *  below BSTR_ERR is returned.  If a value below -count is returned then it
                   2923:  *  is recommended that the negative of this value be used as an update to the
                   2924:  *  count in a subsequent pass.  On other errors, such as running out of 
                   2925:  *  memory, parameter errors or numeric wrap around BSTR_ERR is returned.  
                   2926:  *  BSTR_OK is returned when the output is successfully generated and 
                   2927:  *  appended to b.
                   2928:  *
                   2929:  *  Note: There is no sanity checking of arglist, and this function is
                   2930:  *  destructive of the contents of b from the b->slen point onward.  If there 
                   2931:  *  is an early generation of a '\0' character, the bstring will be truncated 
                   2932:  *  to this end point.
                   2933:  */
                   2934: int bvcformata (bstring b, int count, const char * fmt, va_list arg) {
                   2935: int n, r, l;
                   2936: 
                   2937:        if (b == NULL || fmt == NULL || count <= 0 || b->data == NULL
                   2938:         || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
                   2939: 
                   2940:        if (count > (n = b->slen + count) + 2) return BSTR_ERR;
                   2941:        if (BSTR_OK != balloc (b, n + 2)) return BSTR_ERR;
                   2942: 
                   2943:        exvsnprintf (r, (char *) b->data + b->slen, count + 2, fmt, arg);
                   2944: 
                   2945:        /* Did the operation complete successfully within bounds? */
                   2946: 
                   2947:        if (n >= (l = b->slen + (int) (strlen) ((const char *) b->data + b->slen))) {
                   2948:                b->slen = l;
                   2949:                return BSTR_OK;
                   2950:        }
                   2951: 
                   2952:        /* Abort, since the buffer was not large enough.  The return value 
                   2953:           tries to help set what the retry length should be. */
                   2954: 
                   2955:        b->data[b->slen] = '\0';
                   2956:        if (r > count+1) l = r; else {
                   2957:                l = count+count;
                   2958:                if (count > l) l = INT_MAX;
                   2959:        }
                   2960:        n = -l;
                   2961:        if (n > BSTR_ERR-1) n = BSTR_ERR-1;
                   2962:        return n;
                   2963: }
                   2964: 
                   2965: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>