File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / coova-chilli / bstring / bstrlib.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:48:25 2012 UTC (13 years, 1 month ago) by misho
Branches: coova-chilli, MAIN
CVS tags: v1_0_12, HEAD
coova-chilli

    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>