Merge pull request #56 from wuruilong01/master
[prads.git] / src / bstrlib.c
blob04705cd820a603e62b7c0c1f6191af539b2b0be8
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 */
8 /*
9 * bstrlib.c
11 * This file is the core module for implementing the bstring functions.
14 #include <stdio.h>
15 #include <stddef.h>
16 #include <stdarg.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include "bstrlib.h"
22 /* Optionally include a mechanism for debugging memory */
24 #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
25 #include "memdbg.h"
26 #endif
28 #ifndef bstr__alloc
29 #define bstr__alloc(x) malloc (x)
30 #endif
32 #ifndef bstr__free
33 #define bstr__free(p) free (p)
34 #endif
36 #ifndef bstr__realloc
37 #define bstr__realloc(p,x) realloc ((p), (x))
38 #endif
40 #ifndef bstr__memcpy
41 #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
42 #endif
44 #ifndef bstr__memmove
45 #define bstr__memmove(d,s,l) memmove ((d), (s), (l))
46 #endif
48 #ifndef bstr__memset
49 #define bstr__memset(d,c,l) memset ((d), (c), (l))
50 #endif
52 #ifndef bstr__memcmp
53 #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
54 #endif
56 #ifndef bstr__memchr
57 #define bstr__memchr(s,c,l) memchr ((s), (c), (l))
58 #endif
60 /* Just a length safe wrapper for memmove. */
62 #define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); }
64 /* Compute the snapped size for a given requested size. By snapping to powers
65 of 2 like this, repeated reallocations are avoided. */
66 static int snapUpSize (int i) {
67 if (i < 8) {
68 i = 8;
69 } else {
70 unsigned int j;
71 j = (unsigned int) i;
73 j |= (j >> 1);
74 j |= (j >> 2);
75 j |= (j >> 4);
76 j |= (j >> 8); /* Ok, since int >= 16 bits */
77 #if (UINT_MAX != 0xffff)
78 j |= (j >> 16); /* For 32 bit int systems */
79 #if (UINT_MAX > 0xffffffffUL)
80 j |= (j >> 32); /* For 64 bit int systems */
81 #endif
82 #endif
83 /* Least power of two greater than i */
84 j++;
85 if ((int) j >= i) i = (int) j;
87 return i;
90 /* int balloc (bstring b, int len)
92 * Increase the size of the memory backing the bstring b to at least len.
94 int balloc (bstring b, int olen) {
95 int len;
96 if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 ||
97 b->mlen < b->slen || olen <= 0) {
98 return BSTR_ERR;
101 if (olen >= b->mlen) {
102 unsigned char * x;
104 if ((len = snapUpSize (olen)) <= b->mlen) return BSTR_OK;
106 /* Assume probability of a non-moving realloc is 0.125 */
107 if (7 * b->mlen < 8 * b->slen) {
109 /* If slen is close to mlen in size then use realloc to reduce
110 the memory defragmentation */
112 reallocStrategy:;
114 x = (unsigned char *) bstr__realloc (b->data, (size_t) len);
115 if (x == NULL) {
117 /* Since we failed, try allocating the tighest possible
118 allocation */
120 if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) {
121 return BSTR_ERR;
124 } else {
126 /* If slen is not close to mlen then avoid the penalty of copying
127 the extra bytes that are allocated, but not considered part of
128 the string */
130 if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) {
132 /* Perhaps there is no available memory for the two
133 allocations to be in memory at once */
135 goto reallocStrategy;
137 } else {
138 if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen);
139 bstr__free (b->data);
142 b->data = x;
143 b->mlen = len;
144 b->data[b->slen] = (unsigned char) '\0';
147 return BSTR_OK;
150 /* int ballocmin (bstring b, int len)
152 * Set the size of the memory backing the bstring b to len or b->slen+1,
153 * whichever is larger. Note that repeated use of this function can degrade
154 * performance.
156 int ballocmin (bstring b, int len) {
157 unsigned char * s;
159 if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 ||
160 b->mlen < b->slen || len <= 0) {
161 return BSTR_ERR;
164 if (len < b->slen + 1) len = b->slen + 1;
166 if (len != b->mlen) {
167 s = (unsigned char *) bstr__realloc (b->data, (size_t) len);
168 if (NULL == s) return BSTR_ERR;
169 s[b->slen] = (unsigned char) '\0';
170 b->data = s;
171 b->mlen = len;
174 return BSTR_OK;
177 /* bstring bfromcstr (const char * str)
179 * Create a bstring which contains the contents of the '\0' terminated char *
180 * buffer str.
182 bstring bfromcstr (const char * str) {
183 bstring b;
184 int i;
185 size_t j;
187 if (str == NULL) return NULL;
188 j = (strlen) (str);
189 i = snapUpSize ((int) (j + (2 - (j != 0))));
190 if (i <= (int) j) return NULL;
192 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
193 if (NULL == b) return NULL;
194 b->slen = (int) j;
195 if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
196 bstr__free (b);
197 return NULL;
200 bstr__memcpy (b->data, str, j+1);
201 return b;
204 /* bstring bfromcstralloc (int mlen, const char * str)
206 * Create a bstring which contains the contents of the '\0' terminated char *
207 * buffer str. The memory buffer backing the string is at least len
208 * characters in length.
210 bstring bfromcstralloc (int mlen, const char * str) {
211 bstring b;
212 int i;
213 size_t j;
215 if (str == NULL) return NULL;
216 j = (strlen) (str);
217 i = snapUpSize ((int) (j + (2 - (j != 0))));
218 if (i <= (int) j) return NULL;
220 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
221 if (b == NULL) return NULL;
222 b->slen = (int) j;
223 if (i < mlen) i = mlen;
225 if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
226 bstr__free (b);
227 return NULL;
230 bstr__memcpy (b->data, str, j+1);
231 return b;
234 /* bstring blk2bstr (const void * blk, int len)
236 * Create a bstring which contains the content of the block blk of length
237 * len.
239 bstring blk2bstr (const void * blk, int len) {
240 bstring b;
241 int i;
243 if (blk == NULL || len < 0) return NULL;
244 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
245 if (b == NULL) return NULL;
246 b->slen = len;
248 i = len + (2 - (len != 0));
249 i = snapUpSize (i);
251 b->mlen = i;
253 b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen);
254 if (b->data == NULL) {
255 bstr__free (b);
256 return NULL;
259 if (len > 0) bstr__memcpy (b->data, blk, (size_t) len);
260 b->data[len] = (unsigned char) '\0';
262 return b;
265 /* char * bstr2cstr (const_bstring s, char z)
267 * Create a '\0' terminated char * buffer which is equal to the contents of
268 * the bstring s, except that any contained '\0' characters are converted
269 * to the character in z. This returned value should be freed with a
270 * bcstrfree () call, by the calling application.
272 char * bstr2cstr (const_bstring b, char z) {
273 int i, l;
274 char * r;
276 if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
277 l = b->slen;
278 r = (char *) bstr__alloc ((size_t) (l + 1));
279 if (r == NULL) return r;
281 for (i=0; i < l; i ++) {
282 r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i]));
285 r[l] = (unsigned char) '\0';
287 return r;
290 /* int bcstrfree (char * s)
292 * Frees a C-string generated by bstr2cstr (). This is normally unnecessary
293 * since it just wraps a call to bstr__free (), however, if bstr__alloc ()
294 * and bstr__free () have been redefined as a macros within the bstrlib
295 * module (via defining them in memdbg.h after defining
296 * BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std
297 * library functions, then this allows a correct way of freeing the memory
298 * that allows higher level code to be independent from these macro
299 * redefinitions.
301 int bcstrfree (char * s) {
302 if (s) {
303 bstr__free (s);
304 return BSTR_OK;
306 return BSTR_ERR;
309 /* int bconcat (bstring b0, const_bstring b1)
311 * Concatenate the bstring b1 to the bstring b0.
313 int bconcat (bstring b0, const_bstring b1) {
314 int len, d;
315 bstring aux = (bstring) b1;
317 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR;
319 d = b0->slen;
320 len = b1->slen;
321 if ((d | (b0->mlen - d) | len | (d + len)) < 0) return BSTR_ERR;
323 if (b0->mlen <= d + len + 1) {
324 ptrdiff_t pd = b1->data - b0->data;
325 if (0 <= pd && pd < b0->mlen) {
326 if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
328 if (balloc (b0, d + len + 1) != BSTR_OK) {
329 if (aux != b1) bdestroy (aux);
330 return BSTR_ERR;
334 bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len);
335 b0->data[d + len] = (unsigned char) '\0';
336 b0->slen = d + len;
337 if (aux != b1) bdestroy (aux);
338 return BSTR_OK;
341 /* int bconchar (bstring b, char c)
343 * Concatenate the single character c to the bstring b.
345 int bconchar (bstring b, char c) {
346 int d;
348 if (b == NULL) return BSTR_ERR;
349 d = b->slen;
350 if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
351 b->data[d] = (unsigned char) c;
352 b->data[d + 1] = (unsigned char) '\0';
353 b->slen++;
354 return BSTR_OK;
357 /* int bcatcstr (bstring b, const char * s)
359 * Concatenate a char * string to a bstring.
361 int bcatcstr (bstring b, const char * s) {
362 char * d;
363 int i, l;
365 if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
366 || b->mlen <= 0 || s == NULL) return BSTR_ERR;
368 /* Optimistically concatenate directly */
369 l = b->mlen - b->slen;
370 d = (char *) &b->data[b->slen];
371 for (i=0; i < l; i++) {
372 if ((*d++ = *s++) == '\0') {
373 b->slen += i;
374 return BSTR_OK;
377 b->slen += i;
379 /* Need to explicitely resize and concatenate tail */
380 return bcatblk (b, (const void *) s, (int) strlen (s));
383 /* int bcatblk (bstring b, const void * s, int len)
385 * Concatenate a fixed length buffer to a bstring.
387 int bcatblk (bstring b, const void * s, int len) {
388 int nl;
390 if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
391 || b->mlen <= 0 || s == NULL || len < 0) return BSTR_ERR;
393 if (0 > (nl = b->slen + len)) return BSTR_ERR; /* Overflow? */
394 if (b->mlen <= nl && 0 > balloc (b, nl + 1)) return BSTR_ERR;
396 bBlockCopy (&b->data[b->slen], s, (size_t) len);
397 b->slen = nl;
398 b->data[nl] = (unsigned char) '\0';
399 return BSTR_OK;
402 /* bstring bstrcpy (const_bstring b)
404 * Create a copy of the bstring b.
406 bstring bstrcpy (const_bstring b) {
407 bstring b0;
408 int i,j;
410 /* Attempted to copy an invalid string? */
411 if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
413 b0 = (bstring) bstr__alloc (sizeof (struct tagbstring));
414 if (b0 == NULL) {
415 /* Unable to allocate memory for string header */
416 return NULL;
419 i = b->slen;
420 j = snapUpSize (i + 1);
422 b0->data = (unsigned char *) bstr__alloc (j);
423 if (b0->data == NULL) {
424 j = i + 1;
425 b0->data = (unsigned char *) bstr__alloc (j);
426 if (b0->data == NULL) {
427 /* Unable to allocate memory for string data */
428 bstr__free (b0);
429 return NULL;
433 b0->mlen = j;
434 b0->slen = i;
436 if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i);
437 b0->data[b0->slen] = (unsigned char) '\0';
439 return b0;
442 /* int bassign (bstring a, const_bstring b)
444 * Overwrite the string a with the contents of string b.
446 int bassign (bstring a, const_bstring b) {
447 if (b == NULL || b->data == NULL || b->slen < 0)
448 return BSTR_ERR;
449 if (b->slen != 0) {
450 if (balloc (a, b->slen) != BSTR_OK) return BSTR_ERR;
451 bstr__memmove (a->data, b->data, b->slen);
452 } else {
453 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
454 a->slen < 0 || a->mlen == 0)
455 return BSTR_ERR;
457 a->data[b->slen] = (unsigned char) '\0';
458 a->slen = b->slen;
459 return BSTR_OK;
462 /* int bassignmidstr (bstring a, const_bstring b, int left, int len)
464 * Overwrite the string a with the middle of contents of string b
465 * starting from position left and running for a length len. left and
466 * len are clamped to the ends of b as with the function bmidstr.
468 int bassignmidstr (bstring a, const_bstring b, int left, int len) {
469 if (b == NULL || b->data == NULL || b->slen < 0)
470 return BSTR_ERR;
472 if (left < 0) {
473 len += left;
474 left = 0;
477 if (len > b->slen - left) len = b->slen - left;
479 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
480 a->slen < 0 || a->mlen == 0)
481 return BSTR_ERR;
483 if (len > 0) {
484 if (balloc (a, len) != BSTR_OK) return BSTR_ERR;
485 bstr__memmove (a->data, b->data + left, len);
486 a->slen = len;
487 } else {
488 a->slen = 0;
490 a->data[a->slen] = (unsigned char) '\0';
491 return BSTR_OK;
494 /* int bassigncstr (bstring a, const char * str)
496 * Overwrite the string a with the contents of char * string str. Note that
497 * the bstring a must be a well defined and writable bstring. If an error
498 * occurs BSTR_ERR is returned however a may be partially overwritten.
500 int bassigncstr (bstring a, const char * str) {
501 int i;
502 size_t len;
503 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
504 a->slen < 0 || a->mlen == 0 || NULL == str)
505 return BSTR_ERR;
507 for (i=0; i < a->mlen; i++) {
508 if ('\0' == (a->data[i] = str[i])) {
509 a->slen = i;
510 return BSTR_OK;
514 a->slen = i;
515 len = strlen (str + i);
516 if (len > INT_MAX || i + len + 1 > INT_MAX ||
517 0 > balloc (a, (int) (i + len + 1))) return BSTR_ERR;
518 bBlockCopy (a->data + i, str + i, (size_t) len + 1);
519 a->slen += (int) len;
520 return BSTR_OK;
523 /* int bassignblk (bstring a, const void * s, int len)
525 * Overwrite the string a with the contents of the block (s, len). Note that
526 * the bstring a must be a well defined and writable bstring. If an error
527 * occurs BSTR_ERR is returned and a is not overwritten.
529 int bassignblk (bstring a, const void * s, int len) {
530 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
531 a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1)
532 return BSTR_ERR;
533 if (len + 1 > a->mlen && 0 > balloc (a, len + 1)) return BSTR_ERR;
534 bBlockCopy (a->data, s, (size_t) len);
535 a->data[len] = (unsigned char) '\0';
536 a->slen = len;
537 return BSTR_OK;
540 /* int btrunc (bstring b, int n)
542 * Truncate the bstring to at most n characters.
544 int btrunc (bstring b, int n) {
545 if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen ||
546 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
547 if (b->slen > n) {
548 b->slen = n;
549 b->data[n] = (unsigned char) '\0';
551 return BSTR_OK;
554 #define upcase(c) (toupper ((unsigned char) c))
555 #define downcase(c) (tolower ((unsigned char) c))
556 #define wspace(c) (isspace ((unsigned char) c))
558 /* int btoupper (bstring b)
560 * Convert contents of bstring to upper case.
562 int btoupper (bstring b) {
563 int i, len;
564 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
565 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
566 for (i=0, len = b->slen; i < len; i++) {
567 b->data[i] = (unsigned char) upcase (b->data[i]);
569 return BSTR_OK;
572 /* int btolower (bstring b)
574 * Convert contents of bstring to lower case.
576 int btolower (bstring b) {
577 int i, len;
578 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
579 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
580 for (i=0, len = b->slen; i < len; i++) {
581 b->data[i] = (unsigned char) downcase (b->data[i]);
583 return BSTR_OK;
586 /* int bstricmp (const_bstring b0, const_bstring b1)
588 * Compare two strings without differentiating between case. The return
589 * value is the difference of the values of the characters where the two
590 * strings first differ after lower case transformation, otherwise 0 is
591 * returned indicating that the strings are equal. If the lengths are
592 * different, then a difference from 0 is given, but if the first extra
593 * character is '\0', then it is taken to be the value UCHAR_MAX+1.
595 int bstricmp (const_bstring b0, const_bstring b1) {
596 int i, v, n;
598 if (bdata (b0) == NULL || b0->slen < 0 ||
599 bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN;
600 if ((n = b0->slen) > b1->slen) n = b1->slen;
601 else if (b0->slen == b1->slen && b0->data == b1->data) return BSTR_OK;
603 for (i = 0; i < n; i ++) {
604 v = (char) downcase (b0->data[i])
605 - (char) downcase (b1->data[i]);
606 if (0 != v) return v;
609 if (b0->slen > n) {
610 v = (char) downcase (b0->data[n]);
611 if (v) return v;
612 return UCHAR_MAX + 1;
614 if (b1->slen > n) {
615 v = - (char) downcase (b1->data[n]);
616 if (v) return v;
617 return - (int) (UCHAR_MAX + 1);
619 return BSTR_OK;
622 /* int bstrnicmp (const_bstring b0, const_bstring b1, int n)
624 * Compare two strings without differentiating between case for at most n
625 * characters. If the position where the two strings first differ is
626 * before the nth position, the return value is the difference of the values
627 * of the characters, otherwise 0 is returned. If the lengths are different
628 * and less than n characters, then a difference from 0 is given, but if the
629 * first extra character is '\0', then it is taken to be the value
630 * UCHAR_MAX+1.
632 int bstrnicmp (const_bstring b0, const_bstring b1, int n) {
633 int i, v, m;
635 if (bdata (b0) == NULL || b0->slen < 0 ||
636 bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN;
637 m = n;
638 if (m > b0->slen) m = b0->slen;
639 if (m > b1->slen) m = b1->slen;
641 if (b0->data != b1->data) {
642 for (i = 0; i < m; i ++) {
643 v = (char) downcase (b0->data[i]);
644 v -= (char) downcase (b1->data[i]);
645 if (v != 0) return b0->data[i] - b1->data[i];
649 if (n == m || b0->slen == b1->slen) return BSTR_OK;
651 if (b0->slen > m) {
652 v = (char) downcase (b0->data[m]);
653 if (v) return v;
654 return UCHAR_MAX + 1;
657 v = - (char) downcase (b1->data[m]);
658 if (v) return v;
659 return - (int) (UCHAR_MAX + 1);
662 /* int biseqcaseless (const_bstring b0, const_bstring b1)
664 * Compare two strings for equality without differentiating between case.
665 * If the strings differ other than in case, 0 is returned, if the strings
666 * are the same, 1 is returned, if there is an error, -1 is returned. If
667 * the length of the strings are different, this function is O(1). '\0'
668 * termination characters are not treated in any special way.
670 int biseqcaseless (const_bstring b0, const_bstring b1) {
671 int i, n;
673 if (bdata (b0) == NULL || b0->slen < 0 ||
674 bdata (b1) == NULL || b1->slen < 0) return BSTR_ERR;
675 if (b0->slen != b1->slen) return BSTR_OK;
676 if (b0->data == b1->data || b0->slen == 0) return 1;
677 for (i=0, n=b0->slen; i < n; i++) {
678 if (b0->data[i] != b1->data[i]) {
679 unsigned char c = (unsigned char) downcase (b0->data[i]);
680 if (c != (unsigned char) downcase (b1->data[i])) return 0;
683 return 1;
686 /* int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len)
688 * Compare beginning of string b0 with a block of memory of length len
689 * without differentiating between case for equality. If the beginning of b0
690 * differs from the memory block other than in case (or if b0 is too short),
691 * 0 is returned, if the strings are the same, 1 is returned, if there is an
692 * error, -1 is returned. '\0' characters are not treated in any special
693 * way.
695 int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) {
696 int i;
698 if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
699 return BSTR_ERR;
700 if (b0->slen < len) return BSTR_OK;
701 if (b0->data == (const unsigned char *) blk || len == 0) return 1;
703 for (i = 0; i < len; i ++) {
704 if (b0->data[i] != ((const unsigned char *) blk)[i]) {
705 if (downcase (b0->data[i]) !=
706 downcase (((const unsigned char *) blk)[i])) return 0;
709 return 1;
713 * int bltrimws (bstring b)
715 * Delete whitespace contiguous from the left end of the string.
717 int bltrimws (bstring b) {
718 int i, len;
720 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
721 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
723 for (len = b->slen, i = 0; i < len; i++) {
724 if (!wspace (b->data[i])) {
725 return bdelete (b, 0, i);
729 b->data[0] = (unsigned char) '\0';
730 b->slen = 0;
731 return BSTR_OK;
735 * int brtrimws (bstring b)
737 * Delete whitespace contiguous from the right end of the string.
739 int brtrimws (bstring b) {
740 int i;
742 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
743 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
745 for (i = b->slen - 1; i >= 0; i--) {
746 if (!wspace (b->data[i])) {
747 if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
748 b->slen = i + 1;
749 return BSTR_OK;
753 b->data[0] = (unsigned char) '\0';
754 b->slen = 0;
755 return BSTR_OK;
759 * int btrimws (bstring b)
761 * Delete whitespace contiguous from both ends of the string.
763 int btrimws (bstring b) {
764 int i, j;
766 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
767 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
769 for (i = b->slen - 1; i >= 0; i--) {
770 if (!wspace (b->data[i])) {
771 if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
772 b->slen = i + 1;
773 for (j = 0; wspace (b->data[j]); j++) {}
774 return bdelete (b, 0, j);
778 b->data[0] = (unsigned char) '\0';
779 b->slen = 0;
780 return BSTR_OK;
783 /* int biseq (const_bstring b0, const_bstring b1)
785 * Compare the string b0 and b1. If the strings differ, 0 is returned, if
786 * the strings are the same, 1 is returned, if there is an error, -1 is
787 * returned. If the length of the strings are different, this function is
788 * O(1). '\0' termination characters are not treated in any special way.
790 int biseq (const_bstring b0, const_bstring b1) {
791 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
792 b0->slen < 0 || b1->slen < 0) return BSTR_ERR;
793 if (b0->slen != b1->slen) return BSTR_OK;
794 if (b0->data == b1->data || b0->slen == 0) return 1;
795 return !bstr__memcmp (b0->data, b1->data, b0->slen);
798 /* int bisstemeqblk (const_bstring b0, const void * blk, int len)
800 * Compare beginning of string b0 with a block of memory of length len for
801 * equality. If the beginning of b0 differs from the memory block (or if b0
802 * is too short), 0 is returned, if the strings are the same, 1 is returned,
803 * if there is an error, -1 is returned. '\0' characters are not treated in
804 * any special way.
806 int bisstemeqblk (const_bstring b0, const void * blk, int len) {
807 int i;
809 if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
810 return BSTR_ERR;
811 if (b0->slen < len) return BSTR_OK;
812 if (b0->data == (const unsigned char *) blk || len == 0) return 1;
814 for (i = 0; i < len; i ++) {
815 if (b0->data[i] != ((const unsigned char *) blk)[i]) return BSTR_OK;
817 return 1;
820 /* int biseqcstr (const_bstring b, const char *s)
822 * Compare the bstring b and char * string s. The C string s must be '\0'
823 * terminated at exactly the length of the bstring b, and the contents
824 * between the two must be identical with the bstring b with no '\0'
825 * characters for the two contents to be considered equal. This is
826 * equivalent to the condition that their current contents will be always be
827 * equal when comparing them in the same format after converting one or the
828 * other. If the strings are equal 1 is returned, if they are unequal 0 is
829 * returned and if there is a detectable error BSTR_ERR is returned.
831 int biseqcstr (const_bstring b, const char * s) {
832 int i;
833 if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
834 for (i=0; i < b->slen; i++) {
835 if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK;
837 return s[i] == '\0';
840 /* int biseqcstrcaseless (const_bstring b, const char *s)
842 * Compare the bstring b and char * string s. The C string s must be '\0'
843 * terminated at exactly the length of the bstring b, and the contents
844 * between the two must be identical except for case with the bstring b with
845 * no '\0' characters for the two contents to be considered equal. This is
846 * equivalent to the condition that their current contents will be always be
847 * equal ignoring case when comparing them in the same format after
848 * converting one or the other. If the strings are equal, except for case,
849 * 1 is returned, if they are unequal regardless of case 0 is returned and
850 * if there is a detectable error BSTR_ERR is returned.
852 int biseqcstrcaseless (const_bstring b, const char * s) {
853 int i;
854 if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
855 for (i=0; i < b->slen; i++) {
856 if (s[i] == '\0' ||
857 (b->data[i] != (unsigned char) s[i] &&
858 downcase (b->data[i]) != (unsigned char) downcase (s[i])))
859 return BSTR_OK;
861 return s[i] == '\0';
864 /* int bstrcmp (const_bstring b0, const_bstring b1)
866 * Compare the string b0 and b1. If there is an error, SHRT_MIN is returned,
867 * otherwise a value less than or greater than zero, indicating that the
868 * string pointed to by b0 is lexicographically less than or greater than
869 * the string pointed to by b1 is returned. If the the string lengths are
870 * unequal but the characters up until the length of the shorter are equal
871 * then a value less than, or greater than zero, indicating that the string
872 * pointed to by b0 is shorter or longer than the string pointed to by b1 is
873 * returned. 0 is returned if and only if the two strings are the same. If
874 * the length of the strings are different, this function is O(n). Like its
875 * standard C library counter part strcmp, the comparison does not proceed
876 * past any '\0' termination characters encountered.
878 int bstrcmp (const_bstring b0, const_bstring b1) {
879 int i, v, n;
881 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
882 b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
883 n = b0->slen; if (n > b1->slen) n = b1->slen;
884 if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0))
885 return BSTR_OK;
887 for (i = 0; i < n; i ++) {
888 v = ((char) b0->data[i]) - ((char) b1->data[i]);
889 if (v != 0) return v;
890 if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
893 if (b0->slen > n) return 1;
894 if (b1->slen > n) return -1;
895 return BSTR_OK;
898 /* int bstrncmp (const_bstring b0, const_bstring b1, int n)
900 * Compare the string b0 and b1 for at most n characters. If there is an
901 * error, SHRT_MIN is returned, otherwise a value is returned as if b0 and
902 * b1 were first truncated to at most n characters then bstrcmp was called
903 * with these new strings are paremeters. If the length of the strings are
904 * different, this function is O(n). Like its standard C library counter
905 * part strcmp, the comparison does not proceed past any '\0' termination
906 * characters encountered.
908 int bstrncmp (const_bstring b0, const_bstring b1, int n) {
909 int i, v, m;
911 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
912 b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
913 m = n;
914 if (m > b0->slen) m = b0->slen;
915 if (m > b1->slen) m = b1->slen;
917 if (b0->data != b1->data) {
918 for (i = 0; i < m; i ++) {
919 v = ((char) b0->data[i]) - ((char) b1->data[i]);
920 if (v != 0) return v;
921 if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
925 if (n == m || b0->slen == b1->slen) return BSTR_OK;
927 if (b0->slen > m) return 1;
928 return -1;
931 /* bstring bmidstr (const_bstring b, int left, int len)
933 * Create a bstring which is the substring of b starting from position left
934 * and running for a length len (clamped by the end of the bstring b.) If
935 * b is detectably invalid, then NULL is returned. The section described
936 * by (left, len) is clamped to the boundaries of b.
938 bstring bmidstr (const_bstring b, int left, int len) {
940 if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
942 if (left < 0) {
943 len += left;
944 left = 0;
947 if (len > b->slen - left) len = b->slen - left;
949 if (len <= 0) return bfromcstr ("");
950 return blk2bstr (b->data + left, len);
953 /* int bdelete (bstring b, int pos, int len)
955 * Removes characters from pos to pos+len-1 inclusive and shifts the tail of
956 * the bstring starting from pos+len to pos. len must be positive for this
957 * call to have any effect. The section of the string described by (pos,
958 * len) is clamped to boundaries of the bstring b.
960 int bdelete (bstring b, int pos, int len) {
961 /* Clamp to left side of bstring */
962 if (pos < 0) {
963 len += pos;
964 pos = 0;
967 if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 ||
968 b->mlen < b->slen || b->mlen <= 0)
969 return BSTR_ERR;
970 if (len > 0 && pos < b->slen) {
971 if (pos + len >= b->slen) {
972 b->slen = pos;
973 } else {
974 bBlockCopy ((char *) (b->data + pos),
975 (char *) (b->data + pos + len),
976 b->slen - (pos+len));
977 b->slen -= len;
979 b->data[b->slen] = (unsigned char) '\0';
981 return BSTR_OK;
984 /* int bdestroy (bstring b)
986 * Free up the bstring. Note that if b is detectably invalid or not writable
987 * then no action is performed and BSTR_ERR is returned. Like a freed memory
988 * allocation, dereferences, writes or any other action on b after it has
989 * been bdestroyed is undefined.
991 int bdestroy (bstring b) {
992 if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen ||
993 b->data == NULL)
994 return BSTR_ERR;
996 bstr__free (b->data);
998 /* In case there is any stale usage, there is one more chance to
999 notice this error. */
1001 b->slen = -1;
1002 b->mlen = -__LINE__;
1003 b->data = NULL;
1005 bstr__free (b);
1006 return BSTR_OK;
1009 /* int binstr (const_bstring b1, int pos, const_bstring b2)
1011 * Search for the bstring b2 in b1 starting from position pos, and searching
1012 * forward. If it is found then return with the first position where it is
1013 * found, otherwise return BSTR_ERR. Note that this is just a brute force
1014 * string searcher that does not attempt clever things like the Boyer-Moore
1015 * search algorithm. Because of this there are many degenerate cases where
1016 * this can take much longer than it needs to.
1018 int binstr (const_bstring b1, int pos, const_bstring b2) {
1019 int j, ii, ll, lf;
1020 unsigned char * d0;
1021 unsigned char c0;
1022 register unsigned char * d1;
1023 register unsigned char c1;
1024 register int i;
1026 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1027 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1028 if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
1029 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1030 if (b2->slen == 0) return pos;
1032 /* No space to find such a string? */
1033 if ((lf = b1->slen - b2->slen + 1) <= pos) return BSTR_ERR;
1035 /* An obvious alias case */
1036 if (b1->data == b2->data && pos == 0) return 0;
1038 i = pos;
1040 d0 = b2->data;
1041 d1 = b1->data;
1042 ll = b2->slen;
1044 /* Peel off the b2->slen == 1 case */
1045 c0 = d0[0];
1046 if (1 == ll) {
1047 for (;i < lf; i++) if (c0 == d1[i]) return i;
1048 return BSTR_ERR;
1051 c1 = c0;
1052 j = 0;
1053 lf = b1->slen - 1;
1055 ii = -1;
1056 if (i < lf) do {
1057 /* Unrolled current character test */
1058 if (c1 != d1[i]) {
1059 if (c1 != d1[1+i]) {
1060 i += 2;
1061 continue;
1063 i++;
1066 /* Take note if this is the start of a potential match */
1067 if (0 == j) ii = i;
1069 /* Shift the test character down by one */
1070 j++;
1071 i++;
1073 /* If this isn't past the last character continue */
1074 if (j < ll) {
1075 c1 = d0[j];
1076 continue;
1079 N0:;
1081 /* If no characters mismatched, then we matched */
1082 if (i == ii+j) return ii;
1084 /* Shift back to the beginning */
1085 i -= j;
1086 j = 0;
1087 c1 = c0;
1088 } while (i < lf);
1090 /* Deal with last case if unrolling caused a misalignment */
1091 if (i == lf && ll == j+1 && c1 == d1[i]) goto N0;
1093 return BSTR_ERR;
1096 /* int binstrr (const_bstring b1, int pos, const_bstring b2)
1098 * Search for the bstring b2 in b1 starting from position pos, and searching
1099 * backward. If it is found then return with the first position where it is
1100 * found, otherwise return BSTR_ERR. Note that this is just a brute force
1101 * string searcher that does not attempt clever things like the Boyer-Moore
1102 * search algorithm. Because of this there are many degenerate cases where
1103 * this can take much longer than it needs to.
1105 int binstrr (const_bstring b1, int pos, const_bstring b2) {
1106 int j, i, l;
1107 unsigned char * d0, * d1;
1109 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1110 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1111 if (b1->slen == pos && b2->slen == 0) return pos;
1112 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1113 if (b2->slen == 0) return pos;
1115 /* Obvious alias case */
1116 if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0;
1118 i = pos;
1119 if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
1121 /* If no space to find such a string then snap back */
1122 if (l + 1 <= i) i = l;
1123 j = 0;
1125 d0 = b2->data;
1126 d1 = b1->data;
1127 l = b2->slen;
1129 for (;;) {
1130 if (d0[j] == d1[i + j]) {
1131 j ++;
1132 if (j >= l) return i;
1133 } else {
1134 i --;
1135 if (i < 0) break;
1136 j=0;
1140 return BSTR_ERR;
1143 /* int binstrcaseless (const_bstring b1, int pos, const_bstring b2)
1145 * Search for the bstring b2 in b1 starting from position pos, and searching
1146 * forward but without regard to case. If it is found then return with the
1147 * first position where it is found, otherwise return BSTR_ERR. Note that
1148 * this is just a brute force string searcher that does not attempt clever
1149 * things like the Boyer-Moore search algorithm. Because of this there are
1150 * many degenerate cases where this can take much longer than it needs to.
1152 int binstrcaseless (const_bstring b1, int pos, const_bstring b2) {
1153 int j, i, l, ll;
1154 unsigned char * d0, * d1;
1156 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1157 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1158 if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
1159 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1160 if (b2->slen == 0) return pos;
1162 l = b1->slen - b2->slen + 1;
1164 /* No space to find such a string? */
1165 if (l <= pos) return BSTR_ERR;
1167 /* An obvious alias case */
1168 if (b1->data == b2->data && pos == 0) return BSTR_OK;
1170 i = pos;
1171 j = 0;
1173 d0 = b2->data;
1174 d1 = b1->data;
1175 ll = b2->slen;
1177 for (;;) {
1178 if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
1179 j ++;
1180 if (j >= ll) return i;
1181 } else {
1182 i ++;
1183 if (i >= l) break;
1184 j=0;
1188 return BSTR_ERR;
1191 /* int binstrrcaseless (const_bstring b1, int pos, const_bstring b2)
1193 * Search for the bstring b2 in b1 starting from position pos, and searching
1194 * backward but without regard to case. If it is found then return with the
1195 * first position where it is found, otherwise return BSTR_ERR. Note that
1196 * this is just a brute force string searcher that does not attempt clever
1197 * things like the Boyer-Moore search algorithm. Because of this there are
1198 * many degenerate cases where this can take much longer than it needs to.
1200 int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) {
1201 int j, i, l;
1202 unsigned char * d0, * d1;
1204 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1205 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1206 if (b1->slen == pos && b2->slen == 0) return pos;
1207 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1208 if (b2->slen == 0) return pos;
1210 /* Obvious alias case */
1211 if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK;
1213 i = pos;
1214 if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
1216 /* If no space to find such a string then snap back */
1217 if (l + 1 <= i) i = l;
1218 j = 0;
1220 d0 = b2->data;
1221 d1 = b1->data;
1222 l = b2->slen;
1224 for (;;) {
1225 if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
1226 j ++;
1227 if (j >= l) return i;
1228 } else {
1229 i --;
1230 if (i < 0) break;
1231 j=0;
1235 return BSTR_ERR;
1239 /* int bstrchrp (const_bstring b, int c, int pos)
1241 * Search for the character c in b forwards from the position pos
1242 * (inclusive).
1244 int bstrchrp (const_bstring b, int c, int pos) {
1245 unsigned char * p;
1247 if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
1248 p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos));
1249 if (p) return (int) (p - b->data);
1250 return BSTR_ERR;
1253 /* int bstrrchrp (const_bstring b, int c, int pos)
1255 * Search for the character c in b backwards from the position pos in string
1256 * (inclusive).
1258 int bstrrchrp (const_bstring b, int c, int pos) {
1259 int i;
1261 if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
1262 for (i=pos; i >= 0; i--) {
1263 if (b->data[i] == (unsigned char) c) return i;
1265 return BSTR_ERR;
1268 #if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF)
1269 #define LONG_LOG_BITS_QTY (3)
1270 #define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY)
1271 #define LONG_TYPE unsigned char
1273 #define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY)
1274 struct charField { LONG_TYPE content[CFCLEN]; };
1275 #define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1))))
1276 #define setInCharField(cf,idx) { \
1277 unsigned int c = (unsigned int) (idx); \
1278 (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \
1281 #else
1283 #define CFCLEN (1 << CHAR_BIT)
1284 struct charField { unsigned char content[CFCLEN]; };
1285 #define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)])
1286 #define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0
1288 #endif
1290 /* Convert a bstring to charField */
1291 static int buildCharField (struct charField * cf, const_bstring b) {
1292 int i;
1293 if (b == NULL || b->data == NULL || b->slen <= 0) return BSTR_ERR;
1294 memset ((void *) cf->content, 0, sizeof (struct charField));
1295 for (i=0; i < b->slen; i++) {
1296 setInCharField (cf, b->data[i]);
1298 return BSTR_OK;
1301 static void invertCharField (struct charField * cf) {
1302 int i;
1303 for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i];
1306 /* Inner engine for binchr */
1307 static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) {
1308 int i;
1309 for (i=pos; i < len; i++) {
1310 unsigned char c = (unsigned char) data[i];
1311 if (testInCharField (cf, c)) return i;
1313 return BSTR_ERR;
1316 /* int binchr (const_bstring b0, int pos, const_bstring b1);
1318 * Search for the first position in b0 starting from pos or after, in which
1319 * one of the characters in b1 is found and return it. If such a position
1320 * does not exist in b0, then BSTR_ERR is returned.
1322 int binchr (const_bstring b0, int pos, const_bstring b1) {
1323 struct charField chrs;
1324 if (pos < 0 || b0 == NULL || b0->data == NULL ||
1325 b0->slen <= pos) return BSTR_ERR;
1326 if (1 == b1->slen) return bstrchrp (b0, b1->data[0], pos);
1327 if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
1328 return binchrCF (b0->data, b0->slen, pos, &chrs);
1331 /* Inner engine for binchrr */
1332 static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) {
1333 int i;
1334 for (i=pos; i >= 0; i--) {
1335 unsigned int c = (unsigned int) data[i];
1336 if (testInCharField (cf, c)) return i;
1338 return BSTR_ERR;
1341 /* int binchrr (const_bstring b0, int pos, const_bstring b1);
1343 * Search for the last position in b0 no greater than pos, in which one of
1344 * the characters in b1 is found and return it. If such a position does not
1345 * exist in b0, then BSTR_ERR is returned.
1347 int binchrr (const_bstring b0, int pos, const_bstring b1) {
1348 struct charField chrs;
1349 if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL ||
1350 b0->slen < pos) return BSTR_ERR;
1351 if (pos == b0->slen) pos--;
1352 if (1 == b1->slen) return bstrrchrp (b0, b1->data[0], pos);
1353 if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
1354 return binchrrCF (b0->data, pos, &chrs);
1357 /* int bninchr (const_bstring b0, int pos, const_bstring b1);
1359 * Search for the first position in b0 starting from pos or after, in which
1360 * none of the characters in b1 is found and return it. If such a position
1361 * does not exist in b0, then BSTR_ERR is returned.
1363 int bninchr (const_bstring b0, int pos, const_bstring b1) {
1364 struct charField chrs;
1365 if (pos < 0 || b0 == NULL || b0->data == NULL ||
1366 b0->slen <= pos) return BSTR_ERR;
1367 if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
1368 invertCharField (&chrs);
1369 return binchrCF (b0->data, b0->slen, pos, &chrs);
1372 /* int bninchrr (const_bstring b0, int pos, const_bstring b1);
1374 * Search for the last position in b0 no greater than pos, in which none of
1375 * the characters in b1 is found and return it. If such a position does not
1376 * exist in b0, then BSTR_ERR is returned.
1378 int bninchrr (const_bstring b0, int pos, const_bstring b1) {
1379 struct charField chrs;
1380 if (pos < 0 || b0 == NULL || b0->data == NULL ||
1381 b0->slen < pos) return BSTR_ERR;
1382 if (pos == b0->slen) pos--;
1383 if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
1384 invertCharField (&chrs);
1385 return binchrrCF (b0->data, pos, &chrs);
1388 /* int bsetstr (bstring b0, int pos, bstring b1, unsigned char fill)
1390 * Overwrite the string b0 starting at position pos with the string b1. If
1391 * the position pos is past the end of b0, then the character "fill" is
1392 * appended as necessary to make up the gap between the end of b0 and pos.
1393 * If b1 is NULL, it behaves as if it were a 0-length string.
1395 int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) {
1396 int d, newlen;
1397 ptrdiff_t pd;
1398 bstring aux = (bstring) b1;
1400 if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data ||
1401 b0->mlen < b0->slen || b0->mlen <= 0) return BSTR_ERR;
1402 if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return BSTR_ERR;
1404 d = pos;
1406 /* Aliasing case */
1407 if (NULL != aux) {
1408 if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) {
1409 if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
1411 d += aux->slen;
1414 /* Increase memory size if necessary */
1415 if (balloc (b0, d + 1) != BSTR_OK) {
1416 if (aux != b1) bdestroy (aux);
1417 return BSTR_ERR;
1420 newlen = b0->slen;
1422 /* Fill in "fill" character as necessary */
1423 if (pos > newlen) {
1424 bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen));
1425 newlen = pos;
1428 /* Copy b1 to position pos in b0. */
1429 if (aux != NULL) {
1430 bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen);
1431 if (aux != b1) bdestroy (aux);
1434 /* Indicate the potentially increased size of b0 */
1435 if (d > newlen) newlen = d;
1437 b0->slen = newlen;
1438 b0->data[newlen] = (unsigned char) '\0';
1440 return BSTR_OK;
1443 /* int binsert (bstring b1, int pos, bstring b2, unsigned char fill)
1445 * Inserts the string b2 into b1 at position pos. If the position pos is
1446 * past the end of b1, then the character "fill" is appended as necessary to
1447 * make up the gap between the end of b1 and pos. Unlike bsetstr, binsert
1448 * does not allow b2 to be NULL.
1450 int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) {
1451 int d, l;
1452 ptrdiff_t pd;
1453 bstring aux = (bstring) b2;
1455 if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 ||
1456 b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR;
1458 /* Aliasing case */
1459 if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) {
1460 if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
1463 /* Compute the two possible end pointers */
1464 d = b1->slen + aux->slen;
1465 l = pos + aux->slen;
1466 if ((d|l) < 0) return BSTR_ERR;
1468 if (l > d) {
1469 /* Inserting past the end of the string */
1470 if (balloc (b1, l + 1) != BSTR_OK) {
1471 if (aux != b2) bdestroy (aux);
1472 return BSTR_ERR;
1474 bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen));
1475 b1->slen = l;
1476 } else {
1477 /* Inserting in the middle of the string */
1478 if (balloc (b1, d + 1) != BSTR_OK) {
1479 if (aux != b2) bdestroy (aux);
1480 return BSTR_ERR;
1482 bBlockCopy (b1->data + l, b1->data + pos, d - l);
1483 b1->slen = d;
1485 bBlockCopy (b1->data + pos, aux->data, aux->slen);
1486 b1->data[b1->slen] = (unsigned char) '\0';
1487 if (aux != b2) bdestroy (aux);
1488 return BSTR_OK;
1491 /* int breplace (bstring b1, int pos, int len, bstring b2,
1492 * unsigned char fill)
1494 * Replace a section of a string from pos for a length len with the string b2.
1495 * fill is used is pos > b1->slen.
1497 int breplace (bstring b1, int pos, int len, const_bstring b2,
1498 unsigned char fill) {
1499 int pl, ret;
1500 ptrdiff_t pd;
1501 bstring aux = (bstring) b2;
1503 if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL ||
1504 b2 == NULL || b1->data == NULL || b2->data == NULL ||
1505 b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen ||
1506 b1->mlen <= 0) return BSTR_ERR;
1508 /* Straddles the end? */
1509 if (pl >= b1->slen) {
1510 if ((ret = bsetstr (b1, pos, b2, fill)) < 0) return ret;
1511 if (pos + b2->slen < b1->slen) {
1512 b1->slen = pos + b2->slen;
1513 b1->data[b1->slen] = (unsigned char) '\0';
1515 return ret;
1518 /* Aliasing case */
1519 if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) {
1520 if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
1523 if (aux->slen > len) {
1524 if (balloc (b1, b1->slen + aux->slen - len) != BSTR_OK) {
1525 if (aux != b2) bdestroy (aux);
1526 return BSTR_ERR;
1530 if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len));
1531 bstr__memcpy (b1->data + pos, aux->data, aux->slen);
1532 b1->slen += aux->slen - len;
1533 b1->data[b1->slen] = (unsigned char) '\0';
1534 if (aux != b2) bdestroy (aux);
1535 return BSTR_OK;
1538 /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
1539 * int pos)
1541 * Replace all occurrences of a find string with a replace string after a
1542 * given point in a bstring.
1545 typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2);
1547 static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) {
1548 int i, ret, slen, mlen, delta, acc;
1549 int * d;
1550 int static_d[32];
1551 ptrdiff_t pd;
1552 bstring auxf = (bstring) find;
1553 bstring auxr = (bstring) repl;
1555 if (b == NULL || b->data == NULL || find == NULL ||
1556 find->data == NULL || repl == NULL || repl->data == NULL ||
1557 pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen ||
1558 b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return BSTR_ERR;
1559 if (pos > b->slen - find->slen) return BSTR_OK;
1561 /* Alias with find string */
1562 pd = (ptrdiff_t) (find->data - b->data);
1563 if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) {
1564 if (NULL == (auxf = bstrcpy (find))) return BSTR_ERR;
1567 /* Alias with repl string */
1568 pd = (ptrdiff_t) (repl->data - b->data);
1569 if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) {
1570 if (NULL == (auxr = bstrcpy (repl))) {
1571 if (auxf != find) bdestroy (auxf);
1572 return BSTR_ERR;
1576 delta = auxf->slen - auxr->slen;
1578 /* in-place replacement since find and replace strings are of equal
1579 length */
1580 if (delta == 0) {
1581 while ((pos = instr (b, pos, auxf)) >= 0) {
1582 bstr__memcpy (b->data + pos, auxr->data, auxr->slen);
1583 pos += auxf->slen;
1585 if (auxf != find) bdestroy (auxf);
1586 if (auxr != repl) bdestroy (auxr);
1587 return BSTR_OK;
1590 /* shrinking replacement since auxf->slen > auxr->slen */
1591 if (delta > 0) {
1592 acc = 0;
1594 while ((i = instr (b, pos, auxf)) >= 0) {
1595 if (acc && i > pos)
1596 bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
1597 if (auxr->slen)
1598 bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen);
1599 acc += delta;
1600 pos = i + auxf->slen;
1603 if (acc) {
1604 i = b->slen;
1605 if (i > pos)
1606 bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
1607 b->slen -= acc;
1608 b->data[b->slen] = (unsigned char) '\0';
1611 if (auxf != find) bdestroy (auxf);
1612 if (auxr != repl) bdestroy (auxr);
1613 return BSTR_OK;
1616 /* expanding replacement since find->slen < repl->slen. Its a lot
1617 more complicated. */
1619 mlen = 32;
1620 d = (int *) static_d; /* Avoid malloc for trivial cases */
1621 acc = slen = 0;
1623 while ((pos = instr (b, pos, auxf)) >= 0) {
1624 if (slen + 1 >= mlen) {
1625 int sl;
1626 int * t;
1627 mlen += mlen;
1628 sl = sizeof (int *) * mlen;
1629 if (static_d == d) d = NULL;
1630 if (sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) {
1631 ret = BSTR_ERR;
1632 goto done;
1634 if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d));
1635 d = t;
1637 d[slen] = pos;
1638 slen++;
1639 acc -= delta;
1640 pos += auxf->slen;
1641 if (pos < 0 || acc < 0) {
1642 ret = BSTR_ERR;
1643 goto done;
1646 d[slen] = b->slen;
1648 if (BSTR_OK == (ret = balloc (b, b->slen + acc + 1))) {
1649 b->slen += acc;
1650 for (i = slen-1; i >= 0; i--) {
1651 int s, l;
1652 s = d[i] + auxf->slen;
1653 l = d[i+1] - s;
1654 if (l) {
1655 bstr__memmove (b->data + s + acc, b->data + s, l);
1657 if (auxr->slen) {
1658 bstr__memmove (b->data + s + acc - auxr->slen,
1659 auxr->data, auxr->slen);
1661 acc += delta;
1663 b->data[b->slen] = (unsigned char) '\0';
1666 done:;
1667 if (static_d == d) d = NULL;
1668 bstr__free (d);
1669 if (auxf != find) bdestroy (auxf);
1670 if (auxr != repl) bdestroy (auxr);
1671 return ret;
1674 /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
1675 * int pos)
1677 * Replace all occurrences of a find string with a replace string after a
1678 * given point in a bstring.
1680 int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) {
1681 return findreplaceengine (b, find, repl, pos, binstr);
1684 /* int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl,
1685 * int pos)
1687 * Replace all occurrences of a find string, ignoring case, with a replace
1688 * string after a given point in a bstring.
1690 int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) {
1691 return findreplaceengine (b, find, repl, pos, binstrcaseless);
1694 /* int binsertch (bstring b, int pos, int len, unsigned char fill)
1696 * Inserts the character fill repeatedly into b at position pos for a
1697 * length len. If the position pos is past the end of b, then the
1698 * character "fill" is appended as necessary to make up the gap between the
1699 * end of b and the position pos + len.
1701 int binsertch (bstring b, int pos, int len, unsigned char fill) {
1702 int d, l, i;
1704 if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen ||
1705 b->mlen <= 0 || len < 0) return BSTR_ERR;
1707 /* Compute the two possible end pointers */
1708 d = b->slen + len;
1709 l = pos + len;
1710 if ((d|l) < 0) return BSTR_ERR;
1712 if (l > d) {
1713 /* Inserting past the end of the string */
1714 if (balloc (b, l + 1) != BSTR_OK) return BSTR_ERR;
1715 pos = b->slen;
1716 b->slen = l;
1717 } else {
1718 /* Inserting in the middle of the string */
1719 if (balloc (b, d + 1) != BSTR_OK) return BSTR_ERR;
1720 for (i = d - 1; i >= l; i--) {
1721 b->data[i] = b->data[i - len];
1723 b->slen = d;
1726 for (i=pos; i < l; i++) b->data[i] = fill;
1727 b->data[b->slen] = (unsigned char) '\0';
1728 return BSTR_OK;
1731 /* int bpattern (bstring b, int len)
1733 * Replicate the bstring, b in place, end to end repeatedly until it
1734 * surpasses len characters, then chop the result to exactly len characters.
1735 * This function operates in-place. The function will return with BSTR_ERR
1736 * if b is NULL or of length 0, otherwise BSTR_OK is returned.
1738 int bpattern (bstring b, int len) {
1739 int i, d;
1741 d = blength (b);
1742 if (d <= 0 || len < 0 || balloc (b, len + 1) != BSTR_OK) return BSTR_ERR;
1743 if (len > 0) {
1744 if (d == 1) return bsetstr (b, len, NULL, b->data[0]);
1745 for (i = d; i < len; i++) b->data[i] = b->data[i - d];
1747 b->data[len] = (unsigned char) '\0';
1748 b->slen = len;
1749 return BSTR_OK;
1752 #define BS_BUFF_SZ (1024)
1754 /* int breada (bstring b, bNread readPtr, void * parm)
1756 * Use a finite buffer fread-like function readPtr to concatenate to the
1757 * bstring b the entire contents of file-like source data in a roughly
1758 * efficient way.
1760 int breada (bstring b, bNread readPtr, void * parm) {
1761 int i, l, n;
1763 if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1764 b->mlen <= 0 || readPtr == NULL) return BSTR_ERR;
1766 i = b->slen;
1767 for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) {
1768 if (BSTR_OK != balloc (b, n + 1)) return BSTR_ERR;
1769 l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm);
1770 i += l;
1771 b->slen = i;
1772 if (i < n) break;
1775 b->data[i] = (unsigned char) '\0';
1776 return BSTR_OK;
1779 /* bstring bread (bNread readPtr, void * parm)
1781 * Use a finite buffer fread-like function readPtr to create a bstring
1782 * filled with the entire contents of file-like source data in a roughly
1783 * efficient way.
1785 bstring bread (bNread readPtr, void * parm) {
1786 bstring buff;
1788 if (0 > breada (buff = bfromcstr (""), readPtr, parm)) {
1789 bdestroy (buff);
1790 return NULL;
1792 return buff;
1795 /* int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator)
1797 * Use an fgetc-like single character stream reading function (getcPtr) to
1798 * obtain a sequence of characters which are concatenated to the end of the
1799 * bstring b. The stream read is terminated by the passed in terminator
1800 * parameter.
1802 * If getcPtr returns with a negative number, or the terminator character
1803 * (which is appended) is read, then the stream reading is halted and the
1804 * function returns with a partial result in b. If there is an empty partial
1805 * result, 1 is returned. If no characters are read, or there is some other
1806 * detectable error, BSTR_ERR is returned.
1808 int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1809 int c, d, e;
1811 if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1812 b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
1813 d = 0;
1814 e = b->mlen - 2;
1816 while ((c = getcPtr (parm)) >= 0) {
1817 if (d > e) {
1818 b->slen = d;
1819 if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
1820 e = b->mlen - 2;
1822 b->data[d] = (unsigned char) c;
1823 d++;
1824 if (c == terminator) break;
1827 b->data[d] = (unsigned char) '\0';
1828 b->slen = d;
1830 return d == 0 && c < 0;
1833 /* int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator)
1835 * Use an fgetc-like single character stream reading function (getcPtr) to
1836 * obtain a sequence of characters which are concatenated to the end of the
1837 * bstring b. The stream read is terminated by the passed in terminator
1838 * parameter.
1840 * If getcPtr returns with a negative number, or the terminator character
1841 * (which is appended) is read, then the stream reading is halted and the
1842 * function returns with a partial result concatentated to b. If there is
1843 * an empty partial result, 1 is returned. If no characters are read, or
1844 * there is some other detectable error, BSTR_ERR is returned.
1846 int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1847 int c, d, e;
1849 if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1850 b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
1851 d = b->slen;
1852 e = b->mlen - 2;
1854 while ((c = getcPtr (parm)) >= 0) {
1855 if (d > e) {
1856 b->slen = d;
1857 if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
1858 e = b->mlen - 2;
1860 b->data[d] = (unsigned char) c;
1861 d++;
1862 if (c == terminator) break;
1865 b->data[d] = (unsigned char) '\0';
1866 b->slen = d;
1868 return d == 0 && c < 0;
1871 /* bstring bgets (bNgetc getcPtr, void * parm, char terminator)
1873 * Use an fgetc-like single character stream reading function (getcPtr) to
1874 * obtain a sequence of characters which are concatenated into a bstring.
1875 * The stream read is terminated by the passed in terminator function.
1877 * If getcPtr returns with a negative number, or the terminator character
1878 * (which is appended) is read, then the stream reading is halted and the
1879 * result obtained thus far is returned. If no characters are read, or
1880 * there is some other detectable error, NULL is returned.
1882 bstring bgets (bNgetc getcPtr, void * parm, char terminator) {
1883 bstring buff;
1885 if (0 > bgetsa (buff = bfromcstr (""), getcPtr, parm, terminator) || 0 >= buff->slen) {
1886 bdestroy (buff);
1887 buff = NULL;
1889 return buff;
1892 struct bStream {
1893 bstring buff; /* Buffer for over-reads */
1894 void * parm; /* The stream handle for core stream */
1895 bNread readFnPtr; /* fread compatible fnptr for core stream */
1896 int isEOF; /* track file's EOF state */
1897 int maxBuffSz;
1900 /* struct bStream * bsopen (bNread readPtr, void * parm)
1902 * Wrap a given open stream (described by a fread compatible function
1903 * pointer and stream handle) into an open bStream suitable for the bstring
1904 * library streaming functions.
1906 struct bStream * bsopen (bNread readPtr, void * parm) {
1907 struct bStream * s;
1909 if (readPtr == NULL) return NULL;
1910 s = (struct bStream *) bstr__alloc (sizeof (struct bStream));
1911 if (s == NULL) return NULL;
1912 s->parm = parm;
1913 s->buff = bfromcstr ("");
1914 s->readFnPtr = readPtr;
1915 s->maxBuffSz = BS_BUFF_SZ;
1916 s->isEOF = 0;
1917 return s;
1920 /* int bsbufflength (struct bStream * s, int sz)
1922 * Set the length of the buffer used by the bStream. If sz is zero, the
1923 * length is not set. This function returns with the previous length.
1925 int bsbufflength (struct bStream * s, int sz) {
1926 int oldSz;
1927 if (s == NULL || sz < 0) return BSTR_ERR;
1928 oldSz = s->maxBuffSz;
1929 if (sz > 0) s->maxBuffSz = sz;
1930 return oldSz;
1933 int bseof (const struct bStream * s) {
1934 if (s == NULL || s->readFnPtr == NULL) return BSTR_ERR;
1935 return s->isEOF && (s->buff->slen == 0);
1938 /* void * bsclose (struct bStream * s)
1940 * Close the bStream, and return the handle to the stream that was originally
1941 * used to open the given stream.
1943 void * bsclose (struct bStream * s) {
1944 void * parm;
1945 if (s == NULL) return NULL;
1946 s->readFnPtr = NULL;
1947 if (s->buff) bdestroy (s->buff);
1948 s->buff = NULL;
1949 parm = s->parm;
1950 s->parm = NULL;
1951 s->isEOF = 1;
1952 bstr__free (s);
1953 return parm;
1956 /* int bsreadlna (bstring r, struct bStream * s, char terminator)
1958 * Read a bstring terminated by the terminator character or the end of the
1959 * stream from the bStream (s) and return it into the parameter r. This
1960 * function may read additional characters from the core stream that are not
1961 * returned, but will be retained for subsequent read operations.
1963 int bsreadlna (bstring r, struct bStream * s, char terminator) {
1964 int i, l, ret, rlo;
1965 char * b;
1966 struct tagbstring x;
1968 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 ||
1969 r->slen < 0 || r->mlen < r->slen) return BSTR_ERR;
1970 l = s->buff->slen;
1971 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
1972 b = (char *) s->buff->data;
1973 x.data = (unsigned char *) b;
1975 /* First check if the current buffer holds the terminator */
1976 b[l] = terminator; /* Set sentinel */
1977 for (i=0; b[i] != terminator; i++) ;
1978 if (i < l) {
1979 x.slen = i + 1;
1980 ret = bconcat (r, &x);
1981 s->buff->slen = l;
1982 if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
1983 return BSTR_OK;
1986 rlo = r->slen;
1988 /* If not then just concatenate the entire buffer to the output */
1989 x.slen = l;
1990 if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
1992 /* Perform direct in-place reads into the destination to allow for
1993 the minimum of data-copies */
1994 for (;;) {
1995 if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
1996 b = (char *) (r->data + r->slen);
1997 l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
1998 if (l <= 0) {
1999 r->data[r->slen] = (unsigned char) '\0';
2000 s->buff->slen = 0;
2001 s->isEOF = 1;
2002 /* If nothing was read return with an error message */
2003 return BSTR_ERR & -(r->slen == rlo);
2005 b[l] = terminator; /* Set sentinel */
2006 for (i=0; b[i] != terminator; i++) ;
2007 if (i < l) break;
2008 r->slen += l;
2011 /* Terminator found, push over-read back to buffer */
2012 i++;
2013 r->slen += i;
2014 s->buff->slen = l - i;
2015 bstr__memcpy (s->buff->data, b + i, l - i);
2016 r->data[r->slen] = (unsigned char) '\0';
2017 return BSTR_OK;
2020 /* int bsreadlnsa (bstring r, struct bStream * s, bstring term)
2022 * Read a bstring terminated by any character in the term string or the end
2023 * of the stream from the bStream (s) and return it into the parameter r.
2024 * This function may read additional characters from the core stream that
2025 * are not returned, but will be retained for subsequent read operations.
2027 int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) {
2028 int i, l, ret, rlo;
2029 unsigned char * b;
2030 struct tagbstring x;
2031 struct charField cf;
2033 if (s == NULL || s->buff == NULL || r == NULL || term == NULL ||
2034 term->data == NULL || r->mlen <= 0 || r->slen < 0 ||
2035 r->mlen < r->slen) return BSTR_ERR;
2036 if (term->slen == 1) return bsreadlna (r, s, term->data[0]);
2037 if (term->slen < 1 || buildCharField (&cf, term)) return BSTR_ERR;
2039 l = s->buff->slen;
2040 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2041 b = (unsigned char *) s->buff->data;
2042 x.data = b;
2044 /* First check if the current buffer holds the terminator */
2045 b[l] = term->data[0]; /* Set sentinel */
2046 for (i=0; !testInCharField (&cf, b[i]); i++) ;
2047 if (i < l) {
2048 x.slen = i + 1;
2049 ret = bconcat (r, &x);
2050 s->buff->slen = l;
2051 if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
2052 return BSTR_OK;
2055 rlo = r->slen;
2057 /* If not then just concatenate the entire buffer to the output */
2058 x.slen = l;
2059 if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
2061 /* Perform direct in-place reads into the destination to allow for
2062 the minimum of data-copies */
2063 for (;;) {
2064 if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
2065 b = (unsigned char *) (r->data + r->slen);
2066 l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
2067 if (l <= 0) {
2068 r->data[r->slen] = (unsigned char) '\0';
2069 s->buff->slen = 0;
2070 s->isEOF = 1;
2071 /* If nothing was read return with an error message */
2072 return BSTR_ERR & -(r->slen == rlo);
2075 b[l] = term->data[0]; /* Set sentinel */
2076 for (i=0; !testInCharField (&cf, b[i]); i++) ;
2077 if (i < l) break;
2078 r->slen += l;
2081 /* Terminator found, push over-read back to buffer */
2082 i++;
2083 r->slen += i;
2084 s->buff->slen = l - i;
2085 bstr__memcpy (s->buff->data, b + i, l - i);
2086 r->data[r->slen] = (unsigned char) '\0';
2087 return BSTR_OK;
2090 /* int bsreada (bstring r, struct bStream * s, int n)
2092 * Read a bstring of length n (or, if it is fewer, as many bytes as is
2093 * remaining) from the bStream. This function may read additional
2094 * characters from the core stream that are not returned, but will be
2095 * retained for subsequent read operations. This function will not read
2096 * additional characters from the core stream beyond virtual stream pointer.
2098 int bsreada (bstring r, struct bStream * s, int n) {
2099 int l, ret, orslen;
2100 char * b;
2101 struct tagbstring x;
2103 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
2104 || r->slen < 0 || r->mlen < r->slen || n <= 0) return BSTR_ERR;
2106 n += r->slen;
2107 if (n <= 0) return BSTR_ERR;
2109 l = s->buff->slen;
2111 orslen = r->slen;
2113 if (0 == l) {
2114 if (s->isEOF) return BSTR_ERR;
2115 if (r->mlen > n) {
2116 l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm);
2117 if (0 >= l || l > n - r->slen) {
2118 s->isEOF = 1;
2119 return BSTR_ERR;
2121 r->slen += l;
2122 r->data[r->slen] = (unsigned char) '\0';
2123 return 0;
2127 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2128 b = (char *) s->buff->data;
2129 x.data = (unsigned char *) b;
2131 do {
2132 if (l + r->slen >= n) {
2133 x.slen = n - r->slen;
2134 ret = bconcat (r, &x);
2135 s->buff->slen = l;
2136 if (BSTR_OK == ret) bdelete (s->buff, 0, x.slen);
2137 return BSTR_ERR & -(r->slen == orslen);
2140 x.slen = l;
2141 if (BSTR_OK != bconcat (r, &x)) break;
2143 l = n - r->slen;
2144 if (l > s->maxBuffSz) l = s->maxBuffSz;
2146 l = (int) s->readFnPtr (b, 1, l, s->parm);
2148 } while (l > 0);
2149 if (l < 0) l = 0;
2150 if (l == 0) s->isEOF = 1;
2151 s->buff->slen = l;
2152 return BSTR_ERR & -(r->slen == orslen);
2155 /* int bsreadln (bstring r, struct bStream * s, char terminator)
2157 * Read a bstring terminated by the terminator character or the end of the
2158 * stream from the bStream (s) and return it into the parameter r. This
2159 * function may read additional characters from the core stream that are not
2160 * returned, but will be retained for subsequent read operations.
2162 int bsreadln (bstring r, struct bStream * s, char terminator) {
2163 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0)
2164 return BSTR_ERR;
2165 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2166 r->slen = 0;
2167 return bsreadlna (r, s, terminator);
2170 /* int bsreadlns (bstring r, struct bStream * s, bstring term)
2172 * Read a bstring terminated by any character in the term string or the end
2173 * of the stream from the bStream (s) and return it into the parameter r.
2174 * This function may read additional characters from the core stream that
2175 * are not returned, but will be retained for subsequent read operations.
2177 int bsreadlns (bstring r, struct bStream * s, const_bstring term) {
2178 if (s == NULL || s->buff == NULL || r == NULL || term == NULL
2179 || term->data == NULL || r->mlen <= 0) return BSTR_ERR;
2180 if (term->slen == 1) return bsreadln (r, s, term->data[0]);
2181 if (term->slen < 1) return BSTR_ERR;
2182 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2183 r->slen = 0;
2184 return bsreadlnsa (r, s, term);
2187 /* int bsread (bstring r, struct bStream * s, int n)
2189 * Read a bstring of length n (or, if it is fewer, as many bytes as is
2190 * remaining) from the bStream. This function may read additional
2191 * characters from the core stream that are not returned, but will be
2192 * retained for subsequent read operations. This function will not read
2193 * additional characters from the core stream beyond virtual stream pointer.
2195 int bsread (bstring r, struct bStream * s, int n) {
2196 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
2197 || n <= 0) return BSTR_ERR;
2198 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2199 r->slen = 0;
2200 return bsreada (r, s, n);
2203 /* int bsunread (struct bStream * s, const_bstring b)
2205 * Insert a bstring into the bStream at the current position. These
2206 * characters will be read prior to those that actually come from the core
2207 * stream.
2209 int bsunread (struct bStream * s, const_bstring b) {
2210 if (s == NULL || s->buff == NULL) return BSTR_ERR;
2211 return binsert (s->buff, 0, b, (unsigned char) '?');
2214 /* int bspeek (bstring r, const struct bStream * s)
2216 * Return the currently buffered characters from the bStream that will be
2217 * read prior to reads from the core stream.
2219 int bspeek (bstring r, const struct bStream * s) {
2220 if (s == NULL || s->buff == NULL) return BSTR_ERR;
2221 return bassign (r, s->buff);
2224 /* bstring bjoin (const struct bstrList * bl, const_bstring sep);
2226 * Join the entries of a bstrList into one bstring by sequentially
2227 * concatenating them with the sep string in between. If there is an error
2228 * NULL is returned, otherwise a bstring with the correct result is returned.
2230 bstring bjoin (const struct bstrList * bl, const_bstring sep) {
2231 bstring b;
2232 int i, c, v;
2234 if (bl == NULL || bl->qty < 0) return NULL;
2235 if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL;
2237 for (i = 0, c = 1; i < bl->qty; i++) {
2238 v = bl->entry[i]->slen;
2239 if (v < 0) return NULL; /* Invalid input */
2240 c += v;
2241 if (c < 0) return NULL; /* Wrap around ?? */
2244 if (sep != NULL) c += (bl->qty - 1) * sep->slen;
2246 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
2247 if (NULL == b) return NULL; /* Out of memory */
2248 b->data = (unsigned char *) bstr__alloc (c);
2249 if (b->data == NULL) {
2250 bstr__free (b);
2251 return NULL;
2254 b->mlen = c;
2255 b->slen = c-1;
2257 for (i = 0, c = 0; i < bl->qty; i++) {
2258 if (i > 0 && sep != NULL) {
2259 bstr__memcpy (b->data + c, sep->data, sep->slen);
2260 c += sep->slen;
2262 v = bl->entry[i]->slen;
2263 bstr__memcpy (b->data + c, bl->entry[i]->data, v);
2264 c += v;
2266 b->data[c] = (unsigned char) '\0';
2267 return b;
2270 #define BSSSC_BUFF_LEN (256)
2272 /* int bssplitscb (struct bStream * s, const_bstring splitStr,
2273 * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
2275 * Iterate the set of disjoint sequential substrings read from a stream
2276 * divided by any of the characters in splitStr. An empty splitStr causes
2277 * the whole stream to be iterated once.
2279 * Note: At the point of calling the cb function, the bStream pointer is
2280 * pointed exactly at the position right after having read the split
2281 * character. The cb function can act on the stream by causing the bStream
2282 * pointer to move, and bssplitscb will continue by starting the next split
2283 * at the position of the pointer after the return from cb.
2285 * However, if the cb causes the bStream s to be destroyed then the cb must
2286 * return with a negative value, otherwise bssplitscb will continue in an
2287 * undefined manner.
2289 int bssplitscb (struct bStream * s, const_bstring splitStr,
2290 int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2291 struct charField chrs;
2292 bstring buff;
2293 int i, p, ret;
2295 if (cb == NULL || s == NULL || s->readFnPtr == NULL
2296 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2298 if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
2300 if (splitStr->slen == 0) {
2301 while (bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ;
2302 if ((ret = cb (parm, 0, buff)) > 0)
2303 ret = 0;
2304 } else {
2305 buildCharField (&chrs, splitStr);
2306 ret = p = i = 0;
2307 for (;;) {
2308 if (i >= buff->slen) {
2309 bsreada (buff, s, BSSSC_BUFF_LEN);
2310 if (i >= buff->slen) {
2311 if (0 < (ret = cb (parm, p, buff))) ret = 0;
2312 break;
2315 if (testInCharField (&chrs, buff->data[i])) {
2316 struct tagbstring t;
2317 unsigned char c;
2319 blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1));
2320 if ((ret = bsunread (s, &t)) < 0) break;
2321 buff->slen = i;
2322 c = buff->data[i];
2323 buff->data[i] = (unsigned char) '\0';
2324 if ((ret = cb (parm, p, buff)) < 0) break;
2325 buff->data[i] = c;
2326 buff->slen = 0;
2327 p += i + 1;
2328 i = -1;
2330 i++;
2334 bdestroy (buff);
2335 return ret;
2338 /* int bssplitstrcb (struct bStream * s, const_bstring splitStr,
2339 * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
2341 * Iterate the set of disjoint sequential substrings read from a stream
2342 * divided by the entire substring splitStr. An empty splitStr causes
2343 * each character of the stream to be iterated.
2345 * Note: At the point of calling the cb function, the bStream pointer is
2346 * pointed exactly at the position right after having read the split
2347 * character. The cb function can act on the stream by causing the bStream
2348 * pointer to move, and bssplitscb will continue by starting the next split
2349 * at the position of the pointer after the return from cb.
2351 * However, if the cb causes the bStream s to be destroyed then the cb must
2352 * return with a negative value, otherwise bssplitscb will continue in an
2353 * undefined manner.
2355 int bssplitstrcb (struct bStream * s, const_bstring splitStr,
2356 int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2357 bstring buff;
2358 int i, p, ret;
2360 if (cb == NULL || s == NULL || s->readFnPtr == NULL
2361 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2363 if (splitStr->slen == 1) return bssplitscb (s, splitStr, cb, parm);
2365 if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
2367 if (splitStr->slen == 0) {
2368 for (i=0; bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) {
2369 if ((ret = cb (parm, 0, buff)) < 0) {
2370 bdestroy (buff);
2371 return ret;
2373 buff->slen = 0;
2375 return BSTR_OK;
2376 } else {
2377 ret = p = i = 0;
2378 for (i=p=0;;) {
2379 if ((ret = binstr (buff, 0, splitStr)) >= 0) {
2380 struct tagbstring t;
2381 blk2tbstr (t, buff->data, ret);
2382 i = ret + splitStr->slen;
2383 if ((ret = cb (parm, p, &t)) < 0) break;
2384 p += i;
2385 bdelete (buff, 0, i);
2386 } else {
2387 bsreada (buff, s, BSSSC_BUFF_LEN);
2388 if (bseof (s)) {
2389 if ((ret = cb (parm, p, buff)) > 0) ret = 0;
2390 break;
2396 bdestroy (buff);
2397 return ret;
2400 /* int bstrListCreate (void)
2402 * Create a bstrList.
2404 struct bstrList * bstrListCreate (void) {
2405 struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2406 if (sl) {
2407 sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring));
2408 if (!sl->entry) {
2409 bstr__free (sl);
2410 sl = NULL;
2411 } else {
2412 sl->qty = 0;
2413 sl->mlen = 1;
2416 return sl;
2419 /* int bstrListDestroy (struct bstrList * sl)
2421 * Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate.
2423 int bstrListDestroy (struct bstrList * sl) {
2424 int i;
2425 if (sl == NULL || sl->qty < 0) return BSTR_ERR;
2426 for (i=0; i < sl->qty; i++) {
2427 if (sl->entry[i]) {
2428 bdestroy (sl->entry[i]);
2429 sl->entry[i] = NULL;
2432 sl->qty = -1;
2433 sl->mlen = -1;
2434 bstr__free (sl->entry);
2435 sl->entry = NULL;
2436 bstr__free (sl);
2437 return BSTR_OK;
2440 /* int bstrListAlloc (struct bstrList * sl, int msz)
2442 * Ensure that there is memory for at least msz number of entries for the
2443 * list.
2445 int bstrListAlloc (struct bstrList * sl, int msz) {
2446 bstring * l;
2447 int smsz;
2448 size_t nsz;
2449 if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
2450 if (sl->mlen >= msz) return BSTR_OK;
2451 smsz = snapUpSize (msz);
2452 nsz = ((size_t) smsz) * sizeof (bstring);
2453 if (nsz < (size_t) smsz) return BSTR_ERR;
2454 l = (bstring *) bstr__realloc (sl->entry, nsz);
2455 if (!l) {
2456 smsz = msz;
2457 nsz = ((size_t) smsz) * sizeof (bstring);
2458 l = (bstring *) bstr__realloc (sl->entry, nsz);
2459 if (!l) return BSTR_ERR;
2461 sl->mlen = smsz;
2462 sl->entry = l;
2463 return BSTR_OK;
2466 /* int bstrListAllocMin (struct bstrList * sl, int msz)
2468 * Try to allocate the minimum amount of memory for the list to include at
2469 * least msz entries or sl->qty whichever is greater.
2471 int bstrListAllocMin (struct bstrList * sl, int msz) {
2472 bstring * l;
2473 size_t nsz;
2474 if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
2475 if (msz < sl->qty) msz = sl->qty;
2476 if (sl->mlen == msz) return BSTR_OK;
2477 nsz = ((size_t) msz) * sizeof (bstring);
2478 if (nsz < (size_t) msz) return BSTR_ERR;
2479 l = (bstring *) bstr__realloc (sl->entry, nsz);
2480 if (!l) return BSTR_ERR;
2481 sl->mlen = msz;
2482 sl->entry = l;
2483 return BSTR_OK;
2486 /* int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2487 * int (* cb) (void * parm, int ofs, int len), void * parm)
2489 * Iterate the set of disjoint sequential substrings over str divided by the
2490 * character in splitChar.
2492 * Note: Non-destructive modification of str from within the cb function
2493 * while performing this split is not undefined. bsplitcb behaves in
2494 * sequential lock step with calls to cb. I.e., after returning from a cb
2495 * that return a non-negative integer, bsplitcb continues from the position
2496 * 1 character after the last detected split character and it will halt
2497 * immediately if the length of str falls below this point. However, if the
2498 * cb function destroys str, then it *must* return with a negative value,
2499 * otherwise bsplitcb will continue in an undefined manner.
2501 int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2502 int (* cb) (void * parm, int ofs, int len), void * parm) {
2503 int i, p, ret;
2505 if (cb == NULL || str == NULL || pos < 0 || pos > str->slen)
2506 return BSTR_ERR;
2508 p = pos;
2509 do {
2510 for (i=p; i < str->slen; i++) {
2511 if (str->data[i] == splitChar) break;
2513 if ((ret = cb (parm, p, i - p)) < 0) return ret;
2514 p = i + 1;
2515 } while (p <= str->slen);
2516 return BSTR_OK;
2519 /* int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2520 * int (* cb) (void * parm, int ofs, int len), void * parm)
2522 * Iterate the set of disjoint sequential substrings over str divided by any
2523 * of the characters in splitStr. An empty splitStr causes the whole str to
2524 * be iterated once.
2526 * Note: Non-destructive modification of str from within the cb function
2527 * while performing this split is not undefined. bsplitscb behaves in
2528 * sequential lock step with calls to cb. I.e., after returning from a cb
2529 * that return a non-negative integer, bsplitscb continues from the position
2530 * 1 character after the last detected split character and it will halt
2531 * immediately if the length of str falls below this point. However, if the
2532 * cb function destroys str, then it *must* return with a negative value,
2533 * otherwise bsplitscb will continue in an undefined manner.
2535 int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2536 int (* cb) (void * parm, int ofs, int len), void * parm) {
2537 struct charField chrs;
2538 int i, p, ret;
2540 if (cb == NULL || str == NULL || pos < 0 || pos > str->slen
2541 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2542 if (splitStr->slen == 0) {
2543 if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0;
2544 return ret;
2547 if (splitStr->slen == 1)
2548 return bsplitcb (str, splitStr->data[0], pos, cb, parm);
2550 buildCharField (&chrs, splitStr);
2552 p = pos;
2553 do {
2554 for (i=p; i < str->slen; i++) {
2555 if (testInCharField (&chrs, str->data[i])) break;
2557 if ((ret = cb (parm, p, i - p)) < 0) return ret;
2558 p = i + 1;
2559 } while (p <= str->slen);
2560 return BSTR_OK;
2563 /* int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2564 * int (* cb) (void * parm, int ofs, int len), void * parm)
2566 * Iterate the set of disjoint sequential substrings over str divided by the
2567 * substring splitStr. An empty splitStr causes the whole str to be
2568 * iterated once.
2570 * Note: Non-destructive modification of str from within the cb function
2571 * while performing this split is not undefined. bsplitstrcb behaves in
2572 * sequential lock step with calls to cb. I.e., after returning from a cb
2573 * that return a non-negative integer, bsplitscb continues from the position
2574 * 1 character after the last detected split character and it will halt
2575 * immediately if the length of str falls below this point. However, if the
2576 * cb function destroys str, then it *must* return with a negative value,
2577 * otherwise bsplitscb will continue in an undefined manner.
2579 int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2580 int (* cb) (void * parm, int ofs, int len), void * parm) {
2581 int i, p, ret;
2583 if (cb == NULL || str == NULL || pos < 0 || pos > str->slen
2584 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2586 if (0 == splitStr->slen) {
2587 for (i=pos; i < str->slen; i++) {
2588 if ((ret = cb (parm, i, 1)) < 0) return ret;
2590 return BSTR_OK;
2593 if (splitStr->slen == 1)
2594 return bsplitcb (str, splitStr->data[0], pos, cb, parm);
2596 for (i=p=pos; i <= str->slen - splitStr->slen; i++) {
2597 if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) {
2598 if ((ret = cb (parm, p, i - p)) < 0) return ret;
2599 i += splitStr->slen;
2600 p = i;
2603 if ((ret = cb (parm, p, str->slen - p)) < 0) return ret;
2604 return BSTR_OK;
2607 struct genBstrList {
2608 bstring b;
2609 struct bstrList * bl;
2612 static int bscb (void * parm, int ofs, int len) {
2613 struct genBstrList * g = (struct genBstrList *) parm;
2614 if (g->bl->qty >= g->bl->mlen) {
2615 int mlen = g->bl->mlen * 2;
2616 bstring * tbl;
2618 while (g->bl->qty >= mlen) {
2619 if (mlen < g->bl->mlen) return BSTR_ERR;
2620 mlen += mlen;
2623 tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen);
2624 if (tbl == NULL) return BSTR_ERR;
2626 g->bl->entry = tbl;
2627 g->bl->mlen = mlen;
2630 g->bl->entry[g->bl->qty] = bmidstr (g->b, ofs, len);
2631 g->bl->qty++;
2632 return BSTR_OK;
2635 /* struct bstrList * bsplit (const_bstring str, unsigned char splitChar)
2637 * Create an array of sequential substrings from str divided by the character
2638 * splitChar.
2640 struct bstrList * bsplit (const_bstring str, unsigned char splitChar) {
2641 struct genBstrList g;
2643 if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
2645 g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2646 if (g.bl == NULL) return NULL;
2647 g.bl->mlen = 4;
2648 g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2649 if (NULL == g.bl->entry) {
2650 bstr__free (g.bl);
2651 return NULL;
2654 g.b = (bstring) str;
2655 g.bl->qty = 0;
2656 if (bsplitcb (str, splitChar, 0, bscb, &g) < 0) {
2657 bstrListDestroy (g.bl);
2658 return NULL;
2660 return g.bl;
2663 /* struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr)
2665 * Create an array of sequential substrings from str divided by the entire
2666 * substring splitStr.
2668 struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) {
2669 struct genBstrList g;
2671 if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
2673 g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2674 if (g.bl == NULL) return NULL;
2675 g.bl->mlen = 4;
2676 g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2677 if (NULL == g.bl->entry) {
2678 bstr__free (g.bl);
2679 return NULL;
2682 g.b = (bstring) str;
2683 g.bl->qty = 0;
2684 if (bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) {
2685 bstrListDestroy (g.bl);
2686 return NULL;
2688 return g.bl;
2691 /* struct bstrList * bsplits (const_bstring str, bstring splitStr)
2693 * Create an array of sequential substrings from str divided by any of the
2694 * characters in splitStr. An empty splitStr causes a single entry bstrList
2695 * containing a copy of str to be returned.
2697 struct bstrList * bsplits (const_bstring str, const_bstring splitStr) {
2698 struct genBstrList g;
2700 if ( str == NULL || str->slen < 0 || str->data == NULL ||
2701 splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL)
2702 return NULL;
2704 g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2705 if (g.bl == NULL) return NULL;
2706 g.bl->mlen = 4;
2707 g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2708 if (NULL == g.bl->entry) {
2709 bstr__free (g.bl);
2710 return NULL;
2712 g.b = (bstring) str;
2713 g.bl->qty = 0;
2715 if (bsplitscb (str, splitStr, 0, bscb, &g) < 0) {
2716 bstrListDestroy (g.bl);
2717 return NULL;
2719 return g.bl;
2722 #if defined (__TURBOC__) && !defined (__BORLANDC__)
2723 # ifndef BSTRLIB_NOVSNP
2724 # define BSTRLIB_NOVSNP
2725 # endif
2726 #endif
2728 /* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */
2729 #if defined(__WATCOMC__) || defined(_MSC_VER)
2730 #define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);}
2731 #else
2732 #ifdef BSTRLIB_NOVSNP
2733 /* This is just a hack. If you are using a system without a vsnprintf, it is
2734 not recommended that bformat be used at all. */
2735 #define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;}
2736 #define START_VSNBUFF (256)
2737 #else
2739 #if 0 //defined __GNUC__
2740 /* Something is making gcc complain about this prototype not being here, so
2741 I've just gone ahead and put it in. */
2742 extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg);
2743 #endif
2745 #define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);}
2746 #endif
2747 #endif
2749 #if !defined (BSTRLIB_NOVSNP)
2751 #ifndef START_VSNBUFF
2752 #define START_VSNBUFF (16)
2753 #endif
2755 /* On IRIX vsnprintf returns n-1 when the operation would overflow the target
2756 buffer, WATCOM and MSVC both return -1, while C99 requires that the
2757 returned value be exactly what the length would be if the buffer would be
2758 large enough. This leads to the idea that if the return value is larger
2759 than n, then changing n to the return value will reduce the number of
2760 iterations required. */
2762 /* int bformata (bstring b, const char * fmt, ...)
2764 * After the first parameter, it takes the same parameters as printf (), but
2765 * rather than outputting results to stdio, it appends the results to
2766 * a bstring which contains what would have been output. Note that if there
2767 * is an early generation of a '\0' character, the bstring will be truncated
2768 * to this end point.
2770 int bformata (bstring b, const char * fmt, ...) {
2771 va_list arglist;
2772 bstring buff;
2773 int n, r;
2775 if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0
2776 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
2778 /* Since the length is not determinable beforehand, a search is
2779 performed using the truncating "vsnprintf" call (to avoid buffer
2780 overflows) on increasing potential sizes for the output result. */
2782 if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
2783 if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
2784 n = 1;
2785 if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
2788 for (;;) {
2789 va_start (arglist, fmt);
2790 exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
2791 va_end (arglist);
2793 buff->data[n] = (unsigned char) '\0';
2794 buff->slen = (int) (strlen) ((char *) buff->data);
2796 if (buff->slen < n) break;
2798 if (r > n) n = r; else n += n;
2800 if (BSTR_OK != balloc (buff, n + 2)) {
2801 bdestroy (buff);
2802 return BSTR_ERR;
2806 r = bconcat (b, buff);
2807 bdestroy (buff);
2808 return r;
2811 /* int bassignformat (bstring b, const char * fmt, ...)
2813 * After the first parameter, it takes the same parameters as printf (), but
2814 * rather than outputting results to stdio, it outputs the results to
2815 * the bstring parameter b. Note that if there is an early generation of a
2816 * '\0' character, the bstring will be truncated to this end point.
2818 int bassignformat (bstring b, const char * fmt, ...) {
2819 va_list arglist;
2820 bstring buff;
2821 int n, r;
2823 if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0
2824 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
2826 /* Since the length is not determinable beforehand, a search is
2827 performed using the truncating "vsnprintf" call (to avoid buffer
2828 overflows) on increasing potential sizes for the output result. */
2830 if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
2831 if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
2832 n = 1;
2833 if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
2836 for (;;) {
2837 va_start (arglist, fmt);
2838 exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
2839 va_end (arglist);
2841 buff->data[n] = (unsigned char) '\0';
2842 buff->slen = (int) (strlen) ((char *) buff->data);
2844 if (buff->slen < n) break;
2846 if (r > n) n = r; else n += n;
2848 if (BSTR_OK != balloc (buff, n + 2)) {
2849 bdestroy (buff);
2850 return BSTR_ERR;
2854 r = bassign (b, buff);
2855 bdestroy (buff);
2856 return r;
2859 /* bstring bformat (const char * fmt, ...)
2861 * Takes the same parameters as printf (), but rather than outputting results
2862 * to stdio, it forms a bstring which contains what would have been output.
2863 * Note that if there is an early generation of a '\0' character, the
2864 * bstring will be truncated to this end point.
2866 bstring bformat (const char * fmt, ...) {
2867 va_list arglist;
2868 bstring buff;
2869 int n, r;
2871 if (fmt == NULL) return NULL;
2873 /* Since the length is not determinable beforehand, a search is
2874 performed using the truncating "vsnprintf" call (to avoid buffer
2875 overflows) on increasing potential sizes for the output result. */
2877 if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
2878 if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
2879 n = 1;
2880 if (NULL == (buff = bfromcstralloc (n + 2, ""))) return NULL;
2883 for (;;) {
2884 va_start (arglist, fmt);
2885 exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
2886 va_end (arglist);
2888 buff->data[n] = (unsigned char) '\0';
2889 buff->slen = (int) (strlen) ((char *) buff->data);
2891 if (buff->slen < n) break;
2893 if (r > n) n = r; else n += n;
2895 if (BSTR_OK != balloc (buff, n + 2)) {
2896 bdestroy (buff);
2897 return NULL;
2901 return buff;
2904 /* int bvcformata (bstring b, int count, const char * fmt, va_list arglist)
2906 * The bvcformata function formats data under control of the format control
2907 * string fmt and attempts to append the result to b. The fmt parameter is
2908 * the same as that of the printf function. The variable argument list is
2909 * replaced with arglist, which has been initialized by the va_start macro.
2910 * The size of the output is upper bounded by count. If the required output
2911 * exceeds count, the string b is not augmented with any contents and a value
2912 * below BSTR_ERR is returned. If a value below -count is returned then it
2913 * is recommended that the negative of this value be used as an update to the
2914 * count in a subsequent pass. On other errors, such as running out of
2915 * memory, parameter errors or numeric wrap around BSTR_ERR is returned.
2916 * BSTR_OK is returned when the output is successfully generated and
2917 * appended to b.
2919 * Note: There is no sanity checking of arglist, and this function is
2920 * destructive of the contents of b from the b->slen point onward. If there
2921 * is an early generation of a '\0' character, the bstring will be truncated
2922 * to this end point.
2924 int bvcformata (bstring b, int count, const char * fmt, va_list arg) {
2925 int n, r, l;
2927 if (b == NULL || fmt == NULL || count <= 0 || b->data == NULL
2928 || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
2930 if (count > (n = b->slen + count) + 2) return BSTR_ERR;
2931 if (BSTR_OK != balloc (b, n + 2)) return BSTR_ERR;
2933 exvsnprintf (r, (char *) b->data + b->slen, count + 2, fmt, arg);
2935 /* Did the operation complete successfully within bounds? */
2937 if (n >= (l = b->slen + (int) (strlen) ((const char *) b->data + b->slen))) {
2938 b->slen = l;
2939 return BSTR_OK;
2942 /* Abort, since the buffer was not large enough. The return value
2943 tries to help set what the retry length should be. */
2945 b->data[b->slen] = '\0';
2946 if (r > count+1) l = r; else {
2947 l = count+count;
2948 if (count > l) l = INT_MAX;
2950 n = -l;
2951 if (n > BSTR_ERR-1) n = BSTR_ERR-1;
2952 return n;
2955 #endif