"L. Spiro Engine"
|
00001 00020 #ifndef __LSTL_STRINGBASE_H__ 00021 #define __LSTL_STRINGBASE_H__ 00022 00023 #include "../LSTLib.h" 00024 #include "../Allocator/LSTLAllocator.h" 00025 #include "../Vector/LSTLVectorPoD.h" 00026 00027 00028 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00029 // MACROS 00030 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00031 // Do we want the operators to throw exceptions? Define this if so. 00032 //#define __LSTL_STRINGS_THROW_EXCEPTIONS__ 00033 00034 #if defined( __LSTL_STRINGS_THROW_EXCEPTIONS__ ) 00035 #define LSTL_STRINGS_THROW_DECL throw( ... ) 00036 #define LSTL_STRINGS_THROW( VAL ) throw( VAL ) 00037 #else 00038 #define LSTL_STRINGS_THROW_DECL 00039 #define LSTL_STRINGS_THROW( VAL ) 00040 #endif // #if defined( __LSTL_STRINGS_THROW_EXCEPTIONS__ ) 00041 00042 00043 namespace lstl { 00044 00045 // == Enumerations. 00046 // String exceptions. 00047 enum LSTL_STRING_EXCEPTIONS { 00048 LSTL_SE_OUTOFMEMORY 00049 }; 00050 00056 template <typename _tDerived, typename _tDataType, unsigned _uAllocSize = 32> 00057 class CStringBase : protected CVectorPoD<_tDataType, LSUINT32, _uAllocSize> { 00058 public : 00059 // == Various constructors. 00060 explicit LSE_CALL CStringBase( CAllocator * _paAllocator = NULL ) : 00061 Parent( _paAllocator ) { 00062 } 00063 LSE_CALL CStringBase( const _tDataType &_dtValue, CAllocator * _paAllocator = NULL ) : 00064 Parent( _paAllocator ) { 00065 Append( _dtValue ); 00066 } 00067 LSE_CALL CStringBase( const _tDataType * _pdtValue, CAllocator * _paAllocator = NULL ) : 00068 Parent( _paAllocator ) { 00069 Set( _pdtValue ); 00070 } 00071 LSE_CALL CStringBase( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString, CAllocator * _paAllocator = NULL ) : 00072 Parent( _paAllocator ) { 00073 Set( _sbString ); 00074 } 00075 00076 00077 // == Types. 00081 typedef struct LSSTD_RANGE { 00085 LSUINT32 ui32Start; 00086 00090 LSUINT32 ui32End; 00091 } * LPLSSTD_RANGE, * const LPCLSSTD_RANGE; 00092 00093 00094 // == Operators. 00095 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00096 // + 00097 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00105 CStringBase<_tDerived, _tDataType, _uAllocSize> LSE_CALL operator + ( const _tDataType &_dtValue ) LSTL_STRINGS_THROW_DECL { 00106 CStringBase sbRet( (*this), Parent::m_paOurAllocator ); 00107 if ( !sbRet.Append( _dtValue ) ) { 00108 LSTL_STRINGS_THROW( LSTL_SE_OUTOFMEMORY ); 00109 } 00110 return sbRet; 00111 } 00112 00120 CStringBase<_tDerived, _tDataType, _uAllocSize> LSE_CALL operator + ( const _tDataType * _pdtValue ) LSTL_STRINGS_THROW_DECL { 00121 CStringBase sbRet( (*this), Parent::m_paOurAllocator ); 00122 if ( !sbRet.Append( _pdtValue ) ) { 00123 LSTL_STRINGS_THROW( LSTL_SE_OUTOFMEMORY ); 00124 } 00125 return sbRet; 00126 } 00127 00135 CStringBase<_tDerived, _tDataType, _uAllocSize> LSE_CALL operator + ( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) LSTL_STRINGS_THROW_DECL { 00136 CStringBase sbRet( (*this), Parent::m_paOurAllocator ); 00137 if ( !sbRet.Append( _sbString ) ) { 00138 LSTL_STRINGS_THROW( LSTL_SE_OUTOFMEMORY ); 00139 } 00140 return sbRet; 00141 } 00142 00143 00144 00145 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00146 // += 00147 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00154 CStringBase<_tDerived, _tDataType, _uAllocSize> & LSE_CALL operator += ( const _tDataType &_dtValue ) LSTL_STRINGS_THROW_DECL { 00155 if ( !Append( _dtValue ) ) { LSTL_STRINGS_THROW( LSTL_SE_OUTOFMEMORY ); } 00156 return (*this); 00157 } 00158 00165 CStringBase<_tDerived, _tDataType, _uAllocSize> & LSE_CALL operator += ( const _tDataType * _pdtValue ) LSTL_STRINGS_THROW_DECL { 00166 if ( !Append( _pdtValue ) ) { LSTL_STRINGS_THROW( LSTL_SE_OUTOFMEMORY ); } 00167 return (*this); 00168 } 00169 00176 CStringBase<_tDerived, _tDataType, _uAllocSize> & LSE_CALL operator += ( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) LSTL_STRINGS_THROW_DECL { 00177 if ( !Append( _sbString ) ) { LSTL_STRINGS_THROW( LSTL_SE_OUTOFMEMORY ); } 00178 return (*this); 00179 } 00180 00181 00182 00183 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00184 // COMPARISONS 00185 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00192 LSBOOL LSE_CALL operator == ( const _tDataType * _pdtValue ) const { 00193 const _tDataType * pdtCopy = _pdtValue; 00194 LSUINT32 ui32Len = 0; 00195 while ( (*pdtCopy) && ui32Len < Length() ) { 00196 if ( (*pdtCopy++) != Parent::m_ptData[ui32Len++] ) { return false; } 00197 } 00198 // One or both of the strings ended. If their lengths are the same, they are equal. 00199 if ( (*pdtCopy) ) { return false; } 00200 return static_cast<LSUINT32>(pdtCopy - _pdtValue) == Length(); 00201 } 00202 00209 LSBOOL LSE_CALL operator == ( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00210 return Equals( _sbString ); 00211 } 00212 00219 LSBOOL LSE_CALL operator != ( const _tDataType * _pdtValue ) const { 00220 const _tDataType * pdtCopy = _pdtValue; 00221 LSUINT32 ui32Len = 0; 00222 while ( (*pdtCopy) && ui32Len < Length() ) { 00223 if ( (*pdtCopy++) != Parent::m_ptData[ui32Len++] ) { return true; } 00224 } 00225 // One or both of the strings ended. If their lengths are the same, they are equal. 00226 return ui32Len != Length(); 00227 } 00228 00235 LSBOOL LSE_CALL operator != ( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00236 return !Equals( _sbString ); 00237 } 00238 00246 LSBOOL LSE_CALL operator < ( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00247 return Cmp( _sbString ) < 0; 00248 } 00249 00257 LSBOOL LSE_CALL operator > ( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00258 return Cmp( _sbString ) > 0; 00259 } 00260 00261 00262 // == Functions. 00263 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00264 // ALLOCATION 00265 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00272 LSBOOL LSE_CALL AllocateAtLeast( LSUINT32 _ui32Total ) { 00273 if ( _ui32Total <= Parent::m_tLen + 1UL ) { return true; } // Nothing to do. 00274 return Parent::Allocate( _ui32Total ); 00275 } 00276 00281 LSVOID LSE_CALL Reset() { Parent::Reset(); } 00282 00287 LSVOID LSE_CALL Trash() { 00288 Parent::m_tLen = Parent::m_tAllocated = 0; 00289 Parent::m_ptData = NULL; 00290 } 00291 00296 LSVOID LSE_CALL ResetNoDealloc() { Parent::ResetNoDealloc(); } 00297 00303 LSVOID LSE_CALL SetAllocator( CAllocator * _paAllocator ) { Parent::SetAllocator( _paAllocator ); } 00304 00310 CAllocator * LSE_CALL GetAllocator() { return Parent::GetAllocator(); } 00311 00317 LSVOID LSE_CALL Snap() { 00318 this->Allocate( Parent::m_tLen + 1 ); 00319 } 00320 00321 00322 00323 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00324 // C-STRING 00325 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00331 LSUINT32 LSE_CALL Length() const { return Parent::Length(); } 00332 00339 const _tDataType * LSE_CALL CStr() const { 00340 // An empty string handles the cases where our string is empty. When our string is 00341 // empty the data pointer may also be NULL. Avoid trouble by returning a valid 0-length 00342 // character array when our length is 0. 00343 static const _tDataType dtDefault( 0 ); 00344 return Length() ? Parent::m_ptData : &dtDefault; 00345 } 00346 00347 00348 00349 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00350 // APPEND/REMOVE/SET 00351 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00359 LSBOOL LSE_CALL Append( const _tDataType &_dtValue ) { 00360 LSUINT32 ui32NewLen = Parent::m_tLen + 2; 00361 if ( ui32NewLen >= Parent::m_tAllocated ) { 00362 if ( !Parent::Allocate( ui32NewLen + _uAllocSize ) ) { return false; } 00363 } 00364 Parent::m_ptData[Parent::m_tLen++] = _dtValue; 00365 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00366 return true; 00367 } 00368 00377 LSBOOL LSE_CALL Append( const _tDataType * _pdtValue, LSUINT32 _ui32Len ) { 00378 LSUINT32 ui32NewLen = Parent::m_tLen + _ui32Len + 1; 00379 if ( ui32NewLen >= Parent::m_tAllocated ) { 00380 if ( !Parent::Allocate( ui32NewLen + _uAllocSize ) ) { return false; } 00381 } 00382 CStd::MemCpy( &Parent::m_ptData[Parent::m_tLen], _pdtValue, sizeof( _tDataType ) * _ui32Len ); 00383 Parent::m_tLen += _ui32Len; 00384 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00385 return true; 00386 } 00387 00395 LSBOOL LSE_CALL Append( const _tDataType * _pdtValue ) { 00396 // Redirect. 00397 return Append( _pdtValue, static_cast<_tDerived *>(this)->StrLen( _pdtValue ) ); 00398 } 00399 00406 LSBOOL LSE_CALL Append( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) { 00407 // Redirect. 00408 return Append( _sbString.Parent::m_ptData, _sbString.Length() ); 00409 } 00410 00416 LSVOID LSE_CALL RemChar( LSUINT32 _ui32Index ) { 00417 if ( _ui32Index >= Length() ) { return; } 00418 Parent::RemoveNoDealloc( _ui32Index ); 00419 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00420 } 00421 00429 LSVOID LSE_CALL RemChars( LSUINT32 _ui32Index, LSUINT32 _ui32Total ) { 00430 if ( _ui32Index >= Length() ) { return; } 00431 if ( _ui32Index + _ui32Total > Length() ) { 00432 _ui32Total = Length() - _ui32Index; 00433 } 00434 Parent::RemoveRangeNoDealloc( _ui32Index, _ui32Total ); 00435 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00436 } 00437 00443 LSVOID LSE_CALL RemRange( const LSSTD_RANGE &_rRange ) { 00444 RemChars( _rRange.ui32Start, _rRange.ui32End - _rRange.ui32Start ); 00445 } 00446 00452 LSBOOL LSE_CALL RemLastChar() { 00453 if ( Parent::m_tLen == 0 ) { return false; } 00454 RemChar( Parent::m_tLen - 1 ); 00455 return true; 00456 } 00457 00466 LSBOOL LSE_CALL Set( const _tDataType * _pdtValue, LSUINT32 _ui32Len ) { 00467 if ( (_ui32Len + 1) > Parent::m_tAllocated ) { 00468 if ( !Parent::Allocate( (_ui32Len + 1) ) ) { return false; } 00469 } 00470 CStd::MemCpy( &Parent::m_ptData[0], _pdtValue, sizeof( _tDataType ) * _ui32Len ); 00471 Parent::m_tLen = _ui32Len; 00472 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00473 return true; 00474 } 00475 00483 LSBOOL LSE_CALL Set( const _tDataType * _pdtValue ) { 00484 return Set( _pdtValue, static_cast<_tDerived *>(this)->StrLen( _pdtValue ) ); 00485 } 00486 00494 LSBOOL LSE_CALL Set( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) { 00495 return Set( _sbString.Parent::m_ptData, _sbString.Length() ); 00496 } 00497 00507 LSBOOL LSE_CALL Replace( const LSSTD_RANGE &_rRange, 00508 const _tDataType * _pdtValue, LSUINT32 _ui32Len ) { 00509 // Firstly, if the start of the range is beyond the last character, do nothing. 00510 if ( _rRange.ui32Start > Parent::m_tLen ) { 00511 return false; 00512 } 00513 // If adding to the end, just append. 00514 if ( _rRange.ui32Start == Parent::m_tLen ) { 00515 return Append( _pdtValue, _ui32Len ); 00516 } 00517 00518 00519 LSUINT32 ui32End = CStd::Min( Parent::m_tLen - _rRange.ui32Start, _rRange.ui32End - _rRange.ui32Start ); 00520 // If the new value has the same length as the old, simply copy the value over. 00521 if ( ui32End == _ui32Len ) { 00522 CStd::MemCpy( &Parent::m_ptData[_rRange.ui32Start], _pdtValue, sizeof( _tDataType ) * _ui32Len ); 00523 return true; 00524 } 00525 // Remove the given range. 00526 RemRange( _rRange ); 00527 // Insert the given string. 00528 return Insert( _rRange.ui32Start, _pdtValue, _ui32Len ); 00529 } 00530 00539 LSBOOL LSE_CALL Replace( const LSSTD_RANGE &_rRange, 00540 const _tDataType * _pdtValue ) { 00541 return Replace( _rRange, _pdtValue, static_cast<_tDerived *>(this)->StrLen( _pdtValue ) ); 00542 } 00543 00553 LSBOOL LSE_CALL Insert( LSUINT32 _ui32Pos, 00554 const _tDataType * _pdtValue, LSUINT32 _ui32Len ) { 00555 if ( !_pdtValue ) { return false; } 00556 if ( _ui32Pos > Parent::m_tLen ) { 00557 return false; 00558 } 00559 if ( _ui32Pos == Parent::m_tLen ) { 00560 return Append( _pdtValue, _ui32Len ); 00561 } 00562 00563 // Expand the string to give us enough room to insert. 00564 LSUINT32 ui32NewLen = Parent::m_tLen + _ui32Len + 1; 00565 if ( ui32NewLen >= Parent::m_tAllocated ) { 00566 if ( !Parent::Allocate( ui32NewLen + _uAllocSize ) ) { return false; } 00567 } 00568 CStd::MemMove( &Parent::m_ptData[_ui32Pos+_ui32Len], &Parent::m_ptData[_ui32Pos], sizeof( _tDataType ) * (Parent::m_tLen - _ui32Pos) ); 00569 CStd::MemCpy( &Parent::m_ptData[_ui32Pos], _pdtValue, sizeof( _tDataType ) * _ui32Len ); 00570 Parent::m_tLen += _ui32Len; 00571 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00572 return true; 00573 } 00574 00583 LSBOOL LSE_CALL Insert( LSUINT32 _ui32Pos, 00584 const _tDataType * _pdtValue ) { 00585 if ( !_pdtValue ) { return false; } 00586 return Insert( _ui32Pos, _pdtValue, StrLen( _pdtValue ) ); 00587 } 00588 00597 LSBOOL LSE_CALL Insert( LSUINT32 _ui32Pos, 00598 _tDataType _dtValue ) { 00599 00600 return Insert( _ui32Pos, &_dtValue, 1UL ); 00601 } 00602 00608 _tDataType LSE_CALL GetLastChar() const { 00609 if ( !Parent::m_tLen ) { return _tDataType( 0 ); } 00610 return Parent::m_ptData[Parent::m_tLen-1]; 00611 } 00612 00620 CStringBase<_tDerived, _tDataType, _uAllocSize> LSE_CALL GetToken( _tDataType _tDelimiter, LSUINT32 _ui32Index ) const { 00621 CStringBase<_tDerived, _tDataType, _uAllocSize> sbRet; 00622 00623 LSUINT32 I = 0UL; 00624 for ( ++_ui32Index; _ui32Index > 0UL; --_ui32Index ) { 00625 if ( I == Parent::m_tLen ) { break; } 00626 00627 // Skip the delimiter tokens, if any. 00628 _tDataType tThis = Parent::m_ptData[I++]; 00629 while ( tThis == _tDelimiter && I < Parent::m_tLen ) { 00630 tThis = Parent::m_ptData[I++]; 00631 } 00632 00633 // The next set of characters make a token until the next delimiter. 00634 // If _ui32Index is 1, we store these characters, otherwise not. 00635 while ( tThis != _tDelimiter ) { 00636 if ( _ui32Index == 1 ) { 00637 sbRet += tThis; 00638 } 00639 00640 if ( I == Parent::m_tLen ) { 00641 break; 00642 } 00643 tThis = Parent::m_ptData[I++]; 00644 } 00645 } 00646 00647 return sbRet; 00648 } 00649 00658 LSSTD_RANGE LSE_CALL FindStringMatchCase( LSUINT32 _ui32Start, 00659 const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00660 LSSTD_RANGE rRet; 00661 rRet.ui32Start = Parent::m_tLen; 00662 rRet.ui32End = 0UL; 00663 00664 // Sanity check. 00665 if ( _sbString.Length() + _ui32Start > Parent::m_tLen || _ui32Start >= Parent::m_tLen ) { 00666 return rRet; 00667 } 00668 00669 rRet.ui32Start = _ui32Start; 00670 LSUINT32 ui32End = Parent::m_tLen - _sbString.Length(); 00671 while ( rRet.ui32Start <= ui32End ) { 00672 if ( CStd::MemCmpF( &Parent::m_ptData[rRet.ui32Start], _sbString.CStr(), sizeof( _tDataType ) * _sbString.Length() ) ) { 00673 rRet.ui32End = rRet.ui32Start + _sbString.Length(); 00674 return rRet; 00675 } 00676 ++rRet.ui32Start; 00677 } 00678 rRet.ui32Start = Parent::m_tLen; 00679 return rRet; 00680 } 00681 00691 LSSTD_RANGE LSE_CALL FindString( LSUINT32 _ui32Start, 00692 const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00693 LSSTD_RANGE rRet; 00694 rRet.ui32Start = Parent::m_tLen; 00695 rRet.ui32End = 0UL; 00696 00697 // Sanity check. 00698 if ( _sbString.Length() + _ui32Start > Parent::m_tLen || _ui32Start >= Parent::m_tLen ) { 00699 return rRet; 00700 } 00701 00702 rRet.ui32Start = _ui32Start; 00703 LSUINT32 ui32End = Parent::m_tLen - _sbString.Length(); 00704 while ( rRet.ui32Start <= ui32End ) { 00705 if ( ICmpSubString( rRet.ui32Start, _sbString ) == 0 ) { 00706 rRet.ui32End = rRet.ui32Start + _sbString.Length(); 00707 return rRet; 00708 } 00709 ++rRet.ui32Start; 00710 } 00711 rRet.ui32Start = Parent::m_tLen; 00712 return rRet; 00713 } 00714 00723 LSSTD_RANGE LSE_CALL FindWildcardStringMatchCase( LSUINT32 _ui32Start, 00724 const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 00725 LSSTD_RANGE rRet; 00726 rRet.ui32Start = Parent::m_tLen; 00727 rRet.ui32End = 0UL; 00728 00729 // Sanity check. 00730 if ( _sbString.Length() + _ui32Start > Parent::m_tLen || _ui32Start >= Parent::m_tLen ) { 00731 return rRet; 00732 } 00733 00734 rRet.ui32Start = _ui32Start; 00735 LSUINT32 ui32End = Parent::m_tLen - _sbString.Length(); 00736 while ( rRet.ui32Start <= ui32End ) { 00737 LSUINT32 ui32Len = CmpWildcard( rRet.ui32Start, _sbString, 2048UL ); 00738 if ( ui32Len ) { 00739 rRet.ui32End = rRet.ui32Start + ui32Len; 00740 return rRet; 00741 } 00742 ++rRet.ui32Start; 00743 } 00744 rRet.ui32Start = Parent::m_tLen; 00745 return rRet; 00746 } 00747 00756 LSUINT32 LSE_CALL FindAndReplaceWildcardStringMatchCase( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbReplaceMe, 00757 const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbWithMe, 00758 LSBOOL _bWholeWords = false ) { 00759 00760 LSSTD_RANGE rRange = { 00761 0UL, 00762 0UL 00763 }; 00764 LSUINT32 ui32Count = 0UL; 00765 while ( rRange.ui32Start < Parent::m_tLen ) { 00766 rRange = FindWildcardStringMatchCase( rRange.ui32Start, _sbReplaceMe ); 00767 if ( rRange.ui32End ) { 00768 if ( !_bWholeWords || IsWholeWord( rRange ) ) { 00769 if ( Replace( rRange, _sbWithMe.CStr(), _sbWithMe.Length() ) ) { 00770 ++ui32Count; 00771 } 00772 } 00773 rRange.ui32Start += _sbWithMe.Length(); 00774 } 00775 } 00776 return ui32Count; 00777 } 00778 00786 LSUINT32 LSE_CALL FindAndReplaceChar( _tDataType _tReplaceMe, _tDataType _tWithMe ) { 00787 LSUINT32 ui32Count = 0UL; 00788 for ( LSUINT32 I = Length(); I--; ) { 00789 if ( Parent::m_ptData[I] == _tReplaceMe ) { 00790 Parent::m_ptData[I] = _tWithMe; 00791 ++ui32Count; 00792 } 00793 } 00794 return ui32Count; 00795 } 00796 00803 LSBOOL LSE_CALL IsWholeWord( LSSTD_RANGE _rRange ) const { 00804 // Firstly, is the range valid? 00805 if ( _rRange.ui32Start >= Parent::m_tLen ) { return true; } 00806 if ( _rRange.ui32End >= Parent::m_tLen ) { return true; } 00807 if ( _rRange.ui32Start >= _rRange.ui32End ) { return false; } 00808 00809 // Try to eliminate by the data to the left of the start. 00810 _tDataType dtValue = Parent::m_ptData[_rRange.ui32Start]; 00811 // If either the left- or the right- most characters are not word characters, return true immediately. 00812 if ( !((dtValue >= static_cast<_tDataType>('a') && dtValue <= static_cast<_tDataType>('z')) || 00813 (dtValue >= static_cast<_tDataType>('A') && dtValue <= static_cast<_tDataType>('Z')) || 00814 (dtValue >= static_cast<_tDataType>('0') && dtValue <= static_cast<_tDataType>('9')) || 00815 dtValue == static_cast<_tDataType>('_')) ) { 00816 return true; 00817 } 00818 dtValue = Parent::m_ptData[_rRange.ui32End-1]; 00819 if ( !((dtValue >= static_cast<_tDataType>('a') && dtValue <= static_cast<_tDataType>('z')) || 00820 (dtValue >= static_cast<_tDataType>('A') && dtValue <= static_cast<_tDataType>('Z')) || 00821 (dtValue >= static_cast<_tDataType>('0') && dtValue <= static_cast<_tDataType>('9')) || 00822 dtValue == static_cast<_tDataType>('_')) ) { 00823 return true; 00824 } 00825 00826 // Both the left and right border characters are word characters, so check the next character to the left and right. 00827 if ( _rRange.ui32Start ) { 00828 dtValue = Parent::m_ptData[_rRange.ui32Start-1]; 00829 if ( ((dtValue >= static_cast<_tDataType>('a') && dtValue <= static_cast<_tDataType>('z')) || 00830 (dtValue >= static_cast<_tDataType>('A') && dtValue <= static_cast<_tDataType>('Z')) || 00831 (dtValue >= static_cast<_tDataType>('0') && dtValue <= static_cast<_tDataType>('9')) || 00832 dtValue == static_cast<_tDataType>('_')) ) { 00833 return false; 00834 } 00835 } 00836 if ( _rRange.ui32End < Parent::m_tLen ) { 00837 dtValue = Parent::m_ptData[_rRange.ui32End]; 00838 if ( ((dtValue >= static_cast<_tDataType>('a') && dtValue <= static_cast<_tDataType>('z')) || 00839 (dtValue >= static_cast<_tDataType>('A') && dtValue <= static_cast<_tDataType>('Z')) || 00840 (dtValue >= static_cast<_tDataType>('0') && dtValue <= static_cast<_tDataType>('9')) || 00841 dtValue == static_cast<_tDataType>('_')) ) { 00842 return false; 00843 } 00844 } 00845 00846 // 00847 return true; 00848 } 00849 00855 CStringBase<_tDerived, _tDataType, _uAllocSize> & LSE_CALL RemoveWhitespace() { 00856 if ( !Parent::m_ptData ) { return (*this); } 00857 00858 // Start at the end of the string since removing characters from there is faster. 00859 while ( Parent::m_tLen && CStd::IsWhitespace( Parent::m_ptData[Parent::m_tLen-1] ) ) { 00860 --Parent::m_tLen; 00861 } 00862 Parent::m_ptData[Parent::m_tLen] = _tDataType( 0 ); 00863 00864 00865 // Count the number of characters from the front that need to be removed. 00866 LSUINT32 ui32Total = 0UL; 00867 for ( ; ui32Total < Parent::m_tLen; ++ui32Total ) { 00868 if ( !CStd::IsWhitespace( Parent::m_ptData[ui32Total] ) ) { break; } 00869 } 00870 if ( ui32Total ) { 00871 RemChars( 0UL, ui32Total ); 00872 } 00873 00874 return (*this); 00875 } 00876 00905 CStringBase<_tDerived, _tDataType, _uAllocSize> LSE_CALL DecodeEscapeSequences() const { 00906 CStringBase<_tDerived, _tDataType, _uAllocSize> sbRet( Parent::m_paOurAllocator ); 00907 00908 LSUINT32 ui32Size; 00909 for ( LSUINT32 I = 0UL; I < Parent::m_tLen; I += ui32Size ) { 00910 sbRet.Append( DecodeEscape( &Parent::m_ptData[I], Parent::m_tLen - I, ui32Size ) ); 00911 } 00912 return sbRet; 00913 } 00914 00923 static _tDataType LSE_CALL DecodeEscape( const _tDataType * _pdtValue, LSUINT32 _ui32Len, LSUINT32 &_ui32Size ) { 00924 struct { 00928 _tDataType dtEscape; 00929 00933 _tDataType dtValue; 00934 } sEscapes[] = { 00935 { 'a', '\a' }, 00936 { 'b', '\b' }, 00937 { 'f', '\f' }, 00938 { 'n', '\n' }, 00939 { 'r', '\r' }, 00940 { 't', '\t' }, 00941 { 'v', '\v' }, 00942 { '\\', '\\' }, 00943 { '\'', '\'' }, 00944 { '"', '\"' }, 00945 { '?', '\?' }, 00946 { ' ', ' ' }, 00947 }; 00948 00949 if ( _ui32Len == 0UL ) { 00950 _ui32Size = 0UL; 00951 return static_cast<_tDataType>(0); 00952 } 00953 // If the length is 1 or the next character is not a back slash, the next character is the return. 00954 _ui32Size = 1UL; 00955 if ( _ui32Len == 1UL || _pdtValue[0] != static_cast<_tDataType>('\\') ) { 00956 return _pdtValue[0]; 00957 } 00958 // Possible sequence here. 00959 switch ( _pdtValue[1] ) { 00960 case 'x' : { 00961 // Hex sequence. Decode. 00962 if ( _ui32Len == 2UL ) { 00963 return _pdtValue[0]; 00964 } 00965 _tDataType dtReturn = 0; 00966 _tDataType dtThis; 00967 // Decode the hex characters (maximum of 2). 00968 for ( LSUINT32 I = 2UL; I < _ui32Len && I < 4UL; I++ ) { 00969 if ( _pdtValue[I] >= static_cast<_tDataType>('0') && _pdtValue[I] <= static_cast<_tDataType>('9') ) { 00970 dtThis = _pdtValue[I] - static_cast<_tDataType>('0'); 00971 } 00972 else if ( _pdtValue[I] >= static_cast<_tDataType>('A') && _pdtValue[I] <= static_cast<_tDataType>('F') ) { 00973 dtThis = _pdtValue[I] - static_cast<_tDataType>('A') + 0xA; 00974 } 00975 else if ( _pdtValue[I] >= static_cast<_tDataType>('a') && _pdtValue[I] <= static_cast<_tDataType>('f') ) { 00976 dtThis = _pdtValue[I] - static_cast<_tDataType>('a') + 0xA; 00977 } 00978 else { 00979 // No characters were eaten? 00980 if ( I == 2 ) { return _pdtValue[0]; } 00981 00982 // Eat the x. 00983 ++_ui32Size; 00984 return dtReturn; 00985 } 00986 dtReturn <<= 4; 00987 dtReturn |= dtThis; 00988 ++_ui32Size; 00989 } 00990 // Eat the x. 00991 ++_ui32Size; 00992 return dtReturn; 00993 } 00994 default : { 00995 if ( _pdtValue[1] >= '0' && _pdtValue[1] <= '7' ) { 00996 // Decode octal sequences. 00997 _tDataType dtReturn = 0; 00998 _tDataType dtThis; 00999 for ( LSUINT32 I = 1UL; I < _ui32Len && I < 4UL; I++ ) { 01000 if ( _pdtValue[I] >= '0' && _pdtValue[I] <= '7' ) { 01001 dtThis = _pdtValue[I] - '0'; 01002 } 01003 else { 01004 // No characters were eaten? 01005 if ( I == 1 ) { return _pdtValue[0]; } 01006 return dtReturn; 01007 } 01008 dtReturn <<= 3UL; 01009 dtReturn |= dtThis; 01010 ++_ui32Size; 01011 } 01012 return dtReturn; 01013 } 01014 else { 01015 for ( LSUINT32 J = 0UL; sEscapes[J].dtEscape != ' '; J++ ) { 01016 if ( _pdtValue[1] == sEscapes[J].dtEscape ) { 01017 ++_ui32Size; 01018 return sEscapes[J].dtValue; 01019 } 01020 } 01021 } 01022 } 01023 } 01024 return _pdtValue[0]; 01025 } 01026 01027 01028 01029 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 01030 // COMPARISONS 01031 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 01045 LSINT32 LSE_CALL Cmp( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 01046 LSUINT32 ui32Max = CStd::Max( _sbString.Length(), Length() ); 01047 for ( LSUINT32 I = 0; I < ui32Max; ++I ) { 01048 _tDataType dtLeft = I < Length() ? Parent::m_ptData[I] : _tDataType( 0 ); 01049 _tDataType dtRight = I < _sbString.Length() ? _sbString.Parent::m_ptData[I] : _tDataType( 0 ); 01050 LSINT32 i32Dif = dtLeft - dtRight; 01051 if ( i32Dif != 0 ) { 01052 // Something somewhere needs a change. They'll need a crane! 01053 return i32Dif; 01054 } 01055 } 01056 if ( _sbString.Length() == Length() ) { return 0; } 01057 return _sbString.Length() > Length() ? -_sbString[Length()] : Parent::m_ptData[_sbString.Length()]; 01058 } 01059 01066 LSINT32 LSE_CALL ICmp( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 01067 LSUINT32 ui32Max = CStd::Max( _sbString.Length(), Length() ); 01068 for ( LSUINT32 I = 0; I < ui32Max; ++I ) { 01069 _tDataType dtLeft = I < Length() ? Parent::m_ptData[I] : _tDataType( 0 ); 01070 _tDataType dtRight = I < _sbString.Length() ? _sbString.Parent::m_ptData[I] : _tDataType( 0 ); 01071 LSINT32 i32Dif = CStd::ToLower( dtLeft ) - CStd::ToLower( dtRight ); 01072 if ( i32Dif != 0 ) { 01073 // Somewhere something needs a change. They'll need a crane! 01074 return i32Dif; 01075 } 01076 } 01077 if ( _sbString.Length() == Length() ) { return 0; } 01078 return _sbString.Length() > Length() ? -_sbString[Length()] : Parent::m_ptData[_sbString.Length()]; 01079 } 01080 01088 LSINT32 LSE_CALL ICmpSubString( LSUINT32 _ui32Loc, 01089 const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 01090 if ( _ui32Loc >= Length() ) { 01091 return -1; 01092 } 01093 LSUINT32 ui32Max = CStd::Min( _sbString.Length(), Length() - _ui32Loc ); 01094 for ( LSUINT32 I = 0; I < ui32Max; ++I ) { 01095 _tDataType dtLeft = I < Length() ? Parent::m_ptData[_ui32Loc+I] : _tDataType( 0 ); 01096 _tDataType dtRight = I < _sbString.Length() ? _sbString.Parent::m_ptData[I] : _tDataType( 0 ); 01097 LSINT32 i32Dif = CStd::ToLower( dtLeft ) - CStd::ToLower( dtRight ); 01098 if ( i32Dif != 0 ) { 01099 // Somewhere something needs a change. They'll need a crane! 01100 return i32Dif; 01101 } 01102 } 01103 return _sbString.Length() == Length() - _ui32Loc; 01104 } 01105 01114 LSUINT32 LSE_CALL CmpWildcard( LSUINT32 _ui32Start, 01115 const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString, LSUINT32 _ui32MaxWildcardLen ) const { 01116 if ( _ui32Start >= Length() ) { 01117 return 0; 01118 } 01119 LSUINT32 ui32BufPos = 0UL; 01120 LSUINT32 I = 0UL; 01121 LSUINT32 ui32Len = Length() - _ui32Start; 01122 _tDataType * pdtBuffer = &Parent::m_ptData[_ui32Start]; 01123 for ( ; I < _sbString.Length(); I++, ui32BufPos++ ) { 01124 if ( ui32BufPos == ui32Len ) { goto End; } 01125 switch ( _sbString.CStr()[I] ) { 01126 case '?' : { continue; } 01127 case '*' : { 01128 // Skip all the * and ? characters. 01129 while ( I < _sbString.Length() && (_sbString.CStr()[I] == static_cast<_tDataType>('*') || _sbString.CStr()[I] == static_cast<_tDataType>('?')) ) { I++; } 01130 if ( I == _sbString.Length() ) { goto End; } 01131 01132 // Within the wildcard match length, find the next character. 01133 LSUINT8 ui8This = _sbString.CStr()[I]; 01134 01135 for ( LSUINT32 J = 0; J < _ui32MaxWildcardLen && ui32BufPos < ui32Len && pdtBuffer[ui32BufPos] != ui8This; ui32BufPos++ ) {} 01136 01137 // If this caused us to reach the end of the buffer, fail. 01138 if ( ui32BufPos == ui32Len ) { return 0UL; } 01139 01140 // Everything is good. 01141 break; 01142 } 01143 default : { 01144 if ( _sbString.CStr()[I] != pdtBuffer[ui32BufPos] ) { return 0UL; } 01145 } 01146 } 01147 } 01148 End : 01149 // Skip all the * characters. 01150 while ( I < _sbString.Length() && _sbString.CStr()[I] == static_cast<_tDataType>('*') ) { I++; } 01151 01152 return I == _sbString.Length() ? ui32BufPos : 0UL; 01153 } 01154 01162 LSBOOL LSE_CALL Equals( const CStringBase<_tDerived, _tDataType, _uAllocSize> &_sbString ) const { 01163 if ( Length() != _sbString.Length() ) { return false; } 01164 return CStd::MemCmpF( Parent::m_ptData, _sbString.Parent::m_ptData, sizeof( _tDataType ) * Length() ); 01165 } 01166 01167 01168 protected : 01169 // == Members. 01170 01171 01172 // == Functions. 01177 LSUINT32 LSE_CALL StrLen( const _tDataType * _pdtValue ) const { 01178 const _tDataType * pdtCopy = _pdtValue; 01179 while ( (*pdtCopy++) ) {} 01180 return static_cast<LSUINT32>((pdtCopy - _pdtValue) - 1); 01181 } 01182 01183 private : 01184 typedef CVectorPoD<_tDataType, LSUINT32, _uAllocSize> Parent; 01185 }; 01186 01187 } // namespace lstl 01188 01189 #endif // __LSTL_STRINGBASE_H__