1 /*
2  * This source file is part of the bstring string library.  This code was
3  * written by Paul Hsieh in 2002-2015, and is covered by the BSD open source
4  * license and the GPL. Refer to the accompanying documentation for details
5  * on usage and license.
6  */
7 
8 /*
9  * bstrwrap.c
10  *
11  * This file is the C++ wrapper for the bstring functions.
12  */
13 
14 #if defined (_MSC_VER)
15 # define _CRT_SECURE_NO_WARNINGS
16 #endif
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <limits.h>
23 #include "bstrwrap.h"
24 
25 #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
26 #include "memdbg.h"
27 #endif
28 
29 #ifndef bstr__alloc
30 #define bstr__alloc(x) malloc (x)
31 #endif
32 
33 #ifndef bstr__free
34 #define bstr__free(p) free (p)
35 #endif
36 
37 #ifndef bstr__realloc
38 #define bstr__realloc(p,x) realloc ((p), (x))
39 #endif
40 
41 #ifndef bstr__memcpy
42 #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
43 #endif
44 
45 #ifndef bstr__memmove
46 #define bstr__memmove(d,s,l) memmove ((d), (s), (l))
47 #endif
48 
49 #ifndef bstr__memset
50 #define bstr__memset(d,c,l) memset ((d), (c), (l))
51 #endif
52 
53 #ifndef bstr__memcmp
54 #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
55 #endif
56 
57 #ifndef bstr__memchr
58 #define bstr__memchr(s,c,l) memchr ((s), (c), (l))
59 #endif
60 
61 #if defined(BSTRLIB_CAN_USE_IOSTREAM)
62 #include <iostream>
63 #endif
64 
65 namespace Bstrlib {
66 
67 // Constructors.
68 
CBString()69 CBString::CBString () {
70 	slen = 0;
71 	mlen = 8;
72 	data = (unsigned char *) bstr__alloc (mlen);
73 	if (!data) {
74 		mlen = 0;
75 		bstringThrow ("Failure in default constructor");
76 	} else {
77 		data[0] = '\0';
78 	}
79 }
80 
CBString(const void * blk,int len)81 CBString::CBString (const void * blk, int len) {
82 	data = NULL;
83 	if (len >= 0) {
84 		mlen = len + 1;
85 		slen = len;
86 		data = (unsigned char *) bstr__alloc (mlen);
87 	}
88 	if (!data) {
89 		mlen = slen = 0;
90 		bstringThrow ("Failure in block constructor");
91 	} else {
92 		if (slen > 0) bstr__memcpy (data, blk, slen);
93 		data[slen] = '\0';
94 	}
95 }
96 
CBString(char c,int len)97 CBString::CBString (char c, int len) {
98 	data = NULL;
99 	if (len >= 0) {
100 		mlen = len + 1;
101 		slen = len;
102 		data = (unsigned char *) bstr__alloc (mlen);
103 	}
104 	if (!data) {
105 		mlen = slen = 0;
106 		bstringThrow ("Failure in repeat(char) constructor");
107 	} else {
108 		if (slen > 0) bstr__memset (data, c, slen);
109 		data[slen] = '\0';
110 	}
111 }
112 
CBString(char c)113 CBString::CBString (char c) {
114 	mlen = 2;
115 	slen = 1;
116 	if (NULL == (data = (unsigned char *) bstr__alloc (mlen))) {
117 		mlen = slen = 0;
118 		bstringThrow ("Failure in (char) constructor");
119 	} else {
120 		data[0] = (unsigned char) c;
121 		data[1] = '\0';
122 	}
123 }
124 
CBString(unsigned char c)125 CBString::CBString (unsigned char c) {
126 	mlen = 2;
127 	slen = 1;
128 	if (NULL == (data = (unsigned char *) bstr__alloc (mlen))) {
129 		mlen = slen = 0;
130 		bstringThrow ("Failure in (char) constructor");
131 	} else {
132 		data[0] = c;
133 		data[1] = '\0';
134 	}
135 }
136 
CBString(const char * s)137 CBString::CBString (const char *s) {
138 	if (s) {
139 		size_t sslen = strlen (s);
140 		if (sslen >= INT_MAX) bstringThrow ("Failure in (char *) constructor, string too large")
141 		slen = (int) sslen;
142 		mlen = slen + 1;
143 		if (NULL != (data = (unsigned char *) bstr__alloc (mlen))) {
144 			bstr__memcpy (data, s, mlen);
145 			return;
146 		}
147 	}
148 	data = NULL;
149 	bstringThrow ("Failure in (char *) constructor");
150 }
151 
CBString(int len,const char * s)152 CBString::CBString (int len, const char *s) {
153 	if (s) {
154 		size_t sslen = strlen (s);
155 		if (sslen >= INT_MAX) bstringThrow ("Failure in (char *) constructor, string too large")
156 		slen = (int) sslen;
157 		mlen = slen + 1;
158 		if (mlen < len) mlen = len;
159 		if (NULL != (data = (unsigned char *) bstr__alloc (mlen))) {
160 			bstr__memcpy (data, s, slen + 1);
161 			return;
162 		}
163 	}
164 	data = NULL;
165 	bstringThrow ("Failure in (int len, char *) constructor");
166 }
167 
CBString(const CBString & b)168 CBString::CBString (const CBString& b) {
169 	slen = b.slen;
170 	mlen = slen + 1;
171 	data = NULL;
172 	if (mlen > 0) data = (unsigned char *) bstr__alloc (mlen);
173 	if (!data) {
174 		bstringThrow ("Failure in (CBString) constructor");
175 	} else {
176 		bstr__memcpy (data, b.data, slen);
177 		data[slen] = '\0';
178 	}
179 }
180 
CBString(const tagbstring & x)181 CBString::CBString (const tagbstring& x) {
182 	slen = x.slen;
183 	mlen = slen + 1;
184 	data = NULL;
185 	if (slen >= 0 && x.data != NULL) data = (unsigned char *) bstr__alloc (mlen);
186 	if (!data) {
187 		bstringThrow ("Failure in (tagbstring) constructor");
188 	} else {
189 		bstr__memcpy (data, x.data, slen);
190 		data[slen] = '\0';
191 	}
192 }
193 
194 // Destructor.
195 
~CBString()196 CBString::~CBString () {
197 	if (data != NULL) {
198 		bstr__free (data);
199 		data = NULL;
200 	}
201 	mlen = 0;
202 	slen = -__LINE__;
203 }
204 
205 // = operator.
206 
operator =(char c)207 const CBString& CBString::operator = (char c) {
208 	if (mlen <= 0) bstringThrow ("Write protection error");
209 	if (2 >= mlen) alloc (2);
210 	if (!data) {
211 		mlen = slen = 0;
212 		bstringThrow ("Failure in =(char) operator");
213 	} else {
214 		slen = 1;
215 		data[0] = (unsigned char) c;
216 		data[1] = '\0';
217 	}
218 	return *this;
219 }
220 
operator =(unsigned char c)221 const CBString& CBString::operator = (unsigned char c) {
222 	if (mlen <= 0) bstringThrow ("Write protection error");
223 	if (2 >= mlen) alloc (2);
224 	if (!data) {
225 		mlen = slen = 0;
226 		bstringThrow ("Failure in =(char) operator");
227 	} else {
228 		slen = 1;
229 		data[0] = c;
230 		data[1] = '\0';
231 	}
232 	return *this;
233 }
234 
operator =(const char * s)235 const CBString& CBString::operator = (const char *s) {
236 size_t tmpSlen;
237 
238 	if (mlen <= 0) bstringThrow ("Write protection error");
239 	if (NULL == s) s = "";
240 	if ((tmpSlen = strlen (s)) >= (size_t) mlen) {
241 		if (tmpSlen >= INT_MAX-1) bstringThrow ("Failure in =(const char *) operator, string too large");
242 		alloc ((int) tmpSlen);
243 	}
244 
245 	if (data) {
246 		slen = (int) tmpSlen;
247 		bstr__memcpy (data, s, tmpSlen + 1);
248 	} else {
249 		mlen = slen = 0;
250 		bstringThrow ("Failure in =(const char *) operator");
251 	}
252 	return *this;
253 }
254 
operator =(const CBString & b)255 const CBString& CBString::operator = (const CBString& b) {
256 	if (mlen <= 0) bstringThrow ("Write protection error");
257 	if (b.slen >= mlen) alloc (b.slen);
258 
259 	slen = b.slen;
260 	if (!data) {
261 		mlen = slen = 0;
262 		bstringThrow ("Failure in =(CBString) operator");
263 	} else {
264 		bstr__memcpy (data, b.data, slen);
265 		data[slen] = '\0';
266 	}
267 	return *this;
268 }
269 
operator =(const tagbstring & x)270 const CBString& CBString::operator = (const tagbstring& x) {
271 	if (mlen <= 0) bstringThrow ("Write protection error");
272 	if (x.slen < 0) bstringThrow ("Failure in =(tagbstring) operator, badly formed tagbstring");
273 	if (x.slen >= mlen) alloc (x.slen);
274 
275 	slen = x.slen;
276 	if (!data) {
277 		mlen = slen = 0;
278 		bstringThrow ("Failure in =(tagbstring) operator");
279 	} else {
280 		bstr__memcpy (data, x.data, slen);
281 		data[slen] = '\0';
282 	}
283 	return *this;
284 }
285 
operator +=(const CBString & b)286 const CBString& CBString::operator += (const CBString& b) {
287 	if (BSTR_ERR == bconcat (this, (bstring) &b)) {
288 		bstringThrow ("Failure in concatenate");
289 	}
290 	return *this;
291 }
292 
operator +=(const char * s)293 const CBString& CBString::operator += (const char *s) {
294 	char * d;
295 	int i, l;
296 
297 	if (mlen <= 0) bstringThrow ("Write protection error");
298 
299 	/* Optimistically concatenate directly */
300 	l = mlen - slen;
301 	d = (char *) &data[slen];
302 	for (i=0; i < l; i++) {
303 		if ((*d++ = *s++) == '\0') {
304 			slen += i;
305 			return *this;
306 		}
307 	}
308 	slen += i;
309 
310 	if (BSTR_ERR == bcatcstr (this, s)) {
311 		bstringThrow ("Failure in concatenate");
312 	}
313 	return *this;
314 }
315 
operator +=(char c)316 const CBString& CBString::operator += (char c) {
317 	if (BSTR_ERR == bconchar (this, c)) {
318 		bstringThrow ("Failure in concatenate");
319 	}
320 	return *this;
321 }
322 
operator +=(unsigned char c)323 const CBString& CBString::operator += (unsigned char c) {
324 	if (BSTR_ERR == bconchar (this, (char) c)) {
325 		bstringThrow ("Failure in concatenate");
326 	}
327 	return *this;
328 }
329 
operator +=(const tagbstring & x)330 const CBString& CBString::operator += (const tagbstring& x) {
331 	if (mlen <= 0) bstringThrow ("Write protection error");
332 	if (x.slen < 0) bstringThrow ("Failure in +=(tagbstring) operator, badly formed tagbstring");
333 	alloc (x.slen + slen + 1);
334 
335 	if (!data) {
336 		mlen = slen = 0;
337 		bstringThrow ("Failure in +=(tagbstring) operator");
338 	} else {
339 		bstr__memcpy (data + slen, x.data, x.slen);
340 		slen += x.slen;
341 		data[slen] = '\0';
342 	}
343 	return *this;
344 }
345 
operator +(char c) const346 const CBString CBString::operator + (char c) const {
347 	CBString retval (*this);
348 	retval += c;
349 	return retval;
350 }
351 
operator +(unsigned char c) const352 const CBString CBString::operator + (unsigned char c) const {
353 	CBString retval (*this);
354 	retval += c;
355 	return retval;
356 }
357 
operator +(const CBString & b) const358 const CBString CBString::operator + (const CBString& b) const {
359 	CBString retval (*this);
360 	retval += b;
361 	return retval;
362 }
363 
operator +(const char * s) const364 const CBString CBString::operator + (const char *s) const {
365 	if (s == NULL) bstringThrow ("Failure in + (char *) operator, NULL");
366 	CBString retval (*this);
367 	retval += s;
368 	return retval;
369 }
370 
operator +(const unsigned char * s) const371 const CBString CBString::operator + (const unsigned char *s) const {
372 	if (s == NULL) bstringThrow ("Failure in + (unsigned char *) operator, NULL");
373 	CBString retval (*this);
374 	retval += (const char *) s;
375 	return retval;
376 }
377 
operator +(const tagbstring & x) const378 const CBString CBString::operator + (const tagbstring& x) const {
379 	if (x.slen < 0) bstringThrow ("Failure in + (tagbstring) operator, badly formed tagbstring");
380 	CBString retval (*this);
381 	retval += x;
382 	return retval;
383 }
384 
operator ==(const CBString & b) const385 bool CBString::operator == (const CBString& b) const {
386 	int retval;
387 	if (BSTR_ERR == (retval = biseq ((bstring)this, (bstring)&b))) {
388 		bstringThrow ("Failure in compare (==)");
389 	}
390 	return retval > 0;
391 }
392 
operator ==(const char * s) const393 bool CBString::operator == (const char * s) const {
394 	int retval;
395 	if (NULL == s) {
396 		bstringThrow ("Failure in compare (== NULL)");
397 	}
398 	if (BSTR_ERR == (retval = biseqcstr ((bstring) this, s))) {
399 		bstringThrow ("Failure in compare (==)");
400 	}
401 	return retval > 0;
402 }
403 
operator ==(const unsigned char * s) const404 bool CBString::operator == (const unsigned char * s) const {
405 	int retval;
406 	if (NULL == s) {
407 		bstringThrow ("Failure in compare (== NULL)");
408 	}
409 	if (BSTR_ERR == (retval = biseqcstr ((bstring) this, (const char *) s))) {
410 		bstringThrow ("Failure in compare (==)");
411 	}
412 	return retval > 0;
413 }
414 
operator !=(const CBString & b) const415 bool CBString::operator != (const CBString& b) const {
416 	return ! ((*this) == b);
417 }
418 
operator !=(const char * s) const419 bool CBString::operator != (const char * s) const {
420 	return ! ((*this) == s);
421 }
422 
operator !=(const unsigned char * s) const423 bool CBString::operator != (const unsigned char * s) const {
424 	return ! ((*this) == s);
425 }
426 
operator <(const CBString & b) const427 bool CBString::operator < (const CBString& b) const {
428 	int retval;
429 	if (SHRT_MIN == (retval = bstrcmp ((bstring) this, (bstring)&b))) {
430 		bstringThrow ("Failure in compare (<)");
431 	}
432 	return retval < 0;
433 }
434 
operator <(const char * s) const435 bool CBString::operator < (const char * s) const {
436 	if (s == NULL) {
437 		bstringThrow ("Failure in compare (<)");
438 	}
439 	return strcmp ((const char *)this->data, s) < 0;
440 }
441 
operator <(const unsigned char * s) const442 bool CBString::operator < (const unsigned char * s) const {
443 	if (s == NULL) {
444 		bstringThrow ("Failure in compare (<)");
445 	}
446 	return strcmp ((const char *)this->data, (const char *)s) < 0;
447 }
448 
operator <=(const CBString & b) const449 bool CBString::operator <= (const CBString& b) const {
450 	int retval;
451 	if (SHRT_MIN == (retval = bstrcmp ((bstring) this, (bstring)&b))) {
452 		bstringThrow ("Failure in compare (<=)");
453 	}
454 	return retval <= 0;
455 }
456 
operator <=(const char * s) const457 bool CBString::operator <= (const char * s) const {
458 	if (s == NULL) {
459 		bstringThrow ("Failure in compare (<=)");
460 	}
461 	return strcmp ((const char *)this->data, s) <= 0;
462 }
463 
operator <=(const unsigned char * s) const464 bool CBString::operator <= (const unsigned char * s) const {
465 	if (s == NULL) {
466 		bstringThrow ("Failure in compare (<=)");
467 	}
468 	return strcmp ((const char *)this->data, (const char *)s) <= 0;
469 }
470 
operator >(const CBString & b) const471 bool CBString::operator > (const CBString& b) const {
472 	return ! ((*this) <= b);
473 }
474 
operator >(const char * s) const475 bool CBString::operator > (const char * s) const {
476 	return ! ((*this) <= s);
477 }
478 
operator >(const unsigned char * s) const479 bool CBString::operator > (const unsigned char * s) const {
480 	return ! ((*this) <= s);
481 }
482 
operator >=(const CBString & b) const483 bool CBString::operator >= (const CBString& b) const {
484 	return ! ((*this) < b);
485 }
486 
operator >=(const char * s) const487 bool CBString::operator >= (const char * s) const {
488 	return ! ((*this) < s);
489 }
490 
operator >=(const unsigned char * s) const491 bool CBString::operator >= (const unsigned char * s) const {
492 	return ! ((*this) < s);
493 }
494 
operator double() const495 CBString::operator double () const {
496 double d = 0;
497 	if (1 != sscanf ((const char *)this->data, "%lf", &d)) {
498 		bstringThrow ("Unable to convert to a double");
499 	}
500 	return d;
501 }
502 
operator float() const503 CBString::operator float () const {
504 float d = 0;
505 	if (1 != sscanf ((const char *)this->data, "%f", &d)) {
506 		bstringThrow ("Unable to convert to a float");
507 	}
508 	return d;
509 }
510 
operator int() const511 CBString::operator int () const {
512 int d = 0;
513 	if (1 != sscanf ((const char *)this->data, "%d", &d)) {
514 		bstringThrow ("Unable to convert to an int");
515 	}
516 	return d;
517 }
518 
operator unsigned int() const519 CBString::operator unsigned int () const {
520 unsigned int d = 0;
521 	if (1 != sscanf ((const char *)this->data, "%u", &d)) {
522 		bstringThrow ("Unable to convert to an unsigned int");
523 	}
524 	return d;
525 }
526 
527 #ifdef __TURBOC__
528 # ifndef BSTRLIB_NOVSNP
529 #  define BSTRLIB_NOVSNP
530 # endif
531 #endif
532 
533 /* Give WATCOM C/C++, MSVC some latitude for their non-support of vsnprintf */
534 #if defined(__WATCOMC__) || defined(_MSC_VER)
535 #define exvsnprintf(r,b,n,f,a) {r = _vsnprintf (b,n,f,a);}
536 #else
537 #ifdef BSTRLIB_NOVSNP
538 /* This is just a hack.  If you are using a system without a vsnprintf, it is
539    not recommended that bformat be used at all. */
540 #define exvsnprintf(r,b,n,f,a) {vsprintf (b,f,a); r = -1;}
541 #define START_VSNBUFF (256)
542 #else
543 
544 #if defined (__GNUC__) && !defined (__PPC__)
545 /* Something is making gcc complain about this prototype not being here, so
546    I've just gone ahead and put it in. */
547 extern "C" {
548 extern int vsnprintf (char *buf, size_t count, const char *format, va_list arg);
549 }
550 #endif
551 
552 #define exvsnprintf(r,b,n,f,a) {r = vsnprintf (b,n,f,a);}
553 #endif
554 #endif
555 
556 #ifndef START_VSNBUFF
557 #define START_VSNBUFF (16)
558 #endif
559 
560 /*
561  * Yeah I'd like to just call a vformat function or something, but because of
562  * the ANSI specified brokeness of the va_* macros, it is actually not
563  * possible to do this correctly.
564  */
565 
format(const char * fmt,...)566 void CBString::format (const char * fmt, ...) {
567 	bstring b;
568 	va_list arglist;
569 	int r, n;
570 
571 	if (mlen <= 0) bstringThrow ("Write protection error");
572 	if (fmt == NULL) {
573 		*this = "<NULL>";
574 		bstringThrow ("CBString::format (NULL, ...) is erroneous.");
575 	} else {
576 
577 		if ((b = bfromcstr ("")) == NULL) {
578 #ifdef BSTRLIB_THROWS_EXCEPTIONS
579 			bstringThrow ("CBString::format out of memory.");
580 #else
581 			*this = "<NULL>";
582 #endif
583 		} else {
584 			if ((n = (int) (2 * (strlen) (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
585 			for (;;) {
586 				if (BSTR_OK != balloc (b, n + 2)) {
587 #ifdef BSTRLIB_THROWS_EXCEPTIONS
588 					bstringThrow ("CBString::format out of memory.");
589 #else
590 					b = bformat ("<NULL>");
591 					break;
592 #endif
593 				}
594 
595 				va_start (arglist, fmt);
596 				exvsnprintf (r, (char *) b->data, n + 1, fmt, arglist);
597 				va_end (arglist);
598 
599 				b->data[n] = '\0';
600 				b->slen = (int) (strlen) ((char *) b->data);
601 
602 				if (b->slen < n) break;
603 				if (r > n) n = r; else n += n;
604 			}
605 			*this = *b;
606 			bdestroy (b);
607 		}
608 	}
609 }
610 
formata(const char * fmt,...)611 void CBString::formata (const char * fmt, ...) {
612 	bstring b;
613 	va_list arglist;
614 	int r, n;
615 
616 	if (mlen <= 0) bstringThrow ("Write protection error");
617 	if (fmt == NULL) {
618 		*this += "<NULL>";
619 		bstringThrow ("CBString::formata (NULL, ...) is erroneous.");
620 	} else {
621 
622 		if ((b = bfromcstr ("")) == NULL) {
623 #ifdef BSTRLIB_THROWS_EXCEPTIONS
624 			bstringThrow ("CBString::format out of memory.");
625 #else
626 			*this += "<NULL>";
627 #endif
628 		} else {
629 			if ((n = (int) (2 * (strlen) (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
630 			for (;;) {
631 				if (BSTR_OK != balloc (b, n + 2)) {
632 #ifdef BSTRLIB_THROWS_EXCEPTIONS
633 					bstringThrow ("CBString::format out of memory.");
634 #else
635 					b = bformat ("<NULL>");
636 					break;
637 #endif
638 				}
639 
640 				va_start (arglist, fmt);
641 				exvsnprintf (r, (char *) b->data, n + 1, fmt, arglist);
642 				va_end (arglist);
643 
644 				b->data[n] = '\0';
645 				b->slen = (int) (strlen) ((char *) b->data);
646 
647 				if (b->slen < n) break;
648 				if (r > n) n = r; else n += n;
649 			}
650 			*this += *b;
651 			bdestroy (b);
652 		}
653 	}
654 }
655 
caselessEqual(const CBString & b) const656 int CBString::caselessEqual (const CBString& b) const {
657 int ret;
658 	if (BSTR_ERR == (ret = biseqcaseless ((bstring) this, (bstring) &b))) {
659 		bstringThrow ("CBString::caselessEqual Unable to compare");
660 	}
661 	return ret;
662 }
663 
caselessCmp(const CBString & b) const664 int CBString::caselessCmp (const CBString& b) const {
665 int ret;
666 	if (SHRT_MIN == (ret = bstricmp ((bstring) this, (bstring) &b))) {
667 		bstringThrow ("CBString::caselessCmp Unable to compare");
668 	}
669 	return ret;
670 }
671 
find(const CBString & b,int pos) const672 int CBString::find (const CBString& b, int pos) const {
673 	return binstr ((bstring) this, pos, (bstring) &b);
674 }
675 
676 /*
677     int CBString::find (const char * b, int pos) const;
678 
679     Uses and unrolling and sliding paired indexes character matching.  Since
680     the unrolling is the primary real world impact the true purpose of this
681     algorithm choice is maximize the effectiveness of the unrolling.  The
682     idea is to scan until at least one match of the current indexed character
683     from each string, and then shift indexes of both down by and repeat until
684     the last character form b matches.  When the last character from b
685     matches if the were no mismatches in previous strlen(b) characters then
686     we know we have a full match, otherwise shift both indexes back strlen(b)
687     characters and continue.
688 
689     In general, if there is any character in b that is not at all in this
690     CBString, then this algorithm is O(slen).  The algorithm does not easily
691     degenerate into O(slen * strlen(b)) performance except in very uncommon
692     situations.  Thus from a real world perspective, the overhead of
693     precomputing suffix shifts in the Boyer-Moore algorithm is avoided, while
694     delivering an unrolled matching inner loop most of the time.
695  */
696 
find(const char * b,int pos) const697 int CBString::find (const char * b, int pos) const {
698 int ii, j;
699 unsigned char c0;
700 int i, l;
701 unsigned char cx;
702 unsigned char * pdata;
703 
704 	if (NULL == b) {
705 #ifdef BSTRLIB_THROWS_EXCEPTIONS
706 		bstringThrow ("CBString::find NULL.");
707 #else
708 		return BSTR_ERR;
709 #endif
710 	}
711 
712 	if ((unsigned int) pos > (unsigned int) slen) return BSTR_ERR;
713 	if ('\0' == b[0]) return pos;
714 	if (pos == slen) return BSTR_ERR;
715 	if ('\0' == b[1]) return find (b[0], pos);
716 
717 	cx = c0 = (unsigned char) b[0];
718 	l = slen - 1;
719 
720 	pdata = data;
721 	for (ii = -1, i = pos, j = 0; i < l;) {
722 		/* Unrolled current character test */
723 		if (cx != pdata[i]) {
724 			if (cx != pdata[1+i]) {
725 				i += 2;
726 				continue;
727 			}
728 			i++;
729 		}
730 
731 		/* Take note if this is the start of a potential match */
732 		if (0 == j) ii = i;
733 
734 		/* Shift the test character down by one */
735 		j++;
736 		i++;
737 
738 		/* If this isn't past the last character continue */
739 		if ('\0' != (cx = b[j])) continue;
740 
741 		N0:;
742 
743 		/* If no characters mismatched, then we matched */
744 		if (i == ii+j) return ii;
745 
746 		/* Shift back to the beginning */
747 		i -= j;
748 		j = 0;
749 		cx = c0;
750 	}
751 
752 	/* Deal with last case if unrolling caused a misalignment */
753 	if (i == l && cx == pdata[i] && '\0' == b[j+1]) goto N0;
754 
755 	return BSTR_ERR;
756 }
757 
caselessfind(const CBString & b,int pos) const758 int CBString::caselessfind (const CBString& b, int pos) const {
759 	return binstrcaseless ((bstring) this, pos, (bstring) &b);
760 }
761 
caselessfind(const char * b,int pos) const762 int CBString::caselessfind (const char * b, int pos) const {
763 struct tagbstring t;
764 
765 	if (NULL == b) {
766 #ifdef BSTRLIB_THROWS_EXCEPTIONS
767 		bstringThrow ("CBString::caselessfind NULL.");
768 #else
769 		return BSTR_ERR;
770 #endif
771 	}
772 
773 	if ((unsigned int) pos > (unsigned int) slen) return BSTR_ERR;
774 	if ('\0' == b[0]) return pos;
775 	if (pos == slen) return BSTR_ERR;
776 
777 	btfromcstr (t, b);
778 	return binstrcaseless ((bstring) this, pos, (bstring) &t);
779 }
780 
find(char c,int pos) const781 int CBString::find (char c, int pos) const {
782 	if (pos < 0) return BSTR_ERR;
783 	for (;pos < slen; pos++) {
784 		if (data[pos] == (unsigned char) c) return pos;
785 	}
786 	return BSTR_ERR;
787 }
788 
reversefind(const CBString & b,int pos) const789 int CBString::reversefind (const CBString& b, int pos) const {
790 	return binstrr ((bstring) this, pos, (bstring) &b);
791 }
792 
reversefind(const char * b,int pos) const793 int CBString::reversefind (const char * b, int pos) const {
794 struct tagbstring t;
795 	if (NULL == b) {
796 #ifdef BSTRLIB_THROWS_EXCEPTIONS
797 		bstringThrow ("CBString::reversefind NULL.");
798 #else
799 		return BSTR_ERR;
800 #endif
801 	}
802 	cstr2tbstr (t, b);
803 	return binstrr ((bstring) this, pos, &t);
804 }
805 
caselessreversefind(const CBString & b,int pos) const806 int CBString::caselessreversefind (const CBString& b, int pos) const {
807 	return binstrrcaseless ((bstring) this, pos, (bstring) &b);
808 }
809 
caselessreversefind(const char * b,int pos) const810 int CBString::caselessreversefind (const char * b, int pos) const {
811 struct tagbstring t;
812 
813 	if (NULL == b) {
814 #ifdef BSTRLIB_THROWS_EXCEPTIONS
815 		bstringThrow ("CBString::caselessreversefind NULL.");
816 #else
817 		return BSTR_ERR;
818 #endif
819 	}
820 
821 	if ((unsigned int) pos > (unsigned int) slen) return BSTR_ERR;
822 	if ('\0' == b[0]) return pos;
823 	if (pos == slen) return BSTR_ERR;
824 
825 	btfromcstr (t, b);
826 	return binstrrcaseless ((bstring) this, pos, (bstring) &t);
827 }
828 
reversefind(char c,int pos) const829 int CBString::reversefind (char c, int pos) const {
830 	if (pos > slen) return BSTR_ERR;
831 	if (pos == slen) pos--;
832 	for (;pos >= 0; pos--) {
833 		if (data[pos] == (unsigned char) c) return pos;
834 	}
835 	return BSTR_ERR;
836 }
837 
findchr(const CBString & b,int pos) const838 int CBString::findchr (const CBString& b, int pos) const {
839 	return binchr ((bstring) this, pos, (bstring) &b);
840 }
841 
findchr(const char * s,int pos) const842 int CBString::findchr (const char * s, int pos) const {
843 struct tagbstring t;
844 	if (NULL == s) {
845 #ifdef BSTRLIB_THROWS_EXCEPTIONS
846 		bstringThrow ("CBString::findchr NULL.");
847 #else
848 		return BSTR_ERR;
849 #endif
850 	}
851 	cstr2tbstr (t, s);
852 	return binchr ((bstring) this, pos, (bstring) &t);
853 }
854 
nfindchr(const CBString & b,int pos) const855 int CBString::nfindchr (const CBString& b, int pos) const {
856 	return bninchr ((bstring) this, pos, (bstring) &b);
857 }
858 
nfindchr(const char * s,int pos) const859 int CBString::nfindchr (const char * s, int pos) const {
860 struct tagbstring t;
861 	if (NULL == s) {
862 #ifdef BSTRLIB_THROWS_EXCEPTIONS
863 		bstringThrow ("CBString::nfindchr NULL.");
864 #else
865 		return BSTR_ERR;
866 #endif
867 	}
868 	cstr2tbstr (t, s);
869 	return bninchr ((bstring) this, pos, &t);
870 }
871 
reversefindchr(const CBString & b,int pos) const872 int CBString::reversefindchr (const CBString& b, int pos) const {
873 	return binchrr ((bstring) this, pos, (bstring) &b);
874 }
875 
reversefindchr(const char * s,int pos) const876 int CBString::reversefindchr (const char * s, int pos) const {
877 struct tagbstring t;
878 	if (NULL == s) {
879 #ifdef BSTRLIB_THROWS_EXCEPTIONS
880 		bstringThrow ("CBString::reversefindchr NULL.");
881 #else
882 		return BSTR_ERR;
883 #endif
884 	}
885 	cstr2tbstr (t, s);
886 	return binchrr ((bstring) this, pos, &t);
887 }
888 
nreversefindchr(const CBString & b,int pos) const889 int CBString::nreversefindchr (const CBString& b, int pos) const {
890 	return bninchrr ((bstring) this, pos, (bstring) &b);
891 }
892 
nreversefindchr(const char * s,int pos) const893 int CBString::nreversefindchr (const char * s, int pos) const {
894 struct tagbstring t;
895 	if (NULL == s) {
896 #ifdef BSTRLIB_THROWS_EXCEPTIONS
897 		bstringThrow ("CBString::nreversefindchr NULL.");
898 #else
899 		return BSTR_ERR;
900 #endif
901 	}
902 	cstr2tbstr (t, s);
903 	return bninchrr ((bstring) this, pos, &t);
904 }
905 
midstr(int left,int len) const906 CBString CBString::midstr (int left, int len) const {
907 struct tagbstring t;
908 	if (left < 0) {
909 		len += left;
910 		left = 0;
911 	}
912 	if (len > slen - left) len = slen - left;
913 	if (len <= 0) return CBString ("");
914 	blk2tbstr (t, data + left, len);
915 	return CBString (t);
916 }
917 
alloc(int len)918 void CBString::alloc (int len) {
919 	if (BSTR_ERR == balloc ((bstring)this, len)) {
920 		bstringThrow ("Failure in alloc");
921 	}
922 }
923 
fill(int len,unsigned char cfill)924 void CBString::fill (int len, unsigned char cfill) {
925 	slen = 0;
926 	if (BSTR_ERR == bsetstr (this, len, NULL, cfill)) {
927 		bstringThrow ("Failure in fill");
928 	}
929 }
930 
setsubstr(int pos,const CBString & b,unsigned char cfill)931 void CBString::setsubstr (int pos, const CBString& b, unsigned char cfill) {
932 	if (BSTR_ERR == bsetstr (this, pos, (bstring) &b, cfill)) {
933 		bstringThrow ("Failure in setsubstr");
934 	}
935 }
936 
setsubstr(int pos,const char * s,unsigned char cfill)937 void CBString::setsubstr (int pos, const char * s, unsigned char cfill) {
938 struct tagbstring t;
939 	if (NULL == s) {
940 #ifdef BSTRLIB_THROWS_EXCEPTIONS
941 		bstringThrow ("setsubstr NULL.");
942 #else
943 		return;
944 #endif
945 	}
946 	cstr2tbstr (t, s);
947 	if (BSTR_ERR == bsetstr (this, pos, &t, cfill)) {
948 		bstringThrow ("Failure in setsubstr");
949 	}
950 }
951 
insert(int pos,const CBString & b,unsigned char cfill)952 void CBString::insert (int pos, const CBString& b, unsigned char cfill) {
953 	if (BSTR_ERR == binsert (this, pos, (bstring) &b, cfill)) {
954 		bstringThrow ("Failure in insert");
955 	}
956 }
957 
insert(int pos,const char * s,unsigned char cfill)958 void CBString::insert (int pos, const char * s, unsigned char cfill) {
959 struct tagbstring t;
960 	if (NULL == s) {
961 #ifdef BSTRLIB_THROWS_EXCEPTIONS
962 		bstringThrow ("insert NULL.");
963 #else
964 		return;
965 #endif
966 	}
967 	cstr2tbstr (t, s);
968 	if (BSTR_ERR == binsert (this, pos, &t, cfill)) {
969 		bstringThrow ("Failure in insert");
970 	}
971 }
972 
insertchrs(int pos,int len,unsigned char cfill)973 void CBString::insertchrs (int pos, int len, unsigned char cfill) {
974 	if (BSTR_ERR == binsertch (this, pos, len, cfill)) {
975 		bstringThrow ("Failure in insertchrs");
976 	}
977 }
978 
replace(int pos,int len,const CBString & b,unsigned char cfill)979 void CBString::replace (int pos, int len, const CBString& b, unsigned char cfill) {
980 	if (BSTR_ERR == breplace (this, pos, len, (bstring) &b, cfill)) {
981 		bstringThrow ("Failure in replace");
982 	}
983 }
984 
replace(int pos,int len,const char * s,unsigned char cfill)985 void CBString::replace (int pos, int len, const char * s, unsigned char cfill) {
986 struct tagbstring t;
987 size_t q;
988 
989 	if (mlen <= 0) bstringThrow ("Write protection error");
990 	if (NULL == s || (pos|len) < 0) {
991 		bstringThrow ("Failure in replace");
992 	} else {
993 		if (pos + len >= slen) {
994 			cstr2tbstr (t, s);
995 			if (BSTR_ERR == bsetstr (this, pos, &t, cfill)) {
996 				bstringThrow ("Failure in replace");
997 			} else if (pos + t.slen < slen) {
998 				slen = pos + t.slen;
999 				data[slen] = '\0';
1000 			}
1001 		} else {
1002 
1003 			/* Aliasing case */
1004 			if ((unsigned int) (data - (unsigned char *) s) < (unsigned int) slen) {
1005 				replace (pos, len, CBString(s), cfill);
1006 				return;
1007 			}
1008 
1009 			if ((q = strlen (s)) > (size_t) len || len < 0) {
1010 				if (slen + q - len >= INT_MAX) bstringThrow ("Failure in replace, result too long.");
1011 				alloc ((int) (slen + q - len));
1012 				if (NULL == data) return;
1013 			}
1014 			if ((int) q != len) bstr__memmove (data + pos + q, data + pos + len, slen - (pos + len));
1015 			bstr__memcpy (data + pos, s, q);
1016 			slen += ((int) q) - len;
1017 			data[slen] = '\0';
1018 		}
1019 	}
1020 }
1021 
findreplace(const CBString & sfind,const CBString & repl,int pos)1022 void CBString::findreplace (const CBString& sfind, const CBString& repl, int pos) {
1023 	if (BSTR_ERR == bfindreplace (this, (bstring) &sfind, (bstring) &repl, pos)) {
1024 		bstringThrow ("Failure in findreplace");
1025 	}
1026 }
1027 
findreplace(const CBString & sfind,const char * repl,int pos)1028 void CBString::findreplace (const CBString& sfind, const char * repl, int pos) {
1029 struct tagbstring t;
1030 	if (NULL == repl) {
1031 #ifdef BSTRLIB_THROWS_EXCEPTIONS
1032 		bstringThrow ("findreplace NULL.");
1033 #else
1034 		return;
1035 #endif
1036 	}
1037 	cstr2tbstr (t, repl);
1038 	if (BSTR_ERR == bfindreplace (this, (bstring) &sfind, (bstring) &t, pos)) {
1039 		bstringThrow ("Failure in findreplace");
1040 	}
1041 }
1042 
findreplace(const char * sfind,const CBString & repl,int pos)1043 void CBString::findreplace (const char * sfind, const CBString& repl, int pos) {
1044 struct tagbstring t;
1045 	if (NULL == sfind) {
1046 #ifdef BSTRLIB_THROWS_EXCEPTIONS
1047 		bstringThrow ("findreplace NULL.");
1048 #else
1049 		return;
1050 #endif
1051 	}
1052 	cstr2tbstr (t, sfind);
1053 	if (BSTR_ERR == bfindreplace (this, (bstring) &t, (bstring) &repl, pos)) {
1054 		bstringThrow ("Failure in findreplace");
1055 	}
1056 }
1057 
findreplace(const char * sfind,const char * repl,int pos)1058 void CBString::findreplace (const char * sfind, const char * repl, int pos) {
1059 struct tagbstring t, u;
1060 	if (NULL == repl || NULL == sfind) {
1061 #ifdef BSTRLIB_THROWS_EXCEPTIONS
1062 		bstringThrow ("findreplace NULL.");
1063 #else
1064 		return;
1065 #endif
1066 	}
1067 	cstr2tbstr (t, sfind);
1068 	cstr2tbstr (u, repl);
1069 	if (BSTR_ERR == bfindreplace (this, (bstring) &t, (bstring) &u, pos)) {
1070 		bstringThrow ("Failure in findreplace");
1071 	}
1072 }
1073 
findreplacecaseless(const CBString & sfind,const CBString & repl,int pos)1074 void CBString::findreplacecaseless (const CBString& sfind, const CBString& repl, int pos) {
1075 	if (BSTR_ERR == bfindreplacecaseless (this, (bstring) &sfind, (bstring) &repl, pos)) {
1076 		bstringThrow ("Failure in findreplacecaseless");
1077 	}
1078 }
1079 
findreplacecaseless(const CBString & sfind,const char * repl,int pos)1080 void CBString::findreplacecaseless (const CBString& sfind, const char * repl, int pos) {
1081 struct tagbstring t;
1082 	if (NULL == repl) {
1083 #ifdef BSTRLIB_THROWS_EXCEPTIONS
1084 		bstringThrow ("findreplacecaseless NULL.");
1085 #else
1086 		return;
1087 #endif
1088 	}
1089 	cstr2tbstr (t, repl);
1090 	if (BSTR_ERR == bfindreplacecaseless (this, (bstring) &sfind, (bstring) &t, pos)) {
1091 		bstringThrow ("Failure in findreplacecaseless");
1092 	}
1093 }
1094 
findreplacecaseless(const char * sfind,const CBString & repl,int pos)1095 void CBString::findreplacecaseless (const char * sfind, const CBString& repl, int pos) {
1096 struct tagbstring t;
1097 	if (NULL == sfind) {
1098 #ifdef BSTRLIB_THROWS_EXCEPTIONS
1099 		bstringThrow ("findreplacecaseless NULL.");
1100 #else
1101 		return;
1102 #endif
1103 	}
1104 	cstr2tbstr (t, sfind);
1105 	if (BSTR_ERR == bfindreplacecaseless (this, (bstring) &t, (bstring) &repl, pos)) {
1106 		bstringThrow ("Failure in findreplacecaseless");
1107 	}
1108 }
1109 
findreplacecaseless(const char * sfind,const char * repl,int pos)1110 void CBString::findreplacecaseless (const char * sfind, const char * repl, int pos) {
1111 struct tagbstring t, u;
1112 	if (NULL == repl || NULL == sfind) {
1113 #ifdef BSTRLIB_THROWS_EXCEPTIONS
1114 		bstringThrow ("findreplacecaseless NULL.");
1115 #else
1116 		return;
1117 #endif
1118 	}
1119 	cstr2tbstr (t, sfind);
1120 	cstr2tbstr (u, repl);
1121 	if (BSTR_ERR == bfindreplacecaseless (this, (bstring) &t, (bstring) &u, pos)) {
1122 		bstringThrow ("Failure in findreplacecaseless");
1123 	}
1124 }
1125 
remove(int pos,int len)1126 void CBString::remove (int pos, int len) {
1127 	if (BSTR_ERR == bdelete (this, pos, len)) {
1128 		bstringThrow ("Failure in remove");
1129 	}
1130 }
1131 
trunc(int len)1132 void CBString::trunc (int len) {
1133 	if (len < 0) {
1134 		bstringThrow ("Failure in trunc");
1135 	}
1136 	if (len < slen) {
1137 		slen = len;
1138 		data[len] = '\0';
1139 	}
1140 }
1141 
ltrim(const CBString & b)1142 void CBString::ltrim (const CBString& b) {
1143 	int l = nfindchr (b, 0);
1144 	if (l == BSTR_ERR) l = slen;
1145 	remove (0, l);
1146 }
1147 
rtrim(const CBString & b)1148 void CBString::rtrim (const CBString& b) {
1149 	int l = nreversefindchr (b, slen - 1);
1150 #if BSTR_ERR != -1
1151 	if (l == BSTR_ERR) l = -1;
1152 #endif
1153 	slen = l + 1;
1154 	if (mlen > slen) data[slen] = '\0';
1155 }
1156 
toupper()1157 void CBString::toupper () {
1158 	if (BSTR_ERR == btoupper ((bstring) this)) {
1159 		bstringThrow ("Failure in toupper");
1160 	}
1161 }
1162 
tolower()1163 void CBString::tolower () {
1164 	if (BSTR_ERR == btolower ((bstring) this)) {
1165 		bstringThrow ("Failure in tolower");
1166 	}
1167 }
1168 
repeat(int count)1169 void CBString::repeat (int count) {
1170 	count *= slen;
1171 	if (count == 0) {
1172 		trunc (0);
1173 		return;
1174 	}
1175 	if (count < 0 || BSTR_ERR == bpattern (this, count)) {
1176 		bstringThrow ("Failure in repeat");
1177 	}
1178 }
1179 
gets(bNgetc getcPtr,void * parm,char terminator)1180 int CBString::gets (bNgetc getcPtr, void * parm, char terminator) {
1181 	if (mlen <= 0) bstringThrow ("Write protection error");
1182 	bstring b = bgets (getcPtr, parm, terminator);
1183 	if (b == NULL) {
1184 		slen = 0;
1185 		return -1;
1186 	}
1187 	*this = *b;
1188 	bdestroy (b);
1189 	return 0;
1190 }
1191 
read(bNread readPtr,void * parm)1192 int CBString::read (bNread readPtr, void * parm) {
1193 	if (mlen <= 0) bstringThrow ("Write protection error");
1194 	bstring b = bread (readPtr, parm);
1195 	if (b == NULL) {
1196 		slen = 0;
1197 		return -1;
1198 	}
1199 	*this = *b;
1200 	bdestroy (b);
1201 	return 0;
1202 }
1203 
operator +(const char * a,const CBString & b)1204 const CBString operator + (const char *a, const CBString& b) {
1205 	return CBString(a) + b;
1206 }
1207 
operator +(const unsigned char * a,const CBString & b)1208 const CBString operator + (const unsigned char *a, const CBString& b) {
1209 	return CBString((const char *)a) + b;
1210 }
1211 
operator +(char c,const CBString & b)1212 const CBString operator + (char c, const CBString& b) {
1213 	return CBString(c) + b;
1214 }
1215 
operator +(unsigned char c,const CBString & b)1216 const CBString operator + (unsigned char c, const CBString& b) {
1217 	return CBString(c) + b;
1218 }
1219 
operator +(const tagbstring & x,const CBString & b)1220 const CBString operator + (const tagbstring& x, const CBString& b) {
1221 	return CBString(x) + b;
1222 }
1223 
writeprotect()1224 void CBString::writeprotect () {
1225 	if (mlen >= 0) mlen = -1;
1226 }
1227 
writeallow()1228 void CBString::writeallow () {
1229 	if (mlen == -1) mlen = slen + (slen == 0);
1230 	else if (mlen < 0) {
1231 		bstringThrow ("Cannot unprotect a constant");
1232 	}
1233 }
1234 
1235 #if defined(BSTRLIB_CAN_USE_STL)
1236 
1237 // Constructors.
1238 
CBString(const CBStringList & l)1239 CBString::CBString (const CBStringList& l) {
1240 int c;
1241 size_t i;
1242 
1243 	for (c=1, i=0; i < l.size(); i++) {
1244 		c += l.at(i).slen;
1245 	}
1246 
1247 	mlen = c;
1248 	slen = 0;
1249 	data = (unsigned char *) bstr__alloc (c);
1250 	if (!data) {
1251 		mlen = slen = 0;
1252 		bstringThrow ("Failure in (CBStringList) constructor");
1253 	} else {
1254 		for (i=0; i < l.size(); i++) {
1255 			*this += l.at(i);
1256 		}
1257 	}
1258 }
1259 
CBString(const struct CBStringList & l,const CBString & sep)1260 CBString::CBString (const struct CBStringList& l, const CBString& sep) {
1261 int c, sl = sep.length ();
1262 size_t i;
1263 
1264 	for (c=1, i=0; i < l.size(); i++) {
1265 		c += l.at(i).slen + sl;
1266 	}
1267 
1268 	mlen = c;
1269 	slen = 0;
1270 	data = (unsigned char *) bstr__alloc (mlen);
1271 	if (!data) {
1272 		mlen = slen = 0;
1273 		bstringThrow ("Failure in (CBStringList) constructor");
1274 	} else {
1275 		for (i=0; i < l.size(); i++) {
1276 			if (i > 0) *this += sep;
1277 			*this += l.at(i);
1278 		}
1279 	}
1280 }
1281 
CBString(const struct CBStringList & l,char sep)1282 CBString::CBString (const struct CBStringList& l, char sep) {
1283 int c;
1284 size_t i;
1285 
1286 	for (c=1, i=0; i < l.size(); i++) {
1287 		c += l.at(i).slen + 1;
1288 	}
1289 
1290 	mlen = c;
1291 	slen = 0;
1292 	data = (unsigned char *) bstr__alloc (mlen);
1293 	if (!data) {
1294 		mlen = slen = 0;
1295 		bstringThrow ("Failure in (CBStringList) constructor");
1296 	} else {
1297 		for (i=0; i < l.size(); i++) {
1298 			if (i > 0) *this += sep;
1299 			*this += l.at(i);
1300 		}
1301 	}
1302 }
1303 
CBString(const struct CBStringList & l,unsigned char sep)1304 CBString::CBString (const struct CBStringList& l, unsigned char sep) {
1305 int c;
1306 size_t i;
1307 
1308 	for (c=1, i=0; i < l.size(); i++) {
1309 		c += l.at(i).slen + 1;
1310 	}
1311 
1312 	mlen = c;
1313 	slen = 0;
1314 	data = (unsigned char *) bstr__alloc (mlen);
1315 	if (!data) {
1316 		mlen = slen = 0;
1317 		bstringThrow ("Failure in (CBStringList) constructor");
1318 	} else {
1319 		for (i=0; i < l.size(); i++) {
1320 			if (i > 0) *this += sep;
1321 			*this += l.at(i);
1322 		}
1323 	}
1324 }
1325 
join(const struct CBStringList & l)1326 void CBString::join (const struct CBStringList& l) {
1327 int c;
1328 size_t i;
1329 
1330 	if (mlen <= 0) {
1331 		bstringThrow ("Write protection error");
1332 	}
1333 
1334 	for (c=1, i=0; i < l.size(); i++) {
1335 		c += l.at(i).slen;
1336 		if (c < 0) bstringThrow ("Failure in (CBStringList) constructor, too long");
1337 	}
1338 
1339 	alloc (c);
1340 	slen = 0;
1341 	if (!data) {
1342 		mlen = slen = 0;
1343 		bstringThrow ("Failure in (CBStringList) constructor");
1344 	} else {
1345 		for (i=0; i < l.size(); i++) {
1346 			*this += l.at(i);
1347 		}
1348 	}
1349 }
1350 
join(const struct CBStringList & l,const CBString & sep)1351 void CBString::join (const struct CBStringList& l, const CBString& sep) {
1352 int c, sl = sep.length();
1353 size_t i;
1354 
1355 	if (mlen <= 0) {
1356 		bstringThrow ("Write protection error");
1357 	}
1358 
1359 	for (c=1, i=0; i < l.size(); i++) {
1360 		c += l.at(i).slen + sl;
1361 		if (c < sl) bstringThrow ("Failure in (CBStringList) constructor, too long");
1362 	}
1363 
1364 	alloc (c);
1365 	slen = 0;
1366 	if (!data) {
1367 		mlen = slen = 0;
1368 		bstringThrow ("Failure in (CBStringList) constructor");
1369 	} else {
1370 		for (i=0; i < l.size(); i++) {
1371 			if (i > 0) *this += sep;
1372 			*this += l.at(i);
1373 		}
1374 	}
1375 }
1376 
1377 
join(const struct CBStringList & l,char sep)1378 void CBString::join (const struct CBStringList& l, char sep) {
1379 int c;
1380 size_t i;
1381 
1382 	if (mlen <= 0) {
1383 		bstringThrow ("Write protection error");
1384 	}
1385 
1386 	for (c=1, i=0; i < l.size(); i++) {
1387 		c += l.at(i).slen + 1;
1388 		if (c <= 0) bstringThrow ("Failure in (CBStringList) constructor, too long");
1389 	}
1390 
1391 	alloc (c);
1392 	slen = 0;
1393 	if (!data) {
1394 		mlen = slen = 0;
1395 		bstringThrow ("Failure in (CBStringList) constructor");
1396 	} else {
1397 		for (i=0; i < l.size(); i++) {
1398 			if (i > 0) *this += sep;
1399 			*this += l.at(i);
1400 		}
1401 	}
1402 }
1403 
join(const struct CBStringList & l,unsigned char sep)1404 void CBString::join (const struct CBStringList& l, unsigned char sep) {
1405 int c;
1406 size_t i;
1407 
1408 	if (mlen <= 0) {
1409 		bstringThrow ("Write protection error");
1410 	}
1411 
1412 	for (c=1, i=0; i < l.size(); i++) {
1413 		c += l.at(i).slen + 1;
1414 		if (c <= 0) bstringThrow ("Failure in (CBStringList) constructor, too long");
1415 	}
1416 
1417 	alloc (c);
1418 	slen = 0;
1419 	if (!data) {
1420 		mlen = slen = 0;
1421 		bstringThrow ("Failure in (CBStringList) constructor");
1422 	} else {
1423 		for (i=0; i < l.size(); i++) {
1424 			if (i > 0) *this += sep;
1425 			*this += l.at(i);
1426 		}
1427 	}
1428 }
1429 
1430 // Split functions.
1431 
split(const CBString & b,unsigned char splitChar)1432 void CBStringList::split (const CBString& b, unsigned char splitChar) {
1433 int p, i;
1434 
1435 	p = 0;
1436 	do {
1437 		for (i = p; i < b.length (); i++) {
1438 			if (b.character (i) == splitChar) break;
1439 		}
1440 		if (i >= p) this->push_back (CBString (&(b.data[p]), i - p));
1441 		p = i + 1;
1442 	} while (p <= b.length ());
1443 }
1444 
split(const CBString & b,const CBString & s)1445 void CBStringList::split (const CBString& b, const CBString& s) {
1446 struct { unsigned long content[(1 << CHAR_BIT) / 32]; } chrs;
1447 unsigned char c;
1448 int p, i;
1449 
1450 	if (s.length() == 0) bstringThrow ("Null splitstring failure");
1451 	if (s.length() == 1) {
1452 		this->split (b, s.character (0));
1453 	} else {
1454 
1455 		for (i=0; i < ((1 << CHAR_BIT) / 32); i++) chrs.content[i] = 0x0;
1456 		for (i=0; i < s.length(); i++) {
1457 			c = s.character (i);
1458 			chrs.content[c >> 5] |= ((long)1) << (c & 31);
1459 		}
1460 
1461 		p = 0;
1462 		do {
1463 			for (i = p; i < b.length (); i++) {
1464 				c = b.character (i);
1465 				if (chrs.content[c >> 5] & ((long)1) << (c & 31)) break;
1466 			}
1467 			if (i >= p) this->push_back (CBString (&(b.data[p]), i - p));
1468 			p = i + 1;
1469 		} while (p <= b.length ());
1470 	}
1471 }
1472 
splitstr(const CBString & b,const CBString & s)1473 void CBStringList::splitstr (const CBString& b, const CBString& s) {
1474 int p, i;
1475 
1476 	if (s.length() == 1) {
1477 		this->split (b, s.character (0));
1478 	} else if (s.length() == 0) {
1479 		for (i=0; i < b.length (); i++) {
1480 			this->push_back (CBString (b.data[i]));
1481 		}
1482 	} else {
1483 		for (p=0; (i = b.find (s, p)) >= 0; p = i + s.length ()) {
1484 			this->push_back (b.midstr (p, i - p));
1485 		}
1486 		if (p <= b.length ()) {
1487 			this->push_back (b.midstr (p, b.length () - p));
1488 		}
1489 	}
1490 }
1491 
streamSplitCb(void * parm,int ofs,const_bstring entry)1492 static int streamSplitCb (void * parm, int ofs, const_bstring entry) {
1493 	CBStringList * r = (CBStringList *) parm;
1494 	(void)ofs;
1495 	r->push_back (CBString (*entry));
1496 	return 0;
1497 }
1498 
split(const CBStream & b,const CBString & s)1499 void CBStringList::split (const CBStream& b, const CBString& s) {
1500 	if (0 > bssplitscb (b.m_s, (bstring) &s, streamSplitCb,
1501 	                    (void *) this)) {
1502 		bstringThrow ("Split bstream failure");
1503 	}
1504 }
1505 
split(const CBStream & b,unsigned char splitChar)1506 void CBStringList::split (const CBStream& b, unsigned char splitChar) {
1507 CBString sc (splitChar);
1508 	if (0 > bssplitscb (b.m_s, (bstring) &sc,
1509 	                    streamSplitCb, (void *) this)) {
1510 		bstringThrow ("Split bstream failure");
1511 	}
1512 }
1513 
splitstr(const CBStream & b,const CBString & s)1514 void CBStringList::splitstr (const CBStream& b, const CBString& s) {
1515 	if (0 > bssplitstrcb (b.m_s, (bstring) &s, streamSplitCb,
1516 	                    (void *) this)) {
1517 		bstringThrow ("Split bstream failure");
1518 	}
1519 }
1520 
1521 #endif
1522 
1523 #if defined(BSTRLIB_CAN_USE_IOSTREAM)
1524 
operator <<(std::ostream & sout,CBString b)1525 std::ostream& operator << (std::ostream& sout, CBString b) {
1526 	return sout.write ((const char *)b, b.length());
1527 }
1528 
1529 #include <ctype.h>
1530 
istreamGets(void * parm)1531 static int istreamGets (void * parm) {
1532 	char c = '\n';
1533 	((std::istream *)parm)->get(c);
1534 	if (isspace (c)) c = '\n';
1535 	return c;
1536 }
1537 
operator >>(std::istream & sin,CBString & b)1538 std::istream& operator >> (std::istream& sin, CBString& b) {
1539 	do {
1540 		b.gets ((bNgetc) istreamGets, &sin, '\n');
1541 		if (b.slen > 0 && b.data[b.slen-1] == '\n') b.slen--;
1542 	} while (b.slen == 0 && !sin.eof ());
1543  	return sin;
1544 }
1545 
1546 struct sgetc {
1547 	std::istream * sin;
1548 	char terminator;
1549 };
1550 
istreamGetc(void * parm)1551 static int istreamGetc (void * parm) {
1552 	char c = ((struct sgetc *)parm)->terminator;
1553 	((struct sgetc *)parm)->sin->get(c);
1554 	return c;
1555 }
1556 
getline(std::istream & sin,CBString & b,char terminator)1557 std::istream& getline (std::istream& sin, CBString& b, char terminator) {
1558 struct sgetc parm;
1559 	parm.sin = &sin;
1560 	parm.terminator = terminator;
1561 	b.gets ((bNgetc) istreamGetc, &parm, terminator);
1562 	if (b.slen > 0 && b.data[b.slen-1] == terminator) b.slen--;
1563  	return sin;
1564 }
1565 
1566 #endif
1567 
CBStream(bNread readPtr,void * parm)1568 CBStream::CBStream (bNread readPtr, void * parm) {
1569 	m_s = bsopen (readPtr, parm);
1570 }
1571 
~CBStream()1572 CBStream::~CBStream () {
1573 	bsclose (m_s);
1574 }
1575 
buffLengthSet(int sz)1576 int CBStream::buffLengthSet (int sz) {
1577 	if (sz <= 0) {
1578 		bstringThrow ("buffLengthSet parameter failure");
1579 	}
1580 	return bsbufflength (m_s, sz);
1581 }
1582 
buffLengthGet()1583 int CBStream::buffLengthGet () {
1584 	return bsbufflength (m_s, 0);
1585 }
1586 
readLine(char terminator)1587 CBString CBStream::readLine (char terminator) {
1588 	CBString ret("");
1589 	if (0 > bsreadln ((bstring) &ret, m_s, terminator) && eof () < 0) {
1590 		bstringThrow ("Failed readLine");
1591 	}
1592 	return ret;
1593 }
1594 
readLine(const CBString & terminator)1595 CBString CBStream::readLine (const CBString& terminator) {
1596 	CBString ret("");
1597 	if (0 > bsreadlns ((bstring) &ret, m_s, (bstring) &terminator) && eof () < 0) {
1598 		bstringThrow ("Failed readLine");
1599 	}
1600 	return ret;
1601 }
1602 
readLine(CBString & s,char terminator)1603 void CBStream::readLine (CBString& s, char terminator) {
1604 	if (0 > bsreadln ((bstring) &s, m_s, terminator) && eof () < 0) {
1605 		bstringThrow ("Failed readLine");
1606 	}
1607 }
1608 
readLine(CBString & s,const CBString & terminator)1609 void CBStream::readLine (CBString& s, const CBString& terminator) {
1610 	if (0 > bsreadlns ((bstring) &s, m_s, (bstring) &terminator) && eof () < 0) {
1611 		bstringThrow ("Failed readLine");
1612 	}
1613 }
1614 
readLineAppend(CBString & s,char terminator)1615 void CBStream::readLineAppend (CBString& s, char terminator) {
1616 	if (0 > bsreadlna ((bstring) &s, m_s, terminator) && eof () < 0) {
1617 		bstringThrow ("Failed readLineAppend");
1618 	}
1619 }
1620 
readLineAppend(CBString & s,const CBString & terminator)1621 void CBStream::readLineAppend (CBString& s, const CBString& terminator) {
1622 	if (0 > bsreadlnsa ((bstring) &s, m_s, (bstring) &terminator) && eof () < 0) {
1623 		bstringThrow ("Failed readLineAppend");
1624 	}
1625 }
1626 
1627 #define BS_BUFF_SZ (1024)
1628 
read()1629 CBString CBStream::read () {
1630 	CBString ret("");
1631 	while (!bseof (m_s)) {
1632 		if (0 > bsreada ((bstring) &ret, m_s, BS_BUFF_SZ) && eof () < 0) {
1633 			bstringThrow ("Failed read");
1634 		}
1635 	}
1636 	return ret;
1637 }
1638 
operator >>(CBString & s)1639 CBString& CBStream::operator >> (CBString& s) {
1640 	while (!bseof (m_s)) {
1641 		if (0 > bsreada ((bstring) &s, m_s, BS_BUFF_SZ) && eof () < 0) {
1642 			bstringThrow ("Failed read");
1643 		}
1644 	}
1645 	return s;
1646 }
1647 
read(int n)1648 CBString CBStream::read (int n) {
1649 	CBString ret("");
1650 	if (0 > bsread ((bstring) &ret, m_s, n) && eof () < 0) {
1651 		bstringThrow ("Failed read");
1652 	}
1653 	return ret;
1654 }
1655 
read(CBString & s)1656 void CBStream::read (CBString& s) {
1657 	s.slen = 0;
1658 	while (!bseof (m_s)) {
1659 		if (0 > bsreada ((bstring) &s, m_s, BS_BUFF_SZ)) {
1660 			bstringThrow ("Failed read");
1661 		}
1662 	}
1663 }
1664 
read(CBString & s,int n)1665 void CBStream::read (CBString& s, int n) {
1666 	if (0 > bsread ((bstring) &s, m_s, n)) {
1667 		bstringThrow ("Failed read");
1668 	}
1669 }
1670 
readAppend(CBString & s)1671 void CBStream::readAppend (CBString& s) {
1672 	while (!bseof (m_s)) {
1673 		if (0 > bsreada ((bstring) &s, m_s, BS_BUFF_SZ)) {
1674 			bstringThrow ("Failed readAppend");
1675 		}
1676 	}
1677 }
1678 
readAppend(CBString & s,int n)1679 void CBStream::readAppend (CBString& s, int n) {
1680 	if (0 > bsreada ((bstring) &s, m_s, n)) {
1681 		bstringThrow ("Failed readAppend");
1682 	}
1683 }
1684 
unread(const CBString & s)1685 void CBStream::unread (const CBString& s) {
1686 	if (0 > bsunread (m_s, (bstring) &s)) {
1687 		bstringThrow ("Failed unread");
1688 	}
1689 }
1690 
peek() const1691 CBString CBStream::peek () const {
1692 	CBString ret ("");
1693 	if (0 > bspeek ((bstring) &ret, m_s)) {
1694 		bstringThrow ("Failed peek");
1695 	}
1696 	return ret;
1697 }
1698 
peek(CBString & s) const1699 void CBStream::peek (CBString& s) const {
1700 	s.slen = 0;
1701 	if (0 > bspeek ((bstring) &s, m_s)) {
1702 		bstringThrow ("Failed peek");
1703 	}
1704 }
1705 
peekAppend(CBString & s) const1706 void CBStream::peekAppend (CBString& s) const {
1707 	if (0 > bspeek ((bstring) &s, m_s)) {
1708 		bstringThrow ("Failed peekAppend");
1709 	}
1710 }
1711 
eof() const1712 int CBStream::eof () const {
1713 	int ret = bseof (m_s);
1714 	if (0 > ret) {
1715 		bstringThrow ("Failed eof");
1716 	}
1717 	return ret;
1718 }
1719 
1720 } // namespace Bstrlib
1721