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" 
  44 #ifdef wxUSE_WCSRTOMBS 
  45   #include <wchar.h>    // for wcsrtombs(), see comments where it's used 
  48 #ifdef  WXSTRING_IS_WXOBJECT 
  49   IMPLEMENT_DYNAMIC_CLASS(wxString
, wxObject
) 
  50 #endif  //WXSTRING_IS_WXOBJECT 
  52 // allocating extra space for each string consumes more memory but speeds up 
  53 // the concatenation operations (nLen is the current string's length) 
  54 // NB: EXTRA_ALLOC must be >= 0! 
  55 #define EXTRA_ALLOC       (19 - nLen % 16) 
  57 // --------------------------------------------------------------------------- 
  58 // static class variables definition 
  59 // --------------------------------------------------------------------------- 
  61 #ifdef  STD_STRING_COMPATIBILITY 
  62   const size_t wxString::npos 
= STRING_MAXLEN
; 
  65 // ---------------------------------------------------------------------------- 
  67 // ---------------------------------------------------------------------------- 
  69 // for an empty string, GetStringData() will return this address: this 
  70 // structure has the same layout as wxStringData and it's data() method will 
  71 // return the empty string (dummy pointer) 
  76 } g_strEmpty 
= { {-1, 0, 0}, '\0' }; 
  78 // empty C style string: points to 'string data' byte of g_strEmpty 
  79 extern const char *g_szNul 
= &g_strEmpty
.dummy
; 
  81 // ---------------------------------------------------------------------------- 
  83 // ---------------------------------------------------------------------------- 
  85 #ifdef  STD_STRING_COMPATIBILITY 
  87 // MS Visual C++ version 5.0 provides the new STL headers as well as the old 
  90 // ATTN: you can _not_ use both of these in the same program! 
  99 // for msvc (bcc50+ also) you don't need these NAMESPACE defines, 
 100 // using namespace std; takes care of that. 
 101 #define   NAMESPACE   std:: 
 106     #define wxVsprintf     _vsnprintf 
 109    #if defined ( HAVE_VSNPRINTF ) 
 110      #define wxVsprintf       vsnprintf 
 116     #define wxVsprintf(buffer,len,format,argptr) vsprintf(buffer,format, argptr) 
 117     #pragma message("Using sprintf() because no snprintf()-like function defined") 
 119     #pragma error("No vsnprintf() or vsprintf() function available.") 
 123 NAMESPACE istream
& operator>>(NAMESPACE istream
& is
, wxString
& WXUNUSED(str
)) 
 128     NAMESPACE streambuf 
*sb 
= is
.rdbuf(); 
 131       int ch 
= sb
->sbumpc (); 
 133         is
.setstate(NAMESPACE 
ios::eofbit
); 
 136       else if ( isspace(ch
) ) { 
 148   if ( str
.length() == 0 ) 
 149     is
.setstate(NAMESPACE 
ios::failbit
); 
 154 #endif  //std::string compatibility 
 156 // ---------------------------------------------------------------------------- 
 158 // ---------------------------------------------------------------------------- 
 160 // this small class is used to gather statistics for performance tuning 
 161 //#define WXSTRING_STATISTICS 
 162 #ifdef  WXSTRING_STATISTICS 
 166     Averager(const char *sz
) { m_sz 
= sz
; m_nTotal 
= m_nCount 
= 0; } 
 168    { printf("wxString: average %s = %f\n", m_sz
, ((float)m_nTotal
)/m_nCount
); } 
 170     void Add(size_t n
) { m_nTotal 
+= n
; m_nCount
++; } 
 173     size_t m_nCount
, m_nTotal
; 
 175   } g_averageLength("allocation size"), 
 176     g_averageSummandLength("summand length"), 
 177     g_averageConcatHit("hit probability in concat"), 
 178     g_averageInitialLength("initial string length"); 
 180   #define STATISTICS_ADD(av, val) g_average##av.Add(val) 
 182   #define STATISTICS_ADD(av, val) 
 183 #endif // WXSTRING_STATISTICS 
 185 // =========================================================================== 
 186 // wxString class core 
 187 // =========================================================================== 
 189 // --------------------------------------------------------------------------- 
 191 // --------------------------------------------------------------------------- 
 193 // constructs string of <nLength> copies of character <ch> 
 194 wxString::wxString(char ch
, size_t nLength
) 
 199     AllocBuffer(nLength
); 
 201     wxASSERT( sizeof(char) == 1 );  // can't use memset if not 
 203     memset(m_pchData
, ch
, nLength
); 
 207 // takes nLength elements of psz starting at nPos 
 208 void wxString::InitWith(const char *psz
, size_t nPos
, size_t nLength
) 
 212   wxASSERT( nPos 
<= Strlen(psz
) ); 
 214   if ( nLength 
== STRING_MAXLEN 
) 
 215     nLength 
