summaryrefslogtreecommitdiff
path: root/src/stable/string.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/string.cpp')
-rw-r--r--src/stable/string.cpp1470
1 files changed, 1470 insertions, 0 deletions
diff --git a/src/stable/string.cpp b/src/stable/string.cpp
new file mode 100644
index 0000000..1a9018b
--- /dev/null
+++ b/src/stable/string.cpp
@@ -0,0 +1,1470 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#define BU_TRACE
9#include "bu/trace.h"
10
11#include "bu/string.h"
12#include "bu/hash.h"
13#include "bu/membuf.h"
14#include "bu/formatter.h"
15#include <stdlib.h>
16
17#define nMinSize (256)
18
19Bu::StringCore::StringCore() :
20 nLength( 0 ),
21 pFirst( NULL ),
22 pLast( NULL )
23{
24}
25
26Bu::StringCore::StringCore( const StringCore &rSrc ) :
27 nLength( rSrc.nLength ),
28 pFirst( NULL ),
29 pLast( NULL )
30{
31 if( rSrc.pFirst == NULL || rSrc.nLength == 0 )
32 {
33 pFirst = pLast = NULL;
34 }
35 else
36 {
37 pFirst = pLast = newChunk( nLength );
38 Chunk *pLink = rSrc.pFirst;
39 int iPos = 0;
40 while( pLink != NULL )
41 {
42 memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
43 iPos += pLink->nLength;
44 pLink = pLink->pNext;
45 }
46 }
47}
48
49Bu::StringCore::~StringCore()
50{
51 clear();
52}
53
54void Bu::StringCore::clear() const
55{
56 if( pFirst == NULL )
57 return;
58
59 Chunk *i = pFirst;
60 for(;;)
61 {
62 Chunk *n = i->pNext;
63 delete[] i->pData;
64 delete i;
65 if( n == NULL )
66 break;
67 i = n;
68 }
69 pFirst = pLast = NULL;
70 nLength = 0;
71}
72
73Bu::StringCore::Chunk *Bu::StringCore::newChunk() const
74{
75 Chunk *pNew = new Chunk;
76 pNew->pNext = NULL;
77 return pNew;
78}
79
80Bu::StringCore::Chunk *Bu::StringCore::newChunk( long nLen ) const
81{
82 Chunk *pNew = new Chunk;
83 pNew->pNext = NULL;
84 pNew->nLength = nLen;
85 pNew->pData = new char[(nLen<nMinSize)?(nMinSize):(nLen)+1];
86 pNew->pData[nLen] = (char)0;
87 return pNew;
88}
89
90Bu::StringCore::Chunk *Bu::StringCore::copyChunk(
91 Bu::StringCore::Chunk *pSrc ) const
92{
93 Chunk *pNew = new Chunk;
94 pNew->pNext = pSrc->pNext;
95 pNew->nLength = pSrc->nLength;
96 pNew->pData = new char[
97 (pNew->nLength<nMinSize)?(nMinSize):(pNew->nLength)+1
98 ];
99 memcpy( pNew->pData, pSrc->pData, pSrc->nLength );
100 pNew->pData[pNew->nLength] = (char)0;
101 return pNew;
102}
103
104void Bu::StringCore::appendChunk( Bu::StringCore::Chunk *pNewChunk )
105{
106 if( pFirst == NULL )
107 pLast = pFirst = pNewChunk;
108 else
109 {
110 pLast->pNext = pNewChunk;
111 pLast = pNewChunk;
112 }
113
114 nLength += pNewChunk->nLength;
115}
116
117void Bu::StringCore::prependChunk( Bu::StringCore::Chunk *pNewChunk )
118{
119 if( pFirst == NULL )
120 pLast = pFirst = pNewChunk;
121 else
122 {
123 pNewChunk->pNext = pFirst;
124 pFirst = pNewChunk;
125 }
126
127 nLength += pNewChunk->nLength;
128}
129
130Bu::String::String()
131{
132}
133
134Bu::String::String( const char *pData )
135{
136 append( pData );
137}
138
139Bu::String::String( const char *pData, long nLength )
140{
141 append( pData, nLength );
142}
143
144Bu::String::String( const Bu::String &rSrc ) :
145 Bu::SharedCore<Bu::String, Bu::StringCore>( rSrc )
146{
147}
148
149Bu::String::String( const Bu::String &rSrc, long nLength )
150{
151 append( rSrc, nLength );
152}
153
154Bu::String::String( const Bu::String &rSrc, long nStart, long nLength )
155{
156 append( rSrc, nStart, nLength );
157}
158
159Bu::String::String( long nSize )
160{
161 core->pFirst = core->pLast = core->newChunk( nSize );
162 core->nLength = nSize;
163}
164
165Bu::String::String( const Bu::String::const_iterator &s )
166{
167 append( s );
168}
169
170Bu::String::String( const Bu::String::const_iterator &s,
171 const Bu::String::const_iterator &e )
172{
173 append( s, e );
174}
175
176Bu::String::~String()
177{
178}
179
180void Bu::String::append( const char *pData )
181{
182 if( !pData ) return;
183 long nLen;
184 for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { }
185
186 append( pData, 0, nLen );
187}
188
189void Bu::String::append( const char *pData, long nLen )
190{
191 append( pData, 0, nLen );
192}
193
194void Bu::String::append( const char *pData, long nStart, long nLen )
195{
196 if( !pData ) return;
197 if( nLen <= 0 )
198 return;
199
200 pData += nStart;
201
202 _hardCopy();
203
204 if( core->pLast && core->pLast->nLength < nMinSize )
205 {
206 int nAmnt = nMinSize - core->pLast->nLength;
207 if( nAmnt > nLen )
208 nAmnt = nLen;
209 memcpy(
210 core->pLast->pData+core->pLast->nLength,
211 pData,
212 nAmnt
213 );
214 pData += nAmnt;
215 core->pLast->nLength += nAmnt;
216 nLen -= nAmnt;
217 core->nLength += nAmnt;
218 }
219
220 if( nLen > 0 )
221 {
222 Chunk *pNew = core->newChunk( nLen );
223 memcpy( pNew->pData, pData, nLen );
224 core->appendChunk( pNew );
225// core->nLength += nLen;
226 }
227}
228
229void Bu::String::append( const char &cData )
230{
231 if( core->pLast && core->pLast->nLength < nMinSize )
232 {
233 _hardCopy();
234 core->pLast->pData[core->pLast->nLength] = cData;
235 ++core->pLast->nLength; ++core->nLength;
236// pLast->pData[pLast->nLength] = (char)0;
237 }
238 else
239 {
240 append( &cData, 1 );
241 }
242}
243
244void Bu::String::append( const String & sData )
245{
246 append( sData.getStr(), 0, sData.getSize() );
247}
248
249void Bu::String::append( const String & sData, long nLen )
250{
251 append( sData.getStr(), 0, nLen );
252}
253
254void Bu::String::append( const String & sData, long nStart, long nLen )
255{
256 if( nLen < 0 )
257 nLen = sData.getSize() - nStart;
258 append( sData.getStr(), nStart, nLen );
259}
260
261void Bu::String::append( const const_iterator &s )
262{
263 if( !s.isValid() )
264 return;
265 Chunk *pSrc = s.pChunk;
266
267 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
268 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
269
270 _hardCopy();
271 core->appendChunk( pNew );
272
273 while( (pSrc = pSrc->pNext) )
274 {
275 core->appendChunk( core->copyChunk( pSrc ) );
276 }
277}
278
279void Bu::String::append( const iterator &s )
280{
281 append( const_iterator( s ) );
282}
283
284void Bu::String::append( const const_iterator &s, const const_iterator &e )
285{
286 if( !s.isValid() )
287 return;
288 if( !e.isValid() )
289 {
290 append( s );
291 return;
292 }
293 _hardCopy();
294 if( s.pChunk == e.pChunk )
295 {
296 // Simple case, they're the same chunk
297 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
298 memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
299 core->appendChunk( pNew );
300 }
301 else
302 {
303 // A little trickier, scan the blocks...
304 Chunk *pSrc = s.pChunk;
305 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
306 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
307 core->appendChunk( pNew );
308
309 while( (pSrc = pSrc->pNext) != e.pChunk )
310 {
311 core->appendChunk( core->copyChunk( pSrc ) );
312 }
313
314 pNew = core->newChunk( e.iPos );
315 memcpy( pNew->pData, pSrc->pData, e.iPos );
316 core->appendChunk( pNew );
317 }
318}
319
320void Bu::String::prepend( const String & sData )
321{
322 prepend( sData.getStr(), sData.getSize() );
323}
324
325void Bu::String::prepend( const char *pData )
326{
327 if( pData == NULL )
328 return;
329
330 _hardCopy();
331 long nLen;
332 for( nLen = 0; pData[nLen] != (char)0; nLen++ ) { }
333
334 Chunk *pNew = core->newChunk( nLen );
335 memcpy( pNew->pData, pData, nLen );
336
337 core->prependChunk( pNew );
338}
339
340void Bu::String::prepend( const char *pData, long nLen )
341{
342 Chunk *pNew = core->newChunk( nLen );
343
344 memcpy( pNew->pData, pData, nLen );
345
346 _hardCopy();
347 core->prependChunk( pNew );
348}
349
350void Bu::String::prepend( const char c )
351{
352 prepend( &c, 1 );
353}
354
355void Bu::String::insert( long nPos, const char *pData, long nLen )
356{
357 if( nLen <= 0 )
358 return;
359 if( nPos <= 0 )
360 {
361 prepend( pData, nLen );
362 }
363 else if( nPos >= core->nLength )
364 {
365 append( pData, nLen );
366 }
367 else
368 {
369 // If we're going to flatten anyway, might as well for everyone
370 flatten();
371 _hardCopy();
372 Chunk *p1 = core->newChunk( nPos );
373 Chunk *p2 = core->newChunk( nLen );
374 Chunk *p3 = core->newChunk( core->nLength-nPos );
375 memcpy( p1->pData, core->pFirst->pData, nPos );
376 memcpy( p2->pData, pData, nLen );
377 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
378 core->clear();
379 core->appendChunk( p1 );
380 core->appendChunk( p2 );
381 core->appendChunk( p3 );
382 }
383}
384
385void Bu::String::insert( long nPos, const String &str )
386{
387 if( nPos <= 0 )
388 {
389 prepend( str );
390 }
391 else if( nPos >= core->nLength )
392 {
393 append( str );
394 }
395 else
396 {
397 flatten();
398 _hardCopy();
399 Chunk *p1 = core->newChunk( nPos );
400 Chunk *p3 = core->newChunk( core->nLength-nPos );
401 memcpy( p1->pData, core->pFirst->pData, nPos );
402 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
403 core->clear();
404 core->appendChunk( p1 );
405 for( Chunk *pChnk = str.core->pFirst; pChnk;
406 pChnk = pChnk->pNext )
407 {
408 core->appendChunk( core->copyChunk( pChnk ) );
409 }
410
411 core->appendChunk( p3 );
412 }
413}
414
415void Bu::String::insert( long nPos, const char *pData )
416{
417 insert( nPos, pData, strlen( pData ) );
418}
419
420void Bu::String::remove( long nPos, long nLen )
421{
422 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
423 return;
424 if( nLen > core->nLength-nPos )
425 nLen = core->nLength-nPos;
426 flatten();
427 _hardCopy();
428 memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
429 core->nLength -= nLen;
430 core->pFirst->nLength -= nLen;
431}
432
433void Bu::String::clear()
434{
435 _hardCopy();
436 core->clear();
437}
438
439Bu::String Bu::String::replace( const Bu::String &fnd,
440 const Bu::String &rep ) const
441{
442 String out;
443 const_iterator o = begin();
444 while( true )
445 {
446 const_iterator i = o.find( fnd, fnd.getSize() );
447 if( !i )
448 {
449 out.append( o );
450 return out;
451 }
452 else
453 {
454 out.append( o, i );
455 out.append( rep );
456 o = i;
457 o += fnd.getSize();
458 }
459 }
460}
461
462void Bu::String::resize( long nNewSize )
463{
464 if( core->nLength == nNewSize )
465 return;
466 if( nNewSize < 0 )
467 nNewSize = 0;
468
469 flatten();
470 _hardCopy();
471
472 // TODO: This is bad
473
474 Chunk *pNew = core->newChunk( nNewSize );
475 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
476 if( core->nLength > 0 )
477 {
478 memcpy( pNew->pData, core->pFirst->pData, nNewLen );
479 delete[] core->pFirst->pData;
480 delete core->pFirst;
481 }
482 pNew->pData[nNewLen] = (char)0;
483 core->pFirst = core->pLast = pNew;
484 core->nLength = nNewSize;
485}
486
487long Bu::String::getSize() const
488{
489 return core->nLength;
490}
491
492char *Bu::String::getStr()
493{
494 if( core->pFirst == NULL || core->nLength == 0 )
495 return (char *)"";
496
497 flatten();
498 _hardCopy();
499 core->pFirst->pData[core->nLength] = (char)0;
500 return core->pFirst->pData;
501}
502
503const char *Bu::String::getStr() const
504{
505 if( core->pFirst == NULL || core->nLength == 0 )
506 return (char *)"";
507
508 flatten();
509 core->pFirst->pData[core->nLength] = (char)0;
510 return core->pFirst->pData;
511}
512
513const char *Bu::String::getConstStr() const
514{
515 return getStr();
516}
517
518Bu::String Bu::String::getSubStrIdx( long iStart, long iSize ) const
519{
520 if( iStart < 0 )
521 iStart = 0;
522 if( iStart >= core->nLength )
523 return (const char[]){(char)0};
524 if( iSize < 0 )
525 iSize = core->nLength;
526 if( iStart+iSize > core->nLength )
527 iSize = core->nLength-iStart;
528 if( iSize == 0 )
529 return (const char[]){(char)0};
530
531 flatten();
532 String ret( core->pFirst->pData+iStart, iSize );
533 return ret;
534}
535
536Bu::String Bu::String::getSubStr( const_iterator iBegin,
537 const_iterator iEnd ) const
538{
539 if( !iBegin.isValid() )
540 return String();
541 if( iBegin.pChunk == iEnd.pChunk )
542 {
543 return String( iBegin.pChunk->pData+iBegin.iPos,
544 iEnd.iPos-iBegin.iPos );
545 }
546 else if( !iEnd.isValid() )
547 {
548 String ret;
549 ret.append(
550 iBegin.pChunk->pData+iBegin.iPos,
551 iBegin.pChunk->nLength-iBegin.iPos
552 );
553 for( Chunk *pCur = iBegin.pChunk->pNext;
554 pCur; pCur = pCur->pNext )
555 {
556 ret.append( pCur->pData, pCur->nLength );
557 }
558 return ret;
559 }
560 else
561 {
562 String ret;
563 ret.append(
564 iBegin.pChunk->pData+iBegin.iPos,
565 iBegin.pChunk->nLength-iBegin.iPos
566 );
567 for( Chunk *pCur = iBegin.pChunk->pNext;
568 pCur != iEnd.pChunk; pCur = pCur->pNext )
569 {
570 ret.append( pCur->pData, pCur->nLength );
571 }
572 ret.append(
573 iEnd.pChunk->pData,
574 iEnd.iPos
575 );
576 return ret;
577 }
578}
579
580Bu::StringList Bu::String::split( const char c ) const
581{
582 Bu::StringList ret;
583 const_iterator l, r;
584 l = begin();
585 for(r=l; l;)
586 {
587 for( r = l; r && r != c; r++ ) { }
588 ret.append( String( l, r ) );
589 l = r;
590 l++;
591 }
592 return ret;
593}
594
595Bu::String &Bu::String::operator+=( const char *pData )
596{
597 append( pData );
598
599 return (*this);
600}
601
602Bu::String &Bu::String::operator+=( const Bu::String &rSrc )
603{
604 append( rSrc );
605
606 return (*this);
607}
608
609Bu::String &Bu::String::operator+=( const Bu::String::const_iterator &i )
610{
611 append( i, i+1 );
612
613 return (*this);
614}
615
616Bu::String &Bu::String::operator+=( const char cData )
617{
618 if( core->pLast && core->pLast->nLength < nMinSize )
619 {
620 _hardCopy();
621 core->pLast->pData[core->pLast->nLength] = cData;
622 ++core->pLast->nLength; ++core->nLength;
623// pLast->pData[pLast->nLength] = (char)0;
624 }
625 else
626 {
627 append( &cData, 1 );
628 }
629 //append( pData );
630
631 return (*this);
632}
633
634Bu::String &Bu::String::operator=( const char *pData )
635{
636 set( pData );
637
638 return (*this);
639}
640
641Bu::String Bu::String::operator+( const Bu::String &rRight ) const
642{
643 String ret( *this );
644 ret.append( rRight );
645 return ret;
646}
647
648Bu::String Bu::String::operator+( const char *pRight ) const
649{
650 String ret( *this );
651 ret.append( pRight );
652 return ret;
653}
654
655Bu::String Bu::String::operator+( char *pRight ) const
656{
657 String ret( *this );
658 ret.append( pRight );
659 return ret;
660}
661
662void Bu::String::set( const char *pData )
663{
664 clear();
665 append( pData );
666}
667
668void Bu::String::set( const char *pData, long nSize )
669{
670 clear();
671 append( pData, nSize );
672}
673
674void Bu::String::set( const char *pData, long nStart, long nSize )
675{
676 clear();
677 append( pData, nStart, nSize );
678}
679
680void Bu::String::set( const String &rData )
681{
682 clear();
683 append( rData );
684}
685
686void Bu::String::set( const String &rData, long nSize )
687{
688 clear();
689 append( rData, nSize );
690}
691
692void Bu::String::set( const String &rData, long nStart, long nSize )
693{
694 clear();
695 append( rData, nStart, nSize );
696}
697
698void Bu::String::set( const_iterator s )
699{
700 clear();
701 append( s );
702}
703
704void Bu::String::set( const_iterator s, const_iterator e )
705{
706 clear();
707 append( s, e );
708}
709
710void Bu::String::setSize( long iSize )
711{
712 _hardCopy();
713 core->clear();
714 core->appendChunk( core->newChunk( iSize ) );
715}
716
717bool Bu::String::operator==( const char *pData ) const
718{
719 if( core->pFirst == NULL || core->nLength == 0 ) {
720 if( pData == NULL )
721 return true;
722 if( pData[0] == (char)0 )
723 return true;
724 return false;
725 }
726
727 flatten();
728 core->pFirst->pData[core->nLength] = (char)0;
729 const char *a = pData;
730 char *b = core->pFirst->pData;
731 for( long j = 0; *a!=(char)0 || *b!=(char)0; j++, a++, b++ )
732 {
733 if( *a != *b )
734 return false;
735 if( *a == (char)0 && j < core->nLength )
736 return false;
737 }
738
739 return true;
740}
741
742bool Bu::String::operator==( const String &pData ) const
743{
744 if( core == pData.core )
745 return true;
746 if( core->pFirst == pData.core->pFirst )
747 return true;
748 if( (core->nLength == 0 && pData.core->nLength == 0) )
749 return true;
750 if( core->nLength != pData.core->nLength )
751 return false;
752 if( pData.core->pFirst == NULL || core->pFirst == NULL )
753 return false;
754
755 flatten();
756 pData.flatten();
757 const char *a = pData.core->pFirst->pData;
758 char *b = core->pFirst->pData;
759 for( long j = 0; j < core->nLength; j++, a++, b++ )
760 {
761 if( *a != *b )
762 return false;
763 }
764
765 return true;
766}
767
768bool Bu::String::operator!=(const char *pData ) const
769{
770 return !(*this == pData);
771}
772
773bool Bu::String::operator!=(const String &pData ) const
774{
775 return !(*this == pData);
776}
777
778bool Bu::String::operator<(const String &pData ) const
779{
780 flatten();
781 pData.flatten();
782
783 const char *a = core->pFirst->pData;
784 char *b = pData.core->pFirst->pData;
785 for( long j = 0; j < core->nLength; j++, a++, b++ )
786 {
787 if( *a != *b )
788 return *a < *b;
789 }
790
791 return false;
792}
793
794bool Bu::String::operator<=(const String &pData ) const
795{
796 flatten();
797 pData.flatten();
798
799 const char *a = core->pFirst->pData;
800 char *b = pData.core->pFirst->pData;
801 for( long j = 0; j < core->nLength; j++, a++, b++ )
802 {
803 if( *a != *b )
804 return *a < *b;
805 }
806
807 return true;
808}
809
810bool Bu::String::operator>(const String &pData ) const
811{
812 flatten();
813 pData.flatten();
814
815 const char *a = core->pFirst->pData;
816 char *b = pData.core->pFirst->pData;
817 for( long j = 0; j < core->nLength; j++, a++, b++ )
818 {
819 if( *a != *b )
820 return *a > *b;
821 }
822
823 return false;
824}
825
826bool Bu::String::operator>=(const String &pData ) const
827{
828 flatten();
829 pData.flatten();
830
831 const char *a = core->pFirst->pData;
832 char *b = pData.core->pFirst->pData;
833 for( long j = 0; j < core->nLength; j++, a++, b++ )
834 {
835 if( *a != *b )
836 return *a > *b;
837 }
838
839 return true;
840}
841
842char &Bu::String::operator[]( long nIndex )
843{
844 if( nIndex < 0 || nIndex >= core->nLength )
845 throw Bu::ExceptionBase("Index out of range.");
846 flatten();
847 _hardCopy();
848
849 return core->pFirst->pData[nIndex];
850}
851
852const char &Bu::String::operator[]( long nIndex ) const
853{
854 if( nIndex < 0 || nIndex >= core->nLength )
855 throw Bu::ExceptionBase("Index out of range.");
856 flatten();
857
858 return core->pFirst->pData[nIndex];
859}
860
861bool Bu::String::isSet() const
862{
863 return (core->pFirst != NULL);
864}
865
866bool Bu::String::compareSub( const char *pData, long nIndex, long nLen ) const
867{
868 if( core->pFirst == NULL || core->nLength == 0 ) {
869 if( pData == NULL )
870 return true;
871 if( nLen == 0 )
872 return true;
873 if( pData[0] == (char)0 )
874 return true;
875 return false;
876 }
877 if( nIndex+nLen > core->nLength )
878 return false;
879
880 flatten();
881 core->pFirst->pData[core->nLength] = (char)0;
882 const char *a = pData;
883 char *b = core->pFirst->pData+nIndex;
884 for( long j = 0; j < nLen; j++, a++, b++ )
885 {
886 if( *a != *b )
887 return false;
888 if( *a == (char)0 && j < core->nLength )
889 return false;
890 }
891
892 return true;
893}
894
895bool Bu::String::compareSub( const String &rData, long nIndex, long nLen ) const
896{
897 if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 )
898 return false;
899 if( nLen < 0 )
900 nLen = rData.core->nLength;
901 if( nIndex+nLen > core->nLength )
902 return false;
903
904 flatten();
905 rData.flatten();
906 const char *a = rData.core->pFirst->pData;
907 char *b = core->pFirst->pData + nIndex;
908 for( long j = 0; j < nLen; j++, a++, b++ )
909 {
910 if( *a != *b )
911 return false;
912 }
913
914 return true;
915}
916
917bool Bu::String::isWS( long nIndex ) const
918{
919 flatten();
920
921 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
922 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
923}
924
925bool Bu::String::isAlpha( long nIndex ) const
926{
927 flatten();
928
929 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
930 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
931}
932
933Bu::String Bu::String::toLower() const
934{
935 Bu::String sRet = *this;
936
937 sRet.flatten();
938 sRet._hardCopy();
939
940 for( long j = 0; j < sRet.core->nLength; j++ )
941 {
942 if( sRet.core->pFirst->pData[j] >= 'A' &&
943 sRet.core->pFirst->pData[j] <= 'Z' )
944 sRet.core->pFirst->pData[j] -= 'A'-'a';
945 }
946
947 return sRet;
948}
949
950Bu::String Bu::String::toUpper() const
951{
952 Bu::String sRet = *this;
953
954 sRet.flatten();
955 sRet._hardCopy();
956
957 for( long j = 0; j < sRet.core->nLength; j++ )
958 {
959 if( sRet.core->pFirst->pData[j] >= 'a' &&
960 sRet.core->pFirst->pData[j] <= 'z' )
961 sRet.core->pFirst->pData[j] += 'A'-'a';
962 }
963
964 return sRet;
965}
966
967Bu::String::const_iterator Bu::String::find( const char cChar,
968 Bu::String::const_iterator iStart ) const
969{
970 if( !iStart ) iStart = begin();
971 for( ; iStart; iStart++ )
972 {
973 if( cChar == *iStart )
974 return iStart;
975 }
976 return end();
977}
978
979Bu::String::const_iterator Bu::String::find( const char *sText, int nLen,
980 Bu::String::const_iterator iStart ) const
981{
982 if( !iStart ) iStart = begin();
983 for( ; iStart; iStart++ )
984 {
985 if( iStart.compare( sText, nLen ) )
986 return iStart;
987 }
988 return end();
989}
990
991Bu::String::const_iterator Bu::String::find( const String &rStr,
992 Bu::String::const_iterator iStart ) const
993{
994 if( !iStart ) iStart = begin();
995 for( ; iStart; iStart++ )
996 {
997 if( iStart.compare( rStr ) )
998 return iStart;
999 }
1000 return end();
1001}
1002
1003Bu::String::const_iterator Bu::String::find( const String &rStr, int nLen,
1004 Bu::String::const_iterator iStart ) const
1005{
1006 if( !iStart ) iStart = begin();
1007 for( ; iStart; iStart++ )
1008 {
1009 if( iStart.compare( rStr, nLen ) )
1010 return iStart;
1011 }
1012 return end();
1013}
1014
1015Bu::String::iterator Bu::String::find( const char cChar,
1016 Bu::String::const_iterator iStart )
1017{
1018 if( !iStart ) iStart = begin();
1019 for( ; iStart; iStart++ )
1020 {
1021 if( cChar == *iStart )
1022 return iterator( iStart.pChunk, iStart.iPos );
1023 }
1024 return end();
1025}
1026
1027Bu::String::iterator Bu::String::find( const char *sText, int nLen,
1028 Bu::String::const_iterator iStart )
1029{
1030 if( !iStart ) iStart = begin();
1031 for( ; iStart; iStart++ )
1032 {
1033 if( iStart.compare( sText, nLen ) )
1034 return iterator( iStart.pChunk, iStart.iPos );
1035 }
1036 return end();
1037}
1038
1039Bu::String::iterator Bu::String::find( const String &rStr,
1040 Bu::String::const_iterator iStart )
1041{
1042 if( !iStart ) iStart = begin();
1043 for( ; iStart; iStart++ )
1044 {
1045 if( iStart.compare( rStr ) )
1046 return iterator( iStart.pChunk, iStart.iPos );
1047 }
1048 return end();
1049}
1050
1051Bu::String::iterator Bu::String::find( const String &rStr, int nLen,
1052 Bu::String::const_iterator iStart )
1053{
1054 if( !iStart ) iStart = begin();
1055 for( ; iStart; iStart++ )
1056 {
1057 if( iStart.compare( rStr, nLen ) )
1058 return iterator( iStart.pChunk, iStart.iPos );
1059 }
1060 return end();
1061}
1062
1063long Bu::String::findIdx( const char cChar, long iStart ) const
1064{
1065 flatten();
1066 for( long j = iStart; j < core->pFirst->nLength; j++ )
1067 {
1068 if( core->pFirst->pData[j] == cChar )
1069 return j;
1070 }
1071 return -1;
1072}
1073
1074long Bu::String::findIdx( const char *sText, long iStart ) const
1075{
1076 long nTLen = strlen( sText );
1077 flatten();
1078 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1079 {
1080 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1081 return j;
1082 }
1083 return -1;
1084}
1085
1086long Bu::String::rfindIdx( const char *sText ) const
1087{
1088 long nTLen = strlen( sText );
1089 flatten();
1090 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1091 {
1092 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1093 return j;
1094 }
1095 return -1;
1096}
1097
1098void Bu::String::trimFront( long nAmnt )
1099{
1100 long nNewLen = core->nLength - nAmnt;
1101 flatten();
1102 Chunk *pNew = core->newChunk( nNewLen );
1103 memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1104 _hardCopy();
1105 core->clear();
1106 core->appendChunk( pNew );
1107}
1108/*
1109void Bu::String::trimBack( char c )
1110{
1111 if( core->pFirst == NULL || core->nLength == 0 )
1112 return;
1113 flatten();
1114 for( ; core->pFirst->nLength > 0 &&
1115 core->pFirst->pData[core->pFirst->nLength-1] == c;
1116 core->pFirst->nLength--, core->nLength-- ) { }
1117}
1118*/
1119void Bu::String::trimBack( long iAmnt )
1120{
1121 if( iAmnt < 0 )
1122 return;
1123 if( core->nLength - iAmnt < 0 )
1124 {
1125 clear();
1126 return;
1127 }
1128 if( core->pFirst == NULL || core->nLength == 0 )
1129 return;
1130
1131 flatten();
1132 core->pFirst->nLength -= iAmnt;
1133 core->nLength -= iAmnt;
1134}
1135
1136Bu::String Bu::String::trimWhitespace() const
1137{
1138 if( core->nLength == 0 )
1139 return "";
1140 const_iterator i = begin();
1141 for( ; i && (*i == ' ' || *i == '\t' || *i == '\n' || *i == '\r'); i++ ) { }
1142 if( !i )
1143 return "";
1144
1145 const_iterator e = i;
1146 for( ; e; e++ )
1147 {
1148 if( *e == ' ' || *e == '\t' || *e == '\n' || *e == '\r' )
1149 {
1150 const_iterator t = e;
1151 for( ; t && (*t == ' ' || *t == '\t' || *t == '\n' || *t == '\r'); t++ ) { }
1152 if( t )
1153 {
1154 e = t;
1155 }
1156 else
1157 {
1158 break;
1159 }
1160 }
1161 }
1162
1163 return Bu::String( i, e );
1164}
1165
1166Bu::String::iterator Bu::String::begin()
1167{
1168 if( core->nLength == 0 )
1169 return iterator( NULL, 0 );
1170 return iterator( core->pFirst, 0 );
1171}
1172
1173Bu::String::const_iterator Bu::String::begin() const
1174{
1175 if( core->nLength == 0 )
1176 return const_iterator( NULL, 0 );
1177 return iterator( core->pFirst, 0 );
1178}
1179
1180Bu::String::iterator Bu::String::end()
1181{
1182 return iterator( NULL, 0 );
1183}
1184
1185Bu::String::const_iterator Bu::String::end() const
1186{
1187 return const_iterator( NULL, 0 );
1188}
1189
1190bool Bu::String::isEmpty() const
1191{
1192 if( core->nLength == 0 )
1193 return true;
1194 return false;
1195}
1196
1197void Bu::String::flatten() const
1198{
1199 if( isFlat() )
1200 return;
1201
1202 if( core->pFirst == NULL || core->nLength == 0 )
1203 return;
1204
1205 Chunk *pNew = core->newChunk( core->nLength );
1206 char *pos = pNew->pData;
1207 Chunk *i = core->pFirst;
1208 for(;;)
1209 {
1210 memcpy( pos, i->pData, i->nLength );
1211 pos += i->nLength;
1212 i = i->pNext;
1213 if( i == NULL )
1214 break;
1215 }
1216 core->clear();
1217
1218 core->pLast = core->pFirst = pNew;
1219 core->nLength = pNew->nLength;
1220}
1221
1222bool Bu::String::isFlat() const
1223{
1224 return (core->pFirst == core->pLast);
1225}
1226
1227//
1228// Sub-class Bu::String::FormatProxy
1229//
1230
1231Bu::String::FormatProxy::FormatProxy( const String &rFmt ) :
1232 rFmt( rFmt )
1233{
1234}
1235
1236Bu::String::FormatProxy::~FormatProxy()
1237{
1238}
1239
1240Bu::String::FormatProxy::operator Bu::String() const
1241{
1242 int iCount = lArgs.getSize();
1243 ArgList::const_iterator *aArg =
1244 new ArgList::const_iterator[iCount];
1245 {
1246 int j = 0;
1247 for( ArgList::const_iterator i = lArgs.begin();
1248 i; i++, j++ )
1249 {
1250 aArg[j] = i;
1251 }
1252 }
1253 Bu::MemBuf mbOut;
1254 Bu::Formatter f( mbOut );
1255 for( String::const_iterator s = rFmt.begin(); s; s++ )
1256 {
1257 if( *s == '%' )
1258 {
1259 s++;
1260 if( *s == '%' )
1261 f << *s;
1262 else
1263 {
1264 String sNum;
1265 while( s && *s >= '0' && *s <= '9' )
1266 {
1267 sNum += *s;
1268 s++;
1269 }
1270 int iIndex = strtol( sNum.getStr(), 0, 10 )-1;
1271 if( iIndex < 0 || iIndex >= iCount )
1272 {
1273 delete[] aArg;
1274 throw Bu::ExceptionBase(
1275 "Argument index %d is outside of "
1276 "valid range (1-%d).", iIndex+1, iCount
1277 );
1278 }
1279
1280 f << (*aArg[iIndex]).format << (*aArg[iIndex]).value;
1281 if( s )
1282 f << *s;
1283 }
1284 }
1285 else
1286 {
1287 f << *s;
1288 }
1289 }
1290
1291 delete[] aArg;
1292 return mbOut.getString();
1293}
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341template<> uint32_t Bu::__calcHashCode<Bu::String>( const Bu::String &k )
1342{
1343 long j, sz = k.getSize();
1344 const char *s = k.getStr();
1345
1346 long nPos = 0;
1347 for( j = 0; j < sz; j++, s++ )
1348 {
1349 nPos = *s + (nPos << 6) + (nPos << 16) - nPos;
1350 }
1351
1352 return nPos;
1353}
1354
1355template<> bool Bu::__cmpHashKeys<Bu::String>(
1356 const Bu::String &a, const Bu::String &b )
1357{
1358 return a == b;
1359}
1360
1361template<> void Bu::__tracer_format<Bu::String>( const Bu::String &v )
1362{
1363 printf("(%ld)\"%s\"", v.getSize(), v.getStr() );
1364}
1365
1366bool &Bu::operator<<( bool &dst, const Bu::String &sIn )
1367{
1368 if( sIn == "true" || sIn == "yes" || sIn == "t" )
1369 dst = true;
1370 else
1371 dst = false;
1372
1373 return dst;
1374}
1375
1376uint8_t &Bu::operator<<( uint8_t &dst, const Bu::String &sIn )
1377{
1378 sscanf( sIn.getStr(), "%hhu", &dst );
1379 return dst;
1380}
1381
1382int8_t &Bu::operator<<( int8_t &dst, const Bu::String &sIn )
1383{
1384 sscanf( sIn.getStr(), "%hhd", &dst );
1385 return dst;
1386}
1387
1388char &Bu::operator<<( char &dst, const Bu::String &sIn )
1389{
1390 sscanf( sIn.getStr(), "%hhd", &dst );
1391 return dst;
1392}
1393
1394uint16_t &Bu::operator<<( uint16_t &dst, const Bu::String &sIn )
1395{
1396 sscanf( sIn.getStr(), "%hu", &dst );
1397 return dst;
1398}
1399
1400int16_t &Bu::operator<<( int16_t &dst, const Bu::String &sIn )
1401{
1402 sscanf( sIn.getStr(), "%hd", &dst );
1403 return dst;
1404}
1405
1406uint32_t &Bu::operator<<( uint32_t &dst, const Bu::String &sIn )
1407{
1408 sscanf( sIn.getStr(), "%u", &dst );
1409 return dst;
1410}
1411
1412int32_t &Bu::operator<<( int32_t &dst, const Bu::String &sIn )
1413{
1414 sscanf( sIn.getStr(), "%d", &dst );
1415 return dst;
1416}
1417
1418uint64_t &Bu::operator<<( uint64_t &dst, const Bu::String &sIn )
1419{
1420 sscanf( sIn.getStr(), "%llu", &dst );
1421 return dst;
1422}
1423
1424int64_t &Bu::operator<<( int64_t &dst, const Bu::String &sIn )
1425{
1426 sscanf( sIn.getStr(), "%lld", &dst );
1427 return dst;
1428}
1429
1430float &Bu::operator<<( float &dst, const Bu::String &sIn )
1431{
1432 sscanf( sIn.getStr(), "%f", &dst );
1433 return dst;
1434}
1435
1436double &Bu::operator<<( double &dst, const Bu::String &sIn )
1437{
1438 sscanf( sIn.getStr(), "%lf", &dst );
1439 return dst;
1440}
1441
1442long double &Bu::operator<<( long double &dst, const Bu::String &sIn )
1443{
1444 sscanf( sIn.getStr(), "%Lf", &dst );
1445 return dst;
1446}
1447
1448Bu::String &Bu::operator<<( Bu::String &dst, const Bu::String &sIn )
1449{
1450 dst = sIn;
1451 return dst;
1452}
1453
1454Bu::ArchiveBase &Bu::operator<<( Bu::ArchiveBase &ar, const Bu::String &s )
1455{
1456 long n = s.getSize();
1457 ar << n;
1458 ar.write( s.getConstStr(), n );
1459 return ar;
1460}
1461
1462Bu::ArchiveBase &Bu::operator>>( Bu::ArchiveBase &ar, Bu::String &s )
1463{
1464 long n;
1465 ar >> n;
1466 s.setSize( n );
1467 ar.read( s.getStr(), n );
1468 return ar;
1469}
1470