1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxString class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13   #pragma implementation "string.h" 
  18  *  1) all empty strings use g_strEmpty, nRefs = -1 (set in Init()) 
  19  *  2) AllocBuffer() sets nRefs to 1, Lock() increments it by one 
  20  *  3) Unlock() decrements nRefs and frees memory if it goes to 0 
  23 // =========================================================================== 
  24 // headers, declarations, constants 
  25 // =========================================================================== 
  27 // For compilers that support precompilation, includes "wx.h". 
  28 #include "wx/wxprec.h" 
  36   #include "wx/string.h" 
  38   #include "wx/thread.h" 
  49 // allocating extra space for each string consumes more memory but speeds up 
  50 // the concatenation operations (nLen is the current string's length) 
  51 // NB: EXTRA_ALLOC must be >= 0! 
  52 #define EXTRA_ALLOC       (19 - nLen % 16) 
  54 // --------------------------------------------------------------------------- 
  55 // static class variables definition 
  56 // --------------------------------------------------------------------------- 
  58 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
  59 // must define this static for VA or else you get multiply defined symbols 
  61 const unsigned int wxSTRING_MAXLEN 
= UINT_MAX 
- 100; 
  65   const size_t wxStringBase::npos 
= wxSTRING_MAXLEN
; 
  68 // ---------------------------------------------------------------------------- 
  70 // ---------------------------------------------------------------------------- 
  74 extern const wxChar WXDLLIMPEXP_BASE 
*wxEmptyString 
= _T(""); 
  78 // for an empty string, GetStringData() will return this address: this 
  79 // structure has the same layout as wxStringData and it's data() method will 
  80 // return the empty string (dummy pointer) 
  85 } g_strEmpty 
= { {-1, 0, 0}, wxT('\0') }; 
  87 // empty C style string: points to 'string data' byte of g_strEmpty 
  88 extern const wxChar WXDLLIMPEXP_BASE 
*wxEmptyString 
= &g_strEmpty
.dummy
; 
  92 // ---------------------------------------------------------------------------- 
  94 // ---------------------------------------------------------------------------- 
  96 #if wxUSE_STD_IOSTREAM 
  98 // MS Visual C++ version 5.0 provides the new STL headers as well as the old 
 101 // ATTN: you can _not_ use both of these in the same program! 
 105 wxSTD istream
& operator>>(wxSTD istream
& is
, wxString
& WXUNUSED(str
)) 
 110     streambuf 
*sb 
= is
.rdbuf(); 
 113       int ch 
= sb
->sbumpc (); 
 115         is
