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