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.
11 * This file is the core module for implementing the bstring functions.
21 #include <atalk/bstrlib.h>
23 /* Optionally include a mechanism for debugging memory */
25 #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
30 #define bstr__alloc(x) malloc (x)
34 #define bstr__free(p) free (p)
38 #define bstr__realloc(p,x) realloc ((p), (x))
42 #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
46 #define bstr__memmove(d,s,l) memmove ((d), (s), (l))
50 #define bstr__memset(d,c,l) memset ((d), (c), (l))
54 #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
58 #define bstr__memchr(s,c,l) memchr ((s), (c), (l))
61 /* Just a length safe wrapper for memmove. */
63 #define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); }
65 /* Compute the snapped size for a given requested size. By snapping to powers
66 of 2 like this, repeated reallocations are avoided. */
67 static int snapUpSize (int i) {
77 j |= (j >> 8); /* Ok, since int >= 16 bits */
78 #if (UINT_MAX != 0xffff)
79 j |= (j >> 16); /* For 32 bit int systems */
80 #if (UINT_MAX > 0xffffffffUL)
81 j |= (j >> 32); /* For 64 bit int systems */
84 /* Least power of two greater than i */
86 if ((int) j >= i) i = (int) j;
91 /* int balloc (bstring b, int len)
93 * Increase the size of the memory backing the bstring b to at least len.
95 int balloc (bstring b, int olen) {
97 if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 ||
98 b->mlen < b->slen || olen <= 0) {
102 if (olen >= b->mlen) {
105 if ((len = snapUpSize (olen)) <= b->mlen) return BSTR_OK;
107 /* Assume probability of a non-moving realloc is 0.125 */
108 if (7 * b->mlen < 8 * b->slen) {
110 /* If slen is close to mlen in size then use realloc to reduce
111 the memory defragmentation */
115 x = (unsigned char *) bstr__realloc (b->data, (size_t) len);
118 /* Since we failed, try allocating the tighest possible
121 if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) {
127 /* If slen is not close to mlen then avoid the penalty of copying
128 the extra bytes that are allocated, but not considered part of
131 if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) {
133 /* Perhaps there is no available memory for the two
134 allocations to be in memory at once */
136 goto reallocStrategy;
139 if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen);
140 bstr__free (b->data);
145 b->data[b->slen] = (unsigned char) '\0';
151 /* int ballocmin (bstring b, int len)
153 * Set the size of the memory backing the bstring b to len or b->slen+1,
154 * whichever is larger. Note that repeated use of this function can degrade
157 int ballocmin (bstring b, int len) {
160 if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 ||
161 b->mlen < b->slen || len <= 0) {
165 if (len < b->slen + 1) len = b->slen + 1;
167 if (len != b->mlen) {
168 s = (unsigned char *) bstr__realloc (b->data, (size_t) len);
169 if (NULL == s) return BSTR_ERR;
170 s[b->slen] = (unsigned char) '\0';
178 /* bstring bfromcstr (const char * str)
180 * Create a bstring which contains the contents of the '\0' terminated char *
183 bstring bfromcstr (const char * str) {
188 if (str == NULL) return NULL;
190 i = snapUpSize ((int) (j + (2 - (j != 0))));
191 if (i <= (int) j) return NULL;
193 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
194 if (NULL == b) return NULL;
196 if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
201 bstr__memcpy (b->data, str, j+1);
205 /* bstring bfromcstralloc (int mlen, const char * str)
207 * Create a bstring which contains the contents of the '\0' terminated char *
208 * buffer str. The memory buffer backing the string is at least len
209 * characters in length.
211 bstring bfromcstralloc (int mlen, const char * str) {
216 if (str == NULL) return NULL;
218 i = snapUpSize ((int) (j + (2 - (j != 0))));
219 if (i <= (int) j) return NULL;
221 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
222 if (b == NULL) return NULL;
224 if (i < mlen) i = mlen;
226 if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
231 bstr__memcpy (b->data, str, j+1);
235 /* bstring blk2bstr (const void * blk, int len)
237 * Create a bstring which contains the content of the block blk of length
240 bstring blk2bstr (const void * blk, int len) {
244 if (blk == NULL || len < 0) return NULL;
245 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
246 if (b == NULL) return NULL;
249 i = len + (2 - (len != 0));
254 b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen);
255 if (b->data == NULL) {
260 if (len > 0) bstr__memcpy (b->data, blk, (size_t) len);
261 b->data[len] = (unsigned char) '\0';
266 /* char * bstr2cstr (const_bstring s, char z)
268 * Create a '\0' terminated char * buffer which is equal to the contents of
269 * the bstring s, except that any contained '\0' characters are converted
270 * to the character in z. This returned value should be freed with a
271 * bcstrfree () call, by the calling application.
273 char * bstr2cstr (const_bstring b, char z) {
277 if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
279 r = (char *) bstr__alloc ((size_t) (l + 1));
280 if (r == NULL) return r;
282 for (i=0; i < l; i ++) {
283 r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i]));
286 r[l] = (unsigned char) '\0';
291 /* int bcstrfree (char * s)
293 * Frees a C-string generated by bstr2cstr (). This is normally unnecessary
294 * since it just wraps a call to bstr__free (), however, if bstr__alloc ()
295 * and bstr__free () have been redefined as a macros within the bstrlib
296 * module (via defining them in memdbg.h after defining
297 * BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std
298 * library functions, then this allows a correct way of freeing the memory
299 * that allows higher level code to be independent from these macro
302 int bcstrfree (char * s) {
310 /* int bconcat (bstring b0, const_bstring b1)
312 * Concatenate the bstring b1 to the bstring b0.
314 int bconcat (bstring b0, const_bstring b1) {
316 bstring aux = (bstring) b1;
318 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR;
322 if ((d | (b0->mlen - d) | len | (d + len)) < 0) return BSTR_ERR;
324 if (b0->mlen <= d + len + 1) {
325 ptrdiff_t pd = b1->data - b0->data;
326 if (0 <= pd && pd < b0->mlen) {
327 if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
329 if (balloc (b0, d + len + 1) != BSTR_OK) {
330 if (aux != b1) bdestroy (aux);
335 bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len);
336 b0->data[d + len] = (unsigned char) '\0';
338 if (aux != b1) bdestroy (aux);
342 /* int bconchar (bstring b, char c)
344 * Concatenate the single character c to the bstring b.
346 int bconchar (bstring b, char c) {
349 if (b == NULL) return BSTR_ERR;
351 if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
352 b->data[d] = (unsigned char) c;
353 b->data[d + 1] = (unsigned char) '\0';
358 /* int bcatcstr (bstring b, const char * s)
360 * Concatenate a char * string to a bstring.
362 int bcatcstr (bstring b, const char * s) {
366 if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
367 || b->mlen <= 0 || s == NULL) return BSTR_ERR;
369 /* Optimistically concatenate directly */
370 l = b->mlen - b->slen;
371 d = (char *) &b->data[b->slen];
372 for (i=0; i < l; i++) {
373 if ((*d++ = *s++) == '\0') {
380 /* Need to explicitely resize and concatenate tail */
381 return bcatblk (b, (const void *) s, (int) strlen (s));
384 /* int bcatblk (bstring b, const void * s, int len)
386 * Concatenate a fixed length buffer to a bstring.
388 int bcatblk (bstring b, const void * s, int len) {
391 if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
392 || b->mlen <= 0 || s == NULL || len < 0) return BSTR_ERR;
394 if (0 > (nl = b->slen + len)) return BSTR_ERR; /* Overflow? */
395 if (b->mlen <= nl && 0 > balloc (b, nl + 1)) return BSTR_ERR;
397 bBlockCopy (&b->data[b->slen], s, (size_t) len);
399 b->data[nl] = (unsigned char) '\0';
403 /* bstring bstrcpy (const_bstring b)
405 * Create a copy of the bstring b.
407 bstring bstrcpy (const_bstring b) {
411 /* Attempted to copy an invalid string? */
412 if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
414 b0 = (bstring) bstr__alloc (sizeof (struct tagbstring));
416 /* Unable to allocate memory for string header */
421 j = snapUpSize (i + 1);
423 b0->data = (unsigned char *) bstr__alloc (j);
424 if (b0->data == NULL) {
426 b0->data = (unsigned char *) bstr__alloc (j);
427 if (b0->data == NULL) {
428 /* Unable to allocate memory for string data */
437 if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i);
438 b0->data[b0->slen] = (unsigned char) '\0';
443 /* int bassign (bstring a, const_bstring b)
445 * Overwrite the string a with the contents of string b.
447 int bassign (bstring a, const_bstring b) {
448 if (b == NULL || b->data == NULL || b->slen < 0)
451 if (balloc (a, b->slen) != BSTR_OK) return BSTR_ERR;
452 bstr__memmove (a->data, b->data, b->slen);
454 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
455 a->slen < 0 || a->mlen == 0)
458 a->data[b->slen] = (unsigned char) '\0';
463 /* int bassignmidstr (bstring a, const_bstring b, int left, int len)
465 * Overwrite the string a with the middle of contents of string b
466 * starting from position left and running for a length len. left and
467 * len are clamped to the ends of b as with the function bmidstr.
469 int bassignmidstr (bstring a, const_bstring b, int left, int len) {
470 if (b == NULL || b->data == NULL || b->slen < 0)
478 if (len > b->slen - left) len = b->slen - left;
480 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
481 a->slen < 0 || a->mlen == 0)
485 if (balloc (a, len) != BSTR_OK) return BSTR_ERR;
486 bstr__memmove (a->data, b->data + left, len);
491 a->data[a->slen] = (unsigned char) '\0';
495 /* int bassigncstr (bstring a, const char * str)
497 * Overwrite the string a with the contents of char * string str. Note that
498 * the bstring a must be a well defined and writable bstring. If an error
499 * occurs BSTR_ERR is returned however a may be partially overwritten.
501 int bassigncstr (bstring a, const char * str) {
504 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
505 a->slen < 0 || a->mlen == 0 || NULL == str)
508 for (i=0; i < a->mlen; i++) {
509 if ('\0' == (a->data[i] = str[i])) {
516 len = strlen (str + i);
517 if (len > INT_MAX || i + len + 1 > INT_MAX ||
518 0 > balloc (a, (int) (i + len + 1))) return BSTR_ERR;
519 bBlockCopy (a->data + i, str + i, (size_t) len + 1);
520 a->slen += (int) len;
524 /* int bassignblk (bstring a, const void * s, int len)
526 * Overwrite the string a with the contents of the block (s, len). Note that
527 * the bstring a must be a well defined and writable bstring. If an error
528 * occurs BSTR_ERR is returned and a is not overwritten.
530 int bassignblk (bstring a, const void * s, int len) {
531 if (a == NULL || a->data == NULL || a->mlen < a->slen ||
532 a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1)
534 if (len + 1 > a->mlen && 0 > balloc (a, len + 1)) return BSTR_ERR;
535 bBlockCopy (a->data, s, (size_t) len);
536 a->data[len] = (unsigned char) '\0';
541 /* int btrunc (bstring b, int n)
543 * Truncate the bstring to at most n characters.
545 int btrunc (bstring b, int n) {
546 if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen ||
547 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
550 b->data[n] = (unsigned char) '\0';
555 #define upcase(c) (toupper ((unsigned char) c))
556 #define downcase(c) (tolower ((unsigned char) c))
557 #define wspace(c) (isspace ((unsigned char) c))
559 /* int btoupper (bstring b)
561 * Convert contents of bstring to upper case.
563 int btoupper (bstring b) {
565 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
566 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
567 for (i=0, len = b->slen; i < len; i++) {
568 b->data[i] = (unsigned char) upcase (b->data[i]);
573 /* int btolower (bstring b)
575 * Convert contents of bstring to lower case.
577 int btolower (bstring b) {
579 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
580 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
581 for (i=0, len = b->slen; i < len; i++) {
582 b->data[i] = (unsigned char) downcase (b->data[i]);
587 /* int bstricmp (const_bstring b0, const_bstring b1)
589 * Compare two strings without differentiating between case. The return
590 * value is the difference of the values of the characters where the two
591 * strings first differ after lower case transformation, otherwise 0 is
592 * returned indicating that the strings are equal. If the lengths are
593 * different, then a difference from 0 is given, but if the first extra
594 * character is '\0', then it is taken to be the value UCHAR_MAX+1.
596 int bstricmp (const_bstring b0, const_bstring b1) {
599 if (bdata (b0) == NULL || b0->slen < 0 ||
600 bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN;
601 if ((n = b0->slen) > b1->slen) n = b1->slen;
602 else if (b0->slen == b1->slen && b0->data == b1->data) return BSTR_OK;
604 for (i = 0; i < n; i ++) {
605 v = (char) downcase (b0->data[i])
606 - (char) downcase (b1->data[i]);
607 if (0 != v) return v;
611 v = (char) downcase (b0->data[n]);
613 return UCHAR_MAX + 1;
616 v = - (char) downcase (b1->data[n]);
618 return - (int) (UCHAR_MAX + 1);
623 /* int bstrnicmp (const_bstring b0, const_bstring b1, int n)
625 * Compare two strings without differentiating between case for at most n
626 * characters. If the position where the two strings first differ is
627 * before the nth position, the return value is the difference of the values
628 * of the characters, otherwise 0 is returned. If the lengths are different
629 * and less than n characters, then a difference from 0 is given, but if the
630 * first extra character is '\0', then it is taken to be the value
633 int bstrnicmp (const_bstring b0, const_bstring b1, int n) {
636 if (bdata (b0) == NULL || b0->slen < 0 ||
637 bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN;
639 if (m > b0->slen) m = b0->slen;
640 if (m > b1->slen) m = b1->slen;
642 if (b0->data != b1->data) {
643 for (i = 0; i < m; i ++) {
644 v = (char) downcase (b0->data[i]);
645 v -= (char) downcase (b1->data[i]);
646 if (v != 0) return b0->data[i] - b1->data[i];
650 if (n == m || b0->slen == b1->slen) return BSTR_OK;
653 v = (char) downcase (b0->data[m]);
655 return UCHAR_MAX + 1;
658 v = - (char) downcase (b1->data[m]);
660 return - (int) (UCHAR_MAX + 1);
663 /* int biseqcaseless (const_bstring b0, const_bstring b1)
665 * Compare two strings for equality without differentiating between case.
666 * If the strings differ other than in case, 0 is returned, if the strings
667 * are the same, 1 is returned, if there is an error, -1 is returned. If
668 * the length of the strings are different, this function is O(1). '\0'
669 * termination characters are not treated in any special way.
671 int biseqcaseless (const_bstring b0, const_bstring b1) {
674 if (bdata (b0) == NULL || b0->slen < 0 ||
675 bdata (b1) == NULL || b1->slen < 0) return BSTR_ERR;
676 if (b0->slen != b1->slen) return BSTR_OK;
677 if (b0->data == b1->data || b0->slen == 0) return 1;
678 for (i=0, n=b0->slen; i < n; i++) {
679 if (b0->data[i] != b1->data[i]) {
680 unsigned char c = (unsigned char) downcase (b0->data[i]);
681 if (c != (unsigned char) downcase (b1->data[i])) return 0;
687 /* int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len)
689 * Compare beginning of string b0 with a block of memory of length len
690 * without differentiating between case for equality. If the beginning of b0
691 * differs from the memory block other than in case (or if b0 is too short),
692 * 0 is returned, if the strings are the same, 1 is returned, if there is an
693 * error, -1 is returned. '\0' characters are not treated in any special
696 int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) {
699 if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
701 if (b0->slen < len) return BSTR_OK;
702 if (b0->data == (const unsigned char *) blk || len == 0) return 1;
704 for (i = 0; i < len; i ++) {
705 if (b0->data[i] != ((const unsigned char *) blk)[i]) {
706 if (downcase (b0->data[i]) !=
707 downcase (((const unsigned char *) blk)[i])) return 0;
714 * int bltrimws (bstring b)
716 * Delete whitespace contiguous from the left end of the string.
718 int bltrimws (bstring b) {
721 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
722 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
724 for (len = b->slen, i = 0; i < len; i++) {
725 if (!wspace (b->data[i])) {
726 return bdelete (b, 0, i);
730 b->data[0] = (unsigned char) '\0';
736 * int brtrimws (bstring b)
738 * Delete whitespace contiguous from the right end of the string.
740 int brtrimws (bstring b) {
743 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
744 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
746 for (i = b->slen - 1; i >= 0; i--) {
747 if (!wspace (b->data[i])) {
748 if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
754 b->data[0] = (unsigned char) '\0';
760 * int btrimws (bstring b)
762 * Delete whitespace contiguous from both ends of the string.
764 int btrimws (bstring b) {
767 if (b == NULL || b->data == NULL || b->mlen < b->slen ||
768 b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
770 for (i = b->slen - 1; i >= 0; i--) {
771 if (!wspace (b->data[i])) {
772 if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
774 for (j = 0; wspace (b->data[j]); j++) {}
775 return bdelete (b, 0, j);
779 b->data[0] = (unsigned char) '\0';
784 /* int biseq (const_bstring b0, const_bstring b1)
786 * Compare the string b0 and b1. If the strings differ, 0 is returned, if
787 * the strings are the same, 1 is returned, if there is an error, -1 is
788 * returned. If the length of the strings are different, this function is
789 * O(1). '\0' termination characters are not treated in any special way.
791 int biseq (const_bstring b0, const_bstring b1) {
792 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
793 b0->slen < 0 || b1->slen < 0) return BSTR_ERR;
794 if (b0->slen != b1->slen) return BSTR_OK;
795 if (b0->data == b1->data || b0->slen == 0) return 1;
796 return !bstr__memcmp (b0->data, b1->data, b0->slen);
799 /* int bisstemeqblk (const_bstring b0, const void * blk, int len)
801 * Compare beginning of string b0 with a block of memory of length len for
802 * equality. If the beginning of b0 differs from the memory block (or if b0
803 * is too short), 0 is returned, if the strings are the same, 1 is returned,
804 * if there is an error, -1 is returned. '\0' characters are not treated in
807 int bisstemeqblk (const_bstring b0, const void * blk, int len) {
810 if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
812 if (b0->slen < len) return BSTR_OK;
813 if (b0->data == (const unsigned char *) blk || len == 0) return 1;
815 for (i = 0; i < len; i ++) {
816 if (b0->data[i] != ((const unsigned char *) blk)[i]) return BSTR_OK;
821 /* int biseqcstr (const_bstring b, const char *s)
823 * Compare the bstring b and char * string s. The C string s must be '\0'
824 * terminated at exactly the length of the bstring b, and the contents
825 * between the two must be identical with the bstring b with no '\0'
826 * characters for the two contents to be considered equal. This is
827 * equivalent to the condition that their current contents will be always be
828 * equal when comparing them in the same format after converting one or the
829 * other. If the strings are equal 1 is returned, if they are unequal 0 is
830 * returned and if there is a detectable error BSTR_ERR is returned.
832 int biseqcstr (const_bstring b, const char * s) {
834 if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
835 for (i=0; i < b->slen; i++) {
836 if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK;
841 /* int biseqcstrcaseless (const_bstring b, const char *s)
843 * Compare the bstring b and char * string s. The C string s must be '\0'
844 * terminated at exactly the length of the bstring b, and the contents
845 * between the two must be identical except for case with the bstring b with
846 * no '\0' characters for the two contents to be considered equal. This is
847 * equivalent to the condition that their current contents will be always be
848 * equal ignoring case when comparing them in the same format after
849 * converting one or the other. If the strings are equal, except for case,
850 * 1 is returned, if they are unequal regardless of case 0 is returned and
851 * if there is a detectable error BSTR_ERR is returned.
853 int biseqcstrcaseless (const_bstring b, const char * s) {
855 if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
856 for (i=0; i < b->slen; i++) {
858 (b->data[i] != (unsigned char) s[i] &&
859 downcase (b->data[i]) != (unsigned char) downcase (s[i])))
865 /* int bstrcmp (const_bstring b0, const_bstring b1)
867 * Compare the string b0 and b1. If there is an error, SHRT_MIN is returned,
868 * otherwise a value less than or greater than zero, indicating that the
869 * string pointed to by b0 is lexicographically less than or greater than
870 * the string pointed to by b1 is returned. If the the string lengths are
871 * unequal but the characters up until the length of the shorter are equal
872 * then a value less than, or greater than zero, indicating that the string
873 * pointed to by b0 is shorter or longer than the string pointed to by b1 is
874 * returned. 0 is returned if and only if the two strings are the same. If
875 * the length of the strings are different, this function is O(n). Like its
876 * standard C library counter part strcmp, the comparison does not proceed
877 * past any '\0' termination characters encountered.
879 int bstrcmp (const_bstring b0, const_bstring b1) {
882 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
883 b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
884 n = b0->slen; if (n > b1->slen) n = b1->slen;
885 if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0))
888 for (i = 0; i < n; i ++) {
889 v = ((char) b0->data[i]) - ((char) b1->data[i]);
890 if (v != 0) return v;
891 if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
894 if (b0->slen > n) return 1;
895 if (b1->slen > n) return -1;
899 /* int bstrncmp (const_bstring b0, const_bstring b1, int n)
901 * Compare the string b0 and b1 for at most n characters. If there is an
902 * error, SHRT_MIN is returned, otherwise a value is returned as if b0 and
903 * b1 were first truncated to at most n characters then bstrcmp was called
904 * with these new strings are paremeters. If the length of the strings are
905 * different, this function is O(n). Like its standard C library counter
906 * part strcmp, the comparison does not proceed past any '\0' termination
907 * characters encountered.
909 int bstrncmp (const_bstring b0, const_bstring b1, int n) {
912 if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
913 b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
915 if (m > b0->slen) m = b0->slen;
916 if (m > b1->slen) m = b1->slen;
918 if (b0->data != b1->data) {
919 for (i = 0; i < m; i ++) {
920 v = ((char) b0->data[i]) - ((char) b1->data[i]);
921 if (v != 0) return v;
922 if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
926 if (n == m || b0->slen == b1->slen) return BSTR_OK;
928 if (b0->slen > m) return 1;
932 /* bstring bmidstr (const_bstring b, int left, int len)
934 * Create a bstring which is the substring of b starting from position left
935 * and running for a length len (clamped by the end of the bstring b.) If
936 * b is detectably invalid, then NULL is returned. The section described
937 * by (left, len) is clamped to the boundaries of b.
939 bstring bmidstr (const_bstring b, int left, int len) {
941 if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
948 if (len > b->slen - left) len = b->slen - left;
950 if (len <= 0) return bfromcstr ("");
951 return blk2bstr (b->data + left, len);
954 /* int bdelete (bstring b, int pos, int len)
956 * Removes characters from pos to pos+len-1 inclusive and shifts the tail of
957 * the bstring starting from pos+len to pos. len must be positive for this
958 * call to have any effect. The section of the string described by (pos,
959 * len) is clamped to boundaries of the bstring b.
961 int bdelete (bstring b, int pos, int len) {
962 /* Clamp to left side of bstring */
968 if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 ||
969 b->mlen < b->slen || b->mlen <= 0)
971 if (len > 0 && pos < b->slen) {
972 if (pos + len >= b->slen) {
975 bBlockCopy ((char *) (b->data + pos),
976 (char *) (b->data + pos + len),
977 b->slen - (pos+len));
980 b->data[b->slen] = (unsigned char) '\0';
985 /* int bdestroy (bstring b)
987 * Free up the bstring. Note that if b is detectably invalid or not writable
988 * then no action is performed and BSTR_ERR is returned. Like a freed memory
989 * allocation, dereferences, writes or any other action on b after it has
990 * been bdestroyed is undefined.
992 int bdestroy (bstring b) {
993 if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen ||
997 bstr__free (b->data);
999 /* In case there is any stale usage, there is one more chance to
1000 notice this error. */
1003 b->mlen = -__LINE__;
1010 /* int binstr (const_bstring b1, int pos, const_bstring b2)
1012 * Search for the bstring b2 in b1 starting from position pos, and searching
1013 * forward. If it is found then return with the first position where it is
1014 * found, otherwise return BSTR_ERR. Note that this is just a brute force
1015 * string searcher that does not attempt clever things like the Boyer-Moore
1016 * search algorithm. Because of this there are many degenerate cases where
1017 * this can take much longer than it needs to.
1019 int binstr (const_bstring b1, int pos, const_bstring b2) {
1023 register unsigned char * d1;
1024 register unsigned char c1;
1027 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1028 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1029 if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
1030 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1031 if (b2->slen == 0) return pos;
1033 /* No space to find such a string? */
1034 if ((lf = b1->slen - b2->slen + 1) <= pos) return BSTR_ERR;
1036 /* An obvious alias case */
1037 if (b1->data == b2->data && pos == 0) return 0;
1045 /* Peel off the b2->slen == 1 case */
1048 for (;i < lf; i++) if (c0 == d1[i]) return i;
1058 /* Unrolled current character test */
1060 if (c1 != d1[1+i]) {
1067 /* Take note if this is the start of a potential match */
1070 /* Shift the test character down by one */
1074 /* If this isn't past the last character continue */
1082 /* If no characters mismatched, then we matched */
1083 if (i == ii+j) return ii;
1085 /* Shift back to the beginning */
1091 /* Deal with last case if unrolling caused a misalignment */
1092 if (i == lf && ll == j+1 && c1 == d1[i]) goto N0;
1097 /* int binstrr (const_bstring b1, int pos, const_bstring b2)
1099 * Search for the bstring b2 in b1 starting from position pos, and searching
1100 * backward. If it is found then return with the first position where it is
1101 * found, otherwise return BSTR_ERR. Note that this is just a brute force
1102 * string searcher that does not attempt clever things like the Boyer-Moore
1103 * search algorithm. Because of this there are many degenerate cases where
1104 * this can take much longer than it needs to.
1106 int binstrr (const_bstring b1, int pos, const_bstring b2) {
1108 unsigned char * d0, * d1;
1110 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1111 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1112 if (b1->slen == pos && b2->slen == 0) return pos;
1113 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1114 if (b2->slen == 0) return pos;
1116 /* Obvious alias case */
1117 if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0;
1120 if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
1122 /* If no space to find such a string then snap back */
1123 if (l + 1 <= i) i = l;
1131 if (d0[j] == d1[i + j]) {
1133 if (j >= l) return i;
1144 /* int binstrcaseless (const_bstring b1, int pos, const_bstring b2)
1146 * Search for the bstring b2 in b1 starting from position pos, and searching
1147 * forward but without regard to case. If it is found then return with the
1148 * first position where it is found, otherwise return BSTR_ERR. Note that
1149 * this is just a brute force string searcher that does not attempt clever
1150 * things like the Boyer-Moore search algorithm. Because of this there are
1151 * many degenerate cases where this can take much longer than it needs to.
1153 int binstrcaseless (const_bstring b1, int pos, const_bstring b2) {
1155 unsigned char * d0, * d1;
1157 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1158 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1159 if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
1160 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1161 if (b2->slen == 0) return pos;
1163 l = b1->slen - b2->slen + 1;
1165 /* No space to find such a string? */
1166 if (l <= pos) return BSTR_ERR;
1168 /* An obvious alias case */
1169 if (b1->data == b2->data && pos == 0) return BSTR_OK;
1179 if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
1181 if (j >= ll) return i;
1192 /* int binstrrcaseless (const_bstring b1, int pos, const_bstring b2)
1194 * Search for the bstring b2 in b1 starting from position pos, and searching
1195 * backward but without regard to case. If it is found then return with the
1196 * first position where it is found, otherwise return BSTR_ERR. Note that
1197 * this is just a brute force string searcher that does not attempt clever
1198 * things like the Boyer-Moore search algorithm. Because of this there are
1199 * many degenerate cases where this can take much longer than it needs to.
1201 int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) {
1203 unsigned char * d0, * d1;
1205 if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1206 b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1207 if (b1->slen == pos && b2->slen == 0) return pos;
1208 if (b1->slen < pos || pos < 0) return BSTR_ERR;
1209 if (b2->slen == 0) return pos;
1211 /* Obvious alias case */
1212 if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK;
1215 if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
1217 /* If no space to find such a string then snap back */
1218 if (l + 1 <= i) i = l;
1226 if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
1228 if (j >= l) return i;
1240 /* int bstrchrp (const_bstring b, int c, int pos)
1242 * Search for the character c in b forwards from the position pos
1245 int bstrchrp (const_bstring b, int c, int pos) {
1248 if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
1249 p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos));
1250 if (p) return (int) (p - b->data);
1254 /* int bstrrchrp (const_bstring b, int c, int pos)
1256 * Search for the character c in b backwards from the position pos in string
1259 int bstrrchrp (const_bstring b, int c, int pos) {
1262 if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
1263 for (i=pos; i >= 0; i--) {
1264 if (b->data[i] == (unsigned char) c) return i;
1269 #if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF)
1270 #define LONG_LOG_BITS_QTY (3)
1271 #define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY)
1272 #define LONG_TYPE unsigned char
1274 #define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY)
1275 struct charField { LONG_TYPE content[CFCLEN]; };
1276 #define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1))))
1277 #define setInCharField(cf,idx) { \
1278 unsigned int c = (unsigned int) (idx); \
1279 (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \
1284 #define CFCLEN (1 << CHAR_BIT)
1285 struct charField { unsigned char content[CFCLEN]; };
1286 #define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)])
1287 #define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0
1291 /* Convert a bstring to charField */
1292 static int buildCharField (struct charField * cf, const_bstring b) {
1294 if (b == NULL || b->data == NULL || b->slen <= 0) return BSTR_ERR;
1295 memset ((void *) cf->content, 0, sizeof (struct charField));
1296 for (i=0; i < b->slen; i++) {
1297 setInCharField (cf, b->data[i]);
1302 static void invertCharField (struct charField * cf) {
1304 for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i];
1307 /* Inner engine for binchr */
1308 static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) {
1310 for (i=pos; i < len; i++) {
1311 unsigned char c = (unsigned char) data[i];
1312 if (testInCharField (cf, c)) return i;
1317 /* int binchr (const_bstring b0, int pos, const_bstring b1);
1319 * Search for the first position in b0 starting from pos or after, in which
1320 * one of the characters in b1 is found and return it. If such a position
1321 * does not exist in b0, then BSTR_ERR is returned.
1323 int binchr (const_bstring b0, int pos, const_bstring b1) {
1324 struct charField chrs;
1325 if (pos < 0 || b0 == NULL || b0->data == NULL ||
1326 b0->slen <= pos) return BSTR_ERR;
1327 if (1 == b1->slen) return bstrchrp (b0, b1->data[0], pos);
1328 if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
1329 return binchrCF (b0->data, b0->slen, pos, &chrs);
1332 /* Inner engine for binchrr */
1333 static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) {
1335 for (i=pos; i >= 0; i--) {
1336 unsigned int c = (unsigned int) data[i];
1337 if (testInCharField (cf, c)) return i;
1342 /* int binchrr (const_bstring b0, int pos, const_bstring b1);
1344 * Search for the last position in b0 no greater than pos, in which one of
1345 * the characters in b1 is found and return it. If such a position does not
1346 * exist in b0, then BSTR_ERR is returned.
1348 int binchrr (const_bstring b0, int pos, const_bstring b1) {
1349 struct charField chrs;
1350 if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL ||
1351 b0->slen < pos) return BSTR_ERR;
1352 if (pos == b0->slen) pos--;
1353 if (1 == b1->slen) return bstrrchrp (b0, b1->data[0], pos);
1354 if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
1355 return binchrrCF (b0->data, pos, &chrs);
1358 /* int bninchr (const_bstring b0, int pos, const_bstring b1);
1360 * Search for the first position in b0 starting from pos or after, in which
1361 * none of the characters in b1 is found and return it. If such a position
1362 * does not exist in b0, then BSTR_ERR is returned.
1364 int bninchr (const_bstring b0, int pos, const_bstring b1) {
1365 struct charField chrs;
1366 if (pos < 0 || b0 == NULL || b0->data == NULL ||
1367 b0->slen <= pos) return BSTR_ERR;
1368 if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
1369 invertCharField (&chrs);
1370 return binchrCF (b0->data, b0->slen, pos, &chrs);
1373 /* int bninchrr (const_bstring b0, int pos, const_bstring b1);
1375 * Search for the last position in b0 no greater than pos, in which none of
1376 * the characters in b1 is found and return it. If such a position does not
1377 * exist in b0, then BSTR_ERR is returned.
1379 int bninchrr (const_bstring b0, int pos, const_bstring b1) {
1380 struct charField chrs;
1381 if (pos < 0 || b0 == NULL || b0->data == NULL ||
1382 b0->slen < pos) return BSTR_ERR;
1383 if (pos == b0->slen) pos--;
1384 if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
1385 invertCharField (&chrs);
1386 return binchrrCF (b0->data, pos, &chrs);
1389 /* int bsetstr (bstring b0, int pos, bstring b1, unsigned char fill)
1391 * Overwrite the string b0 starting at position pos with the string b1. If
1392 * the position pos is past the end of b0, then the character "fill" is
1393 * appended as necessary to make up the gap between the end of b0 and pos.
1394 * If b1 is NULL, it behaves as if it were a 0-length string.
1396 int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) {
1399 bstring aux = (bstring) b1;
1401 if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data ||
1402 b0->mlen < b0->slen || b0->mlen <= 0) return BSTR_ERR;
1403 if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return BSTR_ERR;
1409 if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) {
1410 if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
1415 /* Increase memory size if necessary */
1416 if (balloc (b0, d + 1) != BSTR_OK) {
1417 if (aux != b1) bdestroy (aux);
1423 /* Fill in "fill" character as necessary */
1425 bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen));
1429 /* Copy b1 to position pos in b0. */
1431 bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen);
1432 if (aux != b1) bdestroy (aux);
1435 /* Indicate the potentially increased size of b0 */
1436 if (d > newlen) newlen = d;
1439 b0->data[newlen] = (unsigned char) '\0';
1444 /* int binsert (bstring b1, int pos, bstring b2, unsigned char fill)
1446 * Inserts the string b2 into b1 at position pos. If the position pos is
1447 * past the end of b1, then the character "fill" is appended as necessary to
1448 * make up the gap between the end of b1 and pos. Unlike bsetstr, binsert
1449 * does not allow b2 to be NULL.
1451 int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) {
1454 bstring aux = (bstring) b2;
1456 if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 ||
1457 b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR;
1460 if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) {
1461 if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
1464 /* Compute the two possible end pointers */
1465 d = b1->slen + aux->slen;
1466 l = pos + aux->slen;
1467 if ((d|l) < 0) return BSTR_ERR;
1470 /* Inserting past the end of the string */
1471 if (balloc (b1, l + 1) != BSTR_OK) {
1472 if (aux != b2) bdestroy (aux);
1475 bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen));
1478 /* Inserting in the middle of the string */
1479 if (balloc (b1, d + 1) != BSTR_OK) {
1480 if (aux != b2) bdestroy (aux);
1483 bBlockCopy (b1->data + l, b1->data + pos, d - l);
1486 bBlockCopy (b1->data + pos, aux->data, aux->slen);
1487 b1->data[b1->slen] = (unsigned char) '\0';
1488 if (aux != b2) bdestroy (aux);
1492 /* int breplace (bstring b1, int pos, int len, bstring b2,
1493 * unsigned char fill)
1495 * Replace a section of a string from pos for a length len with the string b2.
1496 * fill is used is pos > b1->slen.
1498 int breplace (bstring b1, int pos, int len, const_bstring b2,
1499 unsigned char fill) {
1502 bstring aux = (bstring) b2;
1504 if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL ||
1505 b2 == NULL || b1->data == NULL || b2->data == NULL ||
1506 b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen ||
1507 b1->mlen <= 0) return BSTR_ERR;
1509 /* Straddles the end? */
1510 if (pl >= b1->slen) {
1511 if ((ret = bsetstr (b1, pos, b2, fill)) < 0) return ret;
1512 if (pos + b2->slen < b1->slen) {
1513 b1->slen = pos + b2->slen;
1514 b1->data[b1->slen] = (unsigned char) '\0';
1520 if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) {
1521 if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
1524 if (aux->slen > len) {
1525 if (balloc (b1, b1->slen + aux->slen - len) != BSTR_OK) {
1526 if (aux != b2) bdestroy (aux);
1531 if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len));
1532 bstr__memcpy (b1->data + pos, aux->data, aux->slen);
1533 b1->slen += aux->slen - len;
1534 b1->data[b1->slen] = (unsigned char) '\0';
1535 if (aux != b2) bdestroy (aux);
1539 /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
1542 * Replace all occurrences of a find string with a replace string after a
1543 * given point in a bstring.
1546 typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2);
1548 static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) {
1549 int i, ret, slen, mlen, delta, acc;
1553 bstring auxf = (bstring) find;
1554 bstring auxr = (bstring) repl;
1556 if (b == NULL || b->data == NULL || find == NULL ||
1557 find->data == NULL || repl == NULL || repl->data == NULL ||
1558 pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen ||
1559 b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return BSTR_ERR;
1560 if (pos > b->slen - find->slen) return BSTR_OK;
1562 /* Alias with find string */
1563 pd = (ptrdiff_t) (find->data - b->data);
1564 if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) {
1565 if (NULL == (auxf = bstrcpy (find))) return BSTR_ERR;
1568 /* Alias with repl string */
1569 pd = (ptrdiff_t) (repl->data - b->data);
1570 if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) {
1571 if (NULL == (auxr = bstrcpy (repl))) {
1572 if (auxf != find) bdestroy (auxf);
1577 delta = auxf->slen - auxr->slen;
1579 /* in-place replacement since find and replace strings are of equal
1582 while ((pos = instr (b, pos, auxf)) >= 0) {
1583 bstr__memcpy (b->data + pos, auxr->data, auxr->slen);
1586 if (auxf != find) bdestroy (auxf);
1587 if (auxr != repl) bdestroy (auxr);
1591 /* shrinking replacement since auxf->slen > auxr->slen */
1595 while ((i = instr (b, pos, auxf)) >= 0) {
1597 bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
1599 bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen);
1601 pos = i + auxf->slen;
1607 bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
1609 b->data[b->slen] = (unsigned char) '\0';
1612 if (auxf != find) bdestroy (auxf);
1613 if (auxr != repl) bdestroy (auxr);
1617 /* expanding replacement since find->slen < repl->slen. Its a lot
1618 more complicated. */
1621 d = (int *) static_d; /* Avoid malloc for trivial cases */
1624 while ((pos = instr (b, pos, auxf)) >= 0) {
1625 if (slen + 1 >= mlen) {
1629 sl = sizeof (int *) * mlen;
1630 if (static_d == d) d = NULL;
1631 if (sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) {
1635 if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d));
1642 if (pos < 0 || acc < 0) {
1649 if (BSTR_OK == (ret = balloc (b, b->slen + acc + 1))) {
1651 for (i = slen-1; i >= 0; i--) {
1653 s = d[i] + auxf->slen;
1656 bstr__memmove (b->data + s + acc, b->data + s, l);
1659 bstr__memmove (b->data + s + acc - auxr->slen,
1660 auxr->data, auxr->slen);
1664 b->data[b->slen] = (unsigned char) '\0';
1668 if (static_d == d) d = NULL;
1670 if (auxf != find) bdestroy (auxf);
1671 if (auxr != repl) bdestroy (auxr);
1675 /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
1678 * Replace all occurrences of a find string with a replace string after a
1679 * given point in a bstring.
1681 int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) {
1682 return findreplaceengine (b, find, repl, pos, binstr);
1685 /* int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl,
1688 * Replace all occurrences of a find string, ignoring case, with a replace
1689 * string after a given point in a bstring.
1691 int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) {
1692 return findreplaceengine (b, find, repl, pos, binstrcaseless);
1695 /* int binsertch (bstring b, int pos, int len, unsigned char fill)
1697 * Inserts the character fill repeatedly into b at position pos for a
1698 * length len. If the position pos is past the end of b, then the
1699 * character "fill" is appended as necessary to make up the gap between the
1700 * end of b and the position pos + len.
1702 int binsertch (bstring b, int pos, int len, unsigned char fill) {
1705 if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen ||
1706 b->mlen <= 0 || len < 0) return BSTR_ERR;
1708 /* Compute the two possible end pointers */
1711 if ((d|l) < 0) return BSTR_ERR;
1714 /* Inserting past the end of the string */
1715 if (balloc (b, l + 1) != BSTR_OK) return BSTR_ERR;
1719 /* Inserting in the middle of the string */
1720 if (balloc (b, d + 1) != BSTR_OK) return BSTR_ERR;
1721 for (i = d - 1; i >= l; i--) {
1722 b->data[i] = b->data[i - len];
1727 for (i=pos; i < l; i++) b->data[i] = fill;
1728 b->data[b->slen] = (unsigned char) '\0';
1732 /* int bpattern (bstring b, int len)
1734 * Replicate the bstring, b in place, end to end repeatedly until it
1735 * surpasses len characters, then chop the result to exactly len characters.
1736 * This function operates in-place. The function will return with BSTR_ERR
1737 * if b is NULL or of length 0, otherwise BSTR_OK is returned.
1739 int bpattern (bstring b, int len) {
1743 if (d <= 0 || len < 0 || balloc (b, len + 1) != BSTR_OK) return BSTR_ERR;
1745 if (d == 1) return bsetstr (b, len, NULL, b->data[0]);
1746 for (i = d; i < len; i++) b->data[i] = b->data[i - d];
1748 b->data[len] = (unsigned char) '\0';
1753 #define BS_BUFF_SZ (1024)
1755 /* int breada (bstring b, bNread readPtr, void * parm)
1757 * Use a finite buffer fread-like function readPtr to concatenate to the
1758 * bstring b the entire contents of file-like source data in a roughly
1761 int breada (bstring b, bNread readPtr, void * parm) {
1764 if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1765 b->mlen <= 0 || readPtr == NULL) return BSTR_ERR;
1768 for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) {
1769 if (BSTR_OK != balloc (b, n + 1)) return BSTR_ERR;
1770 l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm);
1776 b->data[i] = (unsigned char) '\0';
1780 /* bstring bread (bNread readPtr, void * parm)
1782 * Use a finite buffer fread-like function readPtr to create a bstring
1783 * filled with the entire contents of file-like source data in a roughly
1786 bstring bread (bNread readPtr, void * parm) {
1789 if (0 > breada (buff = bfromcstr (""), readPtr, parm)) {
1796 /* int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator)
1798 * Use an fgetc-like single character stream reading function (getcPtr) to
1799 * obtain a sequence of characters which are concatenated to the end of the
1800 * bstring b. The stream read is terminated by the passed in terminator
1803 * If getcPtr returns with a negative number, or the terminator character
1804 * (which is appended) is read, then the stream reading is halted and the
1805 * function returns with a partial result in b. If there is an empty partial
1806 * result, 1 is returned. If no characters are read, or there is some other
1807 * detectable error, BSTR_ERR is returned.
1809 int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1812 if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1813 b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
1817 while ((c = getcPtr (parm)) >= 0) {
1820 if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
1823 b->data[d] = (unsigned char) c;
1825 if (c == terminator) break;
1828 b->data[d] = (unsigned char) '\0';
1831 return d == 0 && c < 0;
1834 /* int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator)
1836 * Use an fgetc-like single character stream reading function (getcPtr) to
1837 * obtain a sequence of characters which are concatenated to the end of the
1838 * bstring b. The stream read is terminated by the passed in terminator
1841 * If getcPtr returns with a negative number, or the terminator character
1842 * (which is appended) is read, then the stream reading is halted and the
1843 * function returns with a partial result concatentated to b. If there is
1844 * an empty partial result, 1 is returned. If no characters are read, or
1845 * there is some other detectable error, BSTR_ERR is returned.
1847 int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1850 if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1851 b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
1855 while ((c = getcPtr (parm)) >= 0) {
1858 if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
1861 b->data[d] = (unsigned char) c;
1863 if (c == terminator) break;
1866 b->data[d] = (unsigned char) '\0';
1869 return d == 0 && c < 0;
1872 /* bstring bgets (bNgetc getcPtr, void * parm, char terminator)
1874 * Use an fgetc-like single character stream reading function (getcPtr) to
1875 * obtain a sequence of characters which are concatenated into a bstring.
1876 * The stream read is terminated by the passed in terminator function.
1878 * If getcPtr returns with a negative number, or the terminator character
1879 * (which is appended) is read, then the stream reading is halted and the
1880 * result obtained thus far is returned. If no characters are read, or
1881 * there is some other detectable error, NULL is returned.
1883 bstring bgets (bNgetc getcPtr, void * parm, char terminator) {
1886 if (0 > bgetsa (buff = bfromcstr (""), getcPtr, parm, terminator) || 0 >= buff->slen) {
1894 bstring buff; /* Buffer for over-reads */
1895 void * parm; /* The stream handle for core stream */
1896 bNread readFnPtr; /* fread compatible fnptr for core stream */
1897 int isEOF; /* track file's EOF state */
1901 /* struct bStream * bsopen (bNread readPtr, void * parm)
1903 * Wrap a given open stream (described by a fread compatible function
1904 * pointer and stream handle) into an open bStream suitable for the bstring
1905 * library streaming functions.
1907 struct bStream * bsopen (bNread readPtr, void * parm) {
1910 if (readPtr == NULL) return NULL;
1911 s = (struct bStream *) bstr__alloc (sizeof (struct bStream));
1912 if (s == NULL) return NULL;
1914 s->buff = bfromcstr ("");
1915 s->readFnPtr = readPtr;
1916 s->maxBuffSz = BS_BUFF_SZ;
1921 /* int bsbufflength (struct bStream * s, int sz)
1923 * Set the length of the buffer used by the bStream. If sz is zero, the
1924 * length is not set. This function returns with the previous length.
1926 int bsbufflength (struct bStream * s, int sz) {
1928 if (s == NULL || sz < 0) return BSTR_ERR;
1929 oldSz = s->maxBuffSz;
1930 if (sz > 0) s->maxBuffSz = sz;
1934 int bseof (const struct bStream * s) {
1935 if (s == NULL || s->readFnPtr == NULL) return BSTR_ERR;
1936 return s->isEOF && (s->buff->slen == 0);
1939 /* void * bsclose (struct bStream * s)
1941 * Close the bStream, and return the handle to the stream that was originally
1942 * used to open the given stream.
1944 void * bsclose (struct bStream * s) {
1946 if (s == NULL) return NULL;
1947 s->readFnPtr = NULL;
1948 if (s->buff) bdestroy (s->buff);
1957 /* int bsreadlna (bstring r, struct bStream * s, char terminator)
1959 * Read a bstring terminated by the terminator character or the end of the
1960 * stream from the bStream (s) and return it into the parameter r. This
1961 * function may read additional characters from the core stream that are not
1962 * returned, but will be retained for subsequent read operations.
1964 int bsreadlna (bstring r, struct bStream * s, char terminator) {
1967 struct tagbstring x;
1969 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 ||
1970 r->slen < 0 || r->mlen < r->slen) return BSTR_ERR;
1972 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
1973 b = (char *) s->buff->data;
1974 x.data = (unsigned char *) b;
1976 /* First check if the current buffer holds the terminator */
1977 b[l] = terminator; /* Set sentinel */
1978 for (i=0; b[i] != terminator; i++) ;
1981 ret = bconcat (r, &x);
1983 if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
1989 /* If not then just concatenate the entire buffer to the output */
1991 if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
1993 /* Perform direct in-place reads into the destination to allow for
1994 the minimum of data-copies */
1996 if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
1997 b = (char *) (r->data + r->slen);
1998 l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
2000 r->data[r->slen] = (unsigned char) '\0';
2003 /* If nothing was read return with an error message */
2004 return BSTR_ERR & -(r->slen == rlo);
2006 b[l] = terminator; /* Set sentinel */
2007 for (i=0; b[i] != terminator; i++) ;
2012 /* Terminator found, push over-read back to buffer */
2015 s->buff->slen = l - i;
2016 bstr__memcpy (s->buff->data, b + i, l - i);
2017 r->data[r->slen] = (unsigned char) '\0';
2021 /* int bsreadlnsa (bstring r, struct bStream * s, bstring term)
2023 * Read a bstring terminated by any character in the term string or the end
2024 * of the stream from the bStream (s) and return it into the parameter r.
2025 * This function may read additional characters from the core stream that
2026 * are not returned, but will be retained for subsequent read operations.
2028 int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) {
2031 struct tagbstring x;
2032 struct charField cf;
2034 if (s == NULL || s->buff == NULL || r == NULL || term == NULL ||
2035 term->data == NULL || r->mlen <= 0 || r->slen < 0 ||
2036 r->mlen < r->slen) return BSTR_ERR;
2037 if (term->slen == 1) return bsreadlna (r, s, term->data[0]);
2038 if (term->slen < 1 || buildCharField (&cf, term)) return BSTR_ERR;
2041 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2042 b = (unsigned char *) s->buff->data;
2045 /* First check if the current buffer holds the terminator */
2046 b[l] = term->data[0]; /* Set sentinel */
2047 for (i=0; !testInCharField (&cf, b[i]); i++) ;
2050 ret = bconcat (r, &x);
2052 if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
2058 /* If not then just concatenate the entire buffer to the output */
2060 if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
2062 /* Perform direct in-place reads into the destination to allow for
2063 the minimum of data-copies */
2065 if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
2066 b = (unsigned char *) (r->data + r->slen);
2067 l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
2069 r->data[r->slen] = (unsigned char) '\0';
2072 /* If nothing was read return with an error message */
2073 return BSTR_ERR & -(r->slen == rlo);
2076 b[l] = term->data[0]; /* Set sentinel */
2077 for (i=0; !testInCharField (&cf, b[i]); i++) ;
2082 /* Terminator found, push over-read back to buffer */
2085 s->buff->slen = l - i;
2086 bstr__memcpy (s->buff->data, b + i, l - i);
2087 r->data[r->slen] = (unsigned char) '\0';
2091 /* int bsreada (bstring r, struct bStream * s, int n)
2093 * Read a bstring of length n (or, if it is fewer, as many bytes as is
2094 * remaining) from the bStream. This function may read additional
2095 * characters from the core stream that are not returned, but will be
2096 * retained for subsequent read operations. This function will not read
2097 * additional characters from the core stream beyond virtual stream pointer.
2099 int bsreada (bstring r, struct bStream * s, int n) {
2102 struct tagbstring x;
2104 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
2105 || r->slen < 0 || r->mlen < r->slen || n <= 0) return BSTR_ERR;
2108 if (n <= 0) return BSTR_ERR;
2115 if (s->isEOF) return BSTR_ERR;
2117 l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm);
2118 if (0 >= l || l > n - r->slen) {
2123 r->data[r->slen] = (unsigned char) '\0';
2128 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2129 b = (char *) s->buff->data;
2130 x.data = (unsigned char *) b;
2133 if (l + r->slen >= n) {
2134 x.slen = n - r->slen;
2135 ret = bconcat (r, &x);
2137 if (BSTR_OK == ret) bdelete (s->buff, 0, x.slen);
2138 return BSTR_ERR & -(r->slen == orslen);
2142 if (BSTR_OK != bconcat (r, &x)) break;
2145 if (l > s->maxBuffSz) l = s->maxBuffSz;
2147 l = (int) s->readFnPtr (b, 1, l, s->parm);
2151 if (l == 0) s->isEOF = 1;
2153 return BSTR_ERR & -(r->slen == orslen);
2156 /* int bsreadln (bstring r, struct bStream * s, char terminator)
2158 * Read a bstring terminated by the terminator character or the end of the
2159 * stream from the bStream (s) and return it into the parameter r. This
2160 * function may read additional characters from the core stream that are not
2161 * returned, but will be retained for subsequent read operations.
2163 int bsreadln (bstring r, struct bStream * s, char terminator) {
2164 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0)
2166 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2168 return bsreadlna (r, s, terminator);
2171 /* int bsreadlns (bstring r, struct bStream * s, bstring term)
2173 * Read a bstring terminated by any character in the term string or the end
2174 * of the stream from the bStream (s) and return it into the parameter r.
2175 * This function may read additional characters from the core stream that
2176 * are not returned, but will be retained for subsequent read operations.
2178 int bsreadlns (bstring r, struct bStream * s, const_bstring term) {
2179 if (s == NULL || s->buff == NULL || r == NULL || term == NULL
2180 || term->data == NULL || r->mlen <= 0) return BSTR_ERR;
2181 if (term->slen == 1) return bsreadln (r, s, term->data[0]);
2182 if (term->slen < 1) return BSTR_ERR;
2183 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2185 return bsreadlnsa (r, s, term);
2188 /* int bsread (bstring r, struct bStream * s, int n)
2190 * Read a bstring of length n (or, if it is fewer, as many bytes as is
2191 * remaining) from the bStream. This function may read additional
2192 * characters from the core stream that are not returned, but will be
2193 * retained for subsequent read operations. This function will not read
2194 * additional characters from the core stream beyond virtual stream pointer.
2196 int bsread (bstring r, struct bStream * s, int n) {
2197 if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
2198 || n <= 0) return BSTR_ERR;
2199 if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2201 return bsreada (r, s, n);
2204 /* int bsunread (struct bStream * s, const_bstring b)
2206 * Insert a bstring into the bStream at the current position. These
2207 * characters will be read prior to those that actually come from the core
2210 int bsunread (struct bStream * s, const_bstring b) {
2211 if (s == NULL || s->buff == NULL) return BSTR_ERR;
2212 return binsert (s->buff, 0, b, (unsigned char) '?');
2215 /* int bspeek (bstring r, const struct bStream * s)
2217 * Return the currently buffered characters from the bStream that will be
2218 * read prior to reads from the core stream.
2220 int bspeek (bstring r, const struct bStream * s) {
2221 if (s == NULL || s->buff == NULL) return BSTR_ERR;
2222 return bassign (r, s->buff);
2225 /* bstring bjoin (const struct bstrList * bl, const_bstring sep);
2227 * Join the entries of a bstrList into one bstring by sequentially
2228 * concatenating them with the sep string in between. If there is an error
2229 * NULL is returned, otherwise a bstring with the correct result is returned.
2231 bstring bjoin (const struct bstrList * bl, const_bstring sep) {
2235 if (bl == NULL || bl->qty < 0) return NULL;
2236 if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL;
2238 for (i = 0, c = 1; i < bl->qty; i++) {
2239 v = bl->entry[i]->slen;
2240 if (v < 0) return NULL; /* Invalid input */
2242 if (c < 0) return NULL; /* Wrap around ?? */
2245 if (sep != NULL) c += (bl->qty - 1) * sep->slen;
2247 b = (bstring) bstr__alloc (sizeof (struct tagbstring));
2248 if (NULL == b) return NULL; /* Out of memory */
2249 b->data = (unsigned char *) bstr__alloc (c);
2250 if (b->data == NULL) {
2258 for (i = 0, c = 0; i < bl->qty; i++) {
2259 if (i > 0 && sep != NULL) {
2260 bstr__memcpy (b->data + c, sep->data, sep->slen);
2263 v = bl->entry[i]->slen;
2264 bstr__memcpy (b->data + c, bl->entry[i]->data, v);
2267 b->data[c] = (unsigned char) '\0';
2271 #define BSSSC_BUFF_LEN (256)
2273 /* int bssplitscb (struct bStream * s, const_bstring splitStr,
2274 * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
2276 * Iterate the set of disjoint sequential substrings read from a stream
2277 * divided by any of the characters in splitStr. An empty splitStr causes
2278 * the whole stream to be iterated once.
2280 * Note: At the point of calling the cb function, the bStream pointer is
2281 * pointed exactly at the position right after having read the split
2282 * character. The cb function can act on the stream by causing the bStream
2283 * pointer to move, and bssplitscb will continue by starting the next split
2284 * at the position of the pointer after the return from cb.
2286 * However, if the cb causes the bStream s to be destroyed then the cb must
2287 * return with a negative value, otherwise bssplitscb will continue in an
2290 int bssplitscb (struct bStream * s, const_bstring splitStr,
2291 int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2292 struct charField chrs;
2296 if (cb == NULL || s == NULL || s->readFnPtr == NULL
2297 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2299 if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
2301 if (splitStr->slen == 0) {
2302 while (bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ;
2303 if ((ret = cb (parm, 0, buff)) > 0)
2306 buildCharField (&chrs, splitStr);
2309 if (i >= buff->slen) {
2310 bsreada (buff, s, BSSSC_BUFF_LEN);
2311 if (i >= buff->slen) {
2312 if (0 < (ret = cb (parm, p, buff))) ret = 0;
2316 if (testInCharField (&chrs, buff->data[i])) {
2317 struct tagbstring t;
2320 blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1));
2321 if ((ret = bsunread (s, &t)) < 0) break;
2324 buff->data[i] = (unsigned char) '\0';
2325 if ((ret = cb (parm, p, buff)) < 0) break;
2339 /* int bssplitstrcb (struct bStream * s, const_bstring splitStr,
2340 * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
2342 * Iterate the set of disjoint sequential substrings read from a stream
2343 * divided by the entire substring splitStr. An empty splitStr causes
2344 * each character of the stream to be iterated.
2346 * Note: At the point of calling the cb function, the bStream pointer is
2347 * pointed exactly at the position right after having read the split
2348 * character. The cb function can act on the stream by causing the bStream
2349 * pointer to move, and bssplitscb will continue by starting the next split
2350 * at the position of the pointer after the return from cb.
2352 * However, if the cb causes the bStream s to be destroyed then the cb must
2353 * return with a negative value, otherwise bssplitscb will continue in an
2356 int bssplitstrcb (struct bStream * s, const_bstring splitStr,
2357 int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2361 if (cb == NULL || s == NULL || s->readFnPtr == NULL
2362 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2364 if (splitStr->slen == 1) return bssplitscb (s, splitStr, cb, parm);
2366 if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
2368 if (splitStr->slen == 0) {
2369 for (i=0; bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) {
2370 if ((ret = cb (parm, 0, buff)) < 0) {
2380 if ((ret = binstr (buff, 0, splitStr)) >= 0) {
2381 struct tagbstring t;
2382 blk2tbstr (t, buff->data, ret);
2383 i = ret + splitStr->slen;
2384 if ((ret = cb (parm, p, &t)) < 0) break;
2386 bdelete (buff, 0, i);
2388 bsreada (buff, s, BSSSC_BUFF_LEN);
2390 if ((ret = cb (parm, p, buff)) > 0) ret = 0;
2401 /* int bstrListCreate (void)
2403 * Create a bstrList.
2405 struct bstrList * bstrListCreate (void) {
2406 struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2408 sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring));
2420 /* int bstrListDestroy (struct bstrList * sl)
2422 * Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate.
2424 int bstrListDestroy (struct bstrList * sl) {
2426 if (sl == NULL || sl->qty < 0) return BSTR_ERR;
2427 for (i=0; i < sl->qty; i++) {
2429 bdestroy (sl->entry[i]);
2430 sl->entry[i] = NULL;
2435 bstr__free (sl->entry);
2441 /* int bstrListAlloc (struct bstrList * sl, int msz)
2443 * Ensure that there is memory for at least msz number of entries for the
2446 int bstrListAlloc (struct bstrList * sl, int msz) {
2450 if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
2451 if (sl->mlen >= msz) return BSTR_OK;
2452 smsz = snapUpSize (msz);
2453 nsz = ((size_t) smsz) * sizeof (bstring);
2454 if (nsz < (size_t) smsz) return BSTR_ERR;
2455 l = (bstring *) bstr__realloc (sl->entry, nsz);
2458 nsz = ((size_t) smsz) * sizeof (bstring);
2459 l = (bstring *) bstr__realloc (sl->entry, nsz);
2460 if (!l) return BSTR_ERR;
2467 /* int bstrListAllocMin (struct bstrList * sl, int msz)
2469 * Try to allocate the minimum amount of memory for the list to include at
2470 * least msz entries or sl->qty whichever is greater.
2472 int bstrListAllocMin (struct bstrList * sl, int msz) {
2475 if (!sl || msz <= 0 || !sl->entry || sl->qty < 0 || sl->mlen <= 0 || sl->qty > sl->mlen) return BSTR_ERR;
2476 if (msz < sl->qty) msz = sl->qty;
2477 if (sl->mlen == msz) return BSTR_OK;
2478 nsz = ((size_t) msz) * sizeof (bstring);
2479 if (nsz < (size_t) msz) return BSTR_ERR;
2480 l = (bstring *) bstr__realloc (sl->entry, nsz);
2481 if (!l) return BSTR_ERR;
2487 /* int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2488 * int (* cb) (void * parm, int ofs, int len), void * parm)
2490 * Iterate the set of disjoint sequential substrings over str divided by the
2491 * character in splitChar.
2493 * Note: Non-destructive modification of str from within the cb function
2494 * while performing this split is not undefined. bsplitcb behaves in
2495 * sequential lock step with calls to cb. I.e., after returning from a cb
2496 * that return a non-negative integer, bsplitcb continues from the position
2497 * 1 character after the last detected split character and it will halt
2498 * immediately if the length of str falls below this point. However, if the
2499 * cb function destroys str, then it *must* return with a negative value,
2500 * otherwise bsplitcb will continue in an undefined manner.
2502 int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2503 int (* cb) (void * parm, int ofs, int len), void * parm) {
2506 if (cb == NULL || str == NULL || pos < 0 || pos > str->slen)
2511 for (i=p; i < str->slen; i++) {
2512 if (str->data[i] == splitChar) break;
2514 if ((ret = cb (parm, p, i - p)) < 0) return ret;
2516 } while (p <= str->slen);
2520 /* int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2521 * int (* cb) (void * parm, int ofs, int len), void * parm)
2523 * Iterate the set of disjoint sequential substrings over str divided by any
2524 * of the characters in splitStr. An empty splitStr causes the whole str to
2527 * Note: Non-destructive modification of str from within the cb function
2528 * while performing this split is not undefined. bsplitscb behaves in
2529 * sequential lock step with calls to cb. I.e., after returning from a cb
2530 * that return a non-negative integer, bsplitscb continues from the position
2531 * 1 character after the last detected split character and it will halt
2532 * immediately if the length of str falls below this point. However, if the
2533 * cb function destroys str, then it *must* return with a negative value,
2534 * otherwise bsplitscb will continue in an undefined manner.
2536 int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2537 int (* cb) (void * parm, int ofs, int len), void * parm) {
2538 struct charField chrs;
2541 if (cb == NULL || str == NULL || pos < 0 || pos > str->slen
2542 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2543 if (splitStr->slen == 0) {
2544 if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0;
2548 if (splitStr->slen == 1)
2549 return bsplitcb (str, splitStr->data[0], pos, cb, parm);
2551 buildCharField (&chrs, splitStr);
2555 for (i=p; i < str->slen; i++) {
2556 if (testInCharField (&chrs, str->data[i])) break;
2558 if ((ret = cb (parm, p, i - p)) < 0) return ret;
2560 } while (p <= str->slen);
2564 /* int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2565 * int (* cb) (void * parm, int ofs, int len), void * parm)
2567 * Iterate the set of disjoint sequential substrings over str divided by the
2568 * substring splitStr. An empty splitStr causes the whole str to be
2571 * Note: Non-destructive modification of str from within the cb function
2572 * while performing this split is not undefined. bsplitstrcb behaves in
2573 * sequential lock step with calls to cb. I.e., after returning from a cb
2574 * that return a non-negative integer, bsplitscb continues from the position
2575 * 1 character after the last detected split character and it will halt
2576 * immediately if the length of str falls below this point. However, if the
2577 * cb function destroys str, then it *must* return with a negative value,
2578 * otherwise bsplitscb will continue in an undefined manner.
2580 int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2581 int (* cb) (void * parm, int ofs, int len), void * parm) {
2584 if (cb == NULL || str == NULL || pos < 0 || pos > str->slen
2585 || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2587 if (0 == splitStr->slen) {
2588 for (i=pos; i < str->slen; i++) {
2589 if ((ret = cb (parm, i, 1)) < 0) return ret;
2594 if (splitStr->slen == 1)
2595 return bsplitcb (str, splitStr->data[0], pos, cb, parm);
2597 for (i=p=pos; i <= str->slen - splitStr->slen; i++) {
2598 if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) {
2599 if ((ret = cb (parm, p, i - p)) < 0) return ret;
2600 i += splitStr->slen;
2604 if ((ret = cb (parm, p, str->slen - p)) < 0) return ret;
2608 struct genBstrList {
2610 struct bstrList * bl;
2613 static int bscb (void * parm, int ofs, int len) {
2614 struct genBstrList * g = (struct genBstrList *) parm;
2615 if (g->bl->qty >= g->bl->mlen) {
2616 int mlen = g->bl->mlen * 2;
2619 while (g->bl->qty >= mlen) {
2620 if (mlen < g->bl->mlen) return BSTR_ERR;
2624 tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen);
2625 if (tbl == NULL) return BSTR_ERR;
2631 g->bl->entry[g->bl->qty] = bmidstr (g->b, ofs, len);
2636 /* struct bstrList * bsplit (const_bstring str, unsigned char splitChar)
2638 * Create an array of sequential substrings from str divided by the character
2641 struct bstrList * bsplit (const_bstring str, unsigned char splitChar) {
2642 struct genBstrList g;
2644 if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
2646 g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2647 if (g.bl == NULL) return NULL;
2649 g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2650 if (NULL == g.bl->entry) {
2655 g.b = (bstring) str;
2657 if (bsplitcb (str, splitChar, 0, bscb, &g) < 0) {
2658 bstrListDestroy (g.bl);
2664 /* struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr)
2666 * Create an array of sequential substrings from str divided by the entire
2667 * substring splitStr.
2669 struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) {
2670 struct genBstrList g;
2672 if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
2674 g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2675 if (g.bl == NULL) return NULL;
2677 g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2678 if (NULL == g.bl->entry) {
2683 g.b = (bstring) str;
2685 if (bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) {
2686 bstrListDestroy (g.bl);
2692 /* struct bstrList * bsplits (const_bstring str, bstring splitStr)
2694 * Create an array of sequential substrings from str divided by any of the
2695 * characters in splitStr. An empty splitStr causes a single entry bstrList
2696 * containing a copy of str to be returned.
2698 struct bstrList * bsplits (const_bstring str, const_bstring splitStr) {
2699 struct genBstrList g;
2701 if ( str == NULL || str->slen < 0 || str->data == NULL ||
2702 splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL)
2705 g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2706 if (g.bl == NULL) return NULL;
2708 g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2709 if (NULL == g.bl->entry) {
2713 g.b = (bstring) str;
2716 if (bsplitscb (str, splitStr, 0, bscb, &g) < 0) {
2717 bstrListDestroy (g.bl);
2723 #if defined (__TURBOC__) && !defined (__BORLANDC__)
2724 # ifndef BSTRLIB_NOVSNP
2725 # define BSTRLIB_NOVSNP
2729 /* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */
2730 #if defined(__WATCOMC__) || defined(_MSC_VER)
2731 #define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);}
2733 #ifdef BSTRLIB_NOVSNP
2734 /* This is just a hack. If you are using a system without a vsnprintf, it is
2735 not recommended that bformat be used at all. */
2736 #define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;}
2737 #define START_VSNBUFF (256)
2741 /* Something is making gcc complain about this prototype not being here, so
2742 I've just gone ahead and put it in. */
2743 extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg);
2746 #define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);}
2750 #if !defined (BSTRLIB_NOVSNP)
2752 #ifndef START_VSNBUFF
2753 #define START_VSNBUFF (16)
2756 /* On IRIX vsnprintf returns n-1 when the operation would overflow the target
2757 buffer, WATCOM and MSVC both return -1, while C99 requires that the
2758 returned value be exactly what the length would be if the buffer would be
2759 large enough. This leads to the idea that if the return value is larger
2760 than n, then changing n to the return value will reduce the number of
2761 iterations required. */
2763 /* int bformata (bstring b, const char * fmt, ...)
2765 * After the first parameter, it takes the same parameters as printf (), but
2766 * rather than outputting results to stdio, it appends the results to
2767 * a bstring which contains what would have been output. Note that if there
2768 * is an early generation of a '\0' character, the bstring will be truncated
2769 * to this end point.
2771 int bformata (bstring b, const char * fmt, ...) {
2776 if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0
2777 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
2779 /* Since the length is not determinable beforehand, a search is
2780 performed using the truncating "vsnprintf" call (to avoid buffer
2781 overflows) on increasing potential sizes for the output result. */
2783 if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
2784 if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
2786 if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
2790 va_start (arglist, fmt);
2791 exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
2794 buff->data[n] = (unsigned char) '\0';
2795 buff->slen = (int) (strlen) ((char *) buff->data);
2797 if (buff->slen < n) break;
2799 if (r > n) n = r; else n += n;
2801 if (BSTR_OK != balloc (buff, n + 2)) {
2807 r = bconcat (b, buff);
2812 /* int bassignformat (bstring b, const char * fmt, ...)
2814 * After the first parameter, it takes the same parameters as printf (), but
2815 * rather than outputting results to stdio, it outputs the results to
2816 * the bstring parameter b. Note that if there is an early generation of a
2817 * '\0' character, the bstring will be truncated to this end point.
2819 int bassignformat (bstring b, const char * fmt, ...) {
2824 if (b == NULL || fmt == NULL || b->data == NULL || b->mlen <= 0
2825 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
2827 /* Since the length is not determinable beforehand, a search is
2828 performed using the truncating "vsnprintf" call (to avoid buffer
2829 overflows) on increasing potential sizes for the output result. */
2831 if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
2832 if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
2834 if (NULL == (buff = bfromcstralloc (n + 2, ""))) return BSTR_ERR;
2838 va_start (arglist, fmt);
2839 exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
2842 buff->data[n] = (unsigned char) '\0';
2843 buff->slen = (int) (strlen) ((char *) buff->data);
2845 if (buff->slen < n) break;
2847 if (r > n) n = r; else n += n;
2849 if (BSTR_OK != balloc (buff, n + 2)) {
2855 r = bassign (b, buff);
2860 /* bstring bformat (const char * fmt, ...)
2862 * Takes the same parameters as printf (), but rather than outputting results
2863 * to stdio, it forms a bstring which contains what would have been output.
2864 * Note that if there is an early generation of a '\0' character, the
2865 * bstring will be truncated to this end point.
2867 bstring bformat (const char * fmt, ...) {
2872 if (fmt == NULL) return NULL;
2874 /* Since the length is not determinable beforehand, a search is
2875 performed using the truncating "vsnprintf" call (to avoid buffer
2876 overflows) on increasing potential sizes for the output result. */
2878 if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
2879 if (NULL == (buff = bfromcstralloc (n + 2, ""))) {
2881 if (NULL == (buff = bfromcstralloc (n + 2, ""))) return NULL;
2885 va_start (arglist, fmt);
2886 exvsnprintf (r, (char *) buff->data, n + 1, fmt, arglist);
2889 buff->data[n] = (unsigned char) '\0';
2890 buff->slen = (int) (strlen) ((char *) buff->data);
2892 if (buff->slen < n) break;
2894 if (r > n) n = r; else n += n;
2896 if (BSTR_OK != balloc (buff, n + 2)) {
2905 /* int bvcformata (bstring b, int count, const char * fmt, va_list arglist)
2907 * The bvcformata function formats data under control of the format control
2908 * string fmt and attempts to append the result to b. The fmt parameter is
2909 * the same as that of the printf function. The variable argument list is
2910 * replaced with arglist, which has been initialized by the va_start macro.
2911 * The size of the output is upper bounded by count. If the required output
2912 * exceeds count, the string b is not augmented with any contents and a value
2913 * below BSTR_ERR is returned. If a value below -count is returned then it
2914 * is recommended that the negative of this value be used as an update to the
2915 * count in a subsequent pass. On other errors, such as running out of
2916 * memory, parameter errors or numeric wrap around BSTR_ERR is returned.
2917 * BSTR_OK is returned when the output is successfully generated and
2920 * Note: There is no sanity checking of arglist, and this function is
2921 * destructive of the contents of b from the b->slen point onward. If there
2922 * is an early generation of a '\0' character, the bstring will be truncated
2923 * to this end point.
2925 int bvcformata (bstring b, int count, const char * fmt, va_list arg) {
2928 if (b == NULL || fmt == NULL || count <= 0 || b->data == NULL
2929 || b->mlen <= 0 || b->slen < 0 || b->slen > b->mlen) return BSTR_ERR;
2931 if (count > (n = b->slen + count) + 2) return BSTR_ERR;
2932 if (BSTR_OK != balloc (b, n + 2)) return BSTR_ERR;
2934 exvsnprintf (r, (char *) b->data + b->slen, count + 2, fmt, arg);
2936 /* Did the operation complete successfully within bounds? */
2938 if (n >= (l = b->slen + (int) (strlen) ((const char *) b->data + b->slen))) {
2943 /* Abort, since the buffer was not large enough. The return value
2944 tries to help set what the retry length should be. */
2946 b->data[b->slen] = '\0';
2947 if (r > count+1) l = r; else {
2949 if (count > l) l = INT_MAX;
2952 if (n > BSTR_ERR-1) n = BSTR_ERR-1;