Annotation of embedaddon/coova-chilli/bstring/bstrlib.c, revision 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>