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" 
  49   #include <wchar.h>    // for wcsrtombs(), see comments where it's used 
  52 #ifdef  WXSTRING_IS_WXOBJECT 
  53   IMPLEMENT_DYNAMIC_CLASS(wxString
, wxObject
) 
  54 #endif  //WXSTRING_IS_WXOBJECT 
  56 // allocating extra space for each string consumes more memory but speeds up 
  57 // the concatenation operations (nLen is the current string's length) 
  58 // NB: EXTRA_ALLOC must be >= 0! 
  59 #define EXTRA_ALLOC       (19 - nLen % 16) 
  61 // --------------------------------------------------------------------------- 
  62 // static class variables definition 
  63 // --------------------------------------------------------------------------- 
  65 #ifdef  wxSTD_STRING_COMPATIBILITY 
  66   const size_t wxString::npos 
= wxSTRING_MAXLEN
; 
  67 #endif // wxSTD_STRING_COMPATIBILITY 
  69 // ---------------------------------------------------------------------------- 
  71 // ---------------------------------------------------------------------------- 
  73 // for an empty string, GetStringData() will return this address: this 
  74 // structure has the same layout as wxStringData and it's data() method will 
  75 // return the empty string (dummy pointer) 
  80 } g_strEmpty 
= { {-1, 0, 0}, '\0' }; 
  82 // empty C style string: points to 'string data' byte of g_strEmpty 
  83 extern const char WXDLLEXPORT 
*g_szNul 
= &g_strEmpty
.dummy
; 
  85 // ---------------------------------------------------------------------------- 
  86 // conditional compilation 
  87 // ---------------------------------------------------------------------------- 
  89 // we want to find out if the current platform supports vsnprintf()-like 
  90 // function: for Unix this is done with configure, for Windows we test the 
  91 // compiler explicitly. 
  94         #define wxVsprintf     _vsnprintf 
  98         #define wxVsprintf       vsnprintf 
 100 #endif  // Windows/!Windows 
 103     // in this case we'll use vsprintf() (which is ANSI and thus should be 
 104     // always available), but it's unsafe because it doesn't check for buffer 
 105     // size - so give a warning 
 106     #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr) 
 107 #if defined(__VISUALC__) 
 108     #pragma message("Using sprintf() because no snprintf()-like function defined") 
 109 #elif defined(__GNUG__) 
 110     #warning "Using sprintf() because no snprintf()-like function defined" 
 111 #elif defined(__SUNCC__) 
 112     // nothing -- I don't know about "#warning" for Sun's CC 
 114     // change this to some analogue of '#warning' for your compiler 
 115     #error "Using sprintf() because no snprintf()-like function defined" 
 118 #endif // no vsnprintf 
 120 // ---------------------------------------------------------------------------- 
 122 // ---------------------------------------------------------------------------- 
 124 #ifdef  wxSTD_STRING_COMPATIBILITY 
 126 // MS Visual C++ version 5.0 provides the new STL headers as well as the old 
 129 // ATTN: you can _not_ use both of these in the same program! 
 131 istream
& operator>>(istream
& is
, wxString
& WXUNUSED(str
)) 
 136     streambuf 
*sb 
= is
.rdbuf(); 
 139       int ch 
= sb
->sbumpc (); 
 141         is
.setstate(ios::eofbit
); 
 144       else if ( isspace(ch
) ) { 
 156   if ( str
.length() == 0 ) 
 157     is
.setstate(ios::failbit
); 
 162 #endif  //std::string compatibility 
 164 // ---------------------------------------------------------------------------- 
 166 // ---------------------------------------------------------------------------- 
 168 // this small class is used to gather statistics for performance tuning 
 169 //#define WXSTRING_STATISTICS 
 170 #ifdef  WXSTRING_STATISTICS 
 174     Averager(const char *sz
) { m_sz 
= sz
; m_nTotal 
= m_nCount 
= 0; } 
 176    { printf("wxString: average %s = %f\n", m_sz
, ((float)m_nTotal
)/m_nCount
); } 
 178     void Add(size_t n
) { m_nTotal 
+= n
; m_nCount
++; } 
 181     size_t m_nCount
, m_nTotal
; 
 183   } g_averageLength("allocation size"), 
 184     g_averageSummandLength("summand length"), 
 185     g_averageConcatHit("hit probability in concat"), 
 186     g_averageInitialLength("initial string length"); 
 188   #define STATISTICS_ADD(av, val) g_average##av.Add(val) 
 190   #define STATISTICS_ADD(av, val) 
 191 #endif // WXSTRING_STATISTICS 
 193 // =========================================================================== 
 194 // wxString class core 
 195 // =========================================================================== 
 197 // --------------------------------------------------------------------------- 
 199 // --------------------------------------------------------------------------- 
 201 // constructs string of <nLength> copies of character <ch> 
 202 wxString::wxString(char ch
, size_t nLength
) 
 207     AllocBuffer(nLength
); 
 209     wxASSERT( sizeof(char) == 1 );  // can't use memset if not 
 211     memset(m_pchData
, ch
, nLength
); 
 215 // takes nLength elements of psz starting at nPos 
 216 void wxString::InitWith(const char *psz
, size_t nPos
, size_t nLength
) 
 220   wxASSERT( nPos 
<= Strlen(psz
) ); 
 222   if ( nLength 
== wxSTRING_MAXLEN 
) 
 223     nLength 
