]> arthur.barton.de Git - netatalk.git/blob - libatalk/bstring/bstrlib.c
Log message was using wrong variable
[netatalk.git] / libatalk / bstring / bstrlib.c
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. */
67 static 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  */
95 int 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  */
157 int 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  */
183 bstring bfromcstr (const char * str) {
184 bstring b;
185 int i;
186 size_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  */
211 bstring bfromcstralloc (int mlen, const char * str) {
212 bstring b;
213 int i;
214 size_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  */
240 bstring blk2bstr (const void * blk, int len) {
241 bstring b;
242 int 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  */
273 char * bstr2cstr (const_bstring b, char z) {
274 int i, l;
275 char * 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  */
302 int 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  */
314 int bconcat (bstring b0, const_bstring b1) {
315 int len, d;
316 bstring 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  */
346 int bconchar (bstring b, char c) {
347 int 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  */
362 int bcatcstr (bstring b, const char * s) {
363 char * d;
364 int 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  */
388 int bcatblk (bstring b, const void * s, int len) {
389 int 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  */
407 bstring bstrcpy (const_bstring b) {
408 bstring b0;
409 int 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  */
447 int 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  */
469 int 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  */
501 int bassigncstr (bstring a, const char * str) {
502 int i;
503 size_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  */
530 int 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  */
545 int 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  */
563 int btoupper (bstring b) {
564 int 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  */
577 int btolower (bstring b) {
578 int 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  */
596 int bstricmp (const_bstring b0, const_bstring b1) {
597 int 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  */
633 int bstrnicmp (const_bstring b0, const_bstring b1, int n) {
634 int 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  */
671 int biseqcaseless (const_bstring b0, const_bstring b1) {
672 int 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  */
696 int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) {
697 int 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  */
718 int bltrimws (bstring b) {
719 int 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  */
740 int brtrimws (bstring b) {
741 int 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  */
764 int btrimws (bstring b) {
765 int 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  */
791 int 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  */
807 int bisstemeqblk (const_bstring b0, const void * blk, int len) {
808 int 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  */
832 int biseqcstr (const_bstring b, const char * s) {
833 int 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  */
853 int biseqcstrcaseless (const_bstring b, const char * s) {
854 int 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  */
879 int bstrcmp (const_bstring b0, const_bstring b1) {
880 int 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  */
909 int bstrncmp (const_bstring b0, const_bstring b1, int n) {
910 int 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  */
939 bstring 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  */
961 int 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  */
992 int 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  */
1019 int binstr (const_bstring b1, int pos, const_bstring b2) {
1020 int j, ii, ll, lf;
1021 unsigned char * d0;
1022 unsigned char c0;
1023 register unsigned char * d1;
1024 register unsigned char c1;
1025 register 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  */
1106 int binstrr (const_bstring b1, int pos, const_bstring b2) {
1107 int j, i, l;
1108 unsigned 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  */
1153 int binstrcaseless (const_bstring b1, int pos, const_bstring b2) {
1154 int j, i, l, ll;
1155 unsigned 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  */
1201 int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) {
1202 int j, i, l;
1203 unsigned 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  */
1245 int bstrchrp (const_bstring b, int c, int pos) {
1246 unsigned 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  */
1259 int bstrrchrp (const_bstring b, int c, int pos) {
1260 int 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)
1275 struct 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)
1285 struct 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 */
1292 static int buildCharField (struct charField * cf, const_bstring b) {
1293 int 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
1302 static void invertCharField (struct charField * cf) {
1303 int i;
1304         for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i];
1305 }
1306
1307 /* Inner engine for binchr */
1308 static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) {
1309 int 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  */
1323 int binchr (const_bstring b0, int pos, const_bstring b1) {
1324 struct 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 */
1333 static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) {
1334 int 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  */
1348 int binchrr (const_bstring b0, int pos, const_bstring b1) {
1349 struct 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  */
1364 int bninchr (const_bstring b0, int pos, const_bstring b1) {
1365 struct 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  */
1379 int bninchrr (const_bstring b0, int pos, const_bstring b1) {
1380 struct 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  */
1396 int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) {
1397 int d, newlen;
1398 ptrdiff_t pd;
1399 bstring 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  */
1451 int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) {
1452 int d, l;
1453 ptrdiff_t pd;
1454 bstring 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  */
1498 int breplace (bstring b1, int pos, int len, const_bstring b2, 
1499                           unsigned char fill) {
1500 int pl, ret;
1501 ptrdiff_t pd;
1502 bstring 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
1546 typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2);
1547
1548 static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) {
1549 int i, ret, slen, mlen, delta, acc;
1550 int * d;
1551 int static_d[32];
1552 ptrdiff_t pd;
1553 bstring auxf = (bstring) find;
1554 bstring 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  */
1681 int 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  */
1691 int 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  */
1702 int binsertch (bstring b, int pos, int len, unsigned char fill) {
1703 int 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  */
1739 int bpattern (bstring b, int len) {
1740 int 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  */
1761 int breada (bstring b, bNread readPtr, void * parm) {
1762 int 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  */
1786 bstring bread (bNread readPtr, void * parm) {
1787 bstring 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  */
1809 int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1810 int 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  */
1847 int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1848 int 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  */
1883 bstring bgetstream (bNgetc getcPtr, void * parm, char terminator) {
1884 bstring 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
1893 struct 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  */
1907 struct bStream * bsopen (bNread readPtr, void * parm) {
1908 struct 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  */
1926 int bsbufflength (struct bStream * s, int sz) {
1927 int 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
1934 int 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  */
1944 void * bsclose (struct bStream * s) {
1945 void * 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  */
1964 int bsreadlna (bstring r, struct bStream * s, char terminator) {
1965 int i, l, ret, rlo;
1966 char * b;
1967 struct 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  */
2028 int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) {
2029 int i, l, ret, rlo;
2030 unsigned char * b;
2031 struct tagbstring x;
2032 struct 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  */
2099 int bsreada (bstring r, struct bStream * s, int n) {
2100 int l, ret, orslen;
2101 char * b;
2102 struct 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  */
2163 int 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  */
2178 int 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  */
2196 int 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  */
2210 int 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  */
2220 int 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  */
2231 bstring bjoin (const struct bstrList * bl, const_bstring sep) {
2232 bstring b;
2233 int 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  */
2290 int bssplitscb (struct bStream * s, const_bstring splitStr, 
2291         int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2292 struct charField chrs;
2293 bstring buff;
2294 int 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  */
2356 int bssplitstrcb (struct bStream * s, const_bstring splitStr, 
2357         int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2358 bstring buff;
2359 int 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  */
2405 struct bstrList * bstrListCreate (void) {
2406 struct 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  */
2424 int bstrListDestroy (struct bstrList * sl) {
2425 int 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  */
2446 int bstrListAlloc (struct bstrList * sl, int msz) {
2447 bstring * l;
2448 int smsz;
2449 size_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  */
2472 int bstrListAllocMin (struct bstrList * sl, int msz) {
2473 bstring * l;
2474 size_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  */
2502 int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2503         int (* cb) (void * parm, int ofs, int len), void * parm) {
2504 int 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  */
2536 int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2537         int (* cb) (void * parm, int ofs, int len), void * parm) {
2538 struct charField chrs;
2539 int 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  */
2580 int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2581         int (* cb) (void * parm, int ofs, int len), void * parm) {
2582 int 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
2608 struct genBstrList {
2609         bstring b;
2610         struct bstrList * bl;
2611 };
2612
2613 static int bscb (void * parm, int ofs, int len) {
2614 struct 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  */
2641 struct bstrList * bsplit (const_bstring str, unsigned char splitChar) {
2642 struct 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  */
2669 struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) {
2670 struct 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  */
2698 struct bstrList * bsplits (const_bstring str, const_bstring splitStr) {
2699 struct 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. */
2743 extern 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  */
2771 int bformata (bstring b, const char * fmt, ...) {
2772 va_list arglist;
2773 bstring buff;
2774 int 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  */
2819 int bassignformat (bstring b, const char * fmt, ...) {
2820 va_list arglist;
2821 bstring buff;
2822 int 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  */
2867 bstring bformat (const char * fmt, ...) {
2868 va_list arglist;
2869 bstring buff;
2870 int 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  */
2925 int bvcformata (bstring b, int count, const char * fmt, va_list arg) {
2926 int 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