= Strlen(psz 
+ nPos
); 
 217   STATISTICS_ADD(InitialLength
, nLength
); 
 220     // trailing '\0' is written in AllocBuffer() 
 221     AllocBuffer(nLength
); 
 222     memcpy(m_pchData
, psz 
+ nPos
, nLength
*sizeof(char)); 
 226 // the same as previous constructor, but for compilers using unsigned char 
 227 wxString::wxString(const unsigned char* psz
, size_t nLength
) 
 229   InitWith((const char *)psz
, 0, nLength
); 
 232 #ifdef  STD_STRING_COMPATIBILITY 
 234 // poor man's iterators are "void *" pointers 
 235 wxString::wxString(const void *pStart
, const void *pEnd
) 
 237   InitWith((const char *)pStart
, 0, 
 238            (const char *)pEnd 
- (const char *)pStart
); 
 241 #endif  //std::string compatibility 
 244 wxString::wxString(const wchar_t *pwz
) 
 246   // first get necessary size 
 248   // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't 
 249   //     honor the 3rd parameter, thus it will happily crash here). 
 250 #ifdef wxUSE_WCSRTOMBS 
 251   // don't know if it's really needed (or if we can pass NULL), but better safe 
 254   size_t nLen 
= wcsrtombs((char *) NULL
, &pwz
, 0, &mbstate
); 
 256   size_t nLen 
= wcstombs((char *) NULL
, pwz
, 0); 
 262     wcstombs(m_pchData
, pwz
, nLen
); 
 269 // --------------------------------------------------------------------------- 
 271 // --------------------------------------------------------------------------- 
 273 // allocates memory needed to store a C string of length nLen 
 274 void wxString::AllocBuffer(size_t nLen
) 
 276   wxASSERT( nLen 
>  0         );    // 
 277   wxASSERT( nLen 
<= INT_MAX
-1 );    // max size (enough room for 1 extra) 
 279   STATISTICS_ADD(Length
, nLen
); 
 282   // 1) one extra character for '\0' termination 
 283   // 2) sizeof(wxStringData) for housekeeping info 
 284   wxStringData
* pData 
= (wxStringData
*) 
 285     malloc(sizeof(wxStringData
) + (nLen 
+ EXTRA_ALLOC 
+ 1)*sizeof(char)); 
 287   pData
->nDataLength  
= nLen
; 
 288   pData
->nAllocLength 
= nLen 
+ EXTRA_ALLOC
; 
 289   m_pchData           
= pData
->data();  // data starts after wxStringData 
 290   m_pchData
[nLen
]     = '\0'; 
 293 // must be called before changing this string 
 294 void wxString::CopyBeforeWrite() 
 296   wxStringData