= Strlen(psz 
+ nPos
); 
 225   STATISTICS_ADD(InitialLength
, nLength
); 
 228     // trailing '\0' is written in AllocBuffer() 
 229     AllocBuffer(nLength
); 
 230     memcpy(m_pchData
, psz 
+ nPos
, nLength
*sizeof(char)); 
 234 // the same as previous constructor, but for compilers using unsigned char 
 235 wxString::wxString(const unsigned char* psz
, size_t nLength
) 
 237   InitWith((const char *)psz
, 0, nLength
); 
 240 #ifdef  wxSTD_STRING_COMPATIBILITY 
 242 // poor man's iterators are "void *" pointers 
 243 wxString::wxString(const void *pStart
, const void *pEnd
) 
 245   InitWith((const char *)pStart
, 0, 
 246            (const char *)pEnd 
- (const char *)pStart
); 
 249 #endif  //std::string compatibility 
 252 wxString::wxString(const wchar_t *pwz
) 
 254   // first get necessary size 
 256   // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't 
 257   //     honor the 3rd parameter, thus it will happily crash here). 
 259   // don't know if it's really needed (or if we can pass NULL), but better safe 
 262   size_t nLen 
= wcsrtombs((char *) NULL
, &pwz
, 0, &mbstate
); 
 264   size_t nLen 
= wcstombs((char *) NULL
, pwz
, 0); 
 270     wcstombs(m_pchData
, pwz
, nLen
); 
 277 // --------------------------------------------------------------------------- 
 279 // --------------------------------------------------------------------------- 
 281 // allocates memory needed to store a C string of length nLen 
 282 void wxString::AllocBuffer(size_t nLen
) 
 284   wxASSERT( nLen 
>  0         );    // 
 285   wxASSERT( nLen 
<= INT_MAX
-1 );    // max size (enough room for 1 extra) 
 287   STATISTICS_ADD(Length
, nLen
); 
 290   // 1) one extra character for '\0' termination 
 291   // 2) sizeof(wxStringData) for housekeeping info 
 292   wxStringData
* pData 
= (wxStringData
*) 
 293     malloc(sizeof(wxStringData
) + (nLen 
+ EXTRA_ALLOC 
+ 1)*sizeof(char)); 
 295   pData
->nDataLength  
= nLen
; 
 296   pData
->nAllocLength 
= nLen 
+ EXTRA_ALLOC
; 
 297   m_pchData           
= pData
->data();  // data starts after wxStringData 
 298   m_pchData
[nLen
]     = '\0'; 
 301 // must be called before changing this string 
 302 void wxString::CopyBeforeWrite() 
 304   wxStringData
