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.
22 /* Optionally include a mechanism for debugging memory */
24 #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
29 #define bstr__alloc(x) malloc (x)
33 #define bstr__free(p) free (p)
37 #define bstr__realloc(p,x) realloc ((p), (x))
41 #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
45 #define bstr__memmove(d,s,l) memmove ((d), (s), (l))
49 #define bstr__memset(d,c,l) memset ((d), (c), (l))
53 #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
57 #define bstr__memchr(s,c,l) memchr ((s), (c), (l))
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
) {
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 */
83 /* Least power of two greater than i */
85 if ((int) j
>= i
) i
= (int) j
;
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
) {
96 if (b
== NULL
|| b
->data
== NULL
|| b
->slen
< 0 || b
->mlen
<= 0 ||
97 b
->mlen
< b
->slen
|| olen
<= 0) {
101 if (olen
>= b
->mlen
) {
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 */
114 x
= (unsigned char *) bstr__realloc (b
->data
, (size_t) len
);
117 /* Since we failed, try allocating the tighest possible
120 if (NULL
== (x
= (unsigned char *) bstr__realloc (b
->data
, (size_t) (len
= olen
)))) {
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
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
;
138 if (b
->slen
) bstr__memcpy ((char *) x
, (char *) b
->data
, (size_t) b
->slen
);
139 bstr__free (b
->data
);
144 b
->data
[b
->slen
] = (unsigned char) '\0';
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
156 int ballocmin (bstring b
, int len
) {
159 if (b
== NULL
|| b
->data
== NULL
|| (b
->slen
+1) < 0 || b
->mlen
<= 0 ||
160 b
->mlen
< b
->slen
|| len
<= 0) {
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';
177 /* bstring bfromcstr (const char * str)
179 * Create a bstring which contains the contents of the '\0' terminated char *
182 bstring
bfromcstr (const char * str
) {
187 if (str
== NULL
) return NULL
;
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
;
195 if (NULL
== (b
->data
= (unsigned char *) bstr__alloc (b
->mlen
= i
))) {
200 bstr__memcpy (b
->data
, str
, j
+1);
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
) {
215 if (str
== NULL
) return NULL
;
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
;
223 if (i
< mlen
) i
= mlen
;
225 if (NULL
== (b
->data
= (unsigned char *) bstr__alloc (b
->mlen
= i
))) {
230 bstr__memcpy (b
->data
, str
, j
+1);
234 /* bstring blk2bstr (const void * blk, int len)
236 * Create a bstring which contains the content of the block blk of length
239 bstring
blk2bstr (const void * blk
, int len
) {
243 if (blk
== NULL
|| len
< 0) return NULL
;
244 b
= (bstring
) bstr__alloc (sizeof (struct tagbstring
));
245 if (b
== NULL
) return NULL
;
248 i
= len
+ (2 - (len
!= 0));
253 b
->data
= (unsigned char *) bstr__alloc ((size_t) b
->mlen
);
254 if (b
->data
== NULL
) {
259 if (len
> 0) bstr__memcpy (b
->data
, blk
, (size_t) len
);
260 b
->data
[len
] = (unsigned char) '\0';
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
) {
276 if (b
== NULL
|| b
->slen
< 0 || b
->data
== NULL
) return NULL
;
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';
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
301 int bcstrfree (char * s
) {
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
) {
315 bstring aux
= (bstring
) b1
;
317 if (b0
== NULL
|| b1
== NULL
|| b0
->data
== NULL
|| b1
->data
== NULL
) return BSTR_ERR
;
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
);
334 bBlockCopy (&b0
->data
[d
], &aux
->data
[0], (size_t) len
);
335 b0
->data
[d
+ len
] = (unsigned char) '\0';
337 if (aux
!= b1
) bdestroy (aux
);
341 /* int bconchar (bstring b, char c)
343 * Concatenate the single character c to the bstring b.
345 int bconchar (bstring b
, char c
) {
348 if (b
== NULL
) return BSTR_ERR
;
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';
357 /* int bcatcstr (bstring b, const char * s)
359 * Concatenate a char * string to a bstring.
361 int bcatcstr (bstring b
, const char * s
) {
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') {
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
) {
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
);
398 b
->data
[nl
] = (unsigned char) '\0';
402 /* bstring bstrcpy (const_bstring b)
404 * Create a copy of the bstring b.
406 bstring
bstrcpy (const_bstring b
) {
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
));
415 /* Unable to allocate memory for string header */
420 j
= snapUpSize (i
+ 1);
422 b0
->data
= (unsigned char *) bstr__alloc (j
);
423 if (b0
->data
== NULL
) {
425 b0
->data
= (unsigned char *) bstr__alloc (j
);
426 if (b0
->data
== NULL
) {
427 /* Unable to allocate memory for string data */
436 if (i
) bstr__memcpy ((char *) b0
->data
, (char *) b
->data
, i
);
437 b0
->data
[b0
->slen
] = (unsigned char) '\0';
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)
450 if (balloc (a
, b
->slen
) != BSTR_OK
) return BSTR_ERR
;
451 bstr__memmove (a
->data
, b
->data
, b
->slen
);
453 if (a
== NULL
|| a
->data
== NULL
|| a
->mlen
< a
->slen
||
454 a
->slen
< 0 || a
->mlen
== 0)
457 a
->data
[b
->slen
] = (unsigned char) '\0';
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)
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)
484 if (balloc (a
, len
) != BSTR_OK
) return BSTR_ERR
;
485 bstr__memmove (a
->data
, b
->data
+ left
, len
);
490 a
->data
[a
->slen
] = (unsigned char) '\0';
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
) {
503 if (a
== NULL
|| a
->data
== NULL
|| a
->mlen
< a
->slen
||
504 a
->slen
< 0 || a
->mlen
== 0 || NULL
== str
)
507 for (i
=0; i
< a
->mlen
; i
++) {
508 if ('\0' == (a
->data
[i
] = str
[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
;
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)
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';
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
;
549 b
->data
[n
] = (unsigned char) '\0';
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
) {
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
]);
572 /* int btolower (bstring b)
574 * Convert contents of bstring to lower case.
576 int btolower (bstring b
) {
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
]);
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
) {
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
;
610 v
= (char) downcase (b0
->data
[n
]);
612 return UCHAR_MAX
+ 1;
615 v
= - (char) downcase (b1
->data
[n
]);
617 return - (int) (UCHAR_MAX
+ 1);
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
632 int bstrnicmp (const_bstring b0
, const_bstring b1
, int n
) {
635 if (bdata (b0
) == NULL
|| b0
->slen
< 0 ||
636 bdata (b1
) == NULL
|| b1
->slen
< 0 || n
< 0) return SHRT_MIN
;
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
;
652 v
= (char) downcase (b0
->data
[m
]);
654 return UCHAR_MAX
+ 1;
657 v
= - (char) downcase (b1
->data
[m
]);
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
) {
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;
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
695 int bisstemeqcaselessblk (const_bstring b0
, const void * blk
, int len
) {
698 if (bdata (b0
) == NULL
|| b0
->slen
< 0 || NULL
== blk
|| len
< 0)
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;
713 * int bltrimws (bstring b)
715 * Delete whitespace contiguous from the left end of the string.
717 int bltrimws (bstring b
) {
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';
735 * int brtrimws (bstring b)
737 * Delete whitespace contiguous from the right end of the string.
739 int brtrimws (bstring b
) {
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';
753 b
->data
[0] = (unsigned char) '\0';
759 * int btrimws (bstring b)
761 * Delete whitespace contiguous from both ends of the string.
763 int btrimws (bstring b
) {
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';
773 for (j
= 0; wspace (b
->data
[j
]); j
++) {}
774 return bdelete (b
, 0, j
);
778 b
->data
[0] = (unsigned char) '\0';
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
806 int bisstemeqblk (const_bstring b0
, const void * blk
, int len
) {
809 if (bdata (b0
) == NULL
|| b0
->slen
< 0 || NULL
== blk
|| len
< 0)
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
;
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
) {
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
;
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
) {
854 if (b
== NULL
|| s
== NULL
|| b
->data
== NULL
|| b
->slen
< 0) return BSTR_ERR
;
855 for (i
=0; i
< b
->slen
; i
++) {
857 (b
->data
[i
] != (unsigned char) s
[i
] &&
858 downcase (b
->data
[i
]) != (unsigned char) downcase (s
[i
])))
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
) {
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))
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;
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
) {
911 if (b0
== NULL
|| b1
== NULL
|| b0
->data
== NULL
|| b1
->data
== NULL
||
912 b0
->slen
< 0 || b1
->slen
< 0) return SHRT_MIN
;
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;
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
;
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 */
967 if (len
< 0 || b
== NULL
|| b
->data
== NULL
|| b
->slen
< 0 ||
968 b
->mlen
< b
->slen
|| b
->mlen
<= 0)
970 if (len
> 0 && pos
< b
->slen
) {
971 if (pos
+ len
>= b
->slen
) {
974 bBlockCopy ((char *) (b
->data
+ pos
),
975 (char *) (b
->data
+ pos
+ len
),
976 b
->slen
- (pos
+len
));
979 b
->data
[b
->slen
] = (unsigned char) '\0';
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
||
996 bstr__free (b
->data
);
998 /* In case there is any stale usage, there is one more chance to
999 notice this error. */
1002 b
->mlen
= -__LINE__
;
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
) {
1022 register unsigned char * d1
;
1023 register unsigned char c1
;
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;
1044 /* Peel off the b2->slen == 1 case */
1047 for (;i
< lf
; i
++) if (c0
== d1
[i
]) return i
;
1057 /* Unrolled current character test */
1059 if (c1
!= d1
[1+i
]) {
1066 /* Take note if this is the start of a potential match */
1069 /* Shift the test character down by one */
1073 /* If this isn't past the last character continue */
1081 /* If no characters mismatched, then we matched */
1082 if (i
== ii
+j
) return ii
;
1084 /* Shift back to the beginning */
1090 /* Deal with last case if unrolling caused a misalignment */
1091 if (i
== lf
&& ll
== j
+1 && c1
== d1
[i
]) goto N0
;
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
) {
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;
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
;
1130 if (d0
[j
] == d1
[i
+ j
]) {
1132 if (j
>= l
) return i
;
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
) {
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
;
1178 if (d0
[j
] == d1
[i
+ j
] || downcase (d0
[j
]) == downcase (d1
[i
+ j
])) {
1180 if (j
>= ll
) return i
;
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
) {
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
;
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
;
1225 if (d0
[j
] == d1
[i
+ j
] || downcase (d0
[j
]) == downcase (d1
[i
+ j
])) {
1227 if (j
>= l
) return i
;
1239 /* int bstrchrp (const_bstring b, int c, int pos)
1241 * Search for the character c in b forwards from the position pos
1244 int bstrchrp (const_bstring b
, int c
, int pos
) {
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
);
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
1258 int bstrrchrp (const_bstring b
, int c
, int pos
) {
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
;
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))); \
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
1290 /* Convert a bstring to charField */
1291 static int buildCharField (struct charField
* cf
, const_bstring b
) {
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
]);
1301 static void invertCharField (struct charField
* cf
) {
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
) {
1309 for (i
=pos
; i
< len
; i
++) {
1310 unsigned char c
= (unsigned char) data
[i
];
1311 if (testInCharField (cf
, c
)) return i
;
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
) {
1334 for (i
=pos
; i
>= 0; i
--) {
1335 unsigned int c
= (unsigned int) data
[i
];
1336 if (testInCharField (cf
, c
)) return i
;
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
) {
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
;
1408 if ((pd
= (ptrdiff_t) (b1
->data
- b0
->data
)) >= 0 && pd
< (ptrdiff_t) b0
->mlen
) {
1409 if (NULL
== (aux
= bstrcpy (b1
))) return BSTR_ERR
;
1414 /* Increase memory size if necessary */
1415 if (balloc (b0
, d
+ 1) != BSTR_OK
) {
1416 if (aux
!= b1
) bdestroy (aux
);
1422 /* Fill in "fill" character as necessary */
1424 bstr__memset (b0
->data
+ b0
->slen
, (int) fill
, (size_t) (pos
- b0
->slen
));
1428 /* Copy b1 to position pos in b0. */
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
;
1438 b0
->data
[newlen
] = (unsigned char) '\0';
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
) {
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
;
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
;
1469 /* Inserting past the end of the string */
1470 if (balloc (b1
, l
+ 1) != BSTR_OK
) {
1471 if (aux
!= b2
) bdestroy (aux
);
1474 bstr__memset (b1
->data
+ b1
->slen
, (int) fill
, (size_t) (pos
- b1
->slen
));
1477 /* Inserting in the middle of the string */
1478 if (balloc (b1
, d
+ 1) != BSTR_OK
) {
1479 if (aux
!= b2
) bdestroy (aux
);
1482 bBlockCopy (b1
->data
+ l
, b1
->data
+ pos
, d
- l
);
1485 bBlockCopy (b1
->data
+ pos
, aux
->data
, aux
->slen
);
1486 b1
->data
[b1
->slen
] = (unsigned char) '\0';
1487 if (aux
!= b2
) bdestroy (aux
);
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
) {
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';
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
);
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
);
1538 /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
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
;
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
);
1576 delta
= auxf
->slen
- auxr
->slen
;
1578 /* in-place replacement since find and replace strings are of equal
1581 while ((pos
= instr (b
, pos
, auxf
)) >= 0) {
1582 bstr__memcpy (b
->data
+ pos
, auxr
->data
, auxr
->slen
);
1585 if (auxf
!= find
) bdestroy (auxf
);
1586 if (auxr
!= repl
) bdestroy (auxr
);
1590 /* shrinking replacement since auxf->slen > auxr->slen */
1594 while ((i
= instr (b
, pos
, auxf
)) >= 0) {
1596 bstr__memmove (b
->data
+ pos
- acc
, b
->data
+ pos
, i
- pos
);
1598 bstr__memcpy (b
->data
+ i
- acc
, auxr
->data
, auxr
->slen
);
1600 pos
= i
+ auxf
->slen
;
1606 bstr__memmove (b
->data
+ pos
- acc
, b
->data
+ pos
, i
- pos
);
1608 b
->data
[b
->slen
] = (unsigned char) '\0';
1611 if (auxf
!= find
) bdestroy (auxf
);
1612 if (auxr
!= repl
) bdestroy (auxr
);
1616 /* expanding replacement since find->slen < repl->slen. Its a lot
1617 more complicated. */
1620 d
= (int *) static_d
; /* Avoid malloc for trivial cases */
1623 while ((pos
= instr (b
, pos
, auxf
)) >= 0) {
1624 if (slen
+ 1 >= mlen
) {
1628 sl
= sizeof (int *) * mlen
;
1629 if (static_d
== d
) d
= NULL
;
1630 if (sl
< mlen
|| NULL
== (t
= (int *) bstr__realloc (d
, sl
))) {
1634 if (NULL
== d
) bstr__memcpy (t
, static_d
, sizeof (static_d
));
1641 if (pos
< 0 || acc
< 0) {
1648 if (BSTR_OK
== (ret
= balloc (b
, b
->slen
+ acc
+ 1))) {
1650 for (i
= slen
-1; i
>= 0; i
--) {
1652 s
= d
[i
] + auxf
->slen
;
1655 bstr__memmove (b
->data
+ s
+ acc
, b
->data
+ s
, l
);
1658 bstr__memmove (b
->data
+ s
+ acc
- auxr
->slen
,
1659 auxr
->data
, auxr
->slen
);
1663 b
->data
[b
->slen
] = (unsigned char) '\0';
1667 if (static_d
== d
) d
= NULL
;
1669 if (auxf
!= find
) bdestroy (auxf
);
1670 if (auxr
!= repl
) bdestroy (auxr
);
1674 /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
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,
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
) {
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 */
1710 if ((d
|l
) < 0) return BSTR_ERR
;
1713 /* Inserting past the end of the string */
1714 if (balloc (b
, l
+ 1) != BSTR_OK
) return BSTR_ERR
;
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
];
1726 for (i
=pos
; i
< l
; i
++) b
->data
[i
] = fill
;
1727 b
->data
[b
->slen
] = (unsigned char) '\0';
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
) {
1742 if (d
<= 0 || len
< 0 || balloc (b
, len
+ 1) != BSTR_OK
) return BSTR_ERR
;
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';
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
1760 int breada (bstring b
, bNread readPtr
, void * parm
) {
1763 if (b
== NULL
|| b
->mlen
<= 0 || b
->slen
< 0 || b
->mlen
< b
->slen
||
1764 b
->mlen
<= 0 || readPtr
== NULL
) return BSTR_ERR
;
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
);
1775 b
->data
[i
] = (unsigned char) '\0';
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
1785 bstring
bread (bNread readPtr
, void * parm
) {
1788 if (0 > breada (buff
= bfromcstr (""), readPtr
, parm
)) {
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
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
) {
1811 if (b
== NULL
|| b
->mlen
<= 0 || b
->slen
< 0 || b
->mlen
< b
->slen
||
1812 b
->mlen
<= 0 || getcPtr
== NULL
) return BSTR_ERR
;
1816 while ((c
= getcPtr (parm
)) >= 0) {
1819 if (balloc (b
, d
+ 2) != BSTR_OK
) return BSTR_ERR
;
1822 b
->data
[d
] = (unsigned char) c
;
1824 if (c
== terminator
) break;
1827 b
->data
[d
] = (unsigned char) '\0';
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
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
) {
1849 if (b
== NULL
|| b
->mlen
<= 0 || b
->slen
< 0 || b
->mlen
< b
->slen
||
1850 b
->mlen
<= 0 || getcPtr
== NULL
) return BSTR_ERR
;
1854 while ((c
= getcPtr (parm
)) >= 0) {
1857 if (balloc (b
, d
+ 2) != BSTR_OK
) return BSTR_ERR
;
1860 b
->data
[d
] = (unsigned char) c
;
1862 if (c
== terminator
) break;
1865 b
->data
[d
] = (unsigned char) '\0';
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
) {
1885 if (0 > bgetsa (buff
= bfromcstr (""), getcPtr
, parm
, terminator
) || 0 >= buff
->slen
) {
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 */
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
) {
1909 if (readPtr
== NULL
) return NULL
;
1910 s
= (struct bStream
*) bstr__alloc (sizeof (struct bStream
));
1911 if (s
== NULL
) return NULL
;
1913 s
->buff
= bfromcstr ("");
1914 s
->readFnPtr
= readPtr
;
1915 s
->maxBuffSz
= BS_BUFF_SZ
;
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
) {
1927 if (s
== NULL
|| sz
< 0) return BSTR_ERR
;
1928 oldSz
= s
->maxBuffSz
;
1929 if (sz
> 0) s
->maxBuffSz
= sz
;
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
) {
1945 if (s
== NULL
) return NULL
;
1946 s
->readFnPtr
= NULL
;
1947 if (s
->buff
) bdestroy (s
->buff
);
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
) {
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
;
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
++) ;
1980 ret
= bconcat (r
, &x
);
1982 if (BSTR_OK
== ret
) bdelete (s
->buff
, 0, i
+ 1);
1988 /* If not then just concatenate the entire buffer to the output */
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 */
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
);
1999 r
->data
[r
->slen
] = (unsigned char) '\0';
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
++) ;
2011 /* Terminator found, push over-read back to buffer */
2014 s
->buff
->slen
= l
- i
;
2015 bstr__memcpy (s
->buff
->data
, b
+ i
, l
- i
);
2016 r
->data
[r
->slen
] = (unsigned char) '\0';
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
) {
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
;
2040 if (BSTR_OK
!= balloc (s
->buff
, s
->maxBuffSz
+ 1)) return BSTR_ERR
;
2041 b
= (unsigned char *) s
->buff
->data
;
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
++) ;
2049 ret
= bconcat (r
, &x
);
2051 if (BSTR_OK
== ret
) bdelete (s
->buff
, 0, i
+ 1);
2057 /* If not then just concatenate the entire buffer to the output */
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 */
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
);
2068 r
->data
[r
->slen
] = (unsigned char) '\0';
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
++) ;
2081 /* Terminator found, push over-read back to buffer */
2084 s
->buff
->slen
= l
- i
;
2085 bstr__memcpy (s
->buff
->data
, b
+ i
, l
- i
);
2086 r
->data
[r
->slen
] = (unsigned char) '\0';
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
) {
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
;
2107 if (n
<= 0) return BSTR_ERR
;
2114 if (s
->isEOF
) return BSTR_ERR
;
2116 l
= (int) s
->readFnPtr (r
->data
+ r
->slen
, 1, n
- r
->slen
, s
->parm
);
2117 if (0 >= l
|| l
> n
- r
->slen
) {
2122 r
->data
[r
->slen
] = (unsigned char) '\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
;
2132 if (l
+ r
->slen
>= n
) {
2133 x
.slen
= n
- r
->slen
;
2134 ret
= bconcat (r
, &x
);
2136 if (BSTR_OK
== ret
) bdelete (s
->buff
, 0, x
.slen
);
2137 return BSTR_ERR
& -(r
->slen
== orslen
);
2141 if (BSTR_OK
!= bconcat (r
, &x
)) break;
2144 if (l
> s
->maxBuffSz
) l
= s
->maxBuffSz
;
2146 l
= (int) s
->readFnPtr (b
, 1, l
, s
->parm
);
2150 if (l
== 0) s
->isEOF
= 1;
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)
2165 if (BSTR_OK
!= balloc (s
->buff
, s
->maxBuffSz
+ 1)) return BSTR_ERR
;
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
;
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
;
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
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
) {
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 */
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
) {
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
);
2262 v
= bl
->entry
[i
]->slen
;
2263 bstr__memcpy (b
->data
+ c
, bl
->entry
[i
]->data
, v
);
2266 b
->data
[c
] = (unsigned char) '\0';
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
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
;
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)
2305 buildCharField (&chrs
, splitStr
);
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;
2315 if (testInCharField (&chrs
, buff
->data
[i
])) {
2316 struct tagbstring t
;
2319 blk2tbstr (t
, buff
->data
+ i
+ 1, buff
->slen
- (i
+ 1));
2320 if ((ret
= bsunread (s
, &t
)) < 0) break;
2323 buff
->data
[i
] = (unsigned char) '\0';
2324 if ((ret
= cb (parm
, p
, buff
)) < 0) break;
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
2355 int bssplitstrcb (struct bStream
* s
, const_bstring splitStr
,
2356 int (* cb
) (void * parm
, int ofs
, const_bstring entry
), void * parm
) {
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) {
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;
2385 bdelete (buff
, 0, i
);
2387 bsreada (buff
, s
, BSSSC_BUFF_LEN
);
2389 if ((ret
= cb (parm
, p
, buff
)) > 0) ret
= 0;
2400 /* int bstrListCreate (void)
2402 * Create a bstrList.
2404 struct bstrList
* bstrListCreate (void) {
2405 struct bstrList
* sl
= (struct bstrList
*) bstr__alloc (sizeof (struct bstrList
));
2407 sl
->entry
= (bstring
*) bstr__alloc (1*sizeof (bstring
));
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
) {
2425 if (sl
== NULL
|| sl
->qty
< 0) return BSTR_ERR
;
2426 for (i
=0; i
< sl
->qty
; i
++) {
2428 bdestroy (sl
->entry
[i
]);
2429 sl
->entry
[i
] = NULL
;
2434 bstr__free (sl
->entry
);
2440 /* int bstrListAlloc (struct bstrList * sl, int msz)
2442 * Ensure that there is memory for at least msz number of entries for the
2445 int bstrListAlloc (struct bstrList
* sl
, int msz
) {
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
);
2457 nsz
= ((size_t) smsz
) * sizeof (bstring
);
2458 l
= (bstring
*) bstr__realloc (sl
->entry
, nsz
);
2459 if (!l
) return BSTR_ERR
;
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
) {
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
;
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
) {
2505 if (cb
== NULL
|| str
== NULL
|| pos
< 0 || pos
> str
->slen
)
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
;
2515 } while (p
<= str
->slen
);
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
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
;
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;
2547 if (splitStr
->slen
== 1)
2548 return bsplitcb (str
, splitStr
->data
[0], pos
, cb
, parm
);
2550 buildCharField (&chrs
, splitStr
);
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
;
2559 } while (p
<= str
->slen
);
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
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
) {
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
;
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
;
2603 if ((ret
= cb (parm
, p
, str
->slen
- p
)) < 0) return ret
;
2607 struct genBstrList
{
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;
2618 while (g
->bl
->qty
>= mlen
) {
2619 if (mlen
< g
->bl
->mlen
) return BSTR_ERR
;
2623 tbl
= (bstring
*) bstr__realloc (g
->bl
->entry
, sizeof (bstring
) * mlen
);
2624 if (tbl
== NULL
) return BSTR_ERR
;
2630 g
->bl
->entry
[g
->bl
->qty
] = bmidstr (g
->b
, ofs
, len
);
2635 /* struct bstrList * bsplit (const_bstring str, unsigned char splitChar)
2637 * Create an array of sequential substrings from str divided by the character
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
;
2648 g
.bl
->entry
= (bstring
*) bstr__alloc (g
.bl
->mlen
* sizeof (bstring
));
2649 if (NULL
== g
.bl
->entry
) {
2654 g
.b
= (bstring
) str
;
2656 if (bsplitcb (str
, splitChar
, 0, bscb
, &g
) < 0) {
2657 bstrListDestroy (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
;
2676 g
.bl
->entry
= (bstring
*) bstr__alloc (g
.bl
->mlen
* sizeof (bstring
));
2677 if (NULL
== g
.bl
->entry
) {
2682 g
.b
= (bstring
) str
;
2684 if (bsplitstrcb (str
, splitStr
, 0, bscb
, &g
) < 0) {
2685 bstrListDestroy (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
)
2704 g
.bl
= (struct bstrList
*) bstr__alloc (sizeof (struct bstrList
));
2705 if (g
.bl
== NULL
) return NULL
;
2707 g
.bl
->entry
= (bstring
*) bstr__alloc (g
.bl
->mlen
* sizeof (bstring
));
2708 if (NULL
== g
.bl
->entry
) {
2712 g
.b
= (bstring
) str
;
2715 if (bsplitscb (str
, splitStr
, 0, bscb
, &g
) < 0) {
2716 bstrListDestroy (g
.bl
);
2722 #if defined (__TURBOC__) && !defined (__BORLANDC__)
2723 # ifndef BSTRLIB_NOVSNP
2724 # define BSTRLIB_NOVSNP
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);}
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)
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
);
2745 #define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);}
2749 #if !defined (BSTRLIB_NOVSNP)
2751 #ifndef START_VSNBUFF
2752 #define START_VSNBUFF (16)
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
, ...) {
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, ""))) {
2785 if (NULL
== (buff
= bfromcstralloc (n
+ 2, ""))) return BSTR_ERR
;
2789 va_start (arglist
, fmt
);
2790 exvsnprintf (r
, (char *) buff
->data
, n
+ 1, fmt
, 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)) {
2806 r
= bconcat (b
, buff
);
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
, ...) {
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, ""))) {
2833 if (NULL
== (buff
= bfromcstralloc (n
+ 2, ""))) return BSTR_ERR
;
2837 va_start (arglist
, fmt
);
2838 exvsnprintf (r
, (char *) buff
->data
, n
+ 1, fmt
, 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)) {
2854 r
= bassign (b
, buff
);
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
, ...) {
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, ""))) {
2880 if (NULL
== (buff
= bfromcstralloc (n
+ 2, ""))) return NULL
;
2884 va_start (arglist
, fmt
);
2885 exvsnprintf (r
, (char *) buff
->data
, n
+ 1, fmt
, 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)) {
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
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
) {
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
))) {
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 {
2948 if (count
> l
) l
= INT_MAX
;
2951 if (n
> BSTR_ERR
-1) n
= BSTR_ERR
-1;