* pData 
= GetStringData(); 
 298   if ( pData
->IsShared() ) { 
 299     pData
->Unlock();                // memory not freed because shared 
 300     size_t nLen 
= pData
->nDataLength
; 
 302     memcpy(m_pchData
, pData
->data(), nLen
*sizeof(char)); 
 305   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 308 // must be called before replacing contents of this string 
 309 void wxString::AllocBeforeWrite(size_t nLen
) 
 311   wxASSERT( nLen 
!= 0 );  // doesn't make any sense 
 313   // must not share string and must have enough space 
 314   wxStringData
* pData 
= GetStringData(); 
 315   if ( pData
->IsShared() || (nLen 
> pData
->nAllocLength
) ) { 
 316     // can't work with old buffer, get new one 
 321   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 324 // allocate enough memory for nLen characters 
 325 void wxString::Alloc(size_t nLen
) 
 327   wxStringData 
*pData 
= GetStringData(); 
 328   if ( pData
->nAllocLength 
<= nLen 
) { 
 329     if ( pData
->IsEmpty() ) { 
 332       wxStringData
* pData 
= (wxStringData
*) 
 333         malloc(sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(char)); 
 335       pData
->nDataLength 
= 0; 
 336       pData
->nAllocLength 
= nLen
; 
 337       m_pchData 
= pData
->data();  // data starts after wxStringData 
 338       m_pchData
[0u] = '\0'; 
 340     else if ( pData
->IsShared() ) { 
 341       pData
->Unlock();                // memory not freed because shared 
 342       size_t nOldLen 
= pData
->nDataLength
; 
 344       memcpy(m_pchData
, pData
->data(), nOldLen
*sizeof(char)); 
 349       wxStringData 
*p 
= (wxStringData 
*) 
 350         realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(char)); 
 353         // @@@ what to do on memory error? 
 357       // it's not important if the pointer changed or not (the check for this 
 358       // is not faster than assigning to m_pchData in all cases) 
 359       p
->nAllocLength 
= nLen
; 
 360       m_pchData 
= p
->data(); 
 363   //else: we've already got enough 
 366 // shrink to minimal size (releasing extra memory) 
 367 void wxString::Shrink() 
 369   wxStringData 
*pData 
= GetStringData(); 
 371   // this variable is unused in release build, so avoid the compiler warning by 
 372   // just not declaring it 
 376   realloc(pData
, sizeof(wxStringData
) + (pData
->nDataLength 
+ 1)*sizeof(char)); 
 378   wxASSERT( p 
!= NULL 
);  // can't free memory? 
 379   wxASSERT( p 
== pData 
); // we're decrementing the size - block shouldn't move! 
 382 // get the pointer to writable buffer of (at least) nLen bytes 
 383 char *wxString::GetWriteBuf(size_t nLen
) 
 385   AllocBeforeWrite(nLen
); 
 387   wxASSERT( GetStringData()->nRefs 
== 1 ); 
 388   GetStringData()->Validate(FALSE
); 
 393 // put string back in a reasonable state after GetWriteBuf 
 394 void wxString::UngetWriteBuf() 
 396   GetStringData()->nDataLength 
= strlen(m_pchData
); 
 397   GetStringData()->Validate(TRUE
); 
 400 // --------------------------------------------------------------------------- 
 402 // --------------------------------------------------------------------------- 
 404 // all functions are inline in string.h 
 406 // --------------------------------------------------------------------------- 
 407 // assignment operators 
 408 // --------------------------------------------------------------------------- 
 410 // helper function: does real copy 
 411 void wxString::AssignCopy(size_t nSrcLen
, const char *pszSrcData
) 
 413   if ( nSrcLen 
== 0 ) { 
 417     AllocBeforeWrite(nSrcLen
); 
 418     memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(char)); 
 419     GetStringData()->nDataLength 
= nSrcLen
; 
 420     m_pchData
[nSrcLen
] = '\0'; 
 424 // assigns one string to another 
 425 wxString
& wxString::operator=(const wxString
& stringSrc
) 
 427   wxASSERT( stringSrc
.GetStringData()->IsValid() ); 
 429   // don't copy string over itself 
 430   if ( m_pchData 
!= stringSrc
.m_pchData 
) { 
 431     if ( stringSrc
.GetStringData()->IsEmpty() ) { 
 436       GetStringData()->Unlock(); 
 437       m_pchData 
= stringSrc
.m_pchData
; 
 438       GetStringData()->Lock(); 
 445 // assigns a single character 
 446 wxString
& wxString::operator=(char ch
) 
 453 wxString
& wxString::operator=(const char *psz
) 
 455   AssignCopy(Strlen(psz
), psz
); 
 459 // same as 'signed char' variant 
 460 wxString
& wxString::operator=(const unsigned char* psz
) 
 462   *this = (const char *)psz
; 
 466 wxString
& wxString::operator=(const wchar_t *pwz
) 
 473 // --------------------------------------------------------------------------- 
 474 // string concatenation 
 475 // --------------------------------------------------------------------------- 
 477 // add something to this string 
 478 void wxString::ConcatSelf(int nSrcLen
, const char *pszSrcData
) 
 480   STATISTICS_ADD(SummandLength
, nSrcLen
); 
 482   // concatenating an empty string is a NOP 
 484     wxStringData 
*pData 
= GetStringData(); 
 485     size_t nLen 
= pData
->nDataLength
; 
 486     size_t nNewLen 
= nLen 
+ nSrcLen
; 
 488     // alloc new buffer if current is too small 
 489     if ( pData
->IsShared() ) { 
 490       STATISTICS_ADD(ConcatHit
, 0); 
 492       // we have to allocate another buffer 
 493       wxStringData
* pOldData 
= GetStringData(); 
 494       AllocBuffer(nNewLen
); 
 495       memcpy(m_pchData
, pOldData
->data(), nLen
*sizeof(char)); 
 498     else if ( nNewLen 
> pData
->nAllocLength 
) { 
 499       STATISTICS_ADD(ConcatHit
, 0); 
 501       // we have to grow the buffer 
 505       STATISTICS_ADD(ConcatHit
, 1); 
 507       // the buffer is already big enough 
 510     // should be enough space 
 511     wxASSERT( nNewLen 
<= GetStringData()->nAllocLength 
); 
 513     // fast concatenation - all is done in our buffer 
 514     memcpy(m_pchData 
+ nLen
, pszSrcData
, nSrcLen
*sizeof(char)); 
 516     m_pchData
[nNewLen
] = '\0';              // put terminating '\0' 
 517     GetStringData()->nDataLength 
= nNewLen
; // and fix the length 
 519   //else: the string to append was empty 
 523  * concatenation functions come in 5 flavours: 
 525  *  char   + string      and      string + char 
 526  *  C str  + string      and      string + C str 
 529 wxString 
operator+(const wxString
& string1
, const wxString
& string2
) 
 531   wxASSERT( string1
.GetStringData()->IsValid() ); 
 532   wxASSERT( string2
.GetStringData()->IsValid() ); 
 534   wxString s 
= string1
; 
 540 wxString 
operator+(const wxString
& string
, char ch
) 
 542   wxASSERT( string
.GetStringData()->IsValid() ); 
 550 wxString 
operator+(char ch
, const wxString
& string
) 
 552   wxASSERT( string
.GetStringData()->IsValid() ); 
 560 wxString 
operator+(const wxString
& string
, const char *psz
) 
 562   wxASSERT( string
.GetStringData()->IsValid() ); 
 565   s
.Alloc(Strlen(psz
) + string
.Len()); 
 572 wxString 
operator+(const char *psz
, const wxString
& string
) 
 574   wxASSERT( string
.GetStringData()->IsValid() ); 
 577   s
.Alloc(Strlen(psz
) + string
.Len()); 
 584 // =========================================================================== 
 585 // other common string functions 
 586 // =========================================================================== 
 588 // --------------------------------------------------------------------------- 
 589 // simple sub-string extraction 
 590 // --------------------------------------------------------------------------- 
 592 // helper function: clone the data attached to this string 
 593 void wxString::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const 
 595   if ( nCopyLen 
== 0 ) { 
 599     dest
.AllocBuffer(nCopyLen
); 
 600     memcpy(dest
.m_pchData
, m_pchData 
+ nCopyIndex
, nCopyLen
*sizeof(char)); 
 604 // extract string of length nCount starting at nFirst 
 605 wxString 
wxString::Mid(size_t nFirst
, size_t nCount
) const 
 607   wxStringData 
*pData 
= GetStringData(); 
 608   size_t nLen 
= pData
->nDataLength
; 
 610   // default value of nCount is STRING_MAXLEN and means "till the end" 
 611   if ( nCount 
== STRING_MAXLEN 
) 
 613     nCount 
= nLen 
- nFirst
; 
 616   // out-of-bounds requests return sensible things 
 617   if ( nFirst 
+ nCount 
> nLen 
) 
 619     nCount 
= nLen 
- nFirst
; 
 624     // AllocCopy() will return empty string 
 629   AllocCopy(dest
, nCount
, nFirst
); 
 634 // extract nCount last (rightmost) characters 
 635 wxString 
wxString::Right(size_t nCount
) const 
 637   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 638     nCount 
= GetStringData()->nDataLength
; 
 641   AllocCopy(dest
, nCount
, GetStringData()->nDataLength 
- nCount
); 
 645 // get all characters after the last occurence of ch 
 646 // (returns the whole string if ch not found) 
 647 wxString 
wxString::Right(char ch
) const 
 650   int iPos 
= Find(ch
, TRUE
); 
 651   if ( iPos 
== NOT_FOUND 
) 
 654     str 
= c_str() + iPos 
+ 1; 
 659 // extract nCount first (leftmost) characters 
 660 wxString 
wxString::Left(size_t nCount
) const 
 662   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 663     nCount 
= GetStringData()->nDataLength
; 
 666   AllocCopy(dest
, nCount
, 0); 
 670 // get all characters before the first occurence of ch 
 671 // (returns the whole string if ch not found) 
 672 wxString 
wxString::Left(char ch
) const 
 675   for ( const char *pc 
= m_pchData
; *pc 
!= '\0' && *pc 
!= ch
; pc
++ ) 
 681 /// get all characters before the last occurence of ch 
 682 /// (returns empty string if ch not found) 
 683 wxString 
wxString::Before(char ch
) const 
 686   int iPos 
= Find(ch
, TRUE
); 
 687   if ( iPos 
!= NOT_FOUND 
&& iPos 
!= 0 ) 
 688     str 
= wxString(c_str(), iPos
); 
 693 /// get all characters after the first occurence of ch 
 694 /// (returns empty string if ch not found) 
 695 wxString 
wxString::After(char ch
) const 
 699   if ( iPos 
!= NOT_FOUND 
) 
 700     str 
= c_str() + iPos 
+ 1; 
 705 // replace first (or all) occurences of some substring with another one 
 706 size_t wxString::Replace(const char *szOld
, const char *szNew
, bool bReplaceAll
) 
 708   size_t uiCount 
= 0;   // count of replacements made 
 710   size_t uiOldLen 
= Strlen(szOld
); 
 713   const char *pCurrent 
= m_pchData
; 
 715   while ( *pCurrent 
!= '\0' ) { 
 716     pSubstr 
= strstr(pCurrent
, szOld
); 
 717     if ( pSubstr 
== NULL 
) { 
 718       // strTemp is unused if no replacements were made, so avoid the copy 
 722       strTemp 
+= pCurrent
;    // copy the rest 
 723       break;                  // exit the loop 
 726       // take chars before match 
 727       strTemp
.ConcatSelf(pSubstr 
- pCurrent
, pCurrent
); 
 729       pCurrent 
= pSubstr 
+ uiOldLen
;  // restart after match 
 734       if ( !bReplaceAll 
) { 
 735         strTemp 
+= pCurrent
;    // copy the rest 
 736         break;                  // exit the loop 
 741   // only done if there were replacements, otherwise would have returned above 
 747 bool wxString::IsAscii() const 
 749   const char *s 
= (const char*) *this; 
 751     if(!isascii(*s
)) return(FALSE
); 
 757 bool wxString::IsWord() const 
 759   const char *s 
= (const char*) *this; 
 761     if(!isalpha(*s
)) return(FALSE
); 
 767 bool wxString::IsNumber() const 
 769   const char *s 
= (const char*) *this; 
 771     if(!isdigit(*s
)) return(FALSE
); 
 777 wxString 
wxString::Strip(stripType w
) const 
 780     if ( w 
& leading 
) s
.Trim(FALSE
); 
 781     if ( w 
& trailing 
) s
.Trim(TRUE
); 
 785 // --------------------------------------------------------------------------- 
 787 // --------------------------------------------------------------------------- 
 789 wxString
& wxString::MakeUpper() 
 793   for ( char *p 
= m_pchData
; *p
; p
++ ) 
 794     *p 
= (char)toupper(*p
); 
 799 wxString
& wxString::MakeLower() 
 803   for ( char *p 
= m_pchData
; *p
; p
++ ) 
 804     *p 
= (char)tolower(*p
); 
 809 // --------------------------------------------------------------------------- 
 810 // trimming and padding 
 811 // --------------------------------------------------------------------------- 
 813 // trims spaces (in the sense of isspace) from left or right side 
 814 wxString
& wxString::Trim(bool bFromRight
) 
 816   // first check if we're going to modify the string at all 
 819         (bFromRight 
&& isspace(GetChar(Len() - 1))) || 
 820         (!bFromRight 
&& isspace(GetChar(0u))) 
 824     // ok, there is at least one space to trim 
 829       // find last non-space character 
 830       char *psz 
= m_pchData 
+ GetStringData()->nDataLength 
- 1; 
 831       while ( isspace(*psz
) && (psz 
>= m_pchData
) ) 
 834       // truncate at trailing space start 
 836       GetStringData()->nDataLength 
= psz 
- m_pchData
; 
 840       // find first non-space character 
 841       const char *psz 
= m_pchData
; 
 842       while ( isspace(*psz
) ) 
 845       // fix up data and length 
 846       int nDataLength 
= GetStringData()->nDataLength 
- (psz 
- m_pchData
); 
 847       memmove(m_pchData
, psz
, (nDataLength 
+ 1)*sizeof(char)); 
 848       GetStringData()->nDataLength 
= nDataLength
; 
 855 // adds nCount characters chPad to the string from either side 
 856 wxString
& wxString::Pad(size_t nCount
, char chPad
, bool bFromRight
) 
 858   wxString 
s(chPad
, nCount
); 
 871 // truncate the string 
 872 wxString
& wxString::Truncate(size_t uiLen
) 
 874   *(m_pchData 
+ uiLen
) = '\0'; 
 875   GetStringData()->nDataLength 
= uiLen
; 
 880 // --------------------------------------------------------------------------- 
 881 // finding (return NOT_FOUND if not found and index otherwise) 
 882 // --------------------------------------------------------------------------- 
 885 int wxString::Find(char ch
, bool bFromEnd
) const 
 887   const char *psz 
= bFromEnd 
? strrchr(m_pchData
, ch
) : strchr(m_pchData
, ch
); 
 889   return (psz 
== NULL
) ? NOT_FOUND 
: psz 
- m_pchData
; 
 892 // find a sub-string (like strstr) 
 893 int wxString::Find(const char *pszSub
) const 
 895   const char *psz 
= strstr(m_pchData
, pszSub
); 
 897   return (psz 
== NULL
) ? NOT_FOUND 
: psz 
- m_pchData
; 
 900 // --------------------------------------------------------------------------- 
 901 // stream-like operators 
 902 // --------------------------------------------------------------------------- 
 903 wxString
& wxString::operator<<(int i
) 
 908     return (*this) << res
; 
 911 wxString
& wxString::operator<<(float f
) 
 916     return (*this) << res
; 
 919 wxString
& wxString::operator<<(double d
) 
 924     return (*this) << res
; 
 927 // --------------------------------------------------------------------------- 
 929 // --------------------------------------------------------------------------- 
 930 int wxString::Printf(const char *pszFormat
, ...) 
 933   va_start(argptr
, pszFormat
); 
 935   int iLen 
= PrintfV(pszFormat
, argptr
); 
 942 int wxString::PrintfV(const char* pszFormat
, va_list argptr
) 
 944 #if defined(__BORLANDC__) || defined(__GNUWIN32__) 
 945   static char s_szScratch
[1024]; 
 947   int iLen 
= vsprintf(s_szScratch
, pszFormat
, argptr
); 
 948   AllocBeforeWrite(iLen
); 
 949   strcpy(m_pchData
, s_szScratch
); 
 954   // static buffer to avoid dynamic memory allocation each time 
 955   static char s_szScratch
[1024]; 
 957   int iLen 
= wxVsprintf(s_szScratch
, WXSIZEOF(s_szScratch
), pszFormat
, argptr
); 
 959   if ( (size_t)iLen 
< WXSIZEOF(s_szScratch
) ) { 
 960     buffer 
= s_szScratch
; 
 963       int size 
= WXSIZEOF(s_szScratch
) * 2; 
 964       buffer 
= (char *)malloc(size
); 
 965       while ( buffer 
!= NULL 
) { 
 966           iLen 
= wxVsprintf(buffer
, WXSIZEOF(s_szScratch
), pszFormat
, argptr
); 
 968               // ok, there was enough space 
 972           // still not enough, double it again 
 973           buffer 
= (char *)realloc(buffer
, size 
*= 2); 
 982   AllocBeforeWrite(iLen
); 
 983   strcpy(m_pchData
, buffer
); 
 985   if ( buffer 
!= s_szScratch 
) 
 992 // ---------------------------------------------------------------------------- 
 993 // misc other operations 
 994 // ---------------------------------------------------------------------------- 
 995 bool wxString::Matches(const char *pszMask
) const 
 997   // check char by char 
 999   for ( pszTxt 
= c_str(); *pszMask 
!= '\0'; pszMask
++, pszTxt
++ ) { 
1000     switch ( *pszMask 
) { 
1002         if ( *pszTxt 
== '\0' ) 
1011           // ignore special chars immediately following this one 
1012           while ( *pszMask 
== '*' || *pszMask 
== '?' ) 
1015           // if there is nothing more, match 
1016           if ( *pszMask 
== '\0' ) 
1019           // are there any other metacharacters in the mask? 
1021           const char *pEndMask 
= strpbrk(pszMask
, "*?"); 
1023           if ( pEndMask 
!= NULL 
) { 
1024             // we have to match the string between two metachars 
1025             uiLenMask 
= pEndMask 
- pszMask
; 
1028             // we have to match the remainder of the string 
1029             uiLenMask 
= strlen(pszMask
); 
1032           wxString 
strToMatch(pszMask
, uiLenMask
); 
1033           const char* pMatch 
= strstr(pszTxt
, strToMatch
); 
1034           if ( pMatch 
== NULL 
) 
1037           // -1 to compensate "++" in the loop 
1038           pszTxt 
= pMatch 
+ uiLenMask 
- 1; 
1039           pszMask 
+= uiLenMask 
- 1; 
1044         if ( *pszMask 
!= *pszTxt 
) 
1050   // match only if nothing left 
1051   return *pszTxt 
== '\0'; 
1054 // --------------------------------------------------------------------------- 
1055 // standard C++ library string functions 
1056 // --------------------------------------------------------------------------- 
1057 #ifdef  STD_STRING_COMPATIBILITY 
1059 wxString
& wxString::insert(size_t nPos
, const wxString
& str
) 
1061   wxASSERT( str
.GetStringData()->IsValid() ); 
1062   wxASSERT( nPos 
<= Len() ); 
1064   if ( !str
.IsEmpty() ) { 
1066     char *pc 
= strTmp
.GetWriteBuf(Len() + str
.Len()); 
1067     strncpy(pc
, c_str(), nPos
); 
1068     strcpy(pc 
+ nPos
, str
); 
1069     strcpy(pc 
+ nPos 
+ str
.Len(), c_str() + nPos
); 
1070     strTmp
.UngetWriteBuf(); 
1077 size_t wxString::find(const wxString
& str
, size_t nStart
) const 
1079   wxASSERT( str
.GetStringData()->IsValid() ); 
1080   wxASSERT( nStart 
<= Len() ); 
1082   const char *p 
= strstr(c_str() + nStart
, str
); 
1084   return p 
== NULL 
? npos 
: p 
- c_str(); 
1087 // VC++ 1.5 can't cope with the default argument in the header. 
1088 #if ! (defined(_MSC_VER) && !defined(__WIN32__)) 
1089 size_t wxString::find(const char* sz
, size_t nStart
, size_t n
) const 
1091   return find(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1095 size_t wxString::find(char ch
, size_t nStart
) const 
1097   wxASSERT( nStart 
<= Len() ); 
1099   const char *p 
= strchr(c_str() + nStart
, ch
); 
1101   return p 
== NULL 
? npos 
: p 
- c_str(); 
1104 size_t wxString::rfind(const wxString
& str
, size_t nStart
) const 
1106   wxASSERT( str
.GetStringData()->IsValid() ); 
1107   wxASSERT( nStart 
<= Len() ); 
1109   // # could be quicker than that 
1110   const char *p 
= c_str() + (nStart 
== npos 
? Len() : nStart
); 
1111   while ( p 
>= c_str() + str
.Len() ) { 
1112     if ( strncmp(p 
- str
.Len(), str
, str
.Len()) == 0 ) 
1113       return p 
- str
.Len() - c_str(); 
1120 // VC++ 1.5 can't cope with the default argument in the header. 
1121 #if ! (defined(_MSC_VER) && !defined(__WIN32__)) 
1122 size_t wxString::rfind(const char* sz
, size_t nStart
, size_t n
) const 
1124   return rfind(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1127 size_t wxString::rfind(char ch
, size_t nStart
) const 
1129   wxASSERT( nStart 
<= Len() ); 
1131   const char *p 
= strrchr(c_str() + nStart
, ch
); 
1133   return p 
== NULL 
? npos 
: p 
- c_str(); 
1137 wxString 
wxString::substr(size_t nStart
, size_t nLen
) const 
1139   // npos means 'take all' 
1143   wxASSERT( nStart 
+ nLen 
<= Len() ); 
1145   return wxString(c_str() + nStart
, nLen 
== npos 
? 0 : nLen
); 
1148 wxString
& wxString::erase(size_t nStart
, size_t nLen
) 
1150   wxString 
strTmp(c_str(), nStart
); 
1151   if ( nLen 
!= npos 
) { 
1152     wxASSERT( nStart 
+ nLen 
<= Len() ); 
1154     strTmp
.append(c_str() + nStart 
+ nLen
); 
1161 wxString
& wxString::replace(size_t nStart
, size_t nLen
, const char *sz
) 
1163   wxASSERT( nStart 
+ nLen 
<= Strlen(sz
) ); 
1167     strTmp
.append(c_str(), nStart
); 
1169   strTmp
.append(c_str() + nStart 
+ nLen
); 
1175 wxString
& wxString::replace(size_t nStart
, size_t nLen
, size_t nCount
, char ch
) 
1177   return replace(nStart
, nLen
, wxString(ch
, nCount
)); 
1180 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1181                             const wxString
& str
, size_t nStart2
, size_t nLen2
) 
1183   return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
)); 
1186 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1187                         const char* sz
, size_t nCount
) 
1189   return replace(nStart
, nLen
, wxString(sz
, nCount
)); 
1192 #endif  //std::string compatibility 
1194 // ============================================================================ 
1196 // ============================================================================ 
1198 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) 
1199 #define   ARRAY_MAXSIZE_INCREMENT       4096 
1200 #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h 
1201   #define   ARRAY_DEFAULT_INITIAL_SIZE    (16) 
1204 #define   STRING(p)   ((wxString *)(&(p))) 
1207 wxArrayString::wxArrayString() 
1211   m_pItems 
= (char **) NULL
; 
1215 wxArrayString::wxArrayString(const wxArrayString
& src
) 
1219   m_pItems 
= (char **) NULL
; 
1224 // assignment operator 
1225 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
) 
1230   if ( src
.m_nCount 
> ARRAY_DEFAULT_INITIAL_SIZE 
) 
1231     Alloc(src
.m_nCount
); 
1233   // we can't just copy the pointers here because otherwise we would share 
1234   // the strings with another array 
1235   for ( size_t n 
= 0; n 
< src
.m_nCount
; n
++ ) 
1238   if ( m_nCount 
!= 0 ) 
1239     memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *)); 
1245 void wxArrayString::Grow() 
1247   // only do it if no more place 
1248   if( m_nCount 
== m_nSize 
) { 
1249     if( m_nSize 
== 0 ) { 
1250       // was empty, alloc some memory 
1251       m_nSize 
= ARRAY_DEFAULT_INITIAL_SIZE
; 
1252       m_pItems 
= new char *[m_nSize
]; 
1255       // otherwise when it's called for the first time, nIncrement would be 0 
1256       // and the array would never be expanded 
1257       wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE 
!= 0 ); 
1259       // add 50% but not too much 
1260       size_t nIncrement 
= m_nSize 
< ARRAY_DEFAULT_INITIAL_SIZE
 
1261                           ? ARRAY_DEFAULT_INITIAL_SIZE 
: m_nSize 
>> 1; 
1262       if ( nIncrement 
> ARRAY_MAXSIZE_INCREMENT 
) 
1263         nIncrement 
= ARRAY_MAXSIZE_INCREMENT
; 
1264       m_nSize 
+= nIncrement
; 
1265       char **pNew 
= new char *[m_nSize
]; 
1267       // copy data to new location 
1268       memcpy(pNew
, m_pItems
, m_nCount
*sizeof(char *)); 
1270       // delete old memory (but do not release the strings!) 
1271       wxDELETEA(m_pItems
); 
1278 void wxArrayString::Free() 
1280   for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) { 
1281     STRING(m_pItems
[n
])->GetStringData()->Unlock(); 
1285 // deletes all the strings from the list 
1286 void wxArrayString::Empty() 
1293 // as Empty, but also frees memory 
1294 void wxArrayString::Clear() 
1301   wxDELETEA(m_pItems
); 
1305 wxArrayString::~wxArrayString() 
1309   wxDELETEA(m_pItems
); 
1312 // pre-allocates memory (frees the previous data!) 
1313 void wxArrayString::Alloc(size_t nSize
) 
1315   wxASSERT( nSize 
> 0 ); 
1317   // only if old buffer was not big enough 
1318   if ( nSize 
> m_nSize 
) { 
1320     wxDELETEA(m_pItems
); 
1321     m_pItems 
= new char *[nSize
]; 
1328 // searches the array for an item (forward or backwards) 
1329 int wxArrayString::Index(const char *sz
, bool bCase
, bool bFromEnd
) const 
1332     if ( m_nCount 
> 0 ) { 
1333       size_t ui 
= m_nCount
; 
1335         if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) ) 
1342     for( size_t ui 
= 0; ui 
< m_nCount
; ui
++ ) { 
1343       if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) ) 
1351 // add item at the end 
1352 void wxArrayString::Add(const wxString
& str
) 
1354   wxASSERT( str
.GetStringData()->IsValid() ); 
1358   // the string data must not be deleted! 
1359   str
.GetStringData()->Lock(); 
1360   m_pItems
[m_nCount
++] = (char *)str
.c_str(); 
1363 // add item at the given position 
1364 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
) 
1366   wxASSERT( str
.GetStringData()->IsValid() ); 
1368   wxCHECK_RET( nIndex 
<= m_nCount
, ("bad index in wxArrayString::Insert") ); 
1372   memmove(&m_pItems
[nIndex 
+ 1], &m_pItems
[nIndex
], 
1373           (m_nCount 
- nIndex
)*sizeof(char *)); 
1375   str
.GetStringData()->Lock(); 
1376   m_pItems
[nIndex
] = (char *)str
.c_str(); 
1381 // removes item from array (by index) 
1382 void wxArrayString::Remove(size_t nIndex
) 
1384   wxCHECK_RET( nIndex 
<= m_nCount
, _("bad index in wxArrayString::Remove") ); 
1387   Item(nIndex
).GetStringData()->Unlock(); 
1389   memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex 
+ 1], 
1390           (m_nCount 
- nIndex 
- 1)*sizeof(char *)); 
1394 // removes item from array (by value) 
1395 void wxArrayString::Remove(const char *sz
) 
1397   int iIndex 
= Index(sz
); 
1399   wxCHECK_RET( iIndex 
!= NOT_FOUND
, 
1400                _("removing inexistent element in wxArrayString::Remove") ); 
1405 // sort array elements using passed comparaison function 
1407 void wxArrayString::Sort(bool WXUNUSED(bCase
), bool WXUNUSED(bReverse
) ) 
1410   //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);