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