.setstate(ios::eofbit
); 
 118       else if ( isspace(ch
) ) { 
 130   if ( str
.length() == 0 ) 
 131     is
.setstate(ios::failbit
); 
 136 wxSTD ostream
& operator<<(wxSTD ostream
& os
, const wxString
& str
) 
 142 #endif // wxUSE_STD_IOSTREAM 
 144 // ---------------------------------------------------------------------------- 
 146 // ---------------------------------------------------------------------------- 
 148 // this small class is used to gather statistics for performance tuning 
 149 //#define WXSTRING_STATISTICS 
 150 #ifdef  WXSTRING_STATISTICS 
 154     Averager(const wxChar 
*sz
) { m_sz 
= sz
; m_nTotal 
= m_nCount 
= 0; } 
 156    { wxPrintf("wxString: average %s = %f\n", m_sz
, ((float)m_nTotal
)/m_nCount
); } 
 158     void Add(size_t n
) { m_nTotal 
+= n
; m_nCount
++; } 
 161     size_t m_nCount
, m_nTotal
; 
 163   } g_averageLength("allocation size"), 
 164     g_averageSummandLength("summand length"), 
 165     g_averageConcatHit("hit probability in concat"), 
 166     g_averageInitialLength("initial string length"); 
 168   #define STATISTICS_ADD(av, val) g_average##av.Add(val) 
 170   #define STATISTICS_ADD(av, val) 
 171 #endif // WXSTRING_STATISTICS 
 175 // =========================================================================== 
 176 // wxStringData class deallocation 
 177 // =========================================================================== 
 179 #if defined(__VISUALC__) && defined(_MT) && !defined(_DLL) 
 180 #  pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!") 
 181 void wxStringData::Free() 
 187 // =========================================================================== 
 189 // =========================================================================== 
 191 // takes nLength elements of psz starting at nPos 
 192 void wxStringBase::InitWith(const wxChar 
*psz
, size_t nPos
, size_t nLength
) 
 196   // if the length is not given, assume the string to be NUL terminated 
 197   if ( nLength 
== npos 
) { 
 198     wxASSERT_MSG( nPos 
<= wxStrlen(psz
), _T("index out of bounds") ); 
 200     nLength 
= wxStrlen(psz 
+ nPos
); 
 203   STATISTICS_ADD(InitialLength
, nLength
); 
 206     // trailing '\0' is written in AllocBuffer() 
 207     if ( !AllocBuffer(nLength
) ) { 
 208       wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); 
 211     memcpy(m_pchData
, psz 
+ nPos
, nLength
*sizeof(wxChar
)); 
 215 // poor man's iterators are "void *" pointers 
 216 wxStringBase::wxStringBase(const void *pStart
, const void *pEnd
) 
 218   InitWith((const wxChar 
*)pStart
, 0, 
 219            (const wxChar 
*)pEnd 
- (const wxChar 
*)pStart
); 
 222 wxStringBase::wxStringBase(size_type n
, wxChar ch
) 
 228 // --------------------------------------------------------------------------- 
 230 // --------------------------------------------------------------------------- 
 232 // allocates memory needed to store a C string of length nLen 
 233 bool wxStringBase::AllocBuffer(size_t nLen
) 
 235   // allocating 0 sized buffer doesn't make sense, all empty strings should 
 237   wxASSERT( nLen 
>  0 ); 
 239   // make sure that we don't overflow 
 240   wxASSERT( nLen 
< (INT_MAX 
/ sizeof(wxChar
)) - 
 241                    (sizeof(wxStringData
) + EXTRA_ALLOC 
+ 1) ); 
 243   STATISTICS_ADD(Length
, nLen
); 
 246   // 1) one extra character for '\0' termination 
 247   // 2) sizeof(wxStringData) for housekeeping info 
 248   wxStringData
* pData 
= (wxStringData
*) 
 249     malloc(sizeof(wxStringData
) + (nLen 
+ EXTRA_ALLOC 
+ 1)*sizeof(wxChar
)); 
 251   if ( pData 
== NULL 
) { 
 252     // allocation failures are handled by the caller 
 257   pData
->nDataLength  
= nLen
; 
 258   pData
->nAllocLength 
= nLen 
+ EXTRA_ALLOC
; 
 259   m_pchData           
= pData
->data();  // data starts after wxStringData 
 260   m_pchData
[nLen
]     = wxT('\0'); 
 264 // must be called before changing this string 
 265 bool wxStringBase::CopyBeforeWrite() 
 267   wxStringData
* pData 
= GetStringData(); 
 269   if ( pData
->IsShared() ) { 
 270     pData
->Unlock();                // memory not freed because shared 
 271     size_t nLen 
= pData
->nDataLength
; 
 272     if ( !AllocBuffer(nLen
) ) { 
 273       // allocation failures are handled by the caller 
 276     memcpy(m_pchData
, pData
->data(), nLen
*sizeof(wxChar
)); 
 279   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 284 // must be called before replacing contents of this string 
 285 bool wxStringBase::AllocBeforeWrite(size_t nLen
) 
 287   wxASSERT( nLen 
!= 0 );  // doesn't make any sense 
 289   // must not share string and must have enough space 
 290   wxStringData
* pData 
= GetStringData(); 
 291   if ( pData
->IsShared() || pData
->IsEmpty() ) { 
 292     // can't work with old buffer, get new one 
 294     if ( !AllocBuffer(nLen
) ) { 
 295       // allocation failures are handled by the caller 
 300     if ( nLen 
> pData
->nAllocLength 
) { 
 301       // realloc the buffer instead of calling malloc() again, this is more 
 303       STATISTICS_ADD(Length
, nLen
); 
 307       pData 
= (wxStringData
*) 
 308           realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(wxChar
)); 
 310       if ( pData 
== NULL 
) { 
 311         // allocation failures are handled by the caller 
 312         // keep previous data since reallocation failed 
 316       pData
->nAllocLength 
= nLen
; 
 317       m_pchData 
= pData
->data(); 
 320     // now we have enough space, just update the string length 
 321     pData
->nDataLength 
= nLen
; 
 324   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 329 wxStringBase
& wxStringBase::append(size_t n
, wxChar ch
) 
 331     size_type len 
= length(); 
 333     if ( !CopyBeforeWrite() || !Alloc(len 
+ n
) ) { 
 334       wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); 
 336     GetStringData()->nDataLength 
= len 
+ n
; 
 337     m_pchData
[len 
+ n
] = '\0'; 
 338     for ( size_t i 
= 0; i 
< n
; ++i 
) 
 339         m_pchData
[len 
+ i
] = ch
; 
 343 void wxStringBase::resize(size_t nSize
, wxChar ch
) 
 345     size_t len 
= length(); 
 349         erase(begin() + nSize
, end()); 
 351     else if ( nSize 
> len 
) 
 353         append(nSize 
- len
, ch
); 
 355     //else: we have exactly the specified length, nothing to do 
 358 // allocate enough memory for nLen characters 
 359 bool wxStringBase::Alloc(size_t nLen
) 
 361   wxStringData 
*pData 
= GetStringData(); 
 362   if ( pData
->nAllocLength 
<= nLen 
) { 
 363     if ( pData
->IsEmpty() ) { 
 366       wxStringData
* pData 
= (wxStringData
*) 
 367           malloc(sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(wxChar
)); 
 369       if ( pData 
== NULL 
) { 
 370         // allocation failure handled by caller 
 375       pData
->nDataLength 
= 0; 
 376       pData
->nAllocLength 
= nLen
; 
 377       m_pchData 
= pData
->data();  // data starts after wxStringData 
 378       m_pchData
[0u] = wxT('\0'); 
 380     else if ( pData
->IsShared() ) { 
 381       pData
->Unlock();                // memory not freed because shared 
 382       size_t nOldLen 
= pData
->nDataLength
; 
 383       if ( !AllocBuffer(nLen
) ) { 
 384         // allocation failure handled by caller 
 387       memcpy(m_pchData
, pData
->data(), nOldLen
*sizeof(wxChar
)); 
 392       pData 
= (wxStringData 
*) 
 393         realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(wxChar
)); 
 395       if ( pData 
== NULL 
) { 
 396         // allocation failure handled by caller 
 397         // keep previous data since reallocation failed 
 401       // it's not important if the pointer changed or not (the check for this 
 402       // is not faster than assigning to m_pchData in all cases) 
 403       pData
->nAllocLength 
= nLen
; 
 404       m_pchData 
= pData
->data(); 
 407   //else: we've already got enough 
 411 wxStringBase::iterator 
wxStringBase::erase(iterator it
) 
 413     size_type idx 
= it 
- begin(); 
 415     return begin() + idx
; 
 418 wxStringBase
& wxStringBase::erase(size_t nStart
, size_t nLen
) 
 420   wxASSERT(nStart 
<= length()); 
 421   size_t strLen 
= length() - nStart
; 
 422   // delete nLen or up to the end of the string characters 
 423   nLen 
= strLen 
< nLen 
? strLen 
: nLen
; 
 424   wxString 
strTmp(c_str(), nStart
); 
 425   strTmp
.append(c_str() + nStart 
+ nLen
, length() - nStart 
- nLen
); 
 431 wxStringBase
& wxStringBase::insert(size_t nPos
, const wxChar 
*sz
, size_t n
) 
 433   wxASSERT( nPos 
<= length() ); 
 435   if ( n 
== npos 
) n 
= wxStrlen(sz
); 
 436   if ( n 
== 0 ) return *this; 
 438   if ( !CopyBeforeWrite() || !Alloc(length() + n
) ) { 
 439     wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); 
 442   memmove(m_pchData 
+ nPos 
+ n
, m_pchData 
+ nPos
, 
 443           (length() - nPos
) * sizeof(wxChar
)); 
 444   memcpy(m_pchData 
+ nPos
, sz
, n 
* sizeof(wxChar
)); 
 445   GetStringData()->nDataLength 
= length() + n
; 
 446   m_pchData
[length()] = '\0'; 
 451 void wxStringBase::swap(wxStringBase
& str
) 
 453     wxChar
* tmp 
= str
.m_pchData
; 
 454     str
.m_pchData 
= m_pchData
; 
 458 size_t wxStringBase::find(const wxStringBase
& str
, size_t nStart
) const 
 460   wxASSERT( str
.GetStringData()->IsValid() ); 
 461   wxASSERT( nStart 
<= length() ); 
 463   const wxChar 
*p 
= wxStrstr(c_str() + nStart
, str
.c_str()); 
 465   return p 
== NULL 
? npos 
: p 
- c_str(); 
 468 size_t wxStringBase::find(const wxChar
* sz
, size_t nStart
, size_t n
) const 
 470   return find(wxStringBase(sz
, n
), nStart
); 
 473 size_t wxStringBase::find(wxChar ch
, size_t nStart
) const 
 475   wxASSERT( nStart 
<= length() ); 
 477   const wxChar 
*p 
= wxStrchr(c_str() + nStart
, ch
); 
 479   return p 
== NULL 
? npos 
: p 
- c_str(); 
 482 size_t wxStringBase::rfind(const wxStringBase
& str
, size_t nStart
) const 
 484     wxASSERT( str
.GetStringData()->IsValid() ); 
 485     wxASSERT( nStart 
== npos 
|| nStart 
<= length() ); 
 487     if ( length() >= str
.length() ) 
 489         // avoids a corner case later 
 490         if ( length() == 0 && str
.length() == 0 ) 
 493         // "top" is the point where search starts from 
 494         size_t top 
= length() - str
.length(); 
 496         if ( nStart 
== npos 
) 
 497             nStart 
= length() - 1; 
 501         const wxChar 
*cursor 
= c_str() + top
; 
 504             if ( memcmp(cursor
, str
.c_str(), 
 505                         str
.length() * sizeof(wxChar
)) == 0 ) 
 507                 return cursor 
- c_str(); 
 509         } while ( cursor
-- > c_str() ); 
 515 size_t wxStringBase::rfind(const wxChar
* sz
, size_t nStart
, size_t n
) const 
 517     return rfind(wxStringBase(sz
, n
), nStart
); 
 520 size_t wxStringBase::rfind(wxChar ch
, size_t nStart
) const 
 522     if ( nStart 
== npos 
) 
 528         wxASSERT( nStart 
<= length() ); 
 531     const wxChar 
*actual
; 
 532     for ( actual 
= c_str() + ( nStart 
== npos 
? length() : nStart 
+ 1 ); 
 533           actual 
> c_str(); --actual 
) 
 535         if ( *(actual 
- 1) == ch 
) 
 536             return (actual 
- 1) - c_str(); 
 542 size_t wxStringBase::find_first_of(const wxChar
* sz
, size_t nStart
) const 
 544     const wxChar 
*start 
= c_str() + nStart
; 
 545     const wxChar 
*firstOf 
= wxStrpbrk(start
, sz
); 
 547         return firstOf 
- c_str(); 
 552 size_t wxStringBase::find_first_of(const wxChar
* sz
, size_t nStart
, 
 555     return find_first_of(wxStringBase(sz
, n
), nStart
); 
 558 size_t wxStringBase::find_last_of(const wxChar
* sz
, size_t nStart
) const 
 560     if ( nStart 
== npos 
) 
 562         nStart 
= length() - 1; 
 566         wxASSERT_MSG( nStart 
<= length(), 
 567                         _T("invalid index in find_last_of()") ); 
 570     for ( const wxChar 
*p 
= c_str() + nStart
; p 
>= c_str(); --p 
) 
 572         if ( wxStrchr(sz
, *p
) ) 
 579 size_t wxStringBase::find_last_of(const wxChar
* sz
, size_t nStart
, 
 582     return find_last_of(wxStringBase(sz
, n
), nStart
); 
 585 size_t wxStringBase::find_first_not_of(const wxChar
* sz
, size_t nStart
) const 
 587     if ( nStart 
== npos 
) 
 593         wxASSERT( nStart 
<= length() ); 
 596     size_t nAccept 
= wxStrspn(c_str() + nStart
, sz
); 
 597     if ( nAccept 
>= length() - nStart 
) 
 600         return nStart 
+ nAccept
; 
 603 size_t wxStringBase::find_first_not_of(const wxChar
* sz
, size_t nStart
, 
 606     return find_first_not_of(wxStringBase(sz
, n
), nStart
); 
 609 size_t wxStringBase::find_first_not_of(wxChar ch
, size_t nStart
) const 
 611     wxASSERT( nStart 
<= length() ); 
 613     for ( const wxChar 
*p 
= c_str() + nStart
; *p
; p
++ ) 
 622 size_t wxStringBase::find_last_not_of(const wxChar
* sz
, size_t nStart
) const 
 624     if ( nStart 
== npos 
) 
 626         nStart 
= length() - 1; 
 630         wxASSERT( nStart 
<= length() ); 
 633     for ( const wxChar 
*p 
= c_str() + nStart
; p 
>= c_str(); --p 
) 
 635         if ( !wxStrchr(sz
, *p
) ) 
 642 size_t wxStringBase::find_last_not_of(const wxChar
* sz
, size_t nStart
, 
 645     return find_last_not_of(wxStringBase(sz
, n
), nStart
); 
 648 size_t wxStringBase::find_last_not_of(wxChar ch
, size_t nStart
) const 
 650     if ( nStart 
== npos 
) 
 652         nStart 
= length() - 1; 
 656         wxASSERT( nStart 
<= length() ); 
 659     for ( const wxChar 
*p 
= c_str() + nStart
; p 
>= c_str(); --p 
) 
 668 wxStringBase
& wxStringBase::replace(size_t nStart
, size_t nLen
, 
 671   wxASSERT_MSG( nStart 
<= length(), 
 672                 _T("index out of bounds in wxStringBase::replace") ); 
 673   size_t strLen 
= length() - nStart
; 
 674   nLen 
= strLen 
< nLen 
? strLen 
: nLen
; 
 677   strTmp
.reserve(length()); // micro optimisation to avoid multiple mem allocs 
 680     strTmp
.append(c_str(), nStart
); 
 682   strTmp
.append(c_str() + nStart 
+ nLen
); 
 688 wxStringBase
& wxStringBase::replace(size_t nStart
, size_t nLen
, 
 689                                     size_t nCount
, wxChar ch
) 
 691   return replace(nStart
, nLen
, wxStringBase(ch
, nCount
).c_str()); 
 694 wxStringBase
& wxStringBase::replace(size_t nStart
, size_t nLen
, 
 695                                     const wxStringBase
& str
, 
 696                                     size_t nStart2
, size_t nLen2
) 
 698   return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
)); 
 701 wxStringBase
& wxStringBase::replace(size_t nStart
, size_t nLen
, 
 702                                     const wxChar
* sz
, size_t nCount
) 
 704   return replace(nStart
, nLen
, wxStringBase(sz
, nCount
).c_str()); 
 707 wxStringBase 
wxStringBase::substr(size_t nStart
, size_t nLen
) const 
 710     nLen 
= length() - nStart
; 
 711   return wxStringBase(*this, nStart
, nLen
); 
 714 // assigns one string to another 
 715 wxStringBase
& wxStringBase::operator=(const wxStringBase
& stringSrc
) 
 717   wxASSERT( stringSrc
.GetStringData()->IsValid() ); 
 719   // don't copy string over itself 
 720   if ( m_pchData 
!= stringSrc
.m_pchData 
) { 
 721     if ( stringSrc
.GetStringData()->IsEmpty() ) { 
 726       GetStringData()->Unlock(); 
 727       m_pchData 
= stringSrc
.m_pchData
; 
 728       GetStringData()->Lock(); 
 735 // assigns a single character 
 736 wxStringBase
& wxStringBase::operator=(wxChar ch
) 
 738   if ( !AssignCopy(1, &ch
) ) { 
 739     wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); 
 745 wxStringBase
& wxStringBase::operator=(const wxChar 
*psz
) 
 747   if ( !AssignCopy(wxStrlen(psz
), psz
) ) { 
 748     wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); 
 753 // helper function: does real copy 
 754 bool wxStringBase::AssignCopy(size_t nSrcLen
, const wxChar 
*pszSrcData
) 
 756   if ( nSrcLen 
== 0 ) { 
 760     if ( !AllocBeforeWrite(nSrcLen
) ) { 
 761       // allocation failure handled by caller 
 764     memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(wxChar
)); 
 765     GetStringData()->nDataLength 
= nSrcLen
; 
 766     m_pchData
[nSrcLen
] = wxT('\0'); 
 771 // --------------------------------------------------------------------------- 
 772 // string concatenation 
 773 // --------------------------------------------------------------------------- 
 775 // add something to this string 
 776 bool wxStringBase::ConcatSelf(size_t nSrcLen
, const wxChar 
*pszSrcData
, 
 779   STATISTICS_ADD(SummandLength
, nSrcLen
); 
 781   nSrcLen 
= nSrcLen 
< nMaxLen 
? nSrcLen 
: nMaxLen
; 
 783   // concatenating an empty string is a NOP 
 785     wxStringData 
*pData 
= GetStringData(); 
 786     size_t nLen 
= pData
->nDataLength
; 
 787     size_t nNewLen 
= nLen 
+ nSrcLen
; 
 789     // alloc new buffer if current is too small 
 790     if ( pData
->IsShared() ) { 
 791       STATISTICS_ADD(ConcatHit
, 0); 
 793       // we have to allocate another buffer 
 794       wxStringData
* pOldData 
= GetStringData(); 
 795       if ( !AllocBuffer(nNewLen
) ) { 
 796           // allocation failure handled by caller 
 799       memcpy(m_pchData
, pOldData
->data(), nLen
*sizeof(wxChar
)); 
 802     else if ( nNewLen 
> pData
->nAllocLength 
) { 
 803       STATISTICS_ADD(ConcatHit
, 0); 
 806       // we have to grow the buffer 
 807       if ( capacity() < nNewLen 
) { 
 808           // allocation failure handled by caller 
 813       STATISTICS_ADD(ConcatHit
, 1); 
 815       // the buffer is already big enough 
 818     // should be enough space 
 819     wxASSERT( nNewLen 
<= GetStringData()->nAllocLength 
); 
 821     // fast concatenation - all is done in our buffer 
 822     memcpy(m_pchData 
+ nLen
, pszSrcData
, nSrcLen
*sizeof(wxChar
)); 
 824     m_pchData
[nNewLen
] = wxT('\0');          // put terminating '\0' 
 825     GetStringData()->nDataLength 
= nNewLen
; // and fix the length 
 827   //else: the string to append was empty 
 831 // --------------------------------------------------------------------------- 
 832 // simple sub-string extraction 
 833 // --------------------------------------------------------------------------- 
 835 // helper function: clone the data attached to this string 
 836 bool wxStringBase::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const 
 838   if ( nCopyLen 
== 0 ) { 
 842     if ( !dest
.AllocBuffer(nCopyLen
) ) { 
 843       // allocation failure handled by caller 
 846     memcpy(dest
.m_pchData
, m_pchData 
+ nCopyIndex
, nCopyLen
*sizeof(wxChar
)); 
 853 #if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) 
 856     #define STRINGCLASS wxStringBase 
 858     #define STRINGCLASS wxString 
 861 static inline int wxDoCmp(const wxChar
* s1
, size_t l1
, 
 862                           const wxChar
* s2
, size_t l2
) 
 865         return wxStrncmp(s1
, s2
, l1
); 
 868         int ret 
= wxStrncmp(s1
, s2
, l1
); 
 869         return ret 
== 0 ? -1 : ret
; 
 873         int ret 
= wxStrncmp(s1
, s2
, l2
); 
 874         return ret 
== 0 ? +1 : ret
; 
 877     wxFAIL
;   // must never get there 
 878     return 0; // quiet compilers 
 883 int STRINGCLASS::compare(const wxStringBase
& str
) const 
 885     return ::wxDoCmp(data(), length(), str
.data(), str
.length()); 
 890 int STRINGCLASS::compare(size_t nStart
, size_t nLen
, 
 891                          const wxStringBase
& str
) const 
 893     wxASSERT(nStart 
<= length()); 
 894     size_type strLen 
= length() - nStart
; 
 895     nLen 
= strLen 
< nLen 
? strLen 
: nLen
; 
 896     return ::wxDoCmp(data() + nStart
, nLen
, str
.data(), str
.length()); 
 899 int STRINGCLASS::compare(size_t nStart
, size_t nLen
, 
 900                          const wxStringBase
& str
, 
 901                          size_t nStart2
, size_t nLen2
) const 
 903     wxASSERT(nStart 
<= length()); 
 904     wxASSERT(nStart2 
<= str
.length()); 
 905     size_type strLen  
=     length() - nStart
, 
 906               strLen2 
= str
.length() - nStart2
; 
 907     nLen  
= strLen  
< nLen  
? strLen  
: nLen
; 
 908     nLen2 
= strLen2 
< nLen2 
? strLen2 
: nLen2
; 
 909     return ::wxDoCmp(data() + nStart
, nLen
, str
.data() + nStart2
, nLen2
); 
 914 int STRINGCLASS::compare(const wxChar
* sz
) const 
 916     size_t nLen 
= wxStrlen(sz
); 
 917     return ::wxDoCmp(data(), length(), sz
, nLen
); 
 922 int STRINGCLASS::compare(size_t nStart
, size_t nLen
, 
 923                          const wxChar
* sz
, size_t nCount
) const 
 925     wxASSERT(nStart 
<= length()); 
 926     size_type strLen 
= length() - nStart
; 
 927     nLen 
= strLen 
< nLen 
? strLen 
: nLen
; 
 929         nCount 
= wxStrlen(sz
); 
 931     return ::wxDoCmp(data() + nStart
, nLen
, sz
, nCount
); 
 936 #endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) 
 938 // =========================================================================== 
 939 // wxString class core 
 940 // =========================================================================== 
 942 // --------------------------------------------------------------------------- 
 944 // --------------------------------------------------------------------------- 
 948 // from multibyte string 
 949 wxString::wxString(const char *psz
, wxMBConv
& conv
, size_t nLength
) 
 951     // first get the size of the buffer we need 
 955         // calculate the needed size ourselves or use the provided one 
 956         nLen 
= nLength 
== npos 
? conv
.MB2WC(NULL
, psz
, 0) : nLength
; 
 960         // nothing to convert 
 965     if ( (nLen 
!= 0) && (nLen 
!= (size_t)-1) ) 
 969             wxFAIL_MSG( _T("out of memory in wxString::wxString") ); 
 973             wxWCharBuffer 
buf(nLen 
+ 1); 
 974             // MB2WC wants the buffer size, not the string length hence +1 
 975             nLen 
= conv
.MB2WC(buf
.data(), psz
, nLen 
+ 1); 
 977             if ( nLen 
!= (size_t)-1 ) 
 979                 // initialized ok, set the real length as nLength specified by 
 980                 // the caller could be greater than the real string length 
 981                 assign(buf
.data(), nLen
); 
 984             //else: the conversion failed -- leave the string empty (what else?) 
 993 wxString::wxString(const wchar_t *pwz
, wxMBConv
& conv
, size_t nLength
) 
 995     // first get the size of the buffer we need 
 999         // calculate the needed size ourselves or use the provided one 
1000         nLen 
= nLength 
== npos 
? conv
.WC2MB(NULL
, pwz
, 0) : nLength
; 
1004         // nothing to convert 
1009     if ( (nLen 
!= 0) && (nLen 
!= (size_t)-1) ) 
1013             wxFAIL_MSG( _T("out of memory in wxString::wxString") ); 
1017             wxCharBuffer 
buf(nLen
); 
1018             // WC2MB wants the buffer size, not the string length 
1019             if ( conv
.WC2MB(buf
.data(), pwz
, nLen 
+ 1) != (size_t)-1 ) 
1022                 assign(buf
.data(), nLen
); 
1025             //else: the conversion failed -- leave the string empty (what else?) 
1031 #endif // wxUSE_WCHAR_T 
1033 #endif // Unicode/ANSI 
1035 // shrink to minimal size (releasing extra memory) 
1036 bool wxString::Shrink() 
1038   wxString 
tmp(begin(), end()); 
1040   return tmp
.length() == length(); 
1044 // get the pointer to writable buffer of (at least) nLen bytes 
1045 wxChar 
*wxString::GetWriteBuf(size_t nLen
) 
1047   if ( !AllocBeforeWrite(nLen
) ) { 
1048     // allocation failure handled by caller 
1052   wxASSERT( GetStringData()->nRefs 
== 1 ); 
1053   GetStringData()->Validate(FALSE
); 
1058 // put string back in a reasonable state after GetWriteBuf 
1059 void wxString::UngetWriteBuf() 
1061   GetStringData()->nDataLength 
= wxStrlen(m_pchData
); 
1062   GetStringData()->Validate(TRUE
); 
1065 void wxString::UngetWriteBuf(size_t nLen
) 
1067   GetStringData()->nDataLength 
= nLen
; 
1068   GetStringData()->Validate(TRUE
); 
1072 // --------------------------------------------------------------------------- 
1074 // --------------------------------------------------------------------------- 
1076 // all functions are inline in string.h 
1078 // --------------------------------------------------------------------------- 
1079 // assignment operators 
1080 // --------------------------------------------------------------------------- 
1084 // same as 'signed char' variant 
1085 wxString
& wxString::operator=(const unsigned char* psz
) 
1087   *this = (const char *)psz
; 
1092 wxString
& wxString::operator=(const wchar_t *pwz
) 
1103  * concatenation functions come in 5 flavours: 
1105  *  char   + string      and      string + char 
1106  *  C str  + string      and      string + C str 
1109 wxString 
operator+(const wxString
& str1
, const wxString
& str2
) 
1112   wxASSERT( str1
.GetStringData()->IsValid() ); 
1113   wxASSERT( str2
.GetStringData()->IsValid() ); 
1122 wxString 
operator+(const wxString
& str
, wxChar ch
) 
1125   wxASSERT( str
.GetStringData()->IsValid() ); 
1134 wxString 
operator+(wxChar ch
, const wxString
& str
) 
1137   wxASSERT( str
.GetStringData()->IsValid() ); 
1146 wxString 
operator+(const wxString
& str
, const wxChar 
*psz
) 
1149   wxASSERT( str
.GetStringData()->IsValid() ); 
1153   if ( !s
.Alloc(wxStrlen(psz
) + str
.Len()) ) { 
1154     wxFAIL_MSG( _T("out of memory in wxString::operator+") ); 
1162 wxString 
operator+(const wxChar 
*psz
, const wxString
& str
) 
1165   wxASSERT( str
.GetStringData()->IsValid() ); 
1169   if ( !s
.Alloc(wxStrlen(psz
) + str
.Len()) ) { 
1170     wxFAIL_MSG( _T("out of memory in wxString::operator+") ); 
1178 // =========================================================================== 
1179 // other common string functions 
1180 // =========================================================================== 
1184 wxString 
wxString::FromAscii(const char *ascii
) 
1187        return wxEmptyString
; 
1189     size_t len 
= strlen( ascii 
); 
1194         wxStringBuffer 
buf(res
, len
); 
1196         wchar_t *dest 
= buf
; 
1200            if ( (*dest
++ = (wchar_t)(unsigned char)*ascii
++) == L
'\0' ) 
1208 wxString 
wxString::FromAscii(const char ascii
) 
1210     // What do we do with '\0' ? 
1213     res 
+= (wchar_t)(unsigned char) ascii
; 
1218 const wxCharBuffer 
wxString::ToAscii() const 
1220     // this will allocate enough space for the terminating NUL too 
1221     wxCharBuffer 
buffer(length()); 
1223     signed char *dest 
= (signed char *)buffer
.data(); 
1225     const wchar_t *pwc 
= c_str(); 
1228         *dest
++ = *pwc 
> SCHAR_MAX 
? '_' : *pwc
; 
1230         // the output string can't have embedded NULs anyhow, so we can safely 
1231         // stop at first of them even if we do have any 
1241 // extract string of length nCount starting at nFirst 
1242 wxString 
wxString::Mid(size_t nFirst
, size_t nCount
) const 
1244   size_t nLen 
= length(); 
1246   // default value of nCount is npos and means "till the end" 
1247   if ( nCount 
== npos 
) 
1249     nCount 
= nLen 
- nFirst
; 
1252   // out-of-bounds requests return sensible things 
1253   if ( nFirst 
+ nCount 
> nLen 
) 
1255     nCount 
= nLen 
- nFirst
; 
1258   if ( nFirst 
> nLen 
) 
1260     // AllocCopy() will return empty string 
1264   wxString 
dest(*this, nFirst
, nCount
); 
1265   if ( dest
.length() != nCount 
) { 
1266       wxFAIL_MSG( _T("out of memory in wxString::Mid") ); 
1272 // check that the string starts with prefix and return the rest of the string 
1273 // in the provided pointer if it is not NULL, otherwise return FALSE 
1274 bool wxString::StartsWith(const wxChar 
*prefix
, wxString 
*rest
) const 
1276     wxASSERT_MSG( prefix
, _T("invalid parameter in wxString::StartsWith") ); 
1278     // first check if the beginning of the string matches the prefix: note 
1279     // that we don't have to check that we don't run out of this string as 
1280     // when we reach the terminating NUL, either prefix string ends too (and 
1281     // then it's ok) or we break out of the loop because there is no match 
1282     const wxChar 
*p 
= c_str(); 
1285         if ( *prefix
++ != *p
++ ) 
1294         // put the rest of the string into provided pointer 
1301 // extract nCount last (rightmost) characters 
1302 wxString 
wxString::Right(size_t nCount
) const 
1304   if ( nCount 
> length() ) 
1307   wxString 
dest(*this, length() - nCount
, nCount
); 
1308   if ( dest
.length() != nCount 
) { 
1309     wxFAIL_MSG( _T("out of memory in wxString::Right") ); 
1314 // get all characters after the last occurence of ch 
1315 // (returns the whole string if ch not found) 
1316 wxString 
wxString::AfterLast(wxChar ch
) const 
1319   int iPos 
= Find(ch
, TRUE
); 
1320   if ( iPos 
== wxNOT_FOUND 
) 
1323     str 
= c_str() + iPos 
+ 1; 
1328 // extract nCount first (leftmost) characters 
1329 wxString 
wxString::Left(size_t nCount
) const 
1331   if ( nCount 
> length() ) 
1334   wxString 
dest(*this, 0, nCount
); 
1335   if ( dest
.length() != nCount 
) { 
1336     wxFAIL_MSG( _T("out of memory in wxString::Left") ); 
1341 // get all characters before the first occurence of ch 
1342 // (returns the whole string if ch not found) 
1343 wxString 
wxString::BeforeFirst(wxChar ch
) const 
1345   int iPos 
= Find(ch
); 
1346   if ( iPos 
== wxNOT_FOUND 
) iPos 
= length(); 
1347   return wxString(*this, 0, iPos
); 
1350 /// get all characters before the last occurence of ch 
1351 /// (returns empty string if ch not found) 
1352 wxString 
wxString::BeforeLast(wxChar ch
) const 
1355   int iPos 
= Find(ch
, TRUE
); 
1356   if ( iPos 
!= wxNOT_FOUND 
&& iPos 
!= 0 ) 
1357     str 
= wxString(c_str(), iPos
); 
1362 /// get all characters after the first occurence of ch 
1363 /// (returns empty string if ch not found) 
1364 wxString 
wxString::AfterFirst(wxChar ch
) const 
1367   int iPos 
= Find(ch
); 
1368   if ( iPos 
!= wxNOT_FOUND 
) 
1369     str 
= c_str() + iPos 
+ 1; 
1374 // replace first (or all) occurences of some substring with another one 
1376 wxString::Replace(const wxChar 
*szOld
, const wxChar 
*szNew
, bool bReplaceAll
) 
1378     // if we tried to replace an empty string we'd enter an infinite loop below 
1379     wxCHECK_MSG( szOld 
&& *szOld 
&& szNew
, 0, 
1380                  _T("wxString::Replace(): invalid parameter") ); 
1382   size_t uiCount 
= 0;   // count of replacements made 
1384   size_t uiOldLen 
= wxStrlen(szOld
); 
1387   const wxChar 
*pCurrent 
= c_str(); 
1388   const wxChar 
*pSubstr
; 
1389   while ( *pCurrent 
!= wxT('\0') ) { 
1390     pSubstr 
= wxStrstr(pCurrent
, szOld
); 
1391     if ( pSubstr 
== NULL 
) { 
1392       // strTemp is unused if no replacements were made, so avoid the copy 
1396       strTemp 
+= pCurrent
;    // copy the rest 
1397       break;                  // exit the loop 
1400       // take chars before match 
1401       size_type len 
= strTemp
.length(); 
1402       strTemp
.append(pCurrent
, pSubstr 
- pCurrent
); 
1403       if ( strTemp
.length() != (size_t)(len 
+ pSubstr 
- pCurrent
) ) { 
1404         wxFAIL_MSG( _T("out of memory in wxString::Replace") ); 
1408       pCurrent 
= pSubstr 
+ uiOldLen
;  // restart after match 
1413       if ( !bReplaceAll 
) { 
1414         strTemp 
+= pCurrent
;    // copy the rest 
1415         break;                  // exit the loop 
1420   // only done if there were replacements, otherwise would have returned above 
1426 bool wxString::IsAscii() const 
1428   const wxChar 
*s 
= (const wxChar
*) *this; 
1430     if(!isascii(*s
)) return(FALSE
); 
1436 bool wxString::IsWord() const 
1438   const wxChar 
*s 
= (const wxChar
*) *this; 
1440     if(!wxIsalpha(*s
)) return(FALSE
); 
1446 bool wxString::IsNumber() const 
1448   const wxChar 
*s 
= (const wxChar
*) *this; 
1450      if ((s
[0] == '-') || (s
[0] == '+')) s
++; 
1452     if(!wxIsdigit(*s
)) return(FALSE
); 
1458 wxString 
wxString::Strip(stripType w
) const 
1461     if ( w 
& leading 
) s
.Trim(FALSE
); 
1462     if ( w 
& trailing 
) s
.Trim(TRUE
); 
1466 // --------------------------------------------------------------------------- 
1468 // --------------------------------------------------------------------------- 
1470 wxString
& wxString::MakeUpper() 
1472   for ( iterator it 
= begin(), en 
= end(); it 
!= en
; ++it 
) 
1473     *it 
= (wxChar
)wxToupper(*it
); 
1478 wxString
& wxString::MakeLower() 
1480   for ( iterator it 
= begin(), en 
= end(); it 
!= en
; ++it 
) 
1481     *it 
= (wxChar
)wxTolower(*it
); 
1486 // --------------------------------------------------------------------------- 
1487 // trimming and padding 
1488 // --------------------------------------------------------------------------- 
1490 // some compilers (VC++ 6.0 not to name them) return TRUE for a call to 
1491 // isspace('ê') in the C locale which seems to be broken to me, but we have to 
1492 // live with this by checking that the character is a 7 bit one - even if this 
1493 // may fail to detect some spaces (I don't know if Unicode doesn't have 
1494 // space-like symbols somewhere except in the first 128 chars), it is arguably 
1495 // still better than trimming away accented letters 
1496 inline int wxSafeIsspace(wxChar ch
) { return (ch 
< 127) && wxIsspace(ch
); } 
1498 // trims spaces (in the sense of isspace) from left or right side 
1499 wxString
& wxString::Trim(bool bFromRight
) 
1501   // first check if we're going to modify the string at all 
1504         (bFromRight 
&& wxSafeIsspace(GetChar(Len() - 1))) || 
1505         (!bFromRight 
&& wxSafeIsspace(GetChar(0u))) 
1511       // find last non-space character 
1512       iterator psz 
= begin() + length() - 1; 
1513       while ( wxSafeIsspace(*psz
) && (psz 
>= begin()) ) 
1516       // truncate at trailing space start 
1522       // find first non-space character 
1523       iterator psz 
= begin(); 
1524       while ( wxSafeIsspace(*psz
) ) 
1527       // fix up data and length 
1528       erase(begin(), psz
); 
1535 // adds nCount characters chPad to the string from either side 
1536 wxString
& wxString::Pad(size_t nCount
, wxChar chPad
, bool bFromRight
) 
1538   wxString 
s(chPad
, nCount
); 
1551 // truncate the string 
1552 wxString
& wxString::Truncate(size_t uiLen
) 
1554   if ( uiLen 
< Len() ) { 
1555     erase(begin() + uiLen
, end()); 
1557   //else: nothing to do, string is already short enough 
1562 // --------------------------------------------------------------------------- 
1563 // finding (return wxNOT_FOUND if not found and index otherwise) 
1564 // --------------------------------------------------------------------------- 
1567 int wxString::Find(wxChar ch
, bool bFromEnd
) const 
1569   size_type idx 
= bFromEnd 
? find_last_of(ch
) : find_first_of(ch
); 
1571   return (idx 
== npos
) ? wxNOT_FOUND 
: (int)idx
; 
1574 // find a sub-string (like strstr) 
1575 int wxString::Find(const wxChar 
*pszSub
) const 
1577   size_type idx 
= find(pszSub
); 
1579   return (idx 
== npos
) ? wxNOT_FOUND 
: (int)idx
; 
1582 // ---------------------------------------------------------------------------- 
1583 // conversion to numbers 
1584 // ---------------------------------------------------------------------------- 
1586 bool wxString::ToLong(long *val
, int base
) const 
1588     wxCHECK_MSG( val
, FALSE
, _T("NULL pointer in wxString::ToLong") ); 
1589     wxASSERT_MSG( !base 
|| (base 
> 1 && base 
<= 36), _T("invalid base") ); 
1591     const wxChar 
*start 
= c_str(); 
1593     *val 
= wxStrtol(start
, &end
, base
); 
1595     // return TRUE only if scan was stopped by the terminating NUL and if the 
1596     // string was not empty to start with 
1597     return !*end 
&& (end 
!= start
); 
1600 bool wxString::ToULong(unsigned long *val
, int base
) const 
1602     wxCHECK_MSG( val
, FALSE
, _T("NULL pointer in wxString::ToULong") ); 
1603     wxASSERT_MSG( !base 
|| (base 
> 1 && base 
<= 36), _T("invalid base") ); 
1605     const wxChar 
*start 
= c_str(); 
1607     *val 
= wxStrtoul(start
, &end
, base
); 
1609     // return TRUE only if scan was stopped by the terminating NUL and if the 
1610     // string was not empty to start with 
1611     return !*end 
&& (end 
!= start
); 
1614 bool wxString::ToDouble(double *val
) const 
1616     wxCHECK_MSG( val
, FALSE
, _T("NULL pointer in wxString::ToDouble") ); 
1618     const wxChar 
*start 
= c_str(); 
1620     *val 
= wxStrtod(start
, &end
); 
1622     // return TRUE only if scan was stopped by the terminating NUL and if the 
1623     // string was not empty to start with 
1624     return !*end 
&& (end 
!= start
); 
1627 // --------------------------------------------------------------------------- 
1629 // --------------------------------------------------------------------------- 
1632 wxString 
wxString::Format(const wxChar 
*pszFormat
, ...) 
1635     va_start(argptr
, pszFormat
); 
1638     s
.PrintfV(pszFormat
, argptr
); 
1646 wxString 
wxString::FormatV(const wxChar 
*pszFormat
, va_list argptr
) 
1649     s
.PrintfV(pszFormat
, argptr
); 
1653 int wxString::Printf(const wxChar 
*pszFormat
, ...) 
1656   va_start(argptr
, pszFormat
); 
1658   int iLen 
= PrintfV(pszFormat
, argptr
); 
1665 int wxString::PrintfV(const wxChar
* pszFormat
, va_list argptr
) 
1673             wxStringBuffer 
tmp(*this, size 
+ 1); 
1682             len 
= wxVsnprintf(buf
, size
, pszFormat
, argptr
); 
1684             // some implementations of vsnprintf() don't NUL terminate 
1685             // the string if there is not enough space for it so 
1686             // always do it manually 
1687             buf
[size
] = _T('\0'); 
1690         // vsnprintf() may return either -1 (traditional Unix behaviour) or the 
1691         // total number of characters which would have been written if the 
1692         // buffer were large enough 
1693         if ( len 
>= 0 && len 
<= size 
) 
1695             // ok, there was enough space 
1699         // still not enough, double it again 
1703     // we could have overshot 
1709 // ---------------------------------------------------------------------------- 
1710 // misc other operations 
1711 // ---------------------------------------------------------------------------- 
1713 // returns TRUE if the string matches the pattern which may contain '*' and 
1714 // '?' metacharacters (as usual, '?' matches any character and '*' any number 
1716 bool wxString::Matches(const wxChar 
*pszMask
) const 
1718     // I disable this code as it doesn't seem to be faster (in fact, it seems 
1719     // to be much slower) than the old, hand-written code below and using it 
1720     // here requires always linking with libregex even if the user code doesn't 
1722 #if 0 // wxUSE_REGEX 
1723     // first translate the shell-like mask into a regex 
1725     pattern
.reserve(wxStrlen(pszMask
)); 
1737                 pattern 
+= _T(".*"); 
1748                 // these characters are special in a RE, quote them 
1749                 // (however note that we don't quote '[' and ']' to allow 
1750                 // using them for Unix shell like matching) 
1751                 pattern 
+= _T('\\'); 
1755                 pattern 
+= *pszMask
; 
1763     return wxRegEx(pattern
, wxRE_NOSUB 
| wxRE_EXTENDED
).Matches(c_str()); 
1764 #else // !wxUSE_REGEX 
1765   // TODO: this is, of course, awfully inefficient... 
1767   // the char currently being checked 
1768   const wxChar 
*pszTxt 
= c_str(); 
1770   // the last location where '*' matched 
1771   const wxChar 
*pszLastStarInText 
= NULL
; 
1772   const wxChar 
*pszLastStarInMask 
= NULL
; 
1775   for ( ; *pszMask 
!= wxT('\0'); pszMask
++, pszTxt
++ ) { 
1776     switch ( *pszMask 
) { 
1778         if ( *pszTxt 
== wxT('\0') ) 
1781         // pszTxt and pszMask will be incremented in the loop statement 
1787           // remember where we started to be able to backtrack later 
1788           pszLastStarInText 
= pszTxt
; 
1789           pszLastStarInMask 
= pszMask
; 
1791           // ignore special chars immediately following this one 
1792           // (should this be an error?) 
1793           while ( *pszMask 
== wxT('*') || *pszMask 
== wxT('?') ) 
1796           // if there is nothing more, match 
1797           if ( *pszMask 
== wxT('\0') ) 
1800           // are there any other metacharacters in the mask? 
1802           const wxChar 
*pEndMask 
= wxStrpbrk(pszMask
, wxT("*?")); 
1804           if ( pEndMask 
!= NULL 
) { 
1805             // we have to match the string between two metachars 
1806             uiLenMask 
= pEndMask 
- pszMask
; 
1809             // we have to match the remainder of the string 
1810             uiLenMask 
= wxStrlen(pszMask
); 
1813           wxString 
strToMatch(pszMask
, uiLenMask
); 
1814           const wxChar
* pMatch 
= wxStrstr(pszTxt
, strToMatch
); 
1815           if ( pMatch 
== NULL 
) 
1818           // -1 to compensate "++" in the loop 
1819           pszTxt 
= pMatch 
+ uiLenMask 
- 1; 
1820           pszMask 
+= uiLenMask 
- 1; 
1825         if ( *pszMask 
!= *pszTxt 
) 
1831   // match only if nothing left 
1832   if ( *pszTxt 
== wxT('\0') ) 
1835   // if we failed to match, backtrack if we can 
1836   if ( pszLastStarInText 
) { 
1837     pszTxt 
= pszLastStarInText 
+ 1; 
1838     pszMask 
= pszLastStarInMask
; 
1840     pszLastStarInText 
= NULL
; 
1842     // don't bother resetting pszLastStarInMask, it's unnecessary 
1848 #endif // wxUSE_REGEX/!wxUSE_REGEX 
1851 // Count the number of chars 
1852 int wxString::Freq(wxChar ch
) const 
1856     for (int i 
= 0; i 
< len
; i
++) 
1858         if (GetChar(i
) == ch
) 
1864 // convert to upper case, return the copy of the string 
1865 wxString 
wxString::Upper() const 
1866 { wxString 
s(*this); return s
.MakeUpper(); } 
1868 // convert to lower case, return the copy of the string 
1869 wxString 
wxString::Lower() const { wxString 
s(*this); return s
.MakeLower(); } 
1871 int wxString::sprintf(const wxChar 
*pszFormat
, ...) 
1874     va_start(argptr
, pszFormat
); 
1875     int iLen 
= PrintfV(pszFormat
, argptr
); 
1880 // ============================================================================ 
1882 // ============================================================================ 
1884 #include "wx/arrstr.h" 
1888 // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) 
1889 #define   ARRAY_MAXSIZE_INCREMENT       4096 
1891 #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h 
1892 #define   ARRAY_DEFAULT_INITIAL_SIZE    (16) 
1895 #define   STRING(p)   ((wxString *)(&(p))) 
1898 void wxArrayString::Init(bool autoSort
) 
1902   m_pItems 
= (wxChar 
**) NULL
; 
1903   m_autoSort 
= autoSort
; 
1907 wxArrayString::wxArrayString(const wxArrayString
& src
) 
1909   Init(src
.m_autoSort
); 
1914 // assignment operator 
1915 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
) 
1922   m_autoSort 
= src
.m_autoSort
; 
1927 void wxArrayString::Copy(const wxArrayString
& src
) 
1929   if ( src
.m_nCount 
> ARRAY_DEFAULT_INITIAL_SIZE 
) 
1930     Alloc(src
.m_nCount
); 
1932   for ( size_t n 
= 0; n 
< src
.m_nCount
; n
++ ) 
1937 void wxArrayString::Grow(size_t nIncrement
) 
1939   // only do it if no more place 
1940   if ( (m_nSize 
- m_nCount
) < nIncrement 
) { 
1941     // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would 
1942     // be never resized! 
1943     #if ARRAY_DEFAULT_INITIAL_SIZE == 0 
1944       #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" 
1947     if ( m_nSize 
== 0 ) { 
1948       // was empty, alloc some memory 
1949       m_nSize 
= ARRAY_DEFAULT_INITIAL_SIZE
; 
1950       if (m_nSize 
< nIncrement
) 
1951           m_nSize 
= nIncrement
; 
1952       m_pItems 
= new wxChar 
*[m_nSize
]; 
1955       // otherwise when it's called for the first time, nIncrement would be 0 
1956       // and the array would never be expanded 
1957       // add 50% but not too much 
1958       size_t ndefIncrement 
= m_nSize 
< ARRAY_DEFAULT_INITIAL_SIZE
 
1959                           ? ARRAY_DEFAULT_INITIAL_SIZE 
: m_nSize 
>> 1; 
1960       if ( ndefIncrement 
> ARRAY_MAXSIZE_INCREMENT 
) 
1961         ndefIncrement 
= ARRAY_MAXSIZE_INCREMENT
; 
1962       if ( nIncrement 
< ndefIncrement 
) 
1963         nIncrement 
= ndefIncrement
; 
1964       m_nSize 
+= nIncrement
; 
1965       wxChar 
**pNew 
= new wxChar 
*[m_nSize
]; 
1967       // copy data to new location 
1968       memcpy(pNew
, m_pItems
, m_nCount
*sizeof(wxChar 
*)); 
1970       // delete old memory (but do not release the strings!) 
1971       wxDELETEA(m_pItems
); 
1978 void wxArrayString::Free() 
1980   for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) { 
1981     STRING(m_pItems
[n
])->GetStringData()->Unlock(); 
1985 // deletes all the strings from the list 
1986 void wxArrayString::Empty() 
1993 // as Empty, but also frees memory 
1994 void wxArrayString::Clear() 
2001   wxDELETEA(m_pItems
); 
2005 wxArrayString::~wxArrayString() 
2009   wxDELETEA(m_pItems
); 
2012 void wxArrayString::reserve(size_t nSize
) 
2017 // pre-allocates memory (frees the previous data!) 
2018 void wxArrayString::Alloc(size_t nSize
) 
2020   // only if old buffer was not big enough 
2021   if ( nSize 
> m_nSize 
) { 
2023     wxDELETEA(m_pItems
); 
2024     m_pItems 
= new wxChar 
*[nSize
]; 
2031 // minimizes the memory usage by freeing unused memory 
2032 void wxArrayString::Shrink() 
2034   // only do it if we have some memory to free 
2035   if( m_nCount 
< m_nSize 
) { 
2036     // allocates exactly as much memory as we need 
2037     wxChar 
**pNew 
= new wxChar 
*[m_nCount
]; 
2039     // copy data to new location 
2040     memcpy(pNew
, m_pItems
, m_nCount
*sizeof(wxChar 
*)); 
2046 #if WXWIN_COMPATIBILITY_2_4 
2048 // return a wxString[] as required for some control ctors. 
2049 wxString
* wxArrayString::GetStringArray() const 
2051     wxString 
*array 
= 0; 
2055         array 
= new wxString
[m_nCount
]; 
2056         for( size_t i 
= 0; i 
< m_nCount
; i
++ ) 
2057             array
[i
] = m_pItems
[i
]; 
2063 #endif // WXWIN_COMPATIBILITY_2_4 
2065 // searches the array for an item (forward or backwards) 
2066 int wxArrayString::Index(const wxChar 
*sz
, bool bCase
, bool bFromEnd
) const 
2069     // use binary search in the sorted array 
2070     wxASSERT_MSG( bCase 
&& !bFromEnd
, 
2071                   wxT("search parameters ignored for auto sorted array") ); 
2080       res 
= wxStrcmp(sz
, m_pItems
[i
]); 
2092     // use linear search in unsorted array 
2094       if ( m_nCount 
> 0 ) { 
2095         size_t ui 
= m_nCount
; 
2097           if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) ) 
2104       for( size_t ui 
= 0; ui 
< m_nCount
; ui
++ ) { 
2105         if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) ) 
2114 // add item at the end 
2115 size_t wxArrayString::Add(const wxString
& str
, size_t nInsert
) 
2118     // insert the string at the correct position to keep the array sorted 
2126       res 
= wxStrcmp(str
, m_pItems
[i
]); 
2137     wxASSERT_MSG( lo 
== hi
, wxT("binary search broken") ); 
2139     Insert(str
, lo
, nInsert
); 
2144     wxASSERT( str
.GetStringData()->IsValid() ); 
2148     for (size_t i 
= 0; i 
< nInsert
; i
++) 
2150         // the string data must not be deleted! 
2151         str
.GetStringData()->Lock(); 
2154         m_pItems
[m_nCount 
+ i
] = (wxChar 
*)str
.c_str(); // const_cast 
2156     size_t ret 
= m_nCount
; 
2157     m_nCount 
+= nInsert
; 
2162 // add item at the given position 
2163 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
, size_t nInsert
) 
2165   wxASSERT( str
.GetStringData()->IsValid() ); 
2167   wxCHECK_RET( nIndex 
<= m_nCount
, wxT("bad index in wxArrayString::Insert") ); 
2168   wxCHECK_RET( m_nCount 
<= m_nCount 
+ nInsert
, 
2169                wxT("array size overflow in wxArrayString::Insert") ); 
2173   memmove(&m_pItems
[nIndex 
+ nInsert
], &m_pItems
[nIndex
], 
2174           (m_nCount 
- nIndex
)*sizeof(wxChar 
*)); 
2176   for (size_t i 
= 0; i 
< nInsert
; i
++) 
2178       str
.GetStringData()->Lock(); 
2179       m_pItems
[nIndex 
+ i
] = (wxChar 
*)str
.c_str(); 
2181   m_nCount 
+= nInsert
; 
2185 void wxArrayString::SetCount(size_t count
) 
2190     while ( m_nCount 
< count 
) 
2191         m_pItems
[m_nCount
++] = (wxChar 
*)s
.c_str(); 
2194 // removes item from array (by index) 
2195 void wxArrayString::RemoveAt(size_t nIndex
, size_t nRemove
) 
2197   wxCHECK_RET( nIndex 
< m_nCount
, wxT("bad index in wxArrayString::Remove") ); 
2198   wxCHECK_RET( nIndex 
+ nRemove 
<= m_nCount
, 
2199                wxT("removing too many elements in wxArrayString::Remove") ); 
2202   for (size_t i 
= 0; i 
< nRemove
; i
++) 
2203       Item(nIndex 
+ i
).GetStringData()->Unlock(); 
2205   memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex 
+ nRemove
], 
2206           (m_nCount 
- nIndex 
- nRemove
)*sizeof(wxChar 
*)); 
2207   m_nCount 
-= nRemove
; 
2210 // removes item from array (by value) 
2211 void wxArrayString::Remove(const wxChar 
*sz
) 
2213   int iIndex 
= Index(sz
); 
2215   wxCHECK_RET( iIndex 
!= wxNOT_FOUND
, 
2216                wxT("removing inexistent element in wxArrayString::Remove") ); 
2221 void wxArrayString::assign(const_iterator first
, const_iterator last
) 
2223     reserve(last 
- first
); 
2224     for(; first 
!= last
; ++first
) 
2228 // ---------------------------------------------------------------------------- 
2230 // ---------------------------------------------------------------------------- 
2232 // we can only sort one array at a time with the quick-sort based 
2235   // need a critical section to protect access to gs_compareFunction and 
2236   // gs_sortAscending variables 
2237   static wxCriticalSection 
*gs_critsectStringSort 
= NULL
; 
2239   // call this before the value of the global sort vars is changed/after 
2240   // you're finished with them 
2241   #define START_SORT()     wxASSERT( !gs_critsectStringSort );                \ 
2242                            gs_critsectStringSort = new wxCriticalSection;     \ 
2243                            gs_critsectStringSort->Enter() 
2244   #define END_SORT()       gs_critsectStringSort->Leave();                    \ 
2245                            delete gs_critsectStringSort;                      \ 
2246                            gs_critsectStringSort = NULL 
2248   #define START_SORT() 
2250 #endif // wxUSE_THREADS 
2252 // function to use for string comparaison 
2253 static wxArrayString::CompareFunction gs_compareFunction 
= NULL
; 
2255 // if we don't use the compare function, this flag tells us if we sort the 
2256 // array in ascending or descending order 
2257 static bool gs_sortAscending 
= TRUE
; 
2259 // function which is called by quick sort 
2260 extern "C" int wxC_CALLING_CONV     
// LINKAGEMODE 
2261 wxStringCompareFunction(const void *first
, const void *second
) 
2263   wxString 
*strFirst 
= (wxString 
*)first
; 
2264   wxString 
*strSecond 
= (wxString 
*)second
; 
2266   if ( gs_compareFunction 
) { 
2267     return gs_compareFunction(*strFirst
, *strSecond
); 
2270     // maybe we should use wxStrcoll 
2271     int result 
= wxStrcmp(strFirst
->c_str(), strSecond
->c_str()); 
2273     return gs_sortAscending 
? result 
: -result
; 
2277 // sort array elements using passed comparaison function 
2278 void wxArrayString::Sort(CompareFunction compareFunction
) 
2282   wxASSERT( !gs_compareFunction 
);  // must have been reset to NULL 
2283   gs_compareFunction 
= compareFunction
; 
2287   // reset it to NULL so that Sort(bool) will work the next time 
2288   gs_compareFunction 
= NULL
; 
2293 typedef  int (wxC_CALLING_CONV 
* wxStringCompareFn
)(const void *first
, const void *second
); 
2295 void wxArrayString::Sort(CompareFunction2 compareFunction
) 
2297   qsort(m_pItems
, m_nCount
, sizeof(wxChar 
*), (wxStringCompareFn
)compareFunction
); 
2300 void wxArrayString::Sort(bool reverseOrder
) 
2302   Sort(reverseOrder 
? wxStringSortDescending 
: wxStringSortAscending
); 
2305 void wxArrayString::DoSort() 
2307   wxCHECK_RET( !m_autoSort
, wxT("can't use this method with sorted arrays") ); 
2309   // just sort the pointers using qsort() - of course it only works because 
2310   // wxString() *is* a pointer to its data 
2311   qsort(m_pItems
, m_nCount
, sizeof(wxChar 
*), wxStringCompareFunction
); 
2314 bool wxArrayString::operator==(const wxArrayString
& a
) const 
2316     if ( m_nCount 
!= a
.m_nCount 
) 
2319     for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) 
2321         if ( Item(n
) != a
[n
] ) 
2328 #endif // !wxUSE_STL 
2330 int wxCMPFUNC_CONV 
wxStringSortAscending(wxString
* s1
, wxString
* s2
) 
2332     return wxStrcmp(s1
->c_str(), s2
->c_str()); 
2335 int wxCMPFUNC_CONV 
wxStringSortDescending(wxString
* s1
, wxString
* s2
) 
2337     return -wxStrcmp(s1
->c_str(), s2
->c_str());