* pData 
= GetStringData(); 
 306   if ( pData
->IsShared() ) { 
 307     pData
->Unlock();                // memory not freed because shared 
 308     size_t nLen 
= pData
->nDataLength
; 
 310     memcpy(m_pchData
, pData
->data(), nLen
*sizeof(char)); 
 313   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 316 // must be called before replacing contents of this string 
 317 void wxString::AllocBeforeWrite(size_t nLen
) 
 319   wxASSERT( nLen 
!= 0 );  // doesn't make any sense 
 321   // must not share string and must have enough space 
 322   wxStringData
* pData 
= GetStringData(); 
 323   if ( pData
->IsShared() || (nLen 
> pData
->nAllocLength
) ) { 
 324     // can't work with old buffer, get new one 
 329     // update the string length 
 330     pData
->nDataLength 
= nLen
; 
 333   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 336 // allocate enough memory for nLen characters 
 337 void wxString::Alloc(size_t nLen
) 
 339   wxStringData 
*pData 
= GetStringData(); 
 340   if ( pData
->nAllocLength 
<= nLen 
) { 
 341     if ( pData
->IsEmpty() ) { 
 344       wxStringData
* pData 
= (wxStringData
*) 
 345         malloc(sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(char)); 
 347       pData
->nDataLength 
= 0; 
 348       pData
->nAllocLength 
= nLen
; 
 349       m_pchData 
= pData
->data();  // data starts after wxStringData 
 350       m_pchData
[0u] = '\0'; 
 352     else if ( pData
->IsShared() ) { 
 353       pData
->Unlock();                // memory not freed because shared 
 354       size_t nOldLen 
= pData
->nDataLength
; 
 356       memcpy(m_pchData
, pData
->data(), nOldLen
*sizeof(char)); 
 361       wxStringData 
*p 
= (wxStringData 
*) 
 362         realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(char)); 
 365         // @@@ what to do on memory error? 
 369       // it's not important if the pointer changed or not (the check for this 
 370       // is not faster than assigning to m_pchData in all cases) 
 371       p
->nAllocLength 
= nLen
; 
 372       m_pchData 
= p
->data(); 
 375   //else: we've already got enough 
 378 // shrink to minimal size (releasing extra memory) 
 379 void wxString::Shrink() 
 381   wxStringData 
*pData 
= GetStringData(); 
 383   // this variable is unused in release build, so avoid the compiler warning by 
 384   // just not declaring it 
 388   realloc(pData
, sizeof(wxStringData
) + (pData
->nDataLength 
+ 1)*sizeof(char)); 
 390   wxASSERT( p 
!= NULL 
);  // can't free memory? 
 391   wxASSERT( p 
== pData 
); // we're decrementing the size - block shouldn't move! 
 394 // get the pointer to writable buffer of (at least) nLen bytes 
 395 char *wxString::GetWriteBuf(size_t nLen
) 
 397   AllocBeforeWrite(nLen
); 
 399   wxASSERT( GetStringData()->nRefs 
== 1 ); 
 400   GetStringData()->Validate(FALSE
); 
 405 // put string back in a reasonable state after GetWriteBuf 
 406 void wxString::UngetWriteBuf() 
 408   GetStringData()->nDataLength 
= strlen(m_pchData
); 
 409   GetStringData()->Validate(TRUE
); 
 412 // --------------------------------------------------------------------------- 
 414 // --------------------------------------------------------------------------- 
 416 // all functions are inline in string.h 
 418 // --------------------------------------------------------------------------- 
 419 // assignment operators 
 420 // --------------------------------------------------------------------------- 
 422 // helper function: does real copy 
 423 void wxString::AssignCopy(size_t nSrcLen
, const char *pszSrcData
) 
 425   if ( nSrcLen 
== 0 ) { 
 429     AllocBeforeWrite(nSrcLen
); 
 430     memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(char)); 
 431     GetStringData()->nDataLength 
= nSrcLen
; 
 432     m_pchData
[nSrcLen
] = '\0'; 
 436 // assigns one string to another 
 437 wxString
& wxString::operator=(const wxString
& stringSrc
) 
 439   wxASSERT( stringSrc
.GetStringData()->IsValid() ); 
 441   // don't copy string over itself 
 442   if ( m_pchData 
!= stringSrc
.m_pchData 
) { 
 443     if ( stringSrc
.GetStringData()->IsEmpty() ) { 
 448       GetStringData()->Unlock(); 
 449       m_pchData 
= stringSrc
.m_pchData
; 
 450       GetStringData()->Lock(); 
 457 // assigns a single character 
 458 wxString
& wxString::operator=(char ch
) 
 465 wxString
& wxString::operator=(const char *psz
) 
 467   AssignCopy(Strlen(psz
), psz
); 
 471 // same as 'signed char' variant 
 472 wxString
& wxString::operator=(const unsigned char* psz
) 
 474   *this = (const char *)psz
; 
 478 wxString
& wxString::operator=(const wchar_t *pwz
) 
 485 // --------------------------------------------------------------------------- 
 486 // string concatenation 
 487 // --------------------------------------------------------------------------- 
 489 // add something to this string 
 490 void wxString::ConcatSelf(int nSrcLen
, const char *pszSrcData
) 
 492   STATISTICS_ADD(SummandLength
, nSrcLen
); 
 494   // concatenating an empty string is a NOP 
 496     wxStringData 
*pData 
= GetStringData(); 
 497     size_t nLen 
= pData
->nDataLength
; 
 498     size_t nNewLen 
= nLen 
+ nSrcLen
; 
 500     // alloc new buffer if current is too small 
 501     if ( pData
->IsShared() ) { 
 502       STATISTICS_ADD(ConcatHit
, 0); 
 504       // we have to allocate another buffer 
 505       wxStringData
* pOldData 
= GetStringData(); 
 506       AllocBuffer(nNewLen
); 
 507       memcpy(m_pchData
, pOldData
->data(), nLen
*sizeof(char)); 
 510     else if ( nNewLen 
> pData
->nAllocLength 
) { 
 511       STATISTICS_ADD(ConcatHit
, 0); 
 513       // we have to grow the buffer 
 517       STATISTICS_ADD(ConcatHit
, 1); 
 519       // the buffer is already big enough 
 522     // should be enough space 
 523     wxASSERT( nNewLen 
<= GetStringData()->nAllocLength 
); 
 525     // fast concatenation - all is done in our buffer 
 526     memcpy(m_pchData 
+ nLen
, pszSrcData
, nSrcLen
*sizeof(char)); 
 528     m_pchData
[nNewLen
] = '\0';              // put terminating '\0' 
 529     GetStringData()->nDataLength 
= nNewLen
; // and fix the length 
 531   //else: the string to append was empty 
 535  * concatenation functions come in 5 flavours: 
 537  *  char   + string      and      string + char 
 538  *  C str  + string      and      string + C str 
 541 wxString 
operator+(const wxString
& string1
, const wxString
& string2
) 
 543   wxASSERT( string1
.GetStringData()->IsValid() ); 
 544   wxASSERT( string2
.GetStringData()->IsValid() ); 
 546   wxString s 
= string1
; 
 552 wxString 
operator+(const wxString
& string
, char ch
) 
 554   wxASSERT( string
.GetStringData()->IsValid() ); 
 562 wxString 
operator+(char ch
, const wxString
& string
) 
 564   wxASSERT( string
.GetStringData()->IsValid() ); 
 572 wxString 
operator+(const wxString
& string
, const char *psz
) 
 574   wxASSERT( string
.GetStringData()->IsValid() ); 
 577   s
.Alloc(Strlen(psz
) + string
.Len()); 
 584 wxString 
operator+(const char *psz
, const wxString
& string
) 
 586   wxASSERT( string
.GetStringData()->IsValid() ); 
 589   s
.Alloc(Strlen(psz
) + string
.Len()); 
 596 // =========================================================================== 
 597 // other common string functions 
 598 // =========================================================================== 
 600 // --------------------------------------------------------------------------- 
 601 // simple sub-string extraction 
 602 // --------------------------------------------------------------------------- 
 604 // helper function: clone the data attached to this string 
 605 void wxString::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const 
 607   if ( nCopyLen 
== 0 ) { 
 611     dest
.AllocBuffer(nCopyLen
); 
 612     memcpy(dest
.m_pchData
, m_pchData 
+ nCopyIndex
, nCopyLen
*sizeof(char)); 
 616 // extract string of length nCount starting at nFirst 
 617 wxString 
wxString::Mid(size_t nFirst
, size_t nCount
) const 
 619   wxStringData 
*pData 
= GetStringData(); 
 620   size_t nLen 
= pData
->nDataLength
; 
 622   // default value of nCount is wxSTRING_MAXLEN and means "till the end" 
 623   if ( nCount 
== wxSTRING_MAXLEN 
) 
 625     nCount 
= nLen 
- nFirst
; 
 628   // out-of-bounds requests return sensible things 
 629   if ( nFirst 
+ nCount 
> nLen 
) 
 631     nCount 
= nLen 
- nFirst
; 
 636     // AllocCopy() will return empty string 
 641   AllocCopy(dest
, nCount
, nFirst
); 
 646 // extract nCount last (rightmost) characters 
 647 wxString 
wxString::Right(size_t nCount
) const 
 649   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 650     nCount 
= GetStringData()->nDataLength
; 
 653   AllocCopy(dest
, nCount
, GetStringData()->nDataLength 
- nCount
); 
 657 // get all characters after the last occurence of ch 
 658 // (returns the whole string if ch not found) 
 659 wxString 
wxString::AfterLast(char ch
) const 
 662   int iPos 
= Find(ch
, TRUE
); 
 663   if ( iPos 
== wxNOT_FOUND 
) 
 666     str 
= c_str() + iPos 
+ 1; 
 671 // extract nCount first (leftmost) characters 
 672 wxString 
wxString::Left(size_t nCount
) const 
 674   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 675     nCount 
= GetStringData()->nDataLength
; 
 678   AllocCopy(dest
, nCount
, 0); 
 682 // get all characters before the first occurence of ch 
 683 // (returns the whole string if ch not found) 
 684 wxString 
wxString::BeforeFirst(char ch
) const 
 687   for ( const char *pc 
= m_pchData
; *pc 
!= '\0' && *pc 
!= ch
; pc
++ ) 
 693 /// get all characters before the last occurence of ch 
 694 /// (returns empty string if ch not found) 
 695 wxString 
wxString::BeforeLast(char ch
) const 
 698   int iPos 
= Find(ch
, TRUE
); 
 699   if ( iPos 
!= wxNOT_FOUND 
&& iPos 
!= 0 ) 
 700     str 
= wxString(c_str(), iPos
); 
 705 /// get all characters after the first occurence of ch 
 706 /// (returns empty string if ch not found) 
 707 wxString 
wxString::AfterFirst(char ch
) const 
 711   if ( iPos 
!= wxNOT_FOUND 
) 
 712     str 
= c_str() + iPos 
+ 1; 
 717 // replace first (or all) occurences of some substring with another one 
 718 size_t wxString::Replace(const char *szOld
, const char *szNew
, bool bReplaceAll
) 
 720   size_t uiCount 
= 0;   // count of replacements made 
 722   size_t uiOldLen 
= Strlen(szOld
); 
 725   const char *pCurrent 
= m_pchData
; 
 727   while ( *pCurrent 
!= '\0' ) { 
 728     pSubstr 
= strstr(pCurrent
, szOld
); 
 729     if ( pSubstr 
== NULL 
) { 
 730       // strTemp is unused if no replacements were made, so avoid the copy 
 734       strTemp 
+= pCurrent
;    // copy the rest 
 735       break;                  // exit the loop 
 738       // take chars before match 
 739       strTemp
.ConcatSelf(pSubstr 
- pCurrent
, pCurrent
); 
 741       pCurrent 
= pSubstr 
+ uiOldLen
;  // restart after match 
 746       if ( !bReplaceAll 
) { 
 747         strTemp 
+= pCurrent
;    // copy the rest 
 748         break;                  // exit the loop 
 753   // only done if there were replacements, otherwise would have returned above 
 759 bool wxString::IsAscii() const 
 761   const char *s 
= (const char*) *this; 
 763     if(!isascii(*s
)) return(FALSE
); 
 769 bool wxString::IsWord() const 
 771   const char *s 
= (const char*) *this; 
 773     if(!isalpha(*s
)) return(FALSE
); 
 779 bool wxString::IsNumber() const 
 781   const char *s 
= (const char*) *this; 
 783     if(!isdigit(*s
)) return(FALSE
); 
 789 wxString 
wxString::Strip(stripType w
) const 
 792     if ( w 
& leading 
) s
.Trim(FALSE
); 
 793     if ( w 
& trailing 
) s
.Trim(TRUE
); 
 797 // --------------------------------------------------------------------------- 
 799 // --------------------------------------------------------------------------- 
 801 wxString
& wxString::MakeUpper() 
 805   for ( char *p 
= m_pchData
; *p
; p
++ ) 
 806     *p 
= (char)toupper(*p
); 
 811 wxString
& wxString::MakeLower() 
 815   for ( char *p 
= m_pchData
; *p
; p
++ ) 
 816     *p 
= (char)tolower(*p
); 
 821 // --------------------------------------------------------------------------- 
 822 // trimming and padding 
 823 // --------------------------------------------------------------------------- 
 825 // trims spaces (in the sense of isspace) from left or right side 
 826 wxString
& wxString::Trim(bool bFromRight
) 
 828   // first check if we're going to modify the string at all 
 831         (bFromRight 
&& isspace(GetChar(Len() - 1))) || 
 832         (!bFromRight 
&& isspace(GetChar(0u))) 
 836     // ok, there is at least one space to trim 
 841       // find last non-space character 
 842       char *psz 
= m_pchData 
+ GetStringData()->nDataLength 
- 1; 
 843       while ( isspace(*psz
) && (psz 
>= m_pchData
) ) 
 846       // truncate at trailing space start 
 848       GetStringData()->nDataLength 
= psz 
- m_pchData
; 
 852       // find first non-space character 
 853       const char *psz 
= m_pchData
; 
 854       while ( isspace(*psz
) ) 
 857       // fix up data and length 
 858       int nDataLength 
= GetStringData()->nDataLength 
- (psz 
- (const char*) m_pchData
); 
 859       memmove(m_pchData
, psz
, (nDataLength 
+ 1)*sizeof(char)); 
 860       GetStringData()->nDataLength 
= nDataLength
; 
 867 // adds nCount characters chPad to the string from either side 
 868 wxString
& wxString::Pad(size_t nCount
, char chPad
, bool bFromRight
) 
 870   wxString 
s(chPad
, nCount
); 
 883 // truncate the string 
 884 wxString
& wxString::Truncate(size_t uiLen
) 
 886   if ( uiLen 
< Len() ) { 
 889     *(m_pchData 
+ uiLen
) = '\0'; 
 890     GetStringData()->nDataLength 
= uiLen
; 
 892   //else: nothing to do, string is already short enough 
 897 // --------------------------------------------------------------------------- 
 898 // finding (return wxNOT_FOUND if not found and index otherwise) 
 899 // --------------------------------------------------------------------------- 
 902 int wxString::Find(char ch
, bool bFromEnd
) const 
 904   const char *psz 
= bFromEnd 
? strrchr(m_pchData
, ch
) : strchr(m_pchData
, ch
); 
 906   return (psz 
== NULL
) ? wxNOT_FOUND 
: psz 
- (const char*) m_pchData
; 
 909 // find a sub-string (like strstr) 
 910 int wxString::Find(const char *pszSub
) const 
 912   const char *psz 
= strstr(m_pchData
, pszSub
); 
 914   return (psz 
== NULL
) ? wxNOT_FOUND 
: psz 
- (const char*) m_pchData
; 
 917 // --------------------------------------------------------------------------- 
 918 // stream-like operators 
 919 // --------------------------------------------------------------------------- 
 920 wxString
& wxString::operator<<(int i
) 
 925     return (*this) << res
; 
 928 wxString
& wxString::operator<<(float f
) 
 933     return (*this) << res
; 
 936 wxString
& wxString::operator<<(double d
) 
 941     return (*this) << res
; 
 944 // --------------------------------------------------------------------------- 
 946 // --------------------------------------------------------------------------- 
 947 int wxString::Printf(const char *pszFormat
, ...) 
 950   va_start(argptr
, pszFormat
); 
 952   int iLen 
= PrintfV(pszFormat
, argptr
); 
 959 int wxString::PrintfV(const char* pszFormat
, va_list argptr
) 
 961   // static buffer to avoid dynamic memory allocation each time 
 962   static char s_szScratch
[1024]; 
 964   // NB: wxVsprintf() may return either less than the buffer size or -1 if there 
 965   //     is not enough place depending on implementation 
 966   int iLen 
= wxVsprintf(s_szScratch
, WXSIZEOF(s_szScratch
), pszFormat
, argptr
); 
 968   if ( iLen 
< (int)WXSIZEOF(s_szScratch
) ) { 
 969     buffer 
= s_szScratch
; 
 972       int size 
= WXSIZEOF(s_szScratch
) * 2; 
 973       buffer 
= (char *)malloc(size
); 
 974       while ( buffer 
!= NULL 
) { 
 975           iLen 
= wxVsprintf(buffer
, WXSIZEOF(s_szScratch
), pszFormat
, argptr
); 
 977               // ok, there was enough space 
 981           // still not enough, double it again 
 982           buffer 
= (char *)realloc(buffer
, size 
*= 2); 
 991   AllocBeforeWrite(iLen
); 
 992   strcpy(m_pchData
, buffer
); 
 994   if ( buffer 
!= s_szScratch 
) 
1000 // ---------------------------------------------------------------------------- 
1001 // misc other operations 
1002 // ---------------------------------------------------------------------------- 
1003 bool wxString::Matches(const char *pszMask
) const 
1005   // check char by char 
1007   for ( pszTxt 
= c_str(); *pszMask 
!= '\0'; pszMask
++, pszTxt
++ ) { 
1008     switch ( *pszMask 
) { 
1010         if ( *pszTxt 
== '\0' ) 
1019           // ignore special chars immediately following this one 
1020           while ( *pszMask 
== '*' || *pszMask 
== '?' ) 
1023           // if there is nothing more, match 
1024           if ( *pszMask 
== '\0' ) 
1027           // are there any other metacharacters in the mask? 
1029           const char *pEndMask 
= strpbrk(pszMask
, "*?"); 
1031           if ( pEndMask 
!= NULL 
) { 
1032             // we have to match the string between two metachars 
1033             uiLenMask 
= pEndMask 
- pszMask
; 
1036             // we have to match the remainder of the string 
1037             uiLenMask 
= strlen(pszMask
); 
1040           wxString 
strToMatch(pszMask
, uiLenMask
); 
1041           const char* pMatch 
= strstr(pszTxt
, strToMatch
); 
1042           if ( pMatch 
== NULL 
) 
1045           // -1 to compensate "++" in the loop 
1046           pszTxt 
= pMatch 
+ uiLenMask 
- 1; 
1047           pszMask 
+= uiLenMask 
- 1; 
1052         if ( *pszMask 
!= *pszTxt 
) 
1058   // match only if nothing left 
1059   return *pszTxt 
== '\0'; 
1062 // Count the number of chars 
1063 int wxString::Freq(char ch
) const 
1067     for (int i 
= 0; i 
< len
; i
++) 
1069         if (GetChar(i
) == ch
) 
1075 // convert to upper case, return the copy of the string 
1076 wxString 
wxString::Upper() const 
1077 { wxString 
s(*this); return s
.MakeUpper(); } 
1079 // convert to lower case, return the copy of the string 
1080 wxString 
wxString::Lower() const { wxString 
s(*this); return s
.MakeLower(); } 
1082 int wxString::sprintf(const char *pszFormat
, ...) 
1085     va_start(argptr
, pszFormat
); 
1086     int iLen 
= PrintfV(pszFormat
, argptr
); 
1091 // --------------------------------------------------------------------------- 
1092 // standard C++ library string functions 
1093 // --------------------------------------------------------------------------- 
1094 #ifdef  wxSTD_STRING_COMPATIBILITY 
1096 wxString
& wxString::insert(size_t nPos
, const wxString
& str
) 
1098   wxASSERT( str
.GetStringData()->IsValid() ); 
1099   wxASSERT( nPos 
<= Len() ); 
1101   if ( !str
.IsEmpty() ) { 
1103     char *pc 
= strTmp
.GetWriteBuf(Len() + str
.Len()); 
1104     strncpy(pc
, c_str(), nPos
); 
1105     strcpy(pc 
+ nPos
, str
); 
1106     strcpy(pc 
+ nPos 
+ str
.Len(), c_str() + nPos
); 
1107     strTmp
.UngetWriteBuf(); 
1114 size_t wxString::find(const wxString
& str
, size_t nStart
) const 
1116   wxASSERT( str
.GetStringData()->IsValid() ); 
1117   wxASSERT( nStart 
<= Len() ); 
1119   const char *p 
= strstr(c_str() + nStart
, str
); 
1121   return p 
== NULL 
? npos 
: p 
- c_str(); 
1124 // VC++ 1.5 can't cope with the default argument in the header. 
1125 #if !defined(__VISUALC__) || defined(__WIN32__) 
1126 size_t wxString::find(const char* sz
, size_t nStart
, size_t n
) const 
1128   return find(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1132 // Gives a duplicate symbol (presumably a case-insensitivity problem) 
1133 #if !defined(__BORLANDC__) 
1134 size_t wxString::find(char ch
, size_t nStart
) const 
1136   wxASSERT( nStart 
<= Len() ); 
1138   const char *p 
= strchr(c_str() + nStart
, ch
); 
1140   return p 
== NULL 
? npos 
: p 
- c_str(); 
1144 size_t wxString::rfind(const wxString
& str
, size_t nStart
) const 
1146   wxASSERT( str
.GetStringData()->IsValid() ); 
1147   wxASSERT( nStart 
<= Len() ); 
1149   // # could be quicker than that 
1150   const char *p 
= c_str() + (nStart 
== npos 
? Len() : nStart
); 
1151   while ( p 
>= c_str() + str
.Len() ) { 
1152     if ( strncmp(p 
- str
.Len(), str
, str
.Len()) == 0 ) 
1153       return p 
- str
.Len() - c_str(); 
1160 // VC++ 1.5 can't cope with the default argument in the header. 
1161 #if !defined(__VISUALC__) || defined(__WIN32__) 
1162 size_t wxString::rfind(const char* sz
, size_t nStart
, size_t n
) const 
1164   return rfind(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1167 size_t wxString::rfind(char ch
, size_t nStart
) const 
1169   wxASSERT( nStart 
<= Len() ); 
1171   const char *p 
= strrchr(c_str() + nStart
, ch
); 
1173   return p 
== NULL 
? npos 
: p 
- c_str(); 
1177 wxString 
wxString::substr(size_t nStart
, size_t nLen
) const 
1179   // npos means 'take all' 
1183   wxASSERT( nStart 
+ nLen 
<= Len() ); 
1185   return wxString(c_str() + nStart
, nLen 
== npos 
? 0 : nLen
); 
1188 wxString
& wxString::erase(size_t nStart
, size_t nLen
) 
1190   wxString 
strTmp(c_str(), nStart
); 
1191   if ( nLen 
!= npos 
) { 
1192     wxASSERT( nStart 
+ nLen 
<= Len() ); 
1194     strTmp
.append(c_str() + nStart 
+ nLen
); 
1201 wxString
& wxString::replace(size_t nStart
, size_t nLen
, const char *sz
) 
1203   wxASSERT( nStart 
+ nLen 
<= Strlen(sz
) ); 
1207     strTmp
.append(c_str(), nStart
); 
1209   strTmp
.append(c_str() + nStart 
+ nLen
); 
1215 wxString
& wxString::replace(size_t nStart
, size_t nLen
, size_t nCount
, char ch
) 
1217   return replace(nStart
, nLen
, wxString(ch
, nCount
)); 
1220 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1221                             const wxString
& str
, size_t nStart2
, size_t nLen2
) 
1223   return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
)); 
1226 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1227                         const char* sz
, size_t nCount
) 
1229   return replace(nStart
, nLen
, wxString(sz
, nCount
)); 
1232 #endif  //std::string compatibility 
1234 // ============================================================================ 
1236 // ============================================================================ 
1238 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) 
1239 #define   ARRAY_MAXSIZE_INCREMENT       4096 
1240 #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h 
1241   #define   ARRAY_DEFAULT_INITIAL_SIZE    (16) 
1244 #define   STRING(p)   ((wxString *)(&(p))) 
1247 wxArrayString::wxArrayString() 
1251   m_pItems 
= (char **) NULL
; 
1255 wxArrayString::wxArrayString(const wxArrayString
& src
) 
1259   m_pItems 
= (char **) NULL
; 
1264 // assignment operator 
1265 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
) 
1270   if ( src
.m_nCount 
> ARRAY_DEFAULT_INITIAL_SIZE 
) 
1271     Alloc(src
.m_nCount
); 
1273   // we can't just copy the pointers here because otherwise we would share 
1274   // the strings with another array 
1275   for ( size_t n 
= 0; n 
< src
.m_nCount
; n
++ ) 
1278   if ( m_nCount 
!= 0 ) 
1279     memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *)); 
1285 void wxArrayString::Grow() 
1287   // only do it if no more place 
1288   if( m_nCount 
== m_nSize 
) { 
1289     if( m_nSize 
== 0 ) { 
1290       // was empty, alloc some memory 
1291       m_nSize 
= ARRAY_DEFAULT_INITIAL_SIZE
; 
1292       m_pItems 
= new char *[m_nSize
]; 
1295       // otherwise when it's called for the first time, nIncrement would be 0 
1296       // and the array would never be expanded 
1297       wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE 
!= 0 ); 
1299       // add 50% but not too much 
1300       size_t nIncrement 
= m_nSize 
< ARRAY_DEFAULT_INITIAL_SIZE
 
1301                           ? ARRAY_DEFAULT_INITIAL_SIZE 
: m_nSize 
>> 1; 
1302       if ( nIncrement 
> ARRAY_MAXSIZE_INCREMENT 
) 
1303         nIncrement 
= ARRAY_MAXSIZE_INCREMENT
; 
1304       m_nSize 
+= nIncrement
; 
1305       char **pNew 
= new char *[m_nSize
]; 
1307       // copy data to new location 
1308       memcpy(pNew
, m_pItems
, m_nCount
*sizeof(char *)); 
1310       // delete old memory (but do not release the strings!) 
1311       wxDELETEA(m_pItems
); 
1318 void wxArrayString::Free() 
1320   for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) { 
1321     STRING(m_pItems
[n
])->GetStringData()->Unlock(); 
1325 // deletes all the strings from the list 
1326 void wxArrayString::Empty() 
1333 // as Empty, but also frees memory 
1334 void wxArrayString::Clear() 
1341   wxDELETEA(m_pItems
); 
1345 wxArrayString::~wxArrayString() 
1349   wxDELETEA(m_pItems
); 
1352 // pre-allocates memory (frees the previous data!) 
1353 void wxArrayString::Alloc(size_t nSize
) 
1355   wxASSERT( nSize 
> 0 ); 
1357   // only if old buffer was not big enough 
1358   if ( nSize 
> m_nSize 
) { 
1360     wxDELETEA(m_pItems
); 
1361     m_pItems 
= new char *[nSize
]; 
1368 // searches the array for an item (forward or backwards) 
1369 int wxArrayString::Index(const char *sz
, bool bCase
, bool bFromEnd
) const 
1372     if ( m_nCount 
> 0 ) { 
1373       size_t ui 
= m_nCount
; 
1375         if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) ) 
1382     for( size_t ui 
= 0; ui 
< m_nCount
; ui
++ ) { 
1383       if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) ) 
1391 // add item at the end 
1392 void wxArrayString::Add(const wxString
& str
) 
1394   wxASSERT( str
.GetStringData()->IsValid() ); 
1398   // the string data must not be deleted! 
1399   str
.GetStringData()->Lock(); 
1400   m_pItems
[m_nCount
++] = (char *)str
.c_str(); 
1403 // add item at the given position 
1404 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
) 
1406   wxASSERT( str
.GetStringData()->IsValid() ); 
1408   wxCHECK_RET( nIndex 
<= m_nCount
, ("bad index in wxArrayString::Insert") ); 
1412   memmove(&m_pItems
[nIndex 
+ 1], &m_pItems
[nIndex
], 
1413           (m_nCount 
- nIndex
)*sizeof(char *)); 
1415   str
.GetStringData()->Lock(); 
1416   m_pItems
[nIndex
] = (char *)str
.c_str(); 
1421 // removes item from array (by index) 
1422 void wxArrayString::Remove(size_t nIndex
) 
1424   wxCHECK_RET( nIndex 
<= m_nCount
, _("bad index in wxArrayString::Remove") ); 
1427   Item(nIndex
).GetStringData()->Unlock(); 
1429   memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex 
+ 1], 
1430           (m_nCount 
- nIndex 
- 1)*sizeof(char *)); 
1434 // removes item from array (by value) 
1435 void wxArrayString::Remove(const char *sz
) 
1437   int iIndex 
= Index(sz
); 
1439   wxCHECK_RET( iIndex 
!= wxNOT_FOUND
, 
1440                _("removing inexistent element in wxArrayString::Remove") ); 
1445 // sort array elements using passed comparaison function 
1447 void wxArrayString::Sort(bool WXUNUSED(bCase
), bool WXUNUSED(bReverse
) ) 
1450   //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);