summaryrefslogtreecommitdiff
path: root/src/fbasicstring.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2011-01-20 02:14:08 +0000
committerMike Buland <eichlan@xagasoft.com>2011-01-20 02:14:08 +0000
commitf5aca1a1b402bd7ebc944dc6e6fe65828d863365 (patch)
tree4a0fdd8e166d5c4b03543279d332b9a858ef62df /src/fbasicstring.h
parent10c557562e1d67c55314c212371ea9cb7f802863 (diff)
downloadlibbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.tar.gz
libbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.tar.bz2
libbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.tar.xz
libbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.zip
Bu::FString is now String, and there's a shell script to fix any other programs
that were using fstring, I hope.
Diffstat (limited to 'src/fbasicstring.h')
-rw-r--r--src/fbasicstring.h2101
1 files changed, 0 insertions, 2101 deletions
diff --git a/src/fbasicstring.h b/src/fbasicstring.h
deleted file mode 100644
index 064ff16..0000000
--- a/src/fbasicstring.h
+++ /dev/null
@@ -1,2101 +0,0 @@
1/*
2 * Copyright (C) 2007-2010 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#ifndef BU_F_BASIC_STRING_H
9#define BU_F_BASIC_STRING_H
10
11#include <stdint.h>
12#include <memory>
13
14#ifndef WIN32
15#include <wordexp.h>
16#endif
17
18#include "bu/util.h"
19#include "bu/sharedcore.h"
20#include "bu/exceptionbase.h"
21#include "bu/archivebase.h"
22#include "bu/list.h"
23
24#include <string.h>
25
26namespace Bu
27{
28 /** @cond DEVEL */
29 template< typename chr >
30 struct FStringChunk
31 {
32 long nLength;
33 chr *pData;
34 FStringChunk *pNext;
35 };
36
37#define cpy( dest, src, size ) Bu::memcpy( dest, src, size*sizeof(chr) )
38
39 template< typename chr, int nMinSize, typename chralloc,
40 typename chunkalloc> class FBasicString;
41
42 template<typename chr>
43 size_t strlen( const chr *pData )
44 {
45 for( size_t tLen = 0;; ++tLen )
46 {
47 if( pData[tLen] == (chr)0 )
48 return tLen;
49 }
50 return -1;
51 }
52
53 template<char>
54 size_t strlen( const char *pData )
55 {
56 return ::strlen( pData );
57 }
58
59 template<typename chr>
60 int strncmp( const chr *a, const chr *b, size_t iLen )
61 {
62 for( size_t iPos = 0; iPos < iLen; iPos++ )
63 {
64 if( a[iPos] != b[iPos] )
65 {
66 return a[iPos]-b[iPos];
67 }
68 }
69 return 0;
70 }
71
72 template<char>
73 int strncmp( const char *a, const char *b, size_t iLen )
74 {
75 return ::strncmp( a, b, iLen );
76 }
77
78 template<typename chr, int nMinSize, typename chralloc, typename chunkalloc>
79 struct FStringCore
80 {
81 friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>;
82 friend class SharedCore<
83 FBasicString<chr, nMinSize, chralloc, chunkalloc>,
84 FStringCore<chr, nMinSize, chralloc, chunkalloc>
85 >;
86 private:
87 typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> MyType;
88 typedef struct FStringChunk<chr> Chunk;
89 FStringCore() :
90 nLength( 0 ),
91 pFirst( NULL ),
92 pLast( NULL )
93 {
94 }
95
96 FStringCore( const MyType &rSrc ) :
97 nLength( rSrc.nLength ),
98 pFirst( NULL ),
99 pLast( NULL ),
100 aChr( rSrc.aChr ),
101 aChunk( rSrc.aChunk )
102 {
103 if( rSrc.pFirst == NULL || rSrc.nLength == 0 )
104 {
105 pFirst = pLast = NULL;
106 }
107 else
108 {
109 pFirst = pLast = newChunk( nLength );
110 Chunk *pLink = rSrc.pFirst;
111 int iPos = 0;
112 while( pLink != NULL )
113 {
114 cpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
115 iPos += pLink->nLength;
116 pLink = pLink->pNext;
117 }
118 }
119 }
120
121 virtual ~FStringCore()
122 {
123 clear();
124 }
125
126 mutable long nLength;
127 mutable Chunk *pFirst;
128 mutable Chunk *pLast;
129
130 mutable chralloc aChr;
131 mutable chunkalloc aChunk;
132
133 void clear() const
134 {
135 if( pFirst == NULL )
136 return;
137
138 Chunk *i = pFirst;
139 for(;;)
140 {
141 Chunk *n = i->pNext;
142 aChr.deallocate( i->pData, i->nLength+1 );
143 aChunk.deallocate( i, 1 );
144 if( n == NULL )
145 break;
146 i = n;
147 }
148 pFirst = pLast = NULL;
149 nLength = 0;
150 }
151
152 Chunk *newChunk() const
153 {
154 Chunk *pNew = aChunk.allocate( 1 );
155 pNew->pNext = NULL;
156 return pNew;
157 }
158
159 Chunk *newChunk( long nLen ) const
160 {
161 Chunk *pNew = aChunk.allocate( 1 );
162 pNew->pNext = NULL;
163 pNew->nLength = nLen;
164 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
165 pNew->pData[nLen] = (chr)0;
166 return pNew;
167 }
168
169 Chunk *copyChunk( Chunk *pSrc ) const
170 {
171 Chunk *pNew = aChunk.allocate( 1 );
172 pNew->pNext = pSrc->pNext;
173 pNew->nLength = pSrc->nLength;
174 pNew->pData = aChr.allocate( pSrc->nLength+1 );
175 cpy( pNew->pData, pSrc->pData, pSrc->nLength );
176 pNew->pData[pNew->nLength] = (chr)0;
177 return pNew;
178 }
179
180 void appendChunk( Chunk *pNewChunk )
181 {
182 if( pFirst == NULL )
183 pLast = pFirst = pNewChunk;
184 else
185 {
186 pLast->pNext = pNewChunk;
187 pLast = pNewChunk;
188 }
189
190 nLength += pNewChunk->nLength;
191 }
192
193 void prependChunk( Chunk *pNewChunk )
194 {
195 if( pFirst == NULL )
196 pLast = pFirst = pNewChunk;
197 else
198 {
199 pNewChunk->pNext = pFirst;
200 pFirst = pNewChunk;
201 }
202
203 nLength += pNewChunk->nLength;
204 }
205 };
206 /** @endcond */
207
208 /**
209 * Flexible String class. This class was designed with string passing and
210 * generation in mind. Like the standard string class you can specify what
211 * datatype to use for each character. Unlike the standard string class,
212 * collection of appended and prepended terms is done lazily, making long
213 * operations that involve many appends very inexpensive. In addition
214 * internal ref-counting means that if you pass strings around between
215 * functions there's almost no overhead in time or memory since a reference
216 * is created and no data is actually copied. This also means that you
217 * never need to put any FBasicString into a ref-counting container class.
218 *
219 *@param chr (typename) Type of character (i.e. char)
220 *@param nMinSize (int) Chunk size (default: 256)
221 *@param chralloc (typename) Memory Allocator for chr
222 *@param chunkalloc (typename) Memory Allocator for chr chunks
223 */
224 template< typename chr, int nMinSize=256,
225 typename chralloc=std::allocator<chr>,
226 typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
227 class FBasicString : public SharedCore<
228 FBasicString<chr, nMinSize, chralloc, chunkalloc>,
229 FStringCore<chr, nMinSize, chralloc, chunkalloc> >
230 {
231 protected:
232 typedef struct FStringChunk<chr> Chunk;
233 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
234 typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> Core;
235
236 using SharedCore<MyType, Core >::core;
237 using SharedCore<MyType, Core >::_hardCopy;
238
239 public: // Iterators
240 struct iterator;
241 typedef struct const_iterator
242 {
243 friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>;
244 friend struct iterator;
245 private:
246 const_iterator( Chunk *pChunk, int iPos ) :
247 pChunk( pChunk ),
248 iPos( iPos )
249 {
250 }
251
252 Chunk *pChunk;
253 int iPos;
254
255 public:
256 const_iterator( const const_iterator &i ) :
257 pChunk( i.pChunk ),
258 iPos( i.iPos )
259 {
260 }
261
262 const_iterator( const struct iterator &i ) :
263 pChunk( i.pChunk ),
264 iPos( i.iPos )
265 {
266 }
267
268 const_iterator() :
269 pChunk( NULL ),
270 iPos( 0 )
271 {
272 }
273
274 bool operator==( const const_iterator &i ) const
275 {
276 return pChunk == i.pChunk && iPos == i.iPos;
277 }
278
279 bool operator!=( const const_iterator &i ) const
280 {
281 return !(*this == i);
282 }
283
284 const_iterator &operator=( const const_iterator &i )
285 {
286 pChunk = i.pChunk;
287 iPos = i.iPos;
288 return *this;
289 }
290
291 const_iterator &operator++()
292 {
293 if( !pChunk ) return *this;
294 iPos++;
295 if( iPos >= pChunk->nLength )
296 {
297 iPos = 0;
298 pChunk = pChunk->pNext;
299 }
300 return *this;
301 }
302
303 const_iterator &operator++( int )
304 {
305 if( !pChunk ) return *this;
306 iPos++;
307 if( iPos >= pChunk->nLength )
308 {
309 iPos = 0;
310 pChunk = pChunk->pNext;
311 }
312 return *this;
313 }
314
315 const_iterator &operator+=( int iAmnt )
316 {
317 if( !pChunk ) return *this;
318 iPos += iAmnt;
319 while( iPos >= pChunk->nLength )
320 {
321 iPos -= pChunk->nLength;
322 pChunk = pChunk->pNext;
323 if( pChunk == NULL )
324 break;
325 }
326 return *this;
327 }
328
329 const_iterator operator+( int iAmnt ) const
330 {
331 if( !pChunk ) return *this;
332 const_iterator ret( *this );
333 ret += iAmnt;
334 return ret;
335 }
336
337 const chr &operator *() const
338 {
339 if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator.");
340 return pChunk->pData[iPos];
341 }
342
343 bool operator==( const chr &c ) const
344 {
345 if( !pChunk ) return false;
346 return pChunk->pData[iPos] == c;
347 }
348
349 bool operator!=( const chr &c ) const
350 {
351 if( !pChunk ) return false;
352 return pChunk->pData[iPos] != c;
353 }
354
355 operator bool() const
356 {
357 return pChunk != NULL;
358 }
359
360 bool isValid() const
361 {
362 return pChunk != NULL;
363 }
364
365 bool compare( const const_iterator &c ) const
366 {
367 const_iterator a = *this;
368 const_iterator b = c;
369 if( a == b )
370 return true;
371 for(; a && b; a++, b++ )
372 {
373 if( *a != *b )
374 return false;
375 }
376 return true;
377 }
378
379 bool compare( const const_iterator &c, int nLen ) const
380 {
381 const_iterator a = *this;
382 const_iterator b = c;
383 if( a == b )
384 return true;
385 for(int j = 0; a && b && j < nLen; a++, b++, j++ )
386 {
387 if( *a != *b )
388 return false;
389 }
390 return true;
391 }
392
393 bool compare( const chr *c ) const
394 {
395 if( !pChunk ) return false;
396 const_iterator a = *this;
397 for(; a && *c; a++, c++ )
398 {
399 if( *a != *c )
400 return false;
401 }
402 if( a.isValid() != (*c!=(chr)0) )
403 return false;
404 return true;
405 }
406
407 bool compare( const chr *c, int nLen ) const
408 {
409 if( !pChunk ) return false;
410 const_iterator a = *this;
411 int j = 0;
412 for(; a && j < nLen; a++, c++, j++ )
413 {
414 if( *a != *c )
415 return false;
416 }
417 if( j < nLen )
418 return false;
419 return true;
420 }
421
422 bool compare( const MyType &s ) const
423 {
424 if( !pChunk ) return false;
425 return compare( s.begin() );
426 }
427
428 bool compare( const MyType &s, int nLen ) const
429 {
430 if( !pChunk ) return false;
431 return compare( s.begin(), nLen );
432 }
433
434 const_iterator find( const chr c ) const
435 {
436 for( const_iterator i = *this; i; i++ )
437 {
438 if( *i == c )
439 return i;
440 }
441 return const_iterator( NULL, 0 );
442 }
443
444 const_iterator find( const chr *pStr, int nLen ) const
445 {
446 for( const_iterator i = *this; i; i++ )
447 {
448 if( i.compare( pStr, nLen ) )
449 return i;
450 }
451 return const_iterator( NULL, 0 );
452 }
453
454 const_iterator find( const MyType &s ) const
455 {
456 for( const_iterator i = *this; i; i++ )
457 {
458 if( i.compare( s ) )
459 return i;
460 }
461 return const_iterator( NULL, 0 );
462 }
463
464 const_iterator find( const MyType &s, int nLen ) const
465 {
466 for( const_iterator i = *this; i; i++ )
467 {
468 if( i.compare( s, nLen ) )
469 return i;
470 }
471 return const_iterator( NULL, 0 );
472 }
473 } const_iterator;
474
475 typedef struct iterator
476 {
477 friend class FBasicString<chr, nMinSize, chralloc, chunkalloc>;
478 friend struct const_iterator;
479 private:
480 iterator( Chunk *pChunk, int iPos ) :
481 pChunk( pChunk ),
482 iPos( iPos )
483 {
484 }
485
486 Chunk *pChunk;
487 int iPos;
488
489 public:
490 iterator( const iterator &i ) :
491 pChunk( i.pChunk ),
492 iPos( i.iPos )
493 {
494 }
495
496 iterator() :
497 pChunk( NULL ),
498 iPos( 0 )
499 {
500 }
501
502 operator const_iterator() const
503 {
504 return const_iterator( pChunk, iPos );
505 }
506
507 bool operator==( const iterator &i ) const
508 {
509 return pChunk == i.pChunk && iPos == i.iPos;
510 }
511
512 bool operator!=( const iterator &i ) const
513 {
514 return !(*this == i);
515 }
516
517 iterator &operator=( const iterator &i )
518 {
519 pChunk = i.pChunk;
520 iPos = i.iPos;
521 return *this;
522 }
523
524 iterator &operator++()
525 {
526 if( !pChunk ) return *this;
527 iPos++;
528 if( iPos >= pChunk->nLength )
529 {
530 iPos = 0;
531 pChunk = pChunk->pNext;
532 }
533 return *this;
534 }
535
536 iterator &operator++( int )
537 {
538 if( !pChunk ) return *this;
539 iPos++;
540 if( iPos >= pChunk->nLength )
541 {
542 iPos = 0;
543 pChunk = pChunk->pNext;
544 }
545 return *this;
546 }
547
548 iterator &operator+=( int iAmnt )
549 {
550 if( !pChunk ) return *this;
551 iPos += iAmnt;
552 while( iPos >= pChunk->nLength )
553 {
554 iPos -= pChunk->nLength;
555 pChunk = pChunk->pNext;
556 if( pChunk == NULL )
557 break;
558 }
559 return *this;
560 }
561
562 iterator operator+( int iAmnt ) const
563 {
564 if( !pChunk ) return *this;
565 iterator ret( *this );
566 ret += iAmnt;
567 return ret;
568 }
569
570 chr &operator*()
571 {
572 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
573 return pChunk->pData[iPos];
574 }
575
576 const chr &operator*() const
577 {
578 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
579 return pChunk->pData[iPos];
580 }
581
582 bool operator==( const chr &c ) const
583 {
584 if( !pChunk ) return false;
585 return pChunk->pData[iPos] == c;
586 }
587
588 bool operator!=( const chr &c ) const
589 {
590 if( !pChunk ) return false;
591 return pChunk->pData[iPos] != c;
592 }
593
594 iterator &operator=( const chr &c )
595 {
596 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
597 pChunk->pData[iPos] = c;
598 return *this;
599 }
600
601 operator bool() const
602 {
603 return pChunk != NULL;
604 }
605
606 bool isValid() const
607 {
608 return pChunk != NULL;
609 }
610
611 bool compare( const iterator &c ) const
612 {
613 iterator a = *this;
614 iterator b = c;
615 if( a == b )
616 return true;
617 for(; a && b; a++, b++ )
618 {
619 if( *a != *b )
620 return false;
621 }
622 return true;
623 }
624
625 bool compare( const iterator &c, int nLen ) const
626 {
627 iterator a = *this;
628 iterator b = c;
629 if( a == b )
630 return true;
631 for(int j = 0; a && b && j < nLen; a++, b++, j++ )
632 {
633 if( *a != *b )
634 return false;
635 }
636 return true;
637 }
638
639 bool compare( const chr *c ) const
640 {
641 if( !pChunk ) return false;
642 iterator a = *this;
643 for(; a && *c; a++, c++ )
644 {
645 if( *a != *c )
646 return false;
647 }
648 if( a.isValid() != (*c!=(chr)0) )
649 return false;
650 return true;
651 }
652
653 bool compare( const chr *c, int nLen ) const
654 {
655 if( !pChunk ) return false;
656 iterator a = *this;
657 int j = 0;
658 for(; a && j < nLen; a++, c++, j++ )
659 {
660 if( *a != *c )
661 return false;
662 }
663 if( j < nLen )
664 return false;
665 return true;
666 }
667
668 bool compare( const MyType &s ) const
669 {
670 if( !pChunk ) return false;
671 return compare( s.begin() );
672 }
673
674 bool compare( const MyType &s, int nLen ) const
675 {
676 if( !pChunk ) return false;
677 return compare( s.begin(), nLen );
678 }
679
680 iterator find( const chr c ) const
681 {
682 for( iterator i = *this; i; i++ )
683 {
684 if( *i == c )
685 return i;
686 }
687 return iterator( NULL, 0 );
688 }
689
690 iterator find( const chr *pStr, int nLen ) const
691 {
692 for( iterator i = *this; i; i++ )
693 {
694 if( i.compare( pStr, nLen ) )
695 return i;
696 }
697 return iterator( NULL, 0 );
698 }
699
700 iterator find( const MyType &s ) const
701 {
702 for( iterator i = *this; i; i++ )
703 {
704 if( i.compare( s ) )
705 return i;
706 }
707 return iterator( NULL, 0 );
708 }
709
710 iterator find( const MyType &s, int nLen ) const
711 {
712 for( iterator i = *this; i; i++ )
713 {
714 if( i.compare( s, nLen ) )
715 return i;
716 }
717 return iterator( NULL, 0 );
718 }
719 } iterator;
720
721 public:
722 FBasicString()
723 {
724 }
725
726 FBasicString( const chr *pData )
727 {
728 append( pData );
729 }
730
731 FBasicString( const chr *pData, long nLength )
732 {
733 append( pData, nLength );
734 }
735
736 FBasicString( const MyType &rSrc ) :
737 SharedCore<MyType, Core>( rSrc )
738 {
739 }
740
741 FBasicString( const MyType &rSrc, long nLength )
742 {
743 append( rSrc, nLength );
744 }
745
746 FBasicString( const MyType &rSrc, long nStart, long nLength )
747 {
748 append( rSrc, nStart, nLength );
749 }
750
751 FBasicString( long nSize )
752 {
753 core->pFirst = core->pLast = core->newChunk( nSize );
754 core->nLength = nSize;
755 }
756
757 FBasicString( const const_iterator &s )
758 {
759 append( s );
760 }
761
762 FBasicString( const const_iterator &s, const const_iterator &e )
763 {
764 append( s, e );
765 }
766
767 virtual ~FBasicString()
768 {
769 }
770
771 /**
772 * Append data to your string.
773 *@param pData (const chr *) The data to append.
774 */
775 void append( const chr *pData )
776 {
777 if( !pData ) return;
778 long nLen;
779 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
780
781 append( pData, 0, nLen );
782 }
783
784 /**
785 * Append data to your string.
786 *@param pData (const chr *) The data to append.
787 *@param nLen (long) The length of the data to append.
788 */
789 void append( const chr *pData, long nLen )
790 {
791 append( pData, 0, nLen );
792 }
793
794 /**
795 * Append data to your string.
796 *@param pData (const chr *) The data to append.
797 *@param nStart (long) The start position to copy from.
798 *@param nLen (long) The length of the data to append.
799 */
800 void append( const chr *pData, long nStart, long nLen )
801 {
802 if( !pData ) return;
803 if( nLen <= 0 )
804 return;
805
806 pData += nStart;
807
808 _hardCopy();
809
810 if( core->pLast && core->pLast->nLength < nMinSize )
811 {
812 int nAmnt = nMinSize - core->pLast->nLength;
813 if( nAmnt > nLen )
814 nAmnt = nLen;
815 cpy(
816 core->pLast->pData+core->pLast->nLength,
817 pData,
818 nAmnt
819 );
820 pData += nAmnt;
821 core->pLast->nLength += nAmnt;
822 nLen -= nAmnt;
823 core->nLength += nAmnt;
824 }
825
826 if( nLen > 0 )
827 {
828 Chunk *pNew = core->newChunk( nLen );
829 cpy( pNew->pData, pData, nLen );
830 core->appendChunk( pNew );
831// core->nLength += nLen;
832 }
833 }
834
835 /**
836 * Append a single chr to your string.
837 *@param cData (const chr &) The character to append.
838 */
839 void append( const chr &cData )
840 {
841 if( core->pLast && core->pLast->nLength < nMinSize )
842 {
843 _hardCopy();
844 core->pLast->pData[core->pLast->nLength] = cData;
845 ++core->pLast->nLength; ++core->nLength;
846 // pLast->pData[pLast->nLength] = (chr)0;
847 }
848 else
849 {
850 append( &cData, 1 );
851 }
852 }
853
854 /**
855 * Append another FString to this one.
856 *@param sData (MyType &) The FString to append.
857 *@todo This function can be made much faster by not using getStr()
858 */
859 void append( const MyType & sData )
860 {
861 append( sData.getStr(), 0, sData.getSize() );
862 }
863
864 /**
865 * Append another FString to this one.
866 *@param sData (MyType &) The FString to append.
867 *@param nLen How much data to append.
868 *@todo This function can be made much faster by not using getStr()
869 */
870 void append( const MyType & sData, long nLen )
871 {
872 append( sData.getStr(), 0, nLen );
873 }
874
875 /**
876 * Append another FString to this one.
877 *@param sData (MyType &) The FString to append.
878 *@param nStart Start position in sData to start copying from.
879 *@param nLen How much data to append.
880 *@todo This function can be made much faster by not using getStr()
881 */
882 void append( const MyType & sData, long nStart, long nLen )
883 {
884 if( nLen < 0 )
885 nLen = sData.getSize() - nStart;
886 append( sData.getStr(), nStart, nLen );
887 }
888
889 /**
890 * Append data to this FString using the passed in iterator as a base.
891 * The iterator is const, it is not changed.
892 *@param s Iterator from any compatible FBasicString to copy data from.
893 */
894 void append( const const_iterator &s )
895 {
896 if( !s.isValid() )
897 return;
898 Chunk *pSrc = s.pChunk;
899
900 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
901 cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
902
903 _hardCopy();
904 core->appendChunk( pNew );
905
906 while( (pSrc = pSrc->pNext) )
907 {
908 core->appendChunk( core->copyChunk( pSrc ) );
909 }
910 }
911
912 /**
913 * Append data to this FString using the passed in iterator as a base.
914 * The iterator is const, it is not changed.
915 *@param s Iterator from any compatible FBasicString to copy data from.
916 */
917 void append( const iterator &s ) // I get complaints without this one
918 {
919 append( const_iterator( s ) );
920 }
921
922 /**
923 * Append data to this FString using the passed in iterator as a base,
924 * and copy data until the ending iterator is reached. The character
925 * at the ending iterator is not copied.
926 * The iterators are const, they are not changed.
927 *@param s Iterator from any compatible FBasicString to copy data from.
928 *@param e Iterator to stop copying at.
929 */
930 void append( const const_iterator &s, const const_iterator &e )
931 {
932 if( !s.isValid() )
933 return;
934 if( !e.isValid() )
935 {
936 append( s );
937 return;
938 }
939 _hardCopy();
940 if( s.pChunk == e.pChunk )
941 {
942 // Simple case, they're the same chunk
943 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
944 cpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
945 core->appendChunk( pNew );
946 }
947 else
948 {
949 // A little trickier, scan the blocks...
950 Chunk *pSrc = s.pChunk;
951 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
952 cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
953 core->appendChunk( pNew );
954
955 while( (pSrc = pSrc->pNext) != e.pChunk )
956 {
957 core->appendChunk( core->copyChunk( pSrc ) );
958 }
959
960 pNew = core->newChunk( e.iPos );
961 cpy( pNew->pData, pSrc->pData, e.iPos );
962 core->appendChunk( pNew );
963 }
964 }
965
966 /**
967 * Prepend another FString to this one.
968 *@param sData (MyType &) The FString to prepend.
969 *@todo This function can be made much faster by not using getStr()
970 */
971 void prepend( const MyType & sData )
972 {
973 prepend( sData.getStr(), sData.getSize() );
974 }
975
976 /**
977 * Prepend data to your string.
978 *@param pData (const chr *) The data to prepend.
979 */
980 void prepend( const chr *pData )
981 {
982 if( pData == NULL )
983 return;
984
985 _hardCopy();
986 long nLen;
987 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
988
989 Chunk *pNew = core->newChunk( nLen );
990 cpy( pNew->pData, pData, nLen );
991
992 core->prependChunk( pNew );
993 }
994
995 /**
996 * Prepend data to your string.
997 *@param pData (const chr *) The data to prepend.
998 *@param nLen (long) The length of the data to prepend.
999 */
1000 void prepend( const chr *pData, long nLen )
1001 {
1002 Chunk *pNew = core->newChunk( nLen );
1003
1004 cpy( pNew->pData, pData, nLen );
1005
1006 _hardCopy();
1007 core->prependChunk( pNew );
1008 }
1009
1010 void prepend( const chr c )
1011 {
1012 prepend( &c, 1 );
1013 }
1014
1015 /**
1016 * Insert pData before byte nPos, that is, the first byte of pData will
1017 * start at nPos. This could probably be made faster by avoiding
1018 * flattening.
1019 */
1020 void insert( long nPos, const chr *pData, long nLen )
1021 {
1022 if( nLen <= 0 )
1023 return;
1024 if( nPos <= 0 )
1025 {
1026 prepend( pData, nLen );
1027 }
1028 else if( nPos >= core->nLength )
1029 {
1030 append( pData, nLen );
1031 }
1032 else
1033 {
1034 // If we're going to flatten anyway, might as well for everyone
1035 flatten();
1036 _hardCopy();
1037 Chunk *p1 = core->newChunk( nPos );
1038 Chunk *p2 = core->newChunk( nLen );
1039 Chunk *p3 = core->newChunk( core->nLength-nPos );
1040 cpy( p1->pData, core->pFirst->pData, nPos );
1041 cpy( p2->pData, pData, nLen );
1042 cpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
1043 core->clear();
1044 core->appendChunk( p1 );
1045 core->appendChunk( p2 );
1046 core->appendChunk( p3 );
1047 }
1048 }
1049
1050 void insert( long nPos, const MyType &str )
1051 {
1052 if( nPos <= 0 )
1053 {
1054 prepend( str );
1055 }
1056 else if( nPos >= core->nLength )
1057 {
1058 append( str );
1059 }
1060 else
1061 {
1062 flatten();
1063 _hardCopy();
1064 Chunk *p1 = core->newChunk( nPos );
1065 Chunk *p3 = core->newChunk( core->nLength-nPos );
1066 cpy( p1->pData, core->pFirst->pData, nPos );
1067 cpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
1068 core->clear();
1069 core->appendChunk( p1 );
1070 for( Chunk *pChnk = str.core->pFirst; pChnk;
1071 pChnk = pChnk->pNext )
1072 {
1073 core->appendChunk( core->copyChunk( pChnk ) );
1074 }
1075
1076 core->appendChunk( p3 );
1077 }
1078 }
1079
1080 /**
1081 *@todo This function shouldn't use strlen, we should add our own to
1082 * this class, one that can be overridden in a specific implementation.
1083 */
1084 void insert( long nPos, const chr *pData )
1085 {
1086 insert( nPos, pData, Bu::strlen( pData ) );
1087 }
1088
1089 void remove( long nPos, long nLen )
1090 {
1091 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
1092 return;
1093 if( nLen > core->nLength-nPos )
1094 nLen = core->nLength-nPos;
1095 flatten();
1096 _hardCopy();
1097 memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
1098 core->nLength -= nLen;
1099 core->pFirst->nLength -= nLen;
1100 }
1101
1102 /**
1103 * Clear all data from the string.
1104 */
1105 void clear()
1106 {
1107 _hardCopy();
1108 core->clear();
1109 }
1110
1111 MyType replace( const MyType &fnd, const MyType &rep ) const
1112 {
1113 MyType out;
1114 const_iterator o = begin();
1115 while( true )
1116 {
1117 const_iterator i = o.find( fnd );
1118 if( !i )
1119 {
1120 out.append( o );
1121 return out;
1122 }
1123 else
1124 {
1125 out.append( o, i );
1126 out.append( rep );
1127 o = i;
1128 o += fnd.getSize();
1129 }
1130 }
1131 }
1132
1133 /**
1134 * Force the string to resize
1135 *@param nNewSize (long) The new size of the string.
1136 */
1137 void resize( long nNewSize )
1138 {
1139 if( core->nLength == nNewSize )
1140 return;
1141 if( nNewSize < 0 )
1142 nNewSize = 0;
1143
1144 flatten();
1145 _hardCopy();
1146
1147 Chunk *pNew = core->newChunk( nNewSize );
1148 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
1149 if( core->nLength > 0 )
1150 {
1151 cpy( pNew->pData, core->pFirst->pData, nNewLen );
1152 core->aChr.deallocate( core->pFirst->pData, core->pFirst->nLength+1 );
1153 core->aChunk.deallocate( core->pFirst, 1 );
1154 }
1155 pNew->pData[nNewLen] = (chr)0;
1156 core->pFirst = core->pLast = pNew;
1157 core->nLength = nNewSize;
1158 }
1159
1160 /**
1161 * Get the current size of the string.
1162 *@returns (long) The current size of the string.
1163 */
1164 long getSize() const
1165 {
1166 return core->nLength;
1167 }
1168
1169 /**
1170 * Get a pointer to the string array.
1171 *@returns (chr *) The string data.
1172 */
1173 chr *getStr()
1174 {
1175 if( core->pFirst == NULL || core->nLength == 0 )
1176 return (chr *)"";
1177
1178 flatten();
1179 _hardCopy();
1180 core->pFirst->pData[core->nLength] = (chr)0;
1181 return core->pFirst->pData;
1182 }
1183
1184 /**
1185 * Get a const pointer to the string array.
1186 *@returns (const chr *) The string data.
1187 */
1188 const chr *getStr() const
1189 {
1190 if( core->pFirst == NULL || core->nLength == 0 )
1191 return (chr *)"";
1192
1193 flatten();
1194 core->pFirst->pData[core->nLength] = (chr)0;
1195 return core->pFirst->pData;
1196 }
1197
1198 /**
1199 * A convinience function, this one won't cause as much work as the
1200 * non-const getStr, so if you're not changing the data, consider it.
1201 */
1202 const chr *getConstStr() const
1203 {
1204 return getStr();
1205 }
1206
1207 MyType getSubStrIdx( long iStart, long iSize=-1 ) const
1208 {
1209 if( iStart < 0 )
1210 iStart = 0;
1211 if( iStart >= core->nLength )
1212 return (const chr[]){(chr)0};
1213 if( iSize < 0 )
1214 iSize = core->nLength;
1215 if( iStart+iSize > core->nLength )
1216 iSize = core->nLength-iStart;
1217 if( iSize == 0 )
1218 return (const chr[]){(chr)0};
1219
1220 flatten();
1221 MyType ret( core->pFirst->pData+iStart, iSize );
1222 return ret;
1223 }
1224
1225 MyType getSubStr( const_iterator iBegin,
1226 const_iterator iEnd=typename MyType::const_iterator() ) const
1227 {
1228 if( !iBegin.isValid() )
1229 return MyType();
1230 if( iBegin.pChunk == iEnd.pChunk )
1231 {
1232 return MyType( iBegin.pChunk->pData+iBegin.iPos,
1233 iEnd.iPos-iBegin.iPos );
1234 }
1235 else if( !iEnd.isValid() )
1236 {
1237 MyType ret;
1238 ret.append(
1239 iBegin.pChunk->pData+iBegin.iPos,
1240 iBegin.pChunk->nLength-iBegin.iPos
1241 );
1242 for( Chunk *pCur = iBegin.pChunk->pNext;
1243 pCur; pCur = pCur->pNext )
1244 {
1245 ret.append( pCur->pData, pCur->nLength );
1246 }
1247 return ret;
1248 }
1249 else
1250 {
1251 MyType ret;
1252 ret.append(
1253 iBegin.pChunk->pData+iBegin.iPos,
1254 iBegin.pChunk->nLength-iBegin.iPos
1255 );
1256 for( Chunk *pCur = iBegin.pChunk->pNext;
1257 pCur != iEnd.pChunk; pCur = pCur->pNext )
1258 {
1259 ret.append( pCur->pData, pCur->nLength );
1260 }
1261 ret.append(
1262 iEnd.pChunk->pData,
1263 iEnd.iPos
1264 );
1265 return ret;
1266 }
1267 }
1268
1269 Bu::List<MyType> split( const chr c ) const
1270 {
1271 Bu::List<MyType> ret;
1272 const_iterator l, r;
1273 l = begin();
1274 for(r=l; l;)
1275 {
1276 for( r = l; r && r != c; r++ ) { }
1277 ret.append( MyType( l, r ) );
1278 l = r;
1279 l++;
1280 }
1281 return ret;
1282 }
1283
1284 /**
1285 * Plus equals operator for FString.
1286 *@param pData (const chr *) The data to append to your FString.
1287 */
1288 MyType &operator+=( const chr *pData )
1289 {
1290 append( pData );
1291
1292 return (*this);
1293 }
1294
1295 /**
1296 * Plus equals operator for FString.
1297 *@param rSrc (const MyType &) The FString to append to your FString.
1298 */
1299 MyType &operator+=( const MyType &rSrc )
1300 {
1301 append( rSrc );
1302
1303 return (*this);
1304 }
1305
1306 MyType &operator+=( const MyType::const_iterator &i )
1307 {
1308 append( i, i+1 );
1309
1310 return (*this);
1311 }
1312
1313 /**
1314 * Plus equals operator for FString.
1315 *@param cData (const chr) The character to append to your FString.
1316 */
1317 MyType &operator+=( const chr cData )
1318 {
1319 if( core->pLast && core->pLast->nLength < nMinSize )
1320 {
1321 _hardCopy();
1322 core->pLast->pData[core->pLast->nLength] = cData;
1323 ++core->pLast->nLength; ++core->nLength;
1324 // pLast->pData[pLast->nLength] = (chr)0;
1325 }
1326 else
1327 {
1328 append( &cData, 1 );
1329 }
1330 //append( pData );
1331
1332 return (*this);
1333 }
1334
1335 /**
1336 * Assignment operator.
1337 *@param pData (const chr *) The character array to append to your
1338 * FString.
1339 */
1340 MyType &operator=( const chr *pData )
1341 {
1342 set( pData );
1343
1344 return (*this);
1345 }
1346
1347 MyType operator+( const MyType &rRight ) const
1348 {
1349 MyType ret( *this );
1350 ret.append( rRight );
1351 return ret;
1352 }
1353
1354 MyType operator+( const chr *pRight ) const
1355 {
1356 MyType ret( *this );
1357 ret.append( pRight );
1358 return ret;
1359 }
1360
1361 MyType operator+( chr *pRight ) const
1362 {
1363 MyType ret( *this );
1364 ret.append( pRight );
1365 return ret;
1366 }
1367
1368 /**
1369 * Reset your FString to this character array.
1370 *@param pData (const chr *) The character array to set your FString to.
1371 */
1372 void set( const chr *pData )
1373 {
1374 clear();
1375 append( pData );
1376 }
1377
1378 /**
1379 * Reset your FString to this character array.
1380 *@param pData (const chr *) The character array to set your FString to.
1381 *@param nSize (long) The length of the inputted character array.
1382 */
1383 void set( const chr *pData, long nSize )
1384 {
1385 clear();
1386 append( pData, nSize );
1387 }
1388
1389 void set( const chr *pData, long nStart, long nSize )
1390 {
1391 clear();
1392 append( pData, nStart, nSize );
1393 }
1394
1395 void set( const MyType &rData )
1396 {
1397 clear();
1398 append( rData );
1399 }
1400
1401 void set( const MyType &rData, long nSize )
1402 {
1403 clear();
1404 append( rData, nSize );
1405 }
1406
1407 void set( const MyType &rData, long nStart, long nSize )
1408 {
1409 clear();
1410 append( rData, nStart, nSize );
1411 }
1412
1413 void set( const_iterator s )
1414 {
1415 clear();
1416 append( s );
1417 }
1418
1419 void set( const_iterator s, const_iterator e )
1420 {
1421 clear();
1422 append( s, e );
1423 }
1424
1425 /**
1426 * Resize the string, possibly to make room for a copy. At the moment
1427 * this operation *is* destructive. What was in the string will in no
1428 * way be preserved. This is, however, very fast. If you want to
1429 * keep your data check out resize.
1430 *@param iSize the new size in bytes. The string is guranteed to have
1431 * at least this much contiguous space available when done.
1432 */
1433 void setSize( long iSize )
1434 {
1435 _hardCopy();
1436 core->clear();
1437 core->appendChunk( core->newChunk( iSize ) );
1438 }
1439
1440 void expand()
1441 {
1442#ifndef WIN32
1443 flatten();
1444 _hardCopy();
1445
1446 wordexp_t result;
1447
1448 /* Expand the string for the program to run. */
1449 switch (wordexp ((char *)core->pFirst->pData, &result, 0))
1450 {
1451 case 0: /* Successful. */
1452 {
1453 set( (chr *)result.we_wordv[0] );
1454 wordfree( &result );
1455 return;
1456 }
1457 break;
1458 case WRDE_NOSPACE:
1459 /* If the error was `WRDE_NOSPACE',
1460 then perhaps part of the result was allocated. */
1461 wordfree (&result);
1462 default: /* Some other error. */
1463 return;
1464 }
1465#endif
1466 }
1467
1468 /**
1469 * Assignment operator.
1470 *@param rSrc (const MyType &) The FString to set your FString to.
1471 */
1472 /* MyType &operator=( const MyType &rSrc )
1473 {
1474 set( rSrc );
1475
1476 return (*this);
1477 } */
1478
1479 /**
1480 * Equals comparison operator.
1481 *@param pData (const chr *) The character array to compare your FString
1482 * to.
1483 */
1484 bool operator==( const chr *pData ) const
1485 {
1486 if( core->pFirst == NULL || core->nLength == 0 ) {
1487 if( pData == NULL )
1488 return true;
1489 if( pData[0] == (chr)0 )
1490 return true;
1491 return false;
1492 }
1493
1494 flatten();
1495 core->pFirst->pData[core->nLength] = (chr)0;
1496 const chr *a = pData;
1497 chr *b = core->pFirst->pData;
1498 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
1499 {
1500 if( *a != *b )
1501 return false;
1502 if( *a == (chr)0 && j < core->nLength )
1503 return false;
1504 }
1505
1506 return true;
1507 }
1508
1509 /**
1510 * Equals comparison operator.
1511 *@param pData (const MyType &) The FString to compare your FString to.
1512 */
1513 bool operator==( const MyType &pData ) const
1514 {
1515 if( core == pData.core )
1516 return true;
1517 if( core->pFirst == pData.core->pFirst )
1518 return true;
1519 if( (core->nLength == 0 && pData.core->nLength == 0) )
1520 return true;
1521 if( core->nLength != pData.core->nLength )
1522 return false;
1523 if( pData.core->pFirst == NULL || core->pFirst == NULL )
1524 return false;
1525
1526 flatten();
1527 pData.flatten();
1528 const chr *a = pData.core->pFirst->pData;
1529 chr *b = core->pFirst->pData;
1530 for( long j = 0; j < core->nLength; j++, a++, b++ )
1531 {
1532 if( *a != *b )
1533 return false;
1534 }
1535
1536 return true;
1537 }
1538
1539 /**
1540 * Not equals comparison operator.
1541 *@param pData (const chr *) The character array to compare your FString
1542 * to.
1543 */
1544 bool operator!=(const chr *pData ) const
1545 {
1546 return !(*this == pData);
1547 }
1548
1549 /**
1550 * Not equals comparison operator.
1551 *@param pData (const MyType &) The FString to compare your FString to.
1552 */
1553 bool operator!=(const MyType &pData ) const
1554 {
1555 return !(*this == pData);
1556 }
1557
1558 bool operator<(const MyType &pData ) const
1559 {
1560 flatten();
1561 pData.flatten();
1562
1563 const chr *a = core->pFirst->pData;
1564 chr *b = pData.core->pFirst->pData;
1565 for( long j = 0; j < core->nLength; j++, a++, b++ )
1566 {
1567 if( *a != *b )
1568 return *a < *b;
1569 }
1570
1571 return false;
1572 }
1573
1574 bool operator<=(const MyType &pData ) const
1575 {
1576 flatten();
1577 pData.flatten();
1578
1579 const chr *a = core->pFirst->pData;
1580 chr *b = pData.core->pFirst->pData;
1581 for( long j = 0; j < core->nLength; j++, a++, b++ )
1582 {
1583 if( *a != *b )
1584 return *a < *b;
1585 }
1586
1587 return true;
1588 }
1589
1590 bool operator>(const MyType &pData ) const
1591 {
1592 flatten();
1593 pData.flatten();
1594
1595 const chr *a = core->pFirst->pData;
1596 chr *b = pData.core->pFirst->pData;
1597 for( long j = 0; j < core->nLength; j++, a++, b++ )
1598 {
1599 if( *a != *b )
1600 return *a > *b;
1601 }
1602
1603 return false;
1604 }
1605
1606 bool operator>=(const MyType &pData ) const
1607 {
1608 flatten();
1609 pData.flatten();
1610
1611 const chr *a = core->pFirst->pData;
1612 chr *b = pData.core->pFirst->pData;
1613 for( long j = 0; j < core->nLength; j++, a++, b++ )
1614 {
1615 if( *a != *b )
1616 return *a > *b;
1617 }
1618
1619 return true;
1620 }
1621
1622 /**
1623 * Indexing operator
1624 *@param nIndex (long) The index of the character you want.
1625 *@returns (chr &) The character at position (nIndex).
1626 */
1627 chr &operator[]( long nIndex )
1628 {
1629 if( nIndex < 0 || nIndex >= core->nLength )
1630 throw Bu::ExceptionBase("Index out of range.");
1631 flatten();
1632 _hardCopy();
1633
1634 return core->pFirst->pData[nIndex];
1635 }
1636
1637 /**
1638 * Const indexing operator
1639 *@param nIndex (long) The index of the character you want.
1640 *@returns (const chr &) The character at position (nIndex).
1641 */
1642 const chr &operator[]( long nIndex ) const
1643 {
1644 if( nIndex < 0 || nIndex >= core->nLength )
1645 throw Bu::ExceptionBase("Index out of range.");
1646 flatten();
1647
1648 return core->pFirst->pData[nIndex];
1649 }
1650/*
1651 operator const chr *() const
1652 {
1653 if( !pFirst ) return NULL;
1654 flatten();
1655 return pFirst->pData;
1656 }
1657 */
1658 /*
1659 operator bool() const
1660 {
1661 return (core->pFirst != NULL);
1662 }
1663 */
1664
1665 bool isSet() const
1666 {
1667 return (core->pFirst != NULL);
1668 }
1669
1670 bool compareSub( const chr *pData, long nIndex, long nLen ) const
1671 {
1672 if( core->pFirst == NULL || core->nLength == 0 ) {
1673 if( pData == NULL )
1674 return true;
1675 if( nLen == 0 )
1676 return true;
1677 if( pData[0] == (chr)0 )
1678 return true;
1679 return false;
1680 }
1681 if( nIndex+nLen > core->nLength )
1682 return false;
1683
1684 flatten();
1685 core->pFirst->pData[core->nLength] = (chr)0;
1686 const chr *a = pData;
1687 chr *b = core->pFirst->pData+nIndex;
1688 for( long j = 0; j < nLen; j++, a++, b++ )
1689 {
1690 if( *a != *b )
1691 return false;
1692 if( *a == (chr)0 && j < core->nLength )
1693 return false;
1694 }
1695
1696 return true;
1697 }
1698
1699 bool compareSub( const MyType &rData, long nIndex, long nLen ) const
1700 {
1701 if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 )
1702 return false;
1703 if( nLen < 0 )
1704 nLen = rData.core->nLength;
1705 if( nIndex+nLen > core->nLength )
1706 return false;
1707
1708 flatten();
1709 rData.flatten();
1710 const chr *a = rData.core->pFirst->pData;
1711 chr *b = core->pFirst->pData + nIndex;
1712 for( long j = 0; j < nLen; j++, a++, b++ )
1713 {
1714 if( *a != *b )
1715 return false;
1716 }
1717
1718 return true;
1719 }
1720
1721 /**
1722 * Is the character at index (nIndex) white space?
1723 *@param nIndex (long) The index of the character you want to check.
1724 *@returns (bool) Is it white space?
1725 */
1726 bool isWS( long nIndex ) const
1727 {
1728 flatten();
1729
1730 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
1731 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
1732 }
1733
1734 /**
1735 * Is the character at index (nIndex) a letter?
1736 *@param nIndex (long) The index of the character you want to check.
1737 *@returns (bool) Is it a letter?
1738 */
1739 bool isAlpha( long nIndex ) const
1740 {
1741 flatten();
1742
1743 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
1744 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
1745 }
1746
1747 /**
1748 * Convert your alpha characters to lower case.
1749 */
1750 void toLower()
1751 {
1752 flatten();
1753 _hardCopy();
1754
1755 for( long j = 0; j < core->nLength; j++ )
1756 {
1757 if( core->pFirst->pData[j] >= 'A' && core->pFirst->pData[j] <= 'Z' )
1758 core->pFirst->pData[j] -= 'A'-'a';
1759 }
1760 }
1761
1762 /**
1763 * Convert your alpha characters to upper case.
1764 */
1765 void toUpper()
1766 {
1767 flatten();
1768 _hardCopy();
1769
1770 for( long j = 0; j < core->nLength; j++ )
1771 {
1772 if( core->pFirst->pData[j] >= 'a' && core->pFirst->pData[j] <= 'z' )
1773 core->pFirst->pData[j] += 'A'-'a';
1774 }
1775 }
1776
1777// template<typename out>
1778// void to( out &dst );
1779/* {
1780 flatten();
1781
1782 dst = strtol( pFirst->pData, NULL, 0 );
1783 } */
1784
1785 const_iterator find( const chr cChar,
1786 const_iterator iStart=typename MyType::const_iterator() ) const
1787 {
1788 if( !iStart ) iStart = begin();
1789 for( ; iStart; iStart++ )
1790 {
1791 if( cChar == *iStart )
1792 return iStart;
1793 }
1794 return end();
1795 }
1796
1797 const_iterator find( const chr *sText, int nLen,
1798 const_iterator iStart=typename MyType::const_iterator() ) const
1799 {
1800 if( !iStart ) iStart = begin();
1801 for( ; iStart; iStart++ )
1802 {
1803 if( iStart.compare( sText, nLen ) )
1804 return iStart;
1805 }
1806 return end();
1807 }
1808
1809 const_iterator find( const MyType &rStr,
1810 const_iterator iStart=typename MyType::const_iterator() ) const
1811 {
1812 if( !iStart ) iStart = begin();
1813 for( ; iStart; iStart++ )
1814 {
1815 if( iStart.compare( rStr ) )
1816 return iStart;
1817 }
1818 return end();
1819 }
1820
1821 const_iterator find( const MyType &rStr, int nLen,
1822 const_iterator iStart=typename MyType::const_iterator() ) const
1823 {
1824 if( !iStart ) iStart = begin();
1825 for( ; iStart; iStart++ )
1826 {
1827 if( iStart.compare( rStr, nLen ) )
1828 return iStart;
1829 }
1830 return end();
1831 }
1832
1833 iterator find( const chr cChar,
1834 const_iterator iStart=typename MyType::const_iterator() )
1835 {
1836 if( !iStart ) iStart = begin();
1837 for( ; iStart; iStart++ )
1838 {
1839 if( cChar == *iStart )
1840 return iterator( iStart.pChunk, iStart.iPos );
1841 }
1842 return end();
1843 }
1844
1845 iterator find( const chr *sText, int nLen,
1846 const_iterator iStart=typename MyType::const_iterator() )
1847 {
1848 if( !iStart ) iStart = begin();
1849 for( ; iStart; iStart++ )
1850 {
1851 if( iStart.compare( sText, nLen ) )
1852 return iterator( iStart.pChunk, iStart.iPos );
1853 }
1854 return end();
1855 }
1856
1857 iterator find( const MyType &rStr,
1858 const_iterator iStart=typename MyType::const_iterator() )
1859 {
1860 if( !iStart ) iStart = begin();
1861 for( ; iStart; iStart++ )
1862 {
1863 if( iStart.compare( rStr ) )
1864 return iterator( iStart.pChunk, iStart.iPos );
1865 }
1866 return end();
1867 }
1868
1869 iterator find( const MyType &rStr, int nLen,
1870 const_iterator iStart=typename MyType::const_iterator() )
1871 {
1872 if( !iStart ) iStart = begin();
1873 for( ; iStart; iStart++ )
1874 {
1875 if( iStart.compare( rStr, nLen ) )
1876 return iterator( iStart.pChunk, iStart.iPos );
1877 }
1878 return end();
1879 }
1880
1881 /**
1882 * Find the index of the first occurrance of cChar
1883 *@param cChar The character to search for.
1884 *@param iStart The position in the string to start searching from.
1885 *@returns (long) The index of the first occurrance. -1 for not found.
1886 */
1887 long findIdx( const chr cChar, long iStart=0 ) const
1888 {
1889 flatten();
1890 for( long j = iStart; j < core->pFirst->nLength; j++ )
1891 {
1892 if( core->pFirst->pData[j] == cChar )
1893 return j;
1894 }
1895 return -1;
1896 }
1897
1898 /**
1899 * Find the index of the first occurrance of sText
1900 *@param sText The null-terminated string to search for.
1901 *@param iStart The position in the string to start searching from.
1902 *@returns The index of the first occurrance. -1 for not found.
1903 */
1904 long findIdx( const chr *sText, long iStart=0 ) const
1905 {
1906 long nTLen = strlen( sText );
1907 flatten();
1908 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1909 {
1910 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1911 return j;
1912 }
1913 return -1;
1914 }
1915
1916 /**
1917 * Do a reverse search for (sText)
1918 *@param sText (const chr *) The string to search for.
1919 *@returns (long) The index of the last occurrance. -1 for not found.
1920 */
1921 long rfindIdx( const chr *sText ) const
1922 {
1923 long nTLen = strlen( sText );
1924 flatten();
1925 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1926 {
1927 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1928 return j;
1929 }
1930 return -1;
1931 }
1932
1933 /**
1934 * Remove nAmnt bytes from the front of the string. This function
1935 * operates in O(n) time and should be used sparingly.
1936 */
1937 void trimFront( long nAmnt )
1938 {
1939 long nNewLen = core->nLength - nAmnt;
1940 flatten();
1941 Chunk *pNew = core->newChunk( nNewLen );
1942 cpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1943 _hardCopy();
1944 core->clear();
1945 core->appendChunk( pNew );
1946 }
1947
1948 void trimBack( chr c )
1949 {
1950 if( core->pFirst == NULL || core->nLength == 0 )
1951 return;
1952 flatten();
1953 for( ; core->pFirst->nLength > 0 && core->pFirst->pData[core->pFirst->nLength-1] == c; core->pFirst->nLength--, core->nLength-- ) { }
1954 }
1955
1956 MyType &format( const char *sFrmt, ...)
1957 {
1958 _hardCopy();
1959 clear();
1960
1961 va_list ap;
1962 va_start( ap, sFrmt );
1963
1964 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1965
1966 Chunk *pNew = core->newChunk( iLen );
1967 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
1968 core->appendChunk( pNew );
1969
1970 va_end( ap );
1971
1972 return *this;
1973 }
1974
1975 MyType &formatAppend( const char *sFrmt, ...)
1976 {
1977 _hardCopy();
1978 va_list ap;
1979 va_start( ap, sFrmt );
1980
1981 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1982
1983 Chunk *pNew = core->newChunk( iLen );
1984 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
1985 core->appendChunk( pNew );
1986
1987 va_end( ap );
1988
1989 return *this;
1990 }
1991
1992 MyType &formatPrepend( const char *sFrmt, ...)
1993 {
1994 _hardCopy();
1995 va_list ap;
1996 va_start( ap, sFrmt );
1997
1998 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1999
2000 Chunk *pNew = core->newChunk( iLen );
2001 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
2002 core->prependChunk( pNew );
2003
2004 va_end( ap );
2005
2006 return *this;
2007 }
2008
2009 iterator begin()
2010 {
2011 if( core->nLength == 0 )
2012 return iterator( NULL, 0 );
2013 return iterator( core->pFirst, 0 );
2014 }
2015
2016 const_iterator begin() const
2017 {
2018 if( core->nLength == 0 )
2019 return const_iterator( NULL, 0 );
2020 return iterator( core->pFirst, 0 );
2021 }
2022
2023 iterator end()
2024 {
2025 return iterator( NULL, 0 );
2026 }
2027
2028 const_iterator end() const
2029 {
2030 return const_iterator( NULL, 0 );
2031 }
2032
2033 bool isEmpty() const
2034 {
2035 if( core->nLength == 0 )
2036 return true;
2037 return false;
2038 }
2039
2040 private:
2041 void flatten() const
2042 {
2043 if( isFlat() )
2044 return;
2045
2046 if( core->pFirst == NULL || core->nLength == 0 )
2047 return;
2048
2049 Chunk *pNew = core->newChunk( core->nLength );
2050 chr *pos = pNew->pData;
2051 Chunk *i = core->pFirst;
2052 for(;;)
2053 {
2054 cpy( pos, i->pData, i->nLength );
2055 pos += i->nLength;
2056 i = i->pNext;
2057 if( i == NULL )
2058 break;
2059 }
2060 core->clear();
2061
2062 core->pLast = core->pFirst = pNew;
2063 core->nLength = pNew->nLength;
2064 }
2065
2066 bool isFlat() const
2067 {
2068 return (core->pFirst == core->pLast);
2069 }
2070 };
2071
2072 template<class T> FBasicString<T> operator+( const T *pLeft, const FBasicString<T> &rRight )
2073 {
2074 Bu::FBasicString<T> ret( pLeft );
2075 ret.append( rRight );
2076 return ret;
2077 }
2078
2079 template<class chr, int b, class c, class d>
2080 ArchiveBase &operator<<( ArchiveBase &ar, const FBasicString<chr, b, c, d> &s )
2081 {
2082 long n = s.getSize();
2083 ar << n;
2084 ar.write( s.getConstStr(), n );
2085 return ar;
2086 }
2087
2088 template<class chr, int b, class c, class d>
2089 ArchiveBase &operator>>( ArchiveBase &ar, FBasicString<chr, b, c, d> &s )
2090 {
2091 long n;
2092 ar >> n;
2093 s.setSize( n );
2094 ar.read( s.getStr(), n );
2095 return ar;
2096 }
2097}
2098
2099#undef cpy
2100
2101#endif