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