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:: 
 105 NAMESPACE istream
& operator>>(NAMESPACE istream
& is
, wxString
& WXUNUSED(str
)) 
 110     NAMESPACE streambuf 
*sb 
= is
.rdbuf(); 
 113       int ch 
= sb
->sbumpc (); 
 115         is
.setstate(NAMESPACE 
ios::eofbit
); 
 118       else if ( isspace(ch
) ) { 
 130   if ( str
.length() == 0 ) 
 131     is
.setstate(NAMESPACE 
ios::failbit
); 
 136 #endif  //std::string compatibility 
 138 // ---------------------------------------------------------------------------- 
 140 // ---------------------------------------------------------------------------- 
 142 // this small class is used to gather statistics for performance tuning 
 143 //#define WXSTRING_STATISTICS 
 144 #ifdef  WXSTRING_STATISTICS 
 148     Averager(const char *sz
) { m_sz 
= sz
; m_nTotal 
= m_nCount 
= 0; } 
 150    { printf("wxString: average %s = %f\n", m_sz
, ((float)m_nTotal
)/m_nCount
); } 
 152     void Add(size_t n
) { m_nTotal 
+= n
; m_nCount
++; } 
 155     size_t m_nCount
, m_nTotal
; 
 157   } g_averageLength("allocation size"), 
 158     g_averageSummandLength("summand length"), 
 159     g_averageConcatHit("hit probability in concat"), 
 160     g_averageInitialLength("initial string length"); 
 162   #define STATISTICS_ADD(av, val) g_average##av.Add(val) 
 164   #define STATISTICS_ADD(av, val) 
 165 #endif // WXSTRING_STATISTICS 
 167 // =========================================================================== 
 168 // wxString class core 
 169 // =========================================================================== 
 171 // --------------------------------------------------------------------------- 
 173 // --------------------------------------------------------------------------- 
 175 // constructs string of <nLength> copies of character <ch> 
 176 wxString::wxString(char ch
, size_t nLength
) 
 181     AllocBuffer(nLength
); 
 183     wxASSERT( sizeof(char) == 1 );  // can't use memset if not 
 185     memset(m_pchData
, ch
, nLength
); 
 189 // takes nLength elements of psz starting at nPos 
 190 void wxString::InitWith(const char *psz
, size_t nPos
, size_t nLength
) 
 194   wxASSERT( nPos 
<= Strlen(psz
) ); 
 196   if ( nLength 
== STRING_MAXLEN 
) 
 197     nLength 
= Strlen(psz 
+ nPos
); 
 199   STATISTICS_ADD(InitialLength
, nLength
); 
 202     // trailing '\0' is written in AllocBuffer() 
 203     AllocBuffer(nLength
); 
 204     memcpy(m_pchData
, psz 
+ nPos
, nLength
*sizeof(char)); 
 208 // the same as previous constructor, but for compilers using unsigned char 
 209 wxString::wxString(const unsigned char* psz
, size_t nLength
) 
 211   InitWith((const char *)psz
, 0, nLength
); 
 214 #ifdef  STD_STRING_COMPATIBILITY 
 216 // poor man's iterators are "void *" pointers 
 217 wxString::wxString(const void *pStart
, const void *pEnd
) 
 219   InitWith((const char *)pStart
, 0, 
 220            (const char *)pEnd 
- (const char *)pStart
); 
 223 #endif  //std::string compatibility 
 226 wxString::wxString(const wchar_t *pwz
) 
 228   // first get necessary size 
 230   // NB: GNU libc5 wcstombs() is completely broken, don't use it (it doesn't 
 231   //     honor the 3rd parameter, thus it will happily crash here). 
 232 #ifdef wxUSE_WCSRTOMBS 
 233   // don't know if it's really needed (or if we can pass NULL), but better safe 
 236   size_t nLen 
= wcsrtombs((char *) NULL
, &pwz
, 0, &mbstate
); 
 238   size_t nLen 
= wcstombs((char *) NULL
, pwz
, 0); 
 244     wcstombs(m_pchData
, pwz
, nLen
); 
 251 // --------------------------------------------------------------------------- 
 253 // --------------------------------------------------------------------------- 
 255 // allocates memory needed to store a C string of length nLen 
 256 void wxString::AllocBuffer(size_t nLen
) 
 258   wxASSERT( nLen 
>  0         );    // 
 259   wxASSERT( nLen 
<= INT_MAX
-1 );    // max size (enough room for 1 extra) 
 261   STATISTICS_ADD(Length
, nLen
); 
 264   // 1) one extra character for '\0' termination 
 265   // 2) sizeof(wxStringData) for housekeeping info 
 266   wxStringData
* pData 
= (wxStringData
*) 
 267     malloc(sizeof(wxStringData
) + (nLen 
+ EXTRA_ALLOC 
+ 1)*sizeof(char)); 
 269   pData
->nDataLength  
= nLen
; 
 270   pData
->nAllocLength 
= nLen 
+ EXTRA_ALLOC
; 
 271   m_pchData           
= pData
->data();  // data starts after wxStringData 
 272   m_pchData
[nLen
]     = '\0'; 
 275 // must be called before changing this string 
 276 void wxString::CopyBeforeWrite() 
 278   wxStringData
* pData 
= GetStringData(); 
 280   if ( pData
->IsShared() ) { 
 281     pData
->Unlock();                // memory not freed because shared 
 282     size_t nLen 
= pData
->nDataLength
; 
 284     memcpy(m_pchData
, pData
->data(), nLen
*sizeof(char)); 
 287   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 290 // must be called before replacing contents of this string 
 291 void wxString::AllocBeforeWrite(size_t nLen
) 
 293   wxASSERT( nLen 
!= 0 );  // doesn't make any sense 
 295   // must not share string and must have enough space 
 296   wxStringData
* pData 
= GetStringData(); 
 297   if ( pData
->IsShared() || (nLen 
> pData
->nAllocLength
) ) { 
 298     // can't work with old buffer, get new one 
 303   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner 
 306 // allocate enough memory for nLen characters 
 307 void wxString::Alloc(size_t nLen
) 
 309   wxStringData 
*pData 
= GetStringData(); 
 310   if ( pData
->nAllocLength 
<= nLen 
) { 
 311     if ( pData
->IsEmpty() ) { 
 314       wxStringData
* pData 
= (wxStringData
*) 
 315         malloc(sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(char)); 
 317       pData
->nDataLength 
= 0; 
 318       pData
->nAllocLength 
= nLen
; 
 319       m_pchData 
= pData
->data();  // data starts after wxStringData 
 320       m_pchData
[0u] = '\0'; 
 322     else if ( pData
->IsShared() ) { 
 323       pData
->Unlock();                // memory not freed because shared 
 324       size_t nOldLen 
= pData
->nDataLength
; 
 326       memcpy(m_pchData
, pData
->data(), nOldLen
*sizeof(char)); 
 331       wxStringData 
*p 
= (wxStringData 
*) 
 332         realloc(pData
, sizeof(wxStringData
) + (nLen 
+ 1)*sizeof(char)); 
 335         // @@@ what to do on memory error? 
 339       // it's not important if the pointer changed or not (the check for this 
 340       // is not faster than assigning to m_pchData in all cases) 
 341       p
->nAllocLength 
= nLen
; 
 342       m_pchData 
= p
->data(); 
 345   //else: we've already got enough 
 348 // shrink to minimal size (releasing extra memory) 
 349 void wxString::Shrink() 
 351   wxStringData 
*pData 
= GetStringData(); 
 353   // this variable is unused in release build, so avoid the compiler warning by 
 354   // just not declaring it 
 358   realloc(pData
, sizeof(wxStringData
) + (pData
->nDataLength 
+ 1)*sizeof(char)); 
 360   wxASSERT( p 
!= NULL 
);  // can't free memory? 
 361   wxASSERT( p 
== pData 
); // we're decrementing the size - block shouldn't move! 
 364 // get the pointer to writable buffer of (at least) nLen bytes 
 365 char *wxString::GetWriteBuf(size_t nLen
) 
 367   AllocBeforeWrite(nLen
); 
 369   wxASSERT( GetStringData()->nRefs 
== 1 ); 
 370   GetStringData()->Validate(FALSE
); 
 375 // put string back in a reasonable state after GetWriteBuf 
 376 void wxString::UngetWriteBuf() 
 378   GetStringData()->nDataLength 
= strlen(m_pchData
); 
 379   GetStringData()->Validate(TRUE
); 
 382 // --------------------------------------------------------------------------- 
 384 // --------------------------------------------------------------------------- 
 386 // all functions are inline in string.h 
 388 // --------------------------------------------------------------------------- 
 389 // assignment operators 
 390 // --------------------------------------------------------------------------- 
 392 // helper function: does real copy 
 393 void wxString::AssignCopy(size_t nSrcLen
, const char *pszSrcData
) 
 395   if ( nSrcLen 
== 0 ) { 
 399     AllocBeforeWrite(nSrcLen
); 
 400     memcpy(m_pchData
, pszSrcData
, nSrcLen
*sizeof(char)); 
 401     GetStringData()->nDataLength 
= nSrcLen
; 
 402     m_pchData
[nSrcLen
] = '\0'; 
 406 // assigns one string to another 
 407 wxString
& wxString::operator=(const wxString
& stringSrc
) 
 409   wxASSERT( stringSrc
.GetStringData()->IsValid() ); 
 411   // don't copy string over itself 
 412   if ( m_pchData 
!= stringSrc
.m_pchData 
) { 
 413     if ( stringSrc
.GetStringData()->IsEmpty() ) { 
 418       GetStringData()->Unlock(); 
 419       m_pchData 
= stringSrc
.m_pchData
; 
 420       GetStringData()->Lock(); 
 427 // assigns a single character 
 428 wxString
& wxString::operator=(char ch
) 
 435 wxString
& wxString::operator=(const char *psz
) 
 437   AssignCopy(Strlen(psz
), psz
); 
 441 // same as 'signed char' variant 
 442 wxString
& wxString::operator=(const unsigned char* psz
) 
 444   *this = (const char *)psz
; 
 448 wxString
& wxString::operator=(const wchar_t *pwz
) 
 455 // --------------------------------------------------------------------------- 
 456 // string concatenation 
 457 // --------------------------------------------------------------------------- 
 459 // add something to this string 
 460 void wxString::ConcatSelf(int nSrcLen
, const char *pszSrcData
) 
 462   STATISTICS_ADD(SummandLength
, nSrcLen
); 
 464   // concatenating an empty string is a NOP 
 466     wxStringData 
*pData 
= GetStringData(); 
 467     size_t nLen 
= pData
->nDataLength
; 
 468     size_t nNewLen 
= nLen 
+ nSrcLen
; 
 470     // alloc new buffer if current is too small 
 471     if ( pData
->IsShared() ) { 
 472       STATISTICS_ADD(ConcatHit
, 0); 
 474       // we have to allocate another buffer 
 475       wxStringData
* pOldData 
= GetStringData(); 
 476       AllocBuffer(nNewLen
); 
 477       memcpy(m_pchData
, pOldData
->data(), nLen
*sizeof(char)); 
 480     else if ( nNewLen 
> pData
->nAllocLength 
) { 
 481       STATISTICS_ADD(ConcatHit
, 0); 
 483       // we have to grow the buffer 
 487       STATISTICS_ADD(ConcatHit
, 1); 
 489       // the buffer is already big enough 
 492     // should be enough space 
 493     wxASSERT( nNewLen 
<= GetStringData()->nAllocLength 
); 
 495     // fast concatenation - all is done in our buffer 
 496     memcpy(m_pchData 
+ nLen
, pszSrcData
, nSrcLen
*sizeof(char)); 
 498     m_pchData
[nNewLen
] = '\0';              // put terminating '\0' 
 499     GetStringData()->nDataLength 
= nNewLen
; // and fix the length 
 501   //else: the string to append was empty 
 505  * concatenation functions come in 5 flavours: 
 507  *  char   + string      and      string + char 
 508  *  C str  + string      and      string + C str 
 511 wxString 
operator+(const wxString
& string1
, const wxString
& string2
) 
 513   wxASSERT( string1
.GetStringData()->IsValid() ); 
 514   wxASSERT( string2
.GetStringData()->IsValid() ); 
 516   wxString s 
= string1
; 
 522 wxString 
operator+(const wxString
& string
, char ch
) 
 524   wxASSERT( string
.GetStringData()->IsValid() ); 
 532 wxString 
operator+(char ch
, const wxString
& string
) 
 534   wxASSERT( string
.GetStringData()->IsValid() ); 
 542 wxString 
operator+(const wxString
& string
, const char *psz
) 
 544   wxASSERT( string
.GetStringData()->IsValid() ); 
 547   s
.Alloc(Strlen(psz
) + string
.Len()); 
 554 wxString 
operator+(const char *psz
, const wxString
& string
) 
 556   wxASSERT( string
.GetStringData()->IsValid() ); 
 559   s
.Alloc(Strlen(psz
) + string
.Len()); 
 566 // =========================================================================== 
 567 // other common string functions 
 568 // =========================================================================== 
 570 // --------------------------------------------------------------------------- 
 571 // simple sub-string extraction 
 572 // --------------------------------------------------------------------------- 
 574 // helper function: clone the data attached to this string 
 575 void wxString::AllocCopy(wxString
& dest
, int nCopyLen
, int nCopyIndex
) const 
 577   if ( nCopyLen 
== 0 ) { 
 581     dest
.AllocBuffer(nCopyLen
); 
 582     memcpy(dest
.m_pchData
, m_pchData 
+ nCopyIndex
, nCopyLen
*sizeof(char)); 
 586 // extract string of length nCount starting at nFirst 
 587 wxString 
wxString::Mid(size_t nFirst
, size_t nCount
) const 
 589   wxStringData 
*pData 
= GetStringData(); 
 590   size_t nLen 
= pData
->nDataLength
; 
 592   // default value of nCount is STRING_MAXLEN and means "till the end" 
 593   if ( nCount 
== STRING_MAXLEN 
) 
 595     nCount 
= nLen 
- nFirst
; 
 598   // out-of-bounds requests return sensible things 
 599   if ( nFirst 
+ nCount 
> nLen 
) 
 601     nCount 
= nLen 
- nFirst
; 
 606     // AllocCopy() will return empty string 
 611   AllocCopy(dest
, nCount
, nFirst
); 
 616 // extract nCount last (rightmost) characters 
 617 wxString 
wxString::Right(size_t nCount
) const 
 619   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 620     nCount 
= GetStringData()->nDataLength
; 
 623   AllocCopy(dest
, nCount
, GetStringData()->nDataLength 
- nCount
); 
 627 // get all characters after the last occurence of ch 
 628 // (returns the whole string if ch not found) 
 629 wxString 
wxString::Right(char ch
) const 
 632   int iPos 
= Find(ch
, TRUE
); 
 633   if ( iPos 
== NOT_FOUND 
) 
 636     str 
= c_str() + iPos 
+ 1; 
 641 // extract nCount first (leftmost) characters 
 642 wxString 
wxString::Left(size_t nCount
) const 
 644   if ( nCount 
> (size_t)GetStringData()->nDataLength 
) 
 645     nCount 
= GetStringData()->nDataLength
; 
 648   AllocCopy(dest
, nCount
, 0); 
 652 // get all characters before the first occurence of ch 
 653 // (returns the whole string if ch not found) 
 654 wxString 
wxString::Left(char ch
) const 
 657   for ( const char *pc 
= m_pchData
; *pc 
!= '\0' && *pc 
!= ch
; pc
++ ) 
 663 /// get all characters before the last occurence of ch 
 664 /// (returns empty string if ch not found) 
 665 wxString 
wxString::Before(char ch
) const 
 668   int iPos 
= Find(ch
, TRUE
); 
 669   if ( iPos 
!= NOT_FOUND 
&& iPos 
!= 0 ) 
 670     str 
= wxString(c_str(), iPos
); 
 675 /// get all characters after the first occurence of ch 
 676 /// (returns empty string if ch not found) 
 677 wxString 
wxString::After(char ch
) const 
 681   if ( iPos 
!= NOT_FOUND 
) 
 682     str 
= c_str() + iPos 
+ 1; 
 687 // replace first (or all) occurences of some substring with another one 
 688 size_t wxString::Replace(const char *szOld
, const char *szNew
, bool bReplaceAll
) 
 690   size_t uiCount 
= 0;   // count of replacements made 
 692   size_t uiOldLen 
= Strlen(szOld
); 
 695   const char *pCurrent 
= m_pchData
; 
 697   while ( *pCurrent 
!= '\0' ) { 
 698     pSubstr 
= strstr(pCurrent
, szOld
); 
 699     if ( pSubstr 
== NULL 
) { 
 700       // strTemp is unused if no replacements were made, so avoid the copy 
 704       strTemp 
+= pCurrent
;    // copy the rest 
 705       break;                  // exit the loop 
 708       // take chars before match 
 709       strTemp
.ConcatSelf(pSubstr 
- pCurrent
, pCurrent
); 
 711       pCurrent 
= pSubstr 
+ uiOldLen
;  // restart after match 
 716       if ( !bReplaceAll 
) { 
 717         strTemp 
+= pCurrent
;    // copy the rest 
 718         break;                  // exit the loop 
 723   // only done if there were replacements, otherwise would have returned above 
 729 bool wxString::IsAscii() const 
 731   const char *s 
= (const char*) *this; 
 733     if(!isascii(*s
)) return(FALSE
); 
 739 bool wxString::IsWord() const 
 741   const char *s 
= (const char*) *this; 
 743     if(!isalpha(*s
)) return(FALSE
); 
 749 bool wxString::IsNumber() const 
 751   const char *s 
= (const char*) *this; 
 753     if(!isdigit(*s
)) return(FALSE
); 
 759 wxString 
wxString::Strip(stripType w
) const 
 762     if ( w 
& leading 
) s
.Trim(FALSE
); 
 763     if ( w 
& trailing 
) s
.Trim(TRUE
); 
 767 // --------------------------------------------------------------------------- 
 769 // --------------------------------------------------------------------------- 
 771 wxString
& wxString::MakeUpper() 
 775   for ( char *p 
= m_pchData
; *p
; p
++ ) 
 776     *p 
= (char)toupper(*p
); 
 781 wxString
& wxString::MakeLower() 
 785   for ( char *p 
= m_pchData
; *p
; p
++ ) 
 786     *p 
= (char)tolower(*p
); 
 791 // --------------------------------------------------------------------------- 
 792 // trimming and padding 
 793 // --------------------------------------------------------------------------- 
 795 // trims spaces (in the sense of isspace) from left or right side 
 796 wxString
& wxString::Trim(bool bFromRight
) 
 798   // first check if we're going to modify the string at all 
 801         (bFromRight 
&& isspace(GetChar(Len() - 1))) || 
 802         (!bFromRight 
&& isspace(GetChar(0u))) 
 806     // ok, there is at least one space to trim 
 811       // find last non-space character 
 812       char *psz 
= m_pchData 
+ GetStringData()->nDataLength 
- 1; 
 813       while ( isspace(*psz
) && (psz 
>= m_pchData
) ) 
 816       // truncate at trailing space start 
 818       GetStringData()->nDataLength 
= psz 
- m_pchData
; 
 822       // find first non-space character 
 823       const char *psz 
= m_pchData
; 
 824       while ( isspace(*psz
) ) 
 827       // fix up data and length 
 828       int nDataLength 
= GetStringData()->nDataLength 
- (psz 
- m_pchData
); 
 829       memmove(m_pchData
, psz
, (nDataLength 
+ 1)*sizeof(char)); 
 830       GetStringData()->nDataLength 
= nDataLength
; 
 837 // adds nCount characters chPad to the string from either side 
 838 wxString
& wxString::Pad(size_t nCount
, char chPad
, bool bFromRight
) 
 840   wxString 
s(chPad
, nCount
); 
 853 // truncate the string 
 854 wxString
& wxString::Truncate(size_t uiLen
) 
 856   *(m_pchData 
+ uiLen
) = '\0'; 
 857   GetStringData()->nDataLength 
= uiLen
; 
 862 // --------------------------------------------------------------------------- 
 863 // finding (return NOT_FOUND if not found and index otherwise) 
 864 // --------------------------------------------------------------------------- 
 867 int wxString::Find(char ch
, bool bFromEnd
) const 
 869   const char *psz 
= bFromEnd 
? strrchr(m_pchData
, ch
) : strchr(m_pchData
, ch
); 
 871   return (psz 
== NULL
) ? NOT_FOUND 
: psz 
- m_pchData
; 
 874 // find a sub-string (like strstr) 
 875 int wxString::Find(const char *pszSub
) const 
 877   const char *psz 
= strstr(m_pchData
, pszSub
); 
 879   return (psz 
== NULL
) ? NOT_FOUND 
: psz 
- m_pchData
; 
 882 // --------------------------------------------------------------------------- 
 884 // --------------------------------------------------------------------------- 
 885 int wxString::Printf(const char *pszFormat
, ...) 
 888   va_start(argptr
, pszFormat
); 
 890   int iLen 
= PrintfV(pszFormat
, argptr
); 
 897 int wxString::PrintfV(const char* pszFormat
, va_list argptr
) 
 899   static char s_szScratch
[1024]; 
 901   int iLen 
= vsprintf(s_szScratch
, pszFormat
, argptr
); 
 902   AllocBeforeWrite(iLen
); 
 903   strcpy(m_pchData
, s_szScratch
); 
 908 // ---------------------------------------------------------------------------- 
 909 // misc other operations 
 910 // ---------------------------------------------------------------------------- 
 911 bool wxString::Matches(const char *pszMask
) const 
 913   // check char by char 
 915   for ( pszTxt 
= c_str(); *pszMask 
!= '\0'; pszMask
++, pszTxt
++ ) { 
 916     switch ( *pszMask 
) { 
 918         if ( *pszTxt 
== '\0' ) 
 927           // ignore special chars immediately following this one 
 928           while ( *pszMask 
== '*' || *pszMask 
== '?' ) 
 931           // if there is nothing more, match 
 932           if ( *pszMask 
== '\0' ) 
 935           // are there any other metacharacters in the mask? 
 937           const char *pEndMask 
= strpbrk(pszMask
, "*?"); 
 939           if ( pEndMask 
!= NULL 
) { 
 940             // we have to match the string between two metachars 
 941             uiLenMask 
= pEndMask 
- pszMask
; 
 944             // we have to match the remainder of the string 
 945             uiLenMask 
= strlen(pszMask
); 
 948           wxString 
strToMatch(pszMask
, uiLenMask
); 
 949           const char* pMatch 
= strstr(pszTxt
, strToMatch
); 
 950           if ( pMatch 
== NULL 
) 
 953           // -1 to compensate "++" in the loop 
 954           pszTxt 
= pMatch 
+ uiLenMask 
- 1; 
 955           pszMask 
+= uiLenMask 
- 1; 
 960         if ( *pszMask 
!= *pszTxt 
) 
 966   // match only if nothing left 
 967   return *pszTxt 
== '\0'; 
 970 // --------------------------------------------------------------------------- 
 971 // standard C++ library string functions 
 972 // --------------------------------------------------------------------------- 
 973 #ifdef  STD_STRING_COMPATIBILITY 
 975 wxString
& wxString::insert(size_t nPos
, const wxString
& str
) 
 977   wxASSERT( str
.GetStringData()->IsValid() ); 
 978   wxASSERT( nPos 
<= Len() ); 
 980   if ( !str
.IsEmpty() ) { 
 982     char *pc 
= strTmp
.GetWriteBuf(Len() + str
.Len()); 
 983     strncpy(pc
, c_str(), nPos
); 
 984     strcpy(pc 
+ nPos
, str
); 
 985     strcpy(pc 
+ nPos 
+ str
.Len(), c_str() + nPos
); 
 986     strTmp
.UngetWriteBuf(); 
 993 size_t wxString::find(const wxString
& str
, size_t nStart
) const 
 995   wxASSERT( str
.GetStringData()->IsValid() ); 
 996   wxASSERT( nStart 
<= Len() ); 
 998   const char *p 
= strstr(c_str() + nStart
, str
); 
1000   return p 
== NULL 
? npos 
: p 
- c_str(); 
1003 // VC++ 1.5 can't cope with the default argument in the header. 
1004 #if ! (defined(_MSC_VER) && !defined(__WIN32__)) 
1005 size_t wxString::find(const char* sz
, size_t nStart
, size_t n
) const 
1007   return find(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1011 size_t wxString::find(char ch
, size_t nStart
) const 
1013   wxASSERT( nStart 
<= Len() ); 
1015   const char *p 
= strchr(c_str() + nStart
, ch
); 
1017   return p 
== NULL 
? npos 
: p 
- c_str(); 
1020 size_t wxString::rfind(const wxString
& str
, size_t nStart
) const 
1022   wxASSERT( str
.GetStringData()->IsValid() ); 
1023   wxASSERT( nStart 
<= Len() ); 
1025   // # could be quicker than that 
1026   const char *p 
= c_str() + (nStart 
== npos 
? Len() : nStart
); 
1027   while ( p 
>= c_str() + str
.Len() ) { 
1028     if ( strncmp(p 
- str
.Len(), str
, str
.Len()) == 0 ) 
1029       return p 
- str
.Len() - c_str(); 
1036 // VC++ 1.5 can't cope with the default argument in the header. 
1037 #if ! (defined(_MSC_VER) && !defined(__WIN32__)) 
1038 size_t wxString::rfind(const char* sz
, size_t nStart
, size_t n
) const 
1040   return rfind(wxString(sz
, n 
== npos 
? 0 : n
), nStart
); 
1043 size_t wxString::rfind(char ch
, size_t nStart
) const 
1045   wxASSERT( nStart 
<= Len() ); 
1047   const char *p 
= strrchr(c_str() + nStart
, ch
); 
1049   return p 
== NULL 
? npos 
: p 
- c_str(); 
1053 wxString 
wxString::substr(size_t nStart
, size_t nLen
) const 
1055   // npos means 'take all' 
1059   wxASSERT( nStart 
+ nLen 
<= Len() ); 
1061   return wxString(c_str() + nStart
, nLen 
== npos 
? 0 : nLen
); 
1064 wxString
& wxString::erase(size_t nStart
, size_t nLen
) 
1066   wxString 
strTmp(c_str(), nStart
); 
1067   if ( nLen 
!= npos 
) { 
1068     wxASSERT( nStart 
+ nLen 
<= Len() ); 
1070     strTmp
.append(c_str() + nStart 
+ nLen
); 
1077 wxString
& wxString::replace(size_t nStart
, size_t nLen
, const char *sz
) 
1079   wxASSERT( nStart 
+ nLen 
<= Strlen(sz
) ); 
1083     strTmp
.append(c_str(), nStart
); 
1085   strTmp
.append(c_str() + nStart 
+ nLen
); 
1091 wxString
& wxString::replace(size_t nStart
, size_t nLen
, size_t nCount
, char ch
) 
1093   return replace(nStart
, nLen
, wxString(ch
, nCount
)); 
1096 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1097                             const wxString
& str
, size_t nStart2
, size_t nLen2
) 
1099   return replace(nStart
, nLen
, str
.substr(nStart2
, nLen2
)); 
1102 wxString
& wxString::replace(size_t nStart
, size_t nLen
, 
1103                         const char* sz
, size_t nCount
) 
1105   return replace(nStart
, nLen
, wxString(sz
, nCount
)); 
1108 #endif  //std::string compatibility 
1110 // ============================================================================ 
1112 // ============================================================================ 
1114 // size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) 
1115 #define   ARRAY_MAXSIZE_INCREMENT       4096 
1116 #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h 
1117   #define   ARRAY_DEFAULT_INITIAL_SIZE    (16) 
1120 #define   STRING(p)   ((wxString *)(&(p))) 
1123 wxArrayString::wxArrayString() 
1127   m_pItems 
= (char **) NULL
; 
1131 wxArrayString::wxArrayString(const wxArrayString
& src
) 
1135   m_pItems 
= (char **) NULL
; 
1140 // assignment operator 
1141 wxArrayString
& wxArrayString::operator=(const wxArrayString
& src
) 
1146   if ( src
.m_nCount 
> ARRAY_DEFAULT_INITIAL_SIZE 
) 
1147     Alloc(src
.m_nCount
); 
1149   // we can't just copy the pointers here because otherwise we would share 
1150   // the strings with another array 
1151   for ( size_t n 
= 0; n 
< src
.m_nCount
; n
++ ) 
1154   if ( m_nCount 
!= 0 ) 
1155     memcpy(m_pItems
, src
.m_pItems
, m_nCount
*sizeof(char *)); 
1161 void wxArrayString::Grow() 
1163   // only do it if no more place 
1164   if( m_nCount 
== m_nSize 
) { 
1165     if( m_nSize 
== 0 ) { 
1166       // was empty, alloc some memory 
1167       m_nSize 
= ARRAY_DEFAULT_INITIAL_SIZE
; 
1168       m_pItems 
= new char *[m_nSize
]; 
1171       // otherwise when it's called for the first time, nIncrement would be 0 
1172       // and the array would never be expanded 
1173       wxASSERT( ARRAY_DEFAULT_INITIAL_SIZE 
!= 0 ); 
1175       // add 50% but not too much 
1176       size_t nIncrement 
= m_nSize 
< ARRAY_DEFAULT_INITIAL_SIZE
 
1177                           ? ARRAY_DEFAULT_INITIAL_SIZE 
: m_nSize 
>> 1; 
1178       if ( nIncrement 
> ARRAY_MAXSIZE_INCREMENT 
) 
1179         nIncrement 
= ARRAY_MAXSIZE_INCREMENT
; 
1180       m_nSize 
+= nIncrement
; 
1181       char **pNew 
= new char *[m_nSize
]; 
1183       // copy data to new location 
1184       memcpy(pNew
, m_pItems
, m_nCount
*sizeof(char *)); 
1186       // delete old memory (but do not release the strings!) 
1187       wxDELETEA(m_pItems
); 
1194 void wxArrayString::Free() 
1196   for ( size_t n 
= 0; n 
< m_nCount
; n
++ ) { 
1197     STRING(m_pItems
[n
])->GetStringData()->Unlock(); 
1201 // deletes all the strings from the list 
1202 void wxArrayString::Empty() 
1209 // as Empty, but also frees memory 
1210 void wxArrayString::Clear() 
1217   wxDELETEA(m_pItems
); 
1221 wxArrayString::~wxArrayString() 
1225   wxDELETEA(m_pItems
); 
1228 // pre-allocates memory (frees the previous data!) 
1229 void wxArrayString::Alloc(size_t nSize
) 
1231   wxASSERT( nSize 
> 0 ); 
1233   // only if old buffer was not big enough 
1234   if ( nSize 
> m_nSize 
) { 
1236     wxDELETEA(m_pItems
); 
1237     m_pItems 
= new char *[nSize
]; 
1244 // searches the array for an item (forward or backwards) 
1245 int wxArrayString::Index(const char *sz
, bool bCase
, bool bFromEnd
) const 
1248     if ( m_nCount 
> 0 ) { 
1249       size_t ui 
= m_nCount
; 
1251         if ( STRING(m_pItems
[--ui
])->IsSameAs(sz
, bCase
) ) 
1258     for( size_t ui 
= 0; ui 
< m_nCount
; ui
++ ) { 
1259       if( STRING(m_pItems
[ui
])->IsSameAs(sz
, bCase
) ) 
1267 // add item at the end 
1268 void wxArrayString::Add(const wxString
& str
) 
1270   wxASSERT( str
.GetStringData()->IsValid() ); 
1274   // the string data must not be deleted! 
1275   str
.GetStringData()->Lock(); 
1276   m_pItems
[m_nCount
++] = (char *)str
.c_str(); 
1279 // add item at the given position 
1280 void wxArrayString::Insert(const wxString
& str
, size_t nIndex
) 
1282   wxASSERT( str
.GetStringData()->IsValid() ); 
1284   wxCHECK_RET( nIndex 
<= m_nCount
, ("bad index in wxArrayString::Insert") ); 
1288   memmove(&m_pItems
[nIndex 
+ 1], &m_pItems
[nIndex
], 
1289           (m_nCount 
- nIndex
)*sizeof(char *)); 
1291   str
.GetStringData()->Lock(); 
1292   m_pItems
[nIndex
] = (char *)str
.c_str(); 
1297 // removes item from array (by index) 
1298 void wxArrayString::Remove(size_t nIndex
) 
1300   wxCHECK_RET( nIndex 
<= m_nCount
, _("bad index in wxArrayString::Remove") ); 
1303   Item(nIndex
).GetStringData()->Unlock(); 
1305   memmove(&m_pItems
[nIndex
], &m_pItems
[nIndex 
+ 1], 
1306           (m_nCount 
- nIndex 
- 1)*sizeof(char *)); 
1310 // removes item from array (by value) 
1311 void wxArrayString::Remove(const char *sz
) 
1313   int iIndex 
= Index(sz
); 
1315   wxCHECK_RET( iIndex 
!= NOT_FOUND
, 
1316                _("removing inexistent element in wxArrayString::Remove") ); 
1321 // sort array elements using passed comparaison function 
1323 void wxArrayString::Sort(bool WXUNUSED(bCase
), bool WXUNUSED(bReverse
) ) 
1326   //qsort(m_pItems, m_nCount, sizeof(char *), fCmp);