1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxString class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  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" 
  50   #include <wchar.h>    // for wcsrtombs(), see comments where it's used 
  53 #ifdef  WXSTRING_IS_WXOBJECT 
  54   IMPLEMENT_DYNAMIC_CLASS(wxString
, wxObject
) 
  55 #endif  //WXSTRING_IS_WXOBJECT 
  58 #undef wxUSE_EXPERIMENTAL_PRINTF 
  59 #define wxUSE_EXPERIMENTAL_PRINTF 1 
  62 // allocating extra space for each string consumes more memory but speeds up 
  63 // the concatenation operations (nLen is the current string's length) 
  64 // NB: EXTRA_ALLOC must be >= 0! 
  65 #define EXTRA_ALLOC       (19 - nLen % 16) 
  67 // --------------------------------------------------------------------------- 
  68 // static class variables definition 
  69 // --------------------------------------------------------------------------- 
  71 #ifdef  wxSTD_STRING_COMPATIBILITY 
  72   const size_t wxString::npos 
= wxSTRING_MAXLEN
; 
  73 #endif // wxSTD_STRING_COMPATIBILITY 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  79 // for an empty string, GetStringData() will return this address: this 
  80 // structure has the same layout as wxStringData and it's data() method will 
  81 // return the empty string (dummy pointer) 
  86 } g_strEmpty 
= { {-1, 0, 0}, wxT('\0') }; 
  88 #if defined(__VISAGECPP__) && __IBMCPP__ >= 400 
  89 // must define this static for VA or else you get multiply defined symbols 
  91 const unsigned int wxSTRING_MAXLEN 
= UINT_MAX 
- 100; 
  94 // empty C style string: points to 'string data' byte of g_strEmpty 
  95 extern const wxChar WXDLLEXPORT 
*wxEmptyString 
= &g_strEmpty
.dummy
; 
  97 // ---------------------------------------------------------------------------- 
  98 // conditional compilation 
  99 // ---------------------------------------------------------------------------- 
 101 #if !defined(__WXSW__) && wxUSE_UNICODE 
 102   #ifdef wxUSE_EXPERIMENTAL_PRINTF 
 103     #undef wxUSE_EXPERIMENTAL_PRINTF 
 105   #define wxUSE_EXPERIMENTAL_PRINTF 1 
 108 // we want to find out if the current platform supports vsnprintf()-like 
 109 // function: for Unix this is done with configure, for Windows we test the 
 110 // compiler explicitly. 
 112 // FIXME currently, this is only for ANSI (!Unicode) strings, so we call this 
 113 //       function wxVsnprintfA (A for ANSI), should also find one for Unicode 
 114 //       strings in Unicode build 
 116     #if defined(__VISUALC__) || (defined(__MINGW32__) && wxUSE_NORLANDER_HEADERS) 
 117         #define wxVsnprintfA     _vsnprintf 
 119 #elif defined(__WXMAC__) 
 120     #define wxVsnprintfA       vsnprintf 
 122     #ifdef HAVE_VSNPRINTF 
 123         #define wxVsnprintfA       vsnprintf 
 125 #endif  // Windows/!Windows 
 128     // in this case we'll use vsprintf() (which is ANSI and thus should be 
 129     // always available), but it's unsafe because it doesn't check for buffer 
 130     // size - so give a warning 
 131     #define wxVsnprintfA(buf, len, format, arg) vsprintf(buf, format, arg) 
 133     #if defined(__VISUALC__) 
 134         #pragma message("Using sprintf() because no snprintf()-like function defined") 
 135     #elif defined(__GNUG__) 
 136         #warning "Using sprintf() because no snprintf()-like function defined" 
 138 #endif // no vsnprintf 
 141   // AIX has vsnprintf, but there's no prototype in the system headers. 
 142   extern "C" int vsnprintf(char* str
, size_t n
, const char* format
, va_list ap
); 
 145 // ---------------------------------------------------------------------------- 
 147 // ---------------------------------------------------------------------------- 
 149 #if defined(wxSTD_STRING_COMPATIBILITY) && wxUSE_STD_IOSTREAM 
 151 // MS Visual C++ version 5.0 provides the new STL headers as well as the old 
 154 // ATTN: you can _not_ use both of these in the same program! 
 156 wxSTD istream
& operator>>(wxSTD istream
& is
, wxString
& WXUNUSED(str
)) 
 161     streambuf 
*sb 
= is
.rdbuf(); 
 164       int ch 
= sb
->sbumpc (); 
 166         is
.setstate(ios::eofbit
); 
 169       else if ( isspace(ch
) ) { 
 181   if ( str
.length() == 0 ) 
 182     is
.setstate(ios::failbit
); 
 187 wxSTD ostream
& operator<<(wxSTD ostream
& os
, const wxString
& str
) 
 193 #endif  //std::string compatibility 
 195 extern int WXDLLEXPORT 
wxVsnprintf(wxChar 
*buf
, size_t len
, 
 196                                    const wxChar 
*format
, va_list argptr
) 
 199     // FIXME should use wvsnprintf() or whatever if it's available 
 201     int iLen 
= s
.PrintfV(format
, argptr
); 
 204         wxStrncpy(buf
, s
.c_str(), len
); 
 205         buf
[len
-1] = wxT('\0'); 
 210     // vsnprintf() will not terminate the string with '\0' if there is not 
 211     // enough place, but we want the string to always be NUL terminated 
 212     int rc 
= wxVsnprintfA(buf
, len 
- 1, format
, argptr
); 
 219 #endif // Unicode/ANSI 
 222 extern int WXDLLEXPORT 
wxSnprintf(wxChar 
*buf
, size_t len
, 
 223                                   const wxChar 
*format
, ...) 
 226     va_start(argptr
, format
); 
 228     int iLen 
= wxVsnprintf(buf
, len
, format
, argptr
); 
 235 // ---------------------------------------------------------------------------- 
 237 // ---------------------------------------------------------------------------- 
 239 // this small class is used to gather statistics for performance tuning 
 240 //#define WXSTRING_STATISTICS 
 241 #ifdef  WXSTRING_STATISTICS 
 245     Averager(const char *sz
) { m_sz 
= sz
; m_nTotal 
= m_nCount 
= 0; } 
 247    { printf("wxString: average %s = %f\n", m_sz
, ((float)m_nTotal
)/m_nCount
); } 
 249     void Add(size_t n
) { m_nTotal 
+= n
; m_nCount
++; } 
 252     size_t m_nCount
, m_nTotal
; 
 254   } g_averageLength("allocation size"), 
 255     g_averageSummandLength("summand length"), 
 256     g_averageConcatHit("hit probability in concat"), 
 257     g_averageInitialLength("initial string length"); 
 259   #define STATISTICS_ADD(av, val) g_average##av.Add(val) 
 261   #define STATISTICS_ADD(av, val) 
 262 #endif // WXSTRING_STATISTICS 
 264 // =========================================================================== 
 265 // wxString class core 
 266 // =========================================================================== 
 268 // --------------------------------------------------------------------------- 
 270 // --------------------------------------------------------------------------- 
 272 // constructs string of <nLength> copies of character <ch> 
 273 wxString::wxString(wxChar ch
, size_t nLength
) 
 278     AllocBuffer(nLength
); 
 281     // memset only works on char 
 282     for (size_t n
=0; n
<nLength
; n
++) m_pchData
[n
] = ch
; 
 284     memset(m_pchData
, ch
, nLength
); 
 289 // takes nLength elements of psz starting at nPos 
 290 void wxString::InitWith(const wxChar 
*psz
, size_t nPos
, size_t nLength
) 
 294   // if the length is not given, assume the string to be NUL terminated 
 295   if ( nLength 
== wxSTRING_MAXLEN 
) { 
 296     wxASSERT_MSG( nPos 
<= wxStrlen(psz
), _T("index out of bounds") ); 
 298     nLength 
= wxStrlen(psz 
+ nPos
); 
 301   STATISTICS_ADD(InitialLength
, nLength
); 
 304     // trailing '\0' is written in AllocBuffer() 
 305     AllocBuffer(nLength
); 
 306     memcpy(m_pchData
, psz 
+ nPos
, nLength
*sizeof(wxChar
)); 
 310 #ifdef  wxSTD_STRING_COMPATIBILITY 
 312 // poor man's iterators are "void *" pointers 
 313 wxString::wxString(const void *pStart
, const void *pEnd
) 
 315   InitWith((const wxChar 
*)pStart
, 0, 
 316            (const wxChar 
*)pEnd 
- (const wxChar 
*)pStart
); 
 319 #endif  //std::string compatibility 
 323 // from multibyte string 
 324 wxString::wxString(const char *psz
, wxMBConv
& conv
, size_t nLength
) 
 326   // first get necessary size 
 327   size_t nLen 
= psz 
? conv
.MB2WC((wchar_t *) NULL
, psz
, 0) : 0; 
 329   // nLength is number of *Unicode* characters here! 
 330   if ((nLen 
!= (size_t)-1) && (nLen 
> nLength
)) 
 334   if ( (nLen 
!= 0) && (nLen 
!= (size_t)-1) ) { 
 336     conv
.MB2WC(m_pchData
, psz
, nLen
); 
 347 wxString::wxString(const wchar_t *pwz
, wxMBConv
& conv
) 
 349   // first get necessary size 
 350   size_t nLen 
= pwz 
? conv
.WC2MB((char *) NULL
, pwz
, 0) : 0; 
 353   if ( (nLen 
!= 0) && (nLen 
!= (size_t)-1) ) { 
 355     conv
.WC2MB(m_pchData
, pwz
, nLen
); 
 361 #endif // wxUSE_WCHAR_T 
 363 #endif // Unicode/ANSI 
 365 // --------------------------------------------------------------------------- 
 367 // --------------------------------------------------------------------------- 
 369 // allocates memory needed to store a C string of length nLen 
 370 void wxString::AllocBuffer(size_t nLen
) 
 372   // allocating 0 sized buffer doesn't make sense, all empty strings should 
 374   wxASSERT( nLen 
>  0 ); 
 376   // make sure that we don't overflow 
 377   wxASSERT( nLen 
< (INT_MAX 
/ sizeof(wxChar
)) - 
 378                    (sizeof(wxStringData
) + EXTRA_ALLOC 
+ 1) ); 
 380   STATISTICS_ADD(Length
, nLen
); 
 383   // 1) one extra character for '\0' termination 
 384   // 2) sizeof(wxStringData) for housekeeping info 
 385   wxStringData
* pData 
= (wxStringData
*) 
 386     malloc(sizeof(wxStringData
) + (nLen 
+ EXTRA_ALLOC 
+ 1)*sizeof(wxChar
)); 
 388   pData
->nDataLength  
= nLen
; 
 389   pData
->nAllocLength 
= nLen 
+ EXTRA_ALLOC
; 
 390   m_pchData           
= pData
->data();  // data starts after wxStringData 
 391   m_pchData
[nLen
]     = wxT('\0'); 
 394 // must be called before changing this string 
 395 void wxString::CopyBeforeWrite() 
 397   wxStringData
* pData 
= GetStringData(); 
 399   if ( pData
->IsShared() ) { 
 400     pData
->Unlock();                // memory not freed because shared 
 401     size_t nLen 
= pData
->nDataLength
; 
 403     memcpy(m_pchData
, pData
->data(), nLen
*sizeof(wxChar
)); 
 406   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 409 // must be called before replacing contents of this string 
 410 void wxString::AllocBeforeWrite(size_t nLen
) 
 412   wxASSERT( nLen 
!= 0 );  // doesn't make any sense 
 414   // must not share string and must have enough space 
 415   wxStringData
* pData 
= GetStringData(); 
 416   if ( pData
->IsShared() || pData
->IsEmpty() ) { 
 417     // can't work with old buffer, get new one 
 422     if ( nLen 
> pData
->nAllocLength 
) { 
 423       // realloc the buffer instead of calling malloc() again, this is more 
 425       STATISTICS_ADD(Length
, nLen
); 
 429       wxStringData 
*pDataOld 
= pData
; 
 430       pData 
= (wxStringData
*) 
 431           realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(wxChar
)); 
 436         // FIXME we're going to crash... 
 440       pData
->nAllocLength 
= nLen
; 
 441       m_pchData 
= pData
->data(); 
 444     // now we have enough space, just update the string length 
 445     pData
->nDataLength 
= nLen
; 
 448   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 451 // allocate enough memory for nLen characters 
 452 void wxString::Alloc(size_t nLen
) 
 454   wxStringData 
*pData 
= GetStringData(); 
 455   if ( pData
->nAllocLength 
<= nLen 
) { 
 456     if ( pData
->IsEmpty() ) { 
 459       wxStringData
* pData 
= (wxStringData
*) 
 460         malloc(sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(wxChar
)); 
 462       pData
->nDataLength 
= 0; 
 463       pData
->nAllocLength 
= nLen
; 
 464       m_pchData 
= pData
->data();  // data starts after wxStringData 
 465       m_pchData
[0u] = wxT('\0'); 
 467     else if ( pData
->IsShared() ) { 
 468       pData
->Unlock();                // memory not freed because shared 
 469       size_t nOldLen 
= pData
->nDataLength
; 
 471       memcpy(m_pchData
, pData
->data(), nOldLen
*sizeof(wxChar
)); 
 476       wxStringData 
*pDataOld 
= pData
; 
 477       wxStringData 
*p 
= (wxStringData 
*) 
 478         realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(wxChar
)); 
 484         // FIXME what to do on memory error? 
 488       // it's not important if the pointer changed or not (the check for this 
 489       // is not faster than assigning to m_pchData in all cases) 
 490       p
->nAllocLength 
= nLen
; 
 491       m_pchData 
= p
->data(); 
 494   //else: we've already got enough 
 497 // shrink to minimal size (releasing extra memory) 
 498 void wxString::Shrink() 
 500   wxStringData 
*pData 
= GetStringData(); 
 502   // this variable is unused in release build, so avoid the compiler warning 
 503   // by just not declaring it 
 507   realloc(pData
, sizeof(wxStringData
) + (pData
->nDataLength 
+ 1)*sizeof(wxChar
)); 
 509   // we rely on a reasonable realloc() implementation here - so far I haven't 
 510   // seen any which wouldn't behave like this 
 512   wxASSERT( p 
!= NULL 
);  // can't free memory? 
 513   wxASSERT( p 
== pData 
); // we're decrementing the size - block shouldn't move! 
 516 // get the pointer to writable buffer of (at least) nLen bytes 
 517 wxChar 
*wxString::GetWriteBuf(size_t nLen
) 
 519   AllocBeforeWrite(nLen
); 
 521   wxASSERT( GetStringData()->nRefs 
== 1 ); 
 522   GetStringData()->Validate(FALSE
); 
 527 // put string back in a reasonable state after GetWriteBuf 
 528 void wxString::UngetWriteBuf() 
 530   GetStringData()->nDataLength 
= wxStrlen(m_pchData
); 
 531   GetStringData()->Validate(TRUE
); 
 534 void wxString::UngetWriteBuf(size_t nLen
) 
 536   GetStringData()->nDataLength 
= nLen
; 
 537   GetStringData()->Validate(TRUE
); 
 540 // --------------------------------------------------------------------------- 
 542 // --------------------------------------------------------------------------- 
 544 // all functions are inline in string.h 
 546 // --------------------------------------------------------------------------- 
 547 // assignment operators 
 548 // --------------------------------------------------------------------------- 
 550 // helper function: does real copy 
 551 void wxString::AssignCopy(size_t nSrcLen
, const wxChar 
*pszSrcData
) 
 553   if ( nSrcLen 
== 0 ) { 
 557     AllocBeforeWrite(nSrcLen
); 
 558     memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(wxChar
)); 
 559     GetStringData()->nDataLength 
= nSrcLen
; 
 560     m_pchData
[nSrcLen
] = wxT('\0'); 
 564 // assigns one string to another 
 565 wxString
& wxString::operator=(const wxString
& stringSrc
) 
 567   wxASSERT( stringSrc
.GetStringData()->IsValid() ); 
 569   // don't copy string over itself 
 570   if ( m_pchData 
!= stringSrc
.m_pchData 
) { 
 571     if ( stringSrc
.GetStringData()->IsEmpty() ) { 
 576       GetStringData()->Unlock(); 
 577       m_pchData 
= stringSrc
.m_pchData
; 
 578       GetStringData()->Lock(); 
 585 // assigns a single character 
 586 wxString
& wxString::operator=(wxChar ch
) 
 593 wxString
& wxString::operator=(const wxChar 
*psz
) 
 595   AssignCopy(wxStrlen(psz
), psz
); 
 601 // same as 'signed char' variant 
 602 wxString
& wxString::operator=(const unsigned char* psz
) 
 604   *this = (const char *)psz
; 
 609 wxString
& wxString::operator=(const wchar_t *pwz
) 
 619 // --------------------------------------------------------------------------- 
 620 // string concatenation 
 621 // --------------------------------------------------------------------------- 
 623 // add something to this string 
 624 void wxString::ConcatSelf(int nSrcLen
, const wxChar 
*pszSrcData
) 
 626   STATISTICS_ADD(SummandLength
, nSrcLen
); 
 628   // concatenating an empty string is a NOP 
 630     wxStringData 
*pData 
= GetStringData(); 
 631     size_t nLen 
= pData
->nDataLength
; 
 632     size_t nNewLen 
= nLen 
+ nSrcLen
; 
 634     // alloc new buffer if current is too small 
 635     if ( pData
->IsShared() ) { 
 636       STATISTICS_ADD(ConcatHit
, 0); 
 638       // we have to allocate another buffer 
 639       wxStringData
* pOldData 
= GetStringData(); 
 640       AllocBuffer(nNewLen
); 
 641       memcpy(m_pchData
, pOldData
->data(), nLen
*sizeof(wxChar
)); 
 644     else if ( nNewLen 
> pData
->nAllocLength 
) { 
 645       STATISTICS_ADD(ConcatHit
, 0); 
 647       // we have to grow the buffer 
 651       STATISTICS_ADD(ConcatHit
, 1); 
 653       // the buffer is already big enough 
 656     // should be enough space 
 657     wxASSERT( nNewLen 
<= GetStringData()->nAllocLength 
); 
 659     // fast concatenation - all is done in our buffer 
 660     memcpy(m_pchData 
+ nLen
, pszSrcData
, nSrcLen
*sizeof(wxChar
)); 
 662     m_pchData
[nNewLen
] = wxT('\0');          // put terminating '\0' 
 663     GetStringData()->nDataLength 
= nNewLen
; // and fix the length 
 665   //else: the string to append was empty 
 669  * concatenation functions come in 5 flavours: 
 671  *  char   + string      and      string + char 
 672  *  C str  + string      and      string + C str 
 675 wxString 
operator+(const wxString
& string1
, const wxString
& string2
) 
 677   wxASSERT( string1
.GetStringData()->IsValid() ); 
 678   wxASSERT( string2
.GetStringData()->IsValid() ); 
 680   wxString s 
= string1
; 
 686 wxString 
operator+(const wxString
& string
, wxChar ch
) 
 688   wxASSERT( string
.GetStringData()->IsValid() ); 
 696 wxString 
operator+(wxChar ch
, const wxString
& string
) 
 698   wxASSERT( string
.GetStringData()->IsValid() ); 
 706 wxString 
operator+(const wxString
& string
, const wxChar 
*psz
) 
 708   wxASSERT( string
.GetStringData()->IsValid() ); 
 711   s
.Alloc(wxStrlen(psz
) + string
.Len()); 
 718 wxString 
operator+(const wxChar 
*psz
, const wxString
& string
) 
 720   wxASSERT( string
.GetStringData()->IsValid() ); 
 723   s
.Alloc(wxStrlen(psz
) + string
.Len()); 
 730 // =========================================================================== 
 731 // other common string functions 
 732 // =========================================================================== 
 734 // --------------------------------------------------------------------------- 
 735 // simple sub-string extraction 
 736 // --------------------------------------------------------------------------- 
 738 // helper function: clone the data attached to this string 
 739 void wxString::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const 
 741   if ( nCopyLen 
== 0 ) { 
 745     dest
.AllocBuffer(nCopyLen
); 
 746     memcpy(dest
.m_pchData
, m_pchData 
+ nCopyIndex
, nCopyLen
*sizeof(wxChar
)); 
 750 // extract string of length nCount starting at nFirst 
 751 wxString 
wxString::Mid(size_t nFirst
, size_t nCount
) const 
 753   wxStringData 
*pData 
= GetStringData(); 
 754   size_t nLen 
= pData
->nDataLength
; 
 756   // default value of nCount is wxSTRING_MAXLEN and means "till the end" 
 757   if ( nCount 
== wxSTRING_MAXLEN 
) 
 759     nCount 
= nLen 
- nFirst
; 
 762   // out-of-bounds requests return sensible things 
 763   if ( nFirst 
+ nCount 
> nLen 
) 
 765     nCount 
= nLen 
- nFirst
; 
 770     // AllocCopy() will return empty string 
 775   AllocCopy(dest
, nCount
, nFirst
); 
 780 // check that the tring starts with prefix and return the rest of the string 
 781 // in the provided pointer if it is not NULL, otherwise return FALSE 
 782 bool wxString::StartsWith(const wxChar 
*prefix
, wxString 
*rest
) const 
 784     wxASSERT_MSG( prefix
, _T("invalid parameter in wxString::StartsWith") ); 
 786     // first check if the beginning of the string matches the prefix: note 
 787     // that we don't have to check that we don't run out of this string as 
 788     // when we reach the terminating NUL, either prefix string ends too (and 
 789     // then it's ok) or we break out of the loop because there is no match 
 790     const wxChar 
*p 
= c_str(); 
 793         if ( *prefix
++ != *p
++ ) 
 802         // put the rest of the string into provided pointer 
 809 // extract nCount last (rightmost) characters 
 810 wxString 
wxString::Right(size_t nCount
) const 
 812   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 813     nCount 
= GetStringData()->nDataLength
; 
 816   AllocCopy(dest
, nCount
, GetStringData()->nDataLength 
- nCount
); 
 820 // get all characters after the last occurence of ch 
 821 // (returns the whole string if ch not found) 
 822 wxString 
wxString::AfterLast(wxChar ch
) const 
 825   int iPos 
= Find(ch
, TRUE
); 
 826   if ( iPos 
== wxNOT_FOUND 
) 
 829     str 
= c_str() + iPos 
+ 1; 
 834 // extract nCount first (leftmost) characters 
 835 wxString 
wxString::Left(size_t nCount
) const 
 837   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 838     nCount 
= GetStringData()->nDataLength
; 
 841   AllocCopy(dest
, nCount
, 0); 
 845 // get all characters before the first occurence of ch 
 846 // (returns the whole string if ch not found) 
 847 wxString 
wxString::BeforeFirst(wxChar ch
) const 
 850   for ( const wxChar 
*pc 
= m_pchData
; *pc 
!= wxT('\0') && *pc 
!= ch
; pc
++ ) 
 856 /// get all characters before the last occurence of ch 
 857 /// (returns empty string if ch not found) 
 858 wxString 
wxString::BeforeLast(wxChar ch
) const 
 861   int iPos 
= Find(ch
, TRUE
); 
 862   if ( iPos 
!= wxNOT_FOUND 
&& iPos 
!= 0 ) 
 863     str 
= wxString(c_str(), iPos
); 
 868 /// get all characters after the first occurence of ch 
 869 /// (returns empty string if ch not found) 
 870 wxString 
wxString::AfterFirst(wxChar ch
) const 
 874   if ( iPos 
!= wxNOT_FOUND 
) 
 875     str 
= c_str() + iPos 
+ 1; 
 880 // replace first (or all) occurences of some substring with another one 
 881 size_t wxString::Replace(const wxChar 
*szOld
, const wxChar 
*szNew
, bool bReplaceAll
) 
 883   size_t uiCount 
= 0;   // count of replacements made 
 885   size_t uiOldLen 
= wxStrlen(szOld
); 
 888   const wxChar 
*pCurrent 
= m_pchData
; 
 889   const wxChar 
*pSubstr
; 
 890   while ( *pCurrent 
!= wxT('\0') ) { 
 891     pSubstr 
= wxStrstr(pCurrent
, szOld
); 
 892     if ( pSubstr 
== NULL 
) { 
 893       // strTemp is unused if no replacements were made, so avoid the copy 
 897       strTemp 
+= pCurrent
;    // copy the rest 
 898       break;                  // exit the loop 
 901       // take chars before match 
 902       strTemp
.ConcatSelf(pSubstr 
- pCurrent
, pCurrent
); 
 904       pCurrent 
= pSubstr 
+ uiOldLen
;  // restart after match 
 909       if ( !bReplaceAll 
) { 
 910         strTemp 
+= pCurrent
;    // copy the rest 
 911         break;                  // exit the loop 
 916   // only done if there were replacements, otherwise would have returned above 
 922 bool wxString::IsAscii() const 
 924   const wxChar 
*s 
= (const wxChar
*) *this; 
 926     if(!isascii(*s
)) return(FALSE
); 
 932 bool wxString::IsWord() const 
 934   const wxChar 
*s 
= (const wxChar
*) *this; 
 936     if(!wxIsalpha(*s
)) return(FALSE
); 
 942 bool wxString::IsNumber() const 
 944   const wxChar 
*s 
= (const wxChar
*) *this; 
 946      if ((s
[0] == '-') || (s
[0] == '+')) s
++; 
 948     if(!wxIsdigit(*s
)) return(FALSE
); 
 954 wxString 
wxString::Strip(stripType w
) const 
 957     if ( w 
& leading 
) s
.Trim(FALSE
); 
 958     if ( w 
& trailing 
) s
.Trim(TRUE
); 
 962 // --------------------------------------------------------------------------- 
 964 // --------------------------------------------------------------------------- 
 966 wxString
& wxString::MakeUpper() 
 970   for ( wxChar 
*p 
= m_pchData
; *p
; p
++ ) 
 971     *p 
= (wxChar
)wxToupper(*p
); 
 976 wxString
& wxString::MakeLower() 
 980   for ( wxChar 
*p 
= m_pchData
; *p
; p
++ ) 
 981     *p 
= (wxChar
)wxTolower(*p
); 
 986 // --------------------------------------------------------------------------- 
 987 // trimming and padding 
 988 // --------------------------------------------------------------------------- 
 990 // some compilers (VC++ 6.0 not to name them) return TRUE for a call to 
 991 // isspace('ê') in the C locale which seems to be broken to me, but we have to 
 992 // live with this by checking that the character is a 7 bit one - even if this 
 993 // may fail to detect some spaces (I don't know if Unicode doesn't have 
 994 // space-like symbols somewhere except in the first 128 chars), it is arguably 
 995 // still better than trimming away accented letters 
 996 inline int wxSafeIsspace(wxChar ch
) { return (ch 
< 127) && wxIsspace(ch
); } 
 998 // trims spaces (in the sense of isspace) from left or right side 
 999 wxString
& wxString::Trim(bool bFromRight
) 
1001   // first check if we're going to modify the string at all 
1004         (bFromRight 
&& wxSafeIsspace(GetChar(Len() - 1))) || 
1005         (!bFromRight 
&& wxSafeIsspace(GetChar(0u))) 
1009     // ok, there is at least one space to trim 
1014       // find last non-space character 
1015       wxChar 
*psz 
= m_pchData 
+ GetStringData()->nDataLength 
- 1; 
1016       while ( wxSafeIsspace(*psz
) && (psz 
>= m_pchData
) ) 
1019       // truncate at trailing space start 
1021       GetStringData()->nDataLength 
= psz 
- m_pchData
; 
1025       // find first non-space character 
1026       const wxChar 
*psz 
= m_pchData
; 
1027       while ( wxSafeIsspace(*psz
) ) 
1030       // fix up data and length 
1031       int nDataLength 
= GetStringData()->nDataLength 
- (psz 
- (const wxChar
*) m_pchData
); 
1032       memmove(m_pchData
, psz
, (nDataLength 
+ 1)*sizeof(wxChar
)); 
1033       GetStringData()->nDataLength 
= nDataLength
; 
1040 // adds nCount characters chPad to the string from either side 
1041 wxString
& wxString::Pad(size_t nCount
, wxChar chPad
, bool bFromRight
) 
1043   wxString 
s(chPad
, nCount
); 
1056 // truncate the string 
1057 wxString
& wxString::Truncate(size_t uiLen
) 
1059   if ( uiLen 
< Len() ) { 
1062     *(m_pchData 
+ uiLen
) = wxT('\0'); 
1063     GetStringData()->nDataLength 
= uiLen
; 
1065   //else: nothing to do, string is already short enough 
1070 // --------------------------------------------------------------------------- 
1071 // finding (return wxNOT_FOUND if not found and index otherwise) 
1072 // --------------------------------------------------------------------------- 
1075 int wxString::Find(wxChar ch
, bool bFromEnd
) const 
1077   const wxChar 
*psz 
= bFromEnd 
? wxStrrchr(m_pchData
, ch
) : wxStrchr(m_pchData
, ch
); 
1079   return (psz 
== NULL
) ? wxNOT_FOUND 
: psz 
- (const wxChar
*) m_pchData
; 
1082 // find a sub-string (like strstr) 
1083 int wxString::Find(const wxChar 
*pszSub
) const 
1085   const wxChar 
*psz 
= wxStrstr(m_pchData
, pszSub
); 
1087   return (psz 
== NULL
) ? wxNOT_FOUND 
: psz 
- (const wxChar
*) m_pchData
; 
1090 // ---------------------------------------------------------------------------- 
1091 // conversion to numbers 
1092 // ---------------------------------------------------------------------------- 
1094 bool wxString::ToLong(long *val
) const 
1096     wxCHECK_MSG( val
, FALSE
, _T("NULL pointer in wxString::ToLong") ); 
1098     const wxChar 
*start 
= c_str(); 
1100     *val 
= wxStrtol(start
, &end
, 10); 
1102     // return TRUE only if scan was stopped by the terminating NUL and if the 
1103     // string was not empty to start with 
1104     return !*end 
&& (end 
!= start
); 
1107 bool wxString::ToULong(unsigned long *val
) const 
1109     wxCHECK_MSG( val
, FALSE
, _T("NULL pointer in wxString::ToULong") ); 
1111     const wxChar 
*start 
= c_str(); 
1113     *val 
= wxStrtoul(start
, &end
, 10); 
1115     // return TRUE only if scan was stopped by the terminating NUL and if the 
1116     // string was not empty to start with 
1117     return !*end 
&& (end 
!= start
); 
1120 bool wxString::ToDouble(double *val
) const 
1122     wxCHECK_MSG( val
, FALSE
, _T("NULL pointer in wxString::ToDouble") ); 
1124     const wxChar 
*start 
= c_str(); 
1126     *val 
= wxStrtod(start
, &end
); 
1128     // return TRUE only if scan was stopped by the terminating NUL and if the 
1129     // string was not empty to start with 
1130     return !*end 
&& (end 
!= start
); 
1133 // --------------------------------------------------------------------------- 
1135 // --------------------------------------------------------------------------- 
1138 wxString 
wxString::Format(const wxChar 
*pszFormat
, ...) 
1141     va_start(argptr
, pszFormat
); 
1144     s
.PrintfV(pszFormat
, argptr
); 
1152 wxString 
wxString::FormatV(const wxChar 
*pszFormat
, va_list argptr
) 
1155     s
.PrintfV(pszFormat
, argptr
); 
1159 int wxString::Printf(const wxChar 
*pszFormat
, ...) 
1162   va_start(argptr
, pszFormat
); 
1164   int iLen 
= PrintfV(pszFormat
, argptr
); 
1171 int wxString::PrintfV(const wxChar
* pszFormat
, va_list argptr
) 
1173 #if wxUSE_EXPERIMENTAL_PRINTF 
1174   // the new implementation 
1176   // buffer to avoid dynamic memory allocation each time for small strings 
1177   char szScratch
[1024]; 
1180   for (size_t n 
= 0; pszFormat
[n
]; n
++) 
1181     if (pszFormat
[n
] == wxT('%')) { 
1182       static char s_szFlags
[256] = "%"; 
1184       bool adj_left 
= FALSE
, in_prec 
= FALSE
, 
1185            prec_dot 
= FALSE
, done 
= FALSE
; 
1187       size_t min_width 
= 0, max_width 
= wxSTRING_MAXLEN
; 
1189 #define CHECK_PREC if (in_prec && !prec_dot) { s_szFlags[flagofs++] = '.'; prec_dot = TRUE; } 
1190         switch (pszFormat
[++n
]) { 
1204           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1209           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1216           // dot will be auto-added to s_szFlags if non-negative number follows 
1221           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1226           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1232           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1237           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1241             int len 
= va_arg(argptr
, int); 
1248                 adj_left 
= !adj_left
; 
1249                 s_szFlags
[flagofs
++] = '-'; 
1254             flagofs 
+= ::sprintf(s_szFlags
+flagofs
,"%d",len
); 
1257         case wxT('1'): case wxT('2'): case wxT('3'): 
1258         case wxT('4'): case wxT('5'): case wxT('6'): 
1259         case wxT('7'): case wxT('8'): case wxT('9'): 
1263             while ((pszFormat
[n
]>=wxT('0')) && (pszFormat
[n
]<=wxT('9'))) { 
1264               s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1265               len 
= len
*10 + (pszFormat
[n
] - wxT('0')); 
1268             if (in_prec
) max_width 
= len
; 
1269             else min_width 
= len
; 
1270             n
--; // the main loop pre-increments n again 
1280           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1281           s_szFlags
[flagofs
] = '\0'; 
1283             int val 
= va_arg(argptr
, int); 
1284             ::sprintf(szScratch
, s_szFlags
, val
); 
1286           else if (ilen 
== -1) { 
1287             short int val 
= va_arg(argptr
, short int); 
1288             ::sprintf(szScratch
, s_szFlags
, val
); 
1290           else if (ilen 
== 1) { 
1291             long int val 
= va_arg(argptr
, long int); 
1292             ::sprintf(szScratch
, s_szFlags
, val
); 
1294           else if (ilen 
== 2) { 
1295 #if SIZEOF_LONG_LONG 
1296             long long int val 
= va_arg(argptr
, long long int); 
1297             ::sprintf(szScratch
, s_szFlags
, val
); 
1299             long int val 
= va_arg(argptr
, long int); 
1300             ::sprintf(szScratch
, s_szFlags
, val
); 
1303           else if (ilen 
== 3) { 
1304             size_t val 
= va_arg(argptr
, size_t); 
1305             ::sprintf(szScratch
, s_szFlags
, val
); 
1307           *this += wxString(szScratch
); 
1316           s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1317           s_szFlags
[flagofs
] = '\0'; 
1319             long double val 
= va_arg(argptr
, long double); 
1320             ::sprintf(szScratch
, s_szFlags
, val
); 
1322             double val 
= va_arg(argptr
, double); 
1323             ::sprintf(szScratch
, s_szFlags
, val
); 
1325           *this += wxString(szScratch
); 
1330             void *val 
= va_arg(argptr
, void *); 
1332             s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1333             s_szFlags
[flagofs
] = '\0'; 
1334             ::sprintf(szScratch
, s_szFlags
, val
); 
1335             *this += wxString(szScratch
); 
1341             wxChar val 
= va_arg(argptr
, int); 
1342             // we don't need to honor padding here, do we? 
1349             // wx extension: we'll let %hs mean non-Unicode strings 
1350             char *val 
= va_arg(argptr
, char *); 
1352             // ASCII->Unicode constructor handles max_width right 
1353             wxString 
s(val
, wxConvLibc
, max_width
); 
1355             size_t len 
= wxSTRING_MAXLEN
; 
1357               for (len 
= 0; val
[len
] && (len
<max_width
); len
++); 
1358             } else val 
= wxT("(null)"); 
1359             wxString 
s(val
, len
); 
1361             if (s
.Len() < min_width
) 
1362               s
.Pad(min_width 
- s
.Len(), wxT(' '), adj_left
); 
1365             wxChar 
*val 
= va_arg(argptr
, wxChar 
*); 
1366             size_t len 
= wxSTRING_MAXLEN
; 
1368               for (len 
= 0; val
[len
] && (len
<max_width
); len
++); 
1369             } else val 
= wxT("(null)"); 
1370             wxString 
s(val
, len
); 
1371             if (s
.Len() < min_width
) 
1372               s
.Pad(min_width 
- s
.Len(), wxT(' '), adj_left
); 
1379             int *val 
= va_arg(argptr
, int *); 
1382           else if (ilen 
== -1) { 
1383             short int *val 
= va_arg(argptr
, short int *); 
1386           else if (ilen 
>= 1) { 
1387             long int *val 
= va_arg(argptr
, long int *); 
1393           if (wxIsalpha(pszFormat
[n
])) 
1394             // probably some flag not taken care of here yet 
1395             s_szFlags
[flagofs
++] = pszFormat
[n
]; 
1398             *this += wxT('%'); // just to pass the glibc tst-printf.c 
1406     } else *this += pszFormat
[n
]; 
1409   // buffer to avoid dynamic memory allocation each time for small strings 
1410   char szScratch
[1024]; 
1412   // NB: wxVsnprintf() may return either less than the buffer size or -1 if 
1413   //     there is not enough place depending on implementation 
1414   int iLen 
= wxVsnprintfA(szScratch
, WXSIZEOF(szScratch
), (char *)pszFormat
, argptr
); 
1416     // the whole string is in szScratch 
1420       bool outOfMemory 
= FALSE
; 
1421       int size 
= 2*WXSIZEOF(szScratch
); 
1422       while ( !outOfMemory 
) { 
1423           char *buf 
= GetWriteBuf(size
); 
1425             iLen 
= wxVsnprintfA(buf
, size
, pszFormat
, argptr
); 
1432               // ok, there was enough space 
1436           // still not enough, double it again 
1440       if ( outOfMemory 
) { 
1445 #endif // wxUSE_EXPERIMENTAL_PRINTF/!wxUSE_EXPERIMENTAL_PRINTF 
1450 // ---------------------------------------------------------------------------- 
1451 // misc other operations 
1452 // ---------------------------------------------------------------------------- 
1454 // returns TRUE if the string matches the pattern which may contain '*' and 
1455 // '?' metacharacters (as usual, '?' matches any character and '*' any number 
1457 bool wxString::Matches(const wxChar 
*pszMask
) const 
1459   // TODO: this is, of course, awfully inefficient... 
1461   // the char currently being checked 
1462   const wxChar 
*pszTxt 
= c_str(); 
1464   // the last location where '*' matched 
1465   const wxChar 
*pszLastStarInText 
= NULL
; 
1466   const wxChar 
*pszLastStarInMask 
= NULL
; 
1469   for ( ; *pszMask 
!= wxT('\0'); pszMask
++, pszTxt
++ ) { 
1470     switch ( *pszMask 
) { 
1472         if ( *pszTxt 
== wxT('\0') ) 
1475         // pszTxt and pszMask will be incremented in the loop statement 
1481           // remember where we started to be able to backtrack later 
1482           pszLastStarInText 
= pszTxt
; 
1483           pszLastStarInMask 
= pszMask
; 
1485           // ignore special chars immediately following this one 
1486           // (should this be an error?) 
1487           while ( *pszMask 
== wxT('*') || *pszMask 
== wxT('?') ) 
1490           // if there is nothing more, match 
1491           if ( *pszMask 
== wxT('\0') ) 
1494           // are there any other metacharacters in the mask? 
1496           const wxChar 
*pEndMask 
= wxStrpbrk(pszMask
, wxT("*?")); 
1498           if ( pEndMask 
!= NULL 
) { 
1499             // we have to match the string between two metachars 
1500             uiLenMask 
= pEndMask 
- pszMask
; 
1503             // we have to match the remainder of the string 
1504             uiLenMask 
= wxStrlen(pszMask
); 
1507           wxString 
strToMatch(pszMask
, uiLenMask
); 
1508           const wxChar
* pMatch 
= wxStrstr(pszTxt
, strToMatch
); 
1509           if ( pMatch 
== NULL 
) 
1512           // -1 to compensate "++" in the loop 
1513           pszTxt 
= pMatch 
+ uiLenMask 
- 1; 
1514           pszMask 
+= uiLenMask 
- 1; 
1519         if ( *pszMask 
!= *pszTxt 
) 
1525   // match only if nothing left 
1526   if ( *pszTxt 
== wxT('\0') ) 
1529   // if we failed to match, backtrack if we can 
1530   if ( pszLastStarInText 
) { 
1531     pszTxt 
= pszLastStarInText 
+ 1; 
1532     pszMask 
= pszLastStarInMask
; 
1534     pszLastStarInText 
= NULL
; 
1536     // don't bother resetting pszLastStarInMask, it's unnecessary 
1544 // Count the number of chars 
1545 int wxString::Freq(wxChar ch
) const 
1549     for (int i 
= 0; i 
< len
; i
++) 
1551         if (GetChar(i
) == ch
) 
1557 // convert to upper case, return the copy of the string 
1558 wxString 
wxString::Upper() const 
1559 { wxString 
s(*this); return s
.MakeUpper(); } 
1561 // convert to lower case, return the copy of the string 
1562 wxString 
wxString::Lower() const { wxString 
s(*this); return s
.MakeLower(); } 
1564 int wxString::sprintf(const wxChar 
*pszFormat
, ...) 
1567     va_start(argptr
, pszFormat
); 
1568     int iLen 
= PrintfV(pszFormat
, argptr
); 
1573 // --------------------------------------------------------------------------- 
1574 // standard C++ library string functions 
1575 // --------------------------------------------------------------------------- 
1577 #ifdef  wxSTD_STRING_COMPATIBILITY 
1579 void wxString::resize(size_t nSize
, wxChar ch
) 
1581     size_t len 
= length(); 
1587     else if ( nSize 
> len 
) 
1589         *this += wxString(ch
, len 
- nSize
); 
1591     //else: we have exactly the specified length, nothing to do 
1594 void wxString::swap(wxString
& str
) 
1596     // this is slightly less efficient than fiddling with m_pchData directly, 
1597     // but it is still quite efficient as we don't copy the string here because 
1598     // ref count always stays positive 
1604 wxString
& wxString::insert(size_t nPos
, const wxString
& str
) 
1606   wxASSERT( str
.GetStringData()->IsValid() ); 
1607   wxASSERT( nPos 
<= Len() ); 
1609   if ( !str
.IsEmpty() ) { 
1611     wxChar 
*pc 
= strTmp
.GetWriteBuf(Len() + str
.Len()); 
1612     wxStrncpy(pc
, c_str(), nPos
); 
1613     wxStrcpy(pc 
+ nPos
, str
); 
1614     wxStrcpy(pc 
+ nPos 
+ str
.Len(), c_str() + nPos
); 
1615     strTmp
.UngetWriteBuf(); 
1622 size_t wxString::find(const wxString
& str
, size_t nStart
) const 
1624   wxASSERT( str
.GetStringData()->IsValid() ); 
1625   wxASSERT( nStart 
<= Len() ); 
1627   const wxChar 
*p 
= wxStrstr(c_str() + nStart
, str
); 
1629   return p 
== NULL 
? npos 
: p 
- c_str(); 
1632 // VC++ 1.5 can't cope with the default argument in the header. 
1633 #if !defined(__VISUALC__) || defined(__WIN32__) 
1634 size_t wxString::find(const wxChar
* sz
, size_t nStart
, size_t n
) const 
1636   return find(wxString(sz
, n
), nStart
); 
1640 // Gives a duplicate symbol (presumably a case-insensitivity problem) 
1641 #if !defined(__BORLANDC__) 
1642 size_t wxString::find(wxChar ch
, size_t nStart
) const 
1644   wxASSERT( nStart 
<= Len() ); 
1646   const wxChar 
*p 
= wxStrchr(c_str() + nStart
, ch
); 
1648   return p 
== NULL 
? npos 
: p 
- c_str(); 
1652 size_t wxString::rfind(const wxString
& str
, size_t nStart
) const 
1654   wxASSERT( str
.GetStringData()->IsValid() ); 
1655   wxASSERT( nStart 
<= Len() ); 
1657   // TODO could be made much quicker than that 
1658   const wxChar 
*p 
= c_str() + (nStart 
== npos 
? Len() : nStart
); 
1659   while ( p 
>= c_str() + str
.Len() ) { 
1660     if ( wxStrncmp(p 
- str
.Len(), str
, str
.Len()) == 0 ) 
1661       return p 
- str
.Len() - c_str(); 
1668 // VC++ 1.5 can't cope with the default argument in the header. 
1669 #if !defined(__VISUALC__) || defined(__WIN32__) 
1670 size_t wxString::rfind(const wxChar
* sz
, size_t nStart
, size_t n
) const 
1672     return rfind(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1675 size_t wxString::rfind(wxChar ch
, size_t nStart
) const 
1677     if ( nStart 
== npos 
) 
1683         wxASSERT( nStart 
<= Len() ); 
1686     const wxChar 
*p 
= wxStrrchr(c_str(), ch
); 
1691     size_t result 
= p 
- c_str(); 
1692     return ( result 
> nStart 
) ? npos 
: result
; 
1696 size_t wxString::find_first_of(const wxChar
* sz
, size_t nStart
) const 
1698     const wxChar 
*start 
= c_str() + nStart
; 
1699     const wxChar 
*firstOf 
= wxStrpbrk(start
, sz
); 
1701         return firstOf 
- c_str(); 
1706 size_t wxString::find_last_of(const wxChar
* sz
, size_t nStart
) const 
1708     if ( nStart 
== npos 
) 
1714         wxASSERT( nStart 
<= Len() ); 
1717     for ( const wxChar 
*p 
= c_str() + length() - 1; p 
>= c_str(); p
-- ) 
1719         if ( wxStrchr(sz
, *p
) ) 
1726 size_t wxString::find_first_not_of(const wxChar
* sz
, size_t nStart
) const 
1728     if ( nStart 
== npos 
) 
1734         wxASSERT( nStart 
<= Len() ); 
1737     size_t nAccept 
= wxStrspn(c_str() + nStart
, sz
); 
1738     if ( nAccept 
>= length() - nStart 
) 
1744 size_t wxString::find_first_not_of(wxChar ch
, size_t nStart
) const 
1746     wxASSERT( nStart 
<= Len() ); 
1748     for ( const wxChar 
*p 
= c_str() + nStart
; *p
; p
++ ) 
1757 size_t wxString::find_last_not_of(const wxChar
* sz
, size_t nStart
) const 
1759     if ( nStart 
== npos 
) 
1765         wxASSERT( nStart 
<= Len() ); 
1768     for ( const wxChar 
*p 
= c_str() + nStart 
- 1; p 
>= c_str(); p
-- ) 
1770         if ( !wxStrchr(sz
, *p
) ) 
1777 size_t wxString::find_last_not_of(wxChar ch
, size_t nStart
) const 
1779     if ( nStart 
== npos 
) 
1785         wxASSERT( nStart 
<= Len() ); 
1788     for ( const wxChar 
*p 
= c_str() + nStart 
- 1; p 
>= c_str(); p
-- ) 
1797 wxString
& wxString::erase(size_t nStart
, size_t nLen
) 
1799   wxString 
strTmp(c_str(), nStart
); 
1800   if ( nLen 
!= npos 
) { 
1801     wxASSERT( nStart 
+ nLen 
<= Len() ); 
1803     strTmp
.append(c_str() + nStart 
+ nLen
); 
1810 wxString
& wxString::replace(size_t nStart
, size_t nLen
, const wxChar 
*sz
) 
1812   wxASSERT_MSG( nStart 
+ nLen 
<= Len(), 
1813                 _T("index out of bounds in wxString::replace") ); 
1816   strTmp
.Alloc(Len());      // micro optimisation to avoid multiple mem allocs 
1819     strTmp
.append(c_str(), nStart
); 
1820   strTmp 
<< sz 
<< c_str() + nStart 
+ nLen
; 
1826 wxString
& wxString::replace(size_t nStart
, size_t nLen
, size_t nCount
, wxChar ch
) 
1828   return replace(nStart
, nLen
, wxString(ch
, nCount
)); 
1831 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1832                             const wxString
& str
, size_t nStart2
, size_t nLen2
) 
1834   return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
)); 
1837 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1838                         const wxChar
* sz
, size_t nCount
) 
1840   return replace(nStart
, nLen
, wxString(sz
, nCount
)); 
1843 #endif  //std::string compatibility 
1845 // ============================================================================ 
1847 // ============================================================================ 
1849 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) 
1850 #define   ARRAY_MAXSIZE_INCREMENT       4096 
1851 #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h 
1852   #define   ARRAY_DEFAULT_INITIAL_SIZE    (16) 
1855 #define   STRING(p)   ((wxString *)(&(p))) 
1858 wxArrayString::wxArrayString(bool autoSort
) 
1862   m_pItems 
= (wxChar 
**) NULL
; 
1863   m_autoSort 
= autoSort
; 
1867 wxArrayString::wxArrayString(const wxArrayString
& src
) 
1871   m_pItems 
= (wxChar 
**) NULL
; 
1872   m_autoSort 
= src
.m_autoSort
; 
1877 // assignment operator 
1878 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
) 
1885   m_autoSort 
= src
.m_autoSort
; 
1890 void wxArrayString::Copy(const wxArrayString
& src
) 
1892   if ( src
.m_nCount 
> ARRAY_DEFAULT_INITIAL_SIZE 
) 
1893     Alloc(src
.m_nCount
); 
1895   for ( size_t n 
= 0; n 
< src
.m_nCount
; n
++ ) 
1900 void wxArrayString::Grow() 
1902   // only do it if no more place 
1903   if ( m_nCount 
== m_nSize 
) { 
1904     // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would 
1905     // be never resized! 
1906     #if ARRAY_DEFAULT_INITIAL_SIZE == 0 
1907       #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" 
1910     if ( m_nSize 
== 0 ) { 
1911       // was empty, alloc some memory 
1912       m_nSize 
= ARRAY_DEFAULT_INITIAL_SIZE
; 
1913       m_pItems 
= new wxChar 
*[m_nSize
]; 
1916       // otherwise when it's called for the first time, nIncrement would be 0 
1917       // and the array would never be expanded 
1918       // add 50% but not too much 
1919       size_t nIncrement 
= m_nSize 
< ARRAY_DEFAULT_INITIAL_SIZE
 
1920                           ? ARRAY_DEFAULT_INITIAL_SIZE 
: m_nSize 
>> 1; 
1921       if ( nIncrement 
> ARRAY_MAXSIZE_INCREMENT 
) 
1922         nIncrement 
= ARRAY_MAXSIZE_INCREMENT
; 
1923       m_nSize 
+= nIncrement
; 
1924       wxChar 
**pNew 
= new wxChar 
*[m_nSize
]; 
1926       // copy data to new location 
1927       memcpy(pNew
, m_pItems
, m_nCount
*sizeof(wxChar 
*)); 
1929       // delete old memory (but do not release the strings!) 
1930       wxDELETEA(m_pItems
); 
1937 void wxArrayString::Free() 
1939   for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) { 
1940     STRING(m_pItems
[n
])->GetStringData()->Unlock(); 
1944 // deletes all the strings from the list 
1945 void wxArrayString::Empty() 
1952 // as Empty, but also frees memory 
1953 void wxArrayString::Clear() 
1960   wxDELETEA(m_pItems
); 
1964 wxArrayString::~wxArrayString() 
1968   wxDELETEA(m_pItems
); 
1971 // pre-allocates memory (frees the previous data!) 
1972 void wxArrayString::Alloc(size_t nSize
) 
1974   wxASSERT( nSize 
> 0 ); 
1976   // only if old buffer was not big enough 
1977   if ( nSize 
> m_nSize 
) { 
1979     wxDELETEA(m_pItems
); 
1980     m_pItems 
= new wxChar 
*[nSize
]; 
1987 // minimizes the memory usage by freeing unused memory 
1988 void wxArrayString::Shrink() 
1990   // only do it if we have some memory to free 
1991   if( m_nCount 
< m_nSize 
) { 
1992     // allocates exactly as much memory as we need 
1993     wxChar 
**pNew 
= new wxChar 
*[m_nCount
]; 
1995     // copy data to new location 
1996     memcpy(pNew
, m_pItems
, m_nCount
*sizeof(wxChar 
*)); 
2002 // searches the array for an item (forward or backwards) 
2003 int wxArrayString::Index(const wxChar 
*sz
, bool bCase
, bool bFromEnd
) const 
2006     // use binary search in the sorted array 
2007     wxASSERT_MSG( bCase 
&& !bFromEnd
, 
2008                   wxT("search parameters ignored for auto sorted array") ); 
2017       res 
= wxStrcmp(sz
, m_pItems
[i
]); 
2029     // use linear search in unsorted array 
2031       if ( m_nCount 
> 0 ) { 
2032         size_t ui 
= m_nCount
; 
2034           if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) ) 
2041       for( size_t ui 
= 0; ui 
< m_nCount
; ui
++ ) { 
2042         if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) ) 
2051 // add item at the end 
2052 size_t wxArrayString::Add(const wxString
& str
) 
2055     // insert the string at the correct position to keep the array sorted 
2063       res 
= wxStrcmp(str
, m_pItems
[i
]); 
2074     wxASSERT_MSG( lo 
== hi
, wxT("binary search broken") ); 
2081     wxASSERT( str
.GetStringData()->IsValid() ); 
2085     // the string data must not be deleted! 
2086     str
.GetStringData()->Lock(); 
2089     m_pItems
[m_nCount
] = (wxChar 
*)str
.c_str(); // const_cast 
2095 // add item at the given position 
2096 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
) 
2098   wxASSERT( str
.GetStringData()->IsValid() ); 
2100   wxCHECK_RET( nIndex 
<= m_nCount
, wxT("bad index in wxArrayString::Insert") ); 
2104   memmove(&m_pItems
[nIndex 
+ 1], &m_pItems
[nIndex
], 
2105           (m_nCount 
- nIndex
)*sizeof(wxChar 
*)); 
2107   str
.GetStringData()->Lock(); 
2108   m_pItems
[nIndex
] = (wxChar 
*)str
.c_str(); 
2113 // removes item from array (by index) 
2114 void wxArrayString::Remove(size_t nIndex
) 
2116   wxCHECK_RET( nIndex 
<= m_nCount
, wxT("bad index in wxArrayString::Remove") ); 
2119   Item(nIndex
).GetStringData()->Unlock(); 
2121   memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex 
+ 1], 
2122           (m_nCount 
- nIndex 
- 1)*sizeof(wxChar 
*)); 
2126 // removes item from array (by value) 
2127 void wxArrayString::Remove(const wxChar 
*sz
) 
2129   int iIndex 
= Index(sz
); 
2131   wxCHECK_RET( iIndex 
!= wxNOT_FOUND
, 
2132                wxT("removing inexistent element in wxArrayString::Remove") ); 
2137 // ---------------------------------------------------------------------------- 
2139 // ---------------------------------------------------------------------------- 
2141 // we can only sort one array at a time with the quick-sort based 
2144   // need a critical section to protect access to gs_compareFunction and 
2145   // gs_sortAscending variables 
2146   static wxCriticalSection 
*gs_critsectStringSort 
= NULL
; 
2148   // call this before the value of the global sort vars is changed/after 
2149   // you're finished with them 
2150   #define START_SORT()     wxASSERT( !gs_critsectStringSort );                \ 
2151                            gs_critsectStringSort = new wxCriticalSection;     \ 
2152                            gs_critsectStringSort->Enter() 
2153   #define END_SORT()       gs_critsectStringSort->Leave();                    \ 
2154                            delete gs_critsectStringSort;                      \ 
2155                            gs_critsectStringSort = NULL 
2157   #define START_SORT() 
2159 #endif // wxUSE_THREADS 
2161 // function to use for string comparaison 
2162 static wxArrayString::CompareFunction gs_compareFunction 
= NULL
; 
2164 // if we don't use the compare function, this flag tells us if we sort the 
2165 // array in ascending or descending order 
2166 static bool gs_sortAscending 
= TRUE
; 
2168 // function which is called by quick sort 
2169 static int LINKAGEMODE 
wxStringCompareFunction(const void *first
, const void *second
) 
2171   wxString 
*strFirst 
= (wxString 
*)first
; 
2172   wxString 
*strSecond 
= (wxString 
*)second
; 
2174   if ( gs_compareFunction 
) { 
2175     return gs_compareFunction(*strFirst
, *strSecond
); 
2178     // maybe we should use wxStrcoll 
2179     int result 
= wxStrcmp(strFirst
->c_str(), strSecond
->c_str()); 
2181     return gs_sortAscending 
? result 
: -result
; 
2185 // sort array elements using passed comparaison function 
2186 void wxArrayString::Sort(CompareFunction compareFunction
) 
2190   wxASSERT( !gs_compareFunction 
);  // must have been reset to NULL 
2191   gs_compareFunction 
= compareFunction
; 
2195   // reset it to NULL so that Sort(bool) will work the next time 
2196   gs_compareFunction 
= NULL
; 
2201 void wxArrayString::Sort(bool reverseOrder
) 
2205   wxASSERT( !gs_compareFunction 
);  // must have been reset to NULL 
2206   gs_sortAscending 
= !reverseOrder
; 
2213 void wxArrayString::DoSort() 
2215   wxCHECK_RET( !m_autoSort
, wxT("can't use this method with sorted arrays") ); 
2217   // just sort the pointers using qsort() - of course it only works because 
2218   // wxString() *is* a pointer to its data 
2219   qsort(m_pItems
, m_nCount
, sizeof(wxChar 
*), wxStringCompareFunction
); 
2222 bool wxArrayString::operator==(const wxArrayString
& a
) const 
2224     if ( m_nCount 
!= a
.m_nCount 
) 
2227     for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) 
2229         if ( Item(n
) != a
[n
] )