home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / string.cpp < prev    next >
C/C++ Source or Header  |  2002-08-27  |  56KB  |  2,125 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        string.cpp
  3. // Purpose:     wxString class
  4. // Author:      Vadim Zeitlin
  5. // Modified by:
  6. // Created:     29/01/98
  7. // RCS-ID:      $Id: string.cpp,v 1.163 2002/08/25 17:13:44 VZ Exp $
  8. // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13.   #pragma implementation "string.h"
  14. #endif
  15.  
  16. /*
  17.  * About ref counting:
  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
  21.  */
  22.  
  23. // ===========================================================================
  24. // headers, declarations, constants
  25. // ===========================================================================
  26.  
  27. // For compilers that support precompilation, includes "wx.h".
  28. #include "wx/wxprec.h"
  29.  
  30. #ifdef __BORLANDC__
  31.   #pragma hdrstop
  32. #endif
  33.  
  34. #ifndef WX_PRECOMP
  35.   #include "wx/defs.h"
  36.   #include "wx/string.h"
  37.   #include "wx/intl.h"
  38.   #include "wx/thread.h"
  39. #endif
  40.  
  41. #include <ctype.h>
  42. #include <string.h>
  43. #include <stdlib.h>
  44.  
  45. #ifdef __SALFORDC__
  46.   #include <clib.h>
  47. #endif
  48.  
  49. // allocating extra space for each string consumes more memory but speeds up
  50. // the concatenation operations (nLen is the current string's length)
  51. // NB: EXTRA_ALLOC must be >= 0!
  52. #define EXTRA_ALLOC       (19 - nLen % 16)
  53.  
  54. // ---------------------------------------------------------------------------
  55. // static class variables definition
  56. // ---------------------------------------------------------------------------
  57.  
  58. #if defined(__VISAGECPP__) && __IBMCPP__ >= 400
  59. // must define this static for VA or else you get multiply defined symbols
  60. // everywhere
  61. const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
  62. #endif // Visual Age
  63.  
  64. #ifdef  wxSTD_STRING_COMPATIBILITY
  65.   const size_t wxString::npos = wxSTRING_MAXLEN;
  66. #endif // wxSTD_STRING_COMPATIBILITY
  67.  
  68. // ----------------------------------------------------------------------------
  69. // static data
  70. // ----------------------------------------------------------------------------
  71.  
  72. // for an empty string, GetStringData() will return this address: this
  73. // structure has the same layout as wxStringData and it's data() method will
  74. // return the empty string (dummy pointer)
  75. static const struct
  76. {
  77.   wxStringData data;
  78.   wxChar dummy;
  79. } g_strEmpty = { {-1, 0, 0}, wxT('\0') };
  80.  
  81. // empty C style string: points to 'string data' byte of g_strEmpty
  82. extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy;
  83.  
  84. // ----------------------------------------------------------------------------
  85. // global functions
  86. // ----------------------------------------------------------------------------
  87.  
  88. #if defined(wxSTD_STRING_COMPATIBILITY) && wxUSE_STD_IOSTREAM
  89.  
  90. // MS Visual C++ version 5.0 provides the new STL headers as well as the old
  91. // iostream ones.
  92. //
  93. // ATTN: you can _not_ use both of these in the same program!
  94.  
  95. wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
  96. {
  97. #if 0
  98.   int w = is.width(0);
  99.   if ( is.ipfx(0) ) {
  100.     streambuf *sb = is.rdbuf();
  101.     str.erase();
  102.     while ( true ) {
  103.       int ch = sb->sbumpc ();
  104.       if ( ch == EOF ) {
  105.         is.setstate(ios::eofbit);
  106.         break;
  107.       }
  108.       else if ( isspace(ch) ) {
  109.         sb->sungetc();
  110.         break;
  111.       }
  112.  
  113.       str += ch;
  114.       if ( --w == 1 )
  115.         break;
  116.     }
  117.   }
  118.  
  119.   is.isfx();
  120.   if ( str.length() == 0 )
  121.     is.setstate(ios::failbit);
  122. #endif
  123.   return is;
  124. }
  125.  
  126. wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
  127. {
  128.   os << str.c_str();
  129.   return os;
  130. }
  131.  
  132. #endif  //std::string compatibility
  133.  
  134. // ----------------------------------------------------------------------------
  135. // private classes
  136. // ----------------------------------------------------------------------------
  137.  
  138. // this small class is used to gather statistics for performance tuning
  139. //#define WXSTRING_STATISTICS
  140. #ifdef  WXSTRING_STATISTICS
  141.   class Averager
  142.   {
  143.   public:
  144.     Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; }
  145.    ~Averager()
  146.    { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); }
  147.  
  148.     void Add(size_t n) { m_nTotal += n; m_nCount++; }
  149.  
  150.   private:
  151.     size_t m_nCount, m_nTotal;
  152.     const wxChar *m_sz;
  153.   } g_averageLength("allocation size"),
  154.     g_averageSummandLength("summand length"),
  155.     g_averageConcatHit("hit probability in concat"),
  156.     g_averageInitialLength("initial string length");
  157.  
  158.   #define STATISTICS_ADD(av, val) g_average##av.Add(val)
  159. #else
  160.   #define STATISTICS_ADD(av, val)
  161. #endif // WXSTRING_STATISTICS
  162.  
  163. // ===========================================================================
  164. // wxString class core
  165. // ===========================================================================
  166.  
  167. // ---------------------------------------------------------------------------
  168. // construction
  169. // ---------------------------------------------------------------------------
  170.  
  171. // constructs string of <nLength> copies of character <ch>
  172. wxString::wxString(wxChar ch, size_t nLength)
  173. {
  174.   Init();
  175.  
  176.   if ( nLength > 0 ) {
  177.     if ( !AllocBuffer(nLength) ) {
  178.       wxFAIL_MSG( _T("out of memory in wxString::wxString") );
  179.       return;
  180.     }
  181.  
  182. #if wxUSE_UNICODE
  183.     // memset only works on chars
  184.     for ( size_t n = 0; n < nLength; n++ )
  185.         m_pchData[n] = ch;
  186. #else
  187.     memset(m_pchData, ch, nLength);
  188. #endif
  189.   }
  190. }
  191.  
  192. // takes nLength elements of psz starting at nPos
  193. void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
  194. {
  195.   Init();
  196.  
  197.   // if the length is not given, assume the string to be NUL terminated
  198.   if ( nLength == wxSTRING_MAXLEN ) {
  199.     wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") );
  200.  
  201.     nLength = wxStrlen(psz + nPos);
  202.   }
  203.  
  204.   STATISTICS_ADD(InitialLength, nLength);
  205.  
  206.   if ( nLength > 0 ) {
  207.     // trailing '\0' is written in AllocBuffer()
  208.     if ( !AllocBuffer(nLength) ) {
  209.       wxFAIL_MSG( _T("out of memory in wxString::InitWith") );
  210.       return;
  211.     }
  212.     memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
  213.   }
  214. }
  215.  
  216. #ifdef  wxSTD_STRING_COMPATIBILITY
  217.  
  218. // poor man's iterators are "void *" pointers
  219. wxString::wxString(const void *pStart, const void *pEnd)
  220. {
  221.   InitWith((const wxChar *)pStart, 0,
  222.            (const wxChar *)pEnd - (const wxChar *)pStart);
  223. }
  224.  
  225. #endif  //std::string compatibility
  226.  
  227. #if wxUSE_UNICODE
  228.  
  229. // from multibyte string
  230. wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
  231. {
  232.   // first get necessary size
  233.   size_t nLen = psz ? conv.MB2WC((wchar_t *) NULL, psz, 0) : 0;
  234.  
  235.   // nLength is number of *Unicode* characters here!
  236.   if ((nLen != (size_t)-1) && (nLen > nLength))
  237.     nLen = nLength;
  238.  
  239.   // empty?
  240.   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
  241.     if ( !AllocBuffer(nLen) ) {
  242.       wxFAIL_MSG( _T("out of memory in wxString::wxString") );
  243.       return;
  244.     }
  245.     conv.MB2WC(m_pchData, psz, nLen);
  246.   }
  247.   else {
  248.     Init();
  249.   }
  250. }
  251.  
  252. #else // ANSI
  253.  
  254. #if wxUSE_WCHAR_T
  255. // from wide string
  256. wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
  257. {
  258.   // first get necessary size
  259.   size_t nLen = 0;
  260.   if (pwz)
  261.   {
  262.     if (nLength == wxSTRING_MAXLEN)
  263.       nLen = conv.WC2MB((char *) NULL, pwz, 0);
  264.     else
  265.       nLen = nLength;
  266.   }
  267.  
  268.   // empty?
  269.   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
  270.     if ( !AllocBuffer(nLen) ) {
  271.       wxFAIL_MSG( _T("out of memory in wxString::wxString") );
  272.       return;
  273.     }
  274.     conv.WC2MB(m_pchData, pwz, nLen);
  275.   }
  276.   else {
  277.     Init();
  278.   }
  279. }
  280. #endif // wxUSE_WCHAR_T
  281.  
  282. #endif // Unicode/ANSI
  283.  
  284. // ---------------------------------------------------------------------------
  285. // memory allocation
  286. // ---------------------------------------------------------------------------
  287.  
  288. // allocates memory needed to store a C string of length nLen
  289. bool wxString::AllocBuffer(size_t nLen)
  290. {
  291.   // allocating 0 sized buffer doesn't make sense, all empty strings should
  292.   // reuse g_strEmpty
  293.   wxASSERT( nLen >  0 );
  294.  
  295.   // make sure that we don't overflow
  296.   wxASSERT( nLen < (INT_MAX / sizeof(wxChar)) -
  297.                    (sizeof(wxStringData) + EXTRA_ALLOC + 1) );
  298.  
  299.   STATISTICS_ADD(Length, nLen);
  300.  
  301.   // allocate memory:
  302.   // 1) one extra character for '\0' termination
  303.   // 2) sizeof(wxStringData) for housekeeping info
  304.   wxStringData* pData = (wxStringData*)
  305.     malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
  306.  
  307.   if ( pData == NULL ) {
  308.     // allocation failures are handled by the caller
  309.     return FALSE;
  310.   }
  311.  
  312.   pData->nRefs        = 1;
  313.   pData->nDataLength  = nLen;
  314.   pData->nAllocLength = nLen + EXTRA_ALLOC;
  315.   m_pchData           = pData->data();  // data starts after wxStringData
  316.   m_pchData[nLen]     = wxT('\0');
  317.   return TRUE;
  318. }
  319.  
  320. // must be called before changing this string
  321. bool wxString::CopyBeforeWrite()
  322. {
  323.   wxStringData* pData = GetStringData();
  324.  
  325.   if ( pData->IsShared() ) {
  326.     pData->Unlock();                // memory not freed because shared
  327.     size_t nLen = pData->nDataLength;
  328.     if ( !AllocBuffer(nLen) ) {
  329.       // allocation failures are handled by the caller
  330.       return FALSE;
  331.     }
  332.     memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
  333.   }
  334.  
  335.   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
  336.  
  337.   return TRUE;
  338. }
  339.  
  340. // must be called before replacing contents of this string
  341. bool wxString::AllocBeforeWrite(size_t nLen)
  342. {
  343.   wxASSERT( nLen != 0 );  // doesn't make any sense
  344.  
  345.   // must not share string and must have enough space
  346.   wxStringData* pData = GetStringData();
  347.   if ( pData->IsShared() || pData->IsEmpty() ) {
  348.     // can't work with old buffer, get new one
  349.     pData->Unlock();
  350.     if ( !AllocBuffer(nLen) ) {
  351.       // allocation failures are handled by the caller
  352.       return FALSE;
  353.     }
  354.   }
  355.   else {
  356.     if ( nLen > pData->nAllocLength ) {
  357.       // realloc the buffer instead of calling malloc() again, this is more
  358.       // efficient
  359.       STATISTICS_ADD(Length, nLen);
  360.  
  361.       nLen += EXTRA_ALLOC;
  362.  
  363.       pData = (wxStringData*)
  364.           realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
  365.  
  366.       if ( pData == NULL ) {
  367.         // allocation failures are handled by the caller
  368.         // keep previous data since reallocation failed
  369.         return FALSE;
  370.       }
  371.  
  372.       pData->nAllocLength = nLen;
  373.       m_pchData = pData->data();
  374.     }
  375.  
  376.     // now we have enough space, just update the string length
  377.     pData->nDataLength = nLen;
  378.   }
  379.  
  380.   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
  381.  
  382.   return TRUE;
  383. }
  384.  
  385. // allocate enough memory for nLen characters
  386. bool wxString::Alloc(size_t nLen)
  387. {
  388.   wxStringData *pData = GetStringData();
  389.   if ( pData->nAllocLength <= nLen ) {
  390.     if ( pData->IsEmpty() ) {
  391.       nLen += EXTRA_ALLOC;
  392.  
  393.       wxStringData* pData = (wxStringData*)
  394.           malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
  395.  
  396.       if ( pData == NULL ) {
  397.         // allocation failure handled by caller
  398.         return FALSE;
  399.       }
  400.  
  401.       pData->nRefs = 1;
  402.       pData->nDataLength = 0;
  403.       pData->nAllocLength = nLen;
  404.       m_pchData = pData->data();  // data starts after wxStringData
  405.       m_pchData[0u] = wxT('\0');
  406.     }
  407.     else if ( pData->IsShared() ) {
  408.       pData->Unlock();                // memory not freed because shared
  409.       size_t nOldLen = pData->nDataLength;
  410.       if ( !AllocBuffer(nLen) ) {
  411.         // allocation failure handled by caller
  412.         return FALSE;
  413.       }
  414.       memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
  415.     }
  416.     else {
  417.       nLen += EXTRA_ALLOC;
  418.  
  419.       pData = (wxStringData *)
  420.         realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
  421.  
  422.       if ( pData == NULL ) {
  423.         // allocation failure handled by caller
  424.         // keep previous data since reallocation failed
  425.         return FALSE;
  426.       }
  427.  
  428.       // it's not important if the pointer changed or not (the check for this
  429.       // is not faster than assigning to m_pchData in all cases)
  430.       pData->nAllocLength = nLen;
  431.       m_pchData = pData->data();
  432.     }
  433.   }
  434.   //else: we've already got enough
  435.   return TRUE;
  436. }
  437.  
  438. // shrink to minimal size (releasing extra memory)
  439. bool wxString::Shrink()
  440. {
  441.   wxStringData *pData = GetStringData();
  442.  
  443.   size_t nLen = pData->nDataLength;
  444.   void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
  445.  
  446.   if ( p == NULL) {
  447.       wxFAIL_MSG( _T("out of memory reallocating wxString data") );
  448.       // keep previous data since reallocation failed
  449.       return FALSE;
  450.   }
  451.  
  452.   if ( p != pData )
  453.   {
  454.       // contrary to what one might believe, some realloc() implementation do
  455.       // move the memory block even when its size is reduced
  456.       pData = (wxStringData *)p;
  457.  
  458.       m_pchData = pData->data();
  459.   }
  460.  
  461.   pData->nAllocLength = nLen;
  462.  
  463.   return TRUE;
  464. }
  465.  
  466. // get the pointer to writable buffer of (at least) nLen bytes
  467. wxChar *wxString::GetWriteBuf(size_t nLen)
  468. {
  469.   if ( !AllocBeforeWrite(nLen) ) {
  470.     // allocation failure handled by caller
  471.     return NULL;
  472.   }
  473.  
  474.   wxASSERT( GetStringData()->nRefs == 1 );
  475.   GetStringData()->Validate(FALSE);
  476.  
  477.   return m_pchData;
  478. }
  479.  
  480. // put string back in a reasonable state after GetWriteBuf
  481. void wxString::UngetWriteBuf()
  482. {
  483.   GetStringData()->nDataLength = wxStrlen(m_pchData);
  484.   GetStringData()->Validate(TRUE);
  485. }
  486.  
  487. void wxString::UngetWriteBuf(size_t nLen)
  488. {
  489.   GetStringData()->nDataLength = nLen;
  490.   GetStringData()->Validate(TRUE);
  491. }
  492.  
  493. // ---------------------------------------------------------------------------
  494. // data access
  495. // ---------------------------------------------------------------------------
  496.  
  497. // all functions are inline in string.h
  498.  
  499. // ---------------------------------------------------------------------------
  500. // assignment operators
  501. // ---------------------------------------------------------------------------
  502.  
  503. // helper function: does real copy
  504. bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
  505. {
  506.   if ( nSrcLen == 0 ) {
  507.     Reinit();
  508.   }
  509.   else {
  510.     if ( !AllocBeforeWrite(nSrcLen) ) {
  511.       // allocation failure handled by caller
  512.       return FALSE;
  513.     }
  514.     memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
  515.     GetStringData()->nDataLength = nSrcLen;
  516.     m_pchData[nSrcLen] = wxT('\0');
  517.   }
  518.   return TRUE;
  519. }
  520.  
  521. // assigns one string to another
  522. wxString& wxString::operator=(const wxString& stringSrc)
  523. {
  524.   wxASSERT( stringSrc.GetStringData()->IsValid() );
  525.  
  526.   // don't copy string over itself
  527.   if ( m_pchData != stringSrc.m_pchData ) {
  528.     if ( stringSrc.GetStringData()->IsEmpty() ) {
  529.       Reinit();
  530.     }
  531.     else {
  532.       // adjust references
  533.       GetStringData()->Unlock();
  534.       m_pchData = stringSrc.m_pchData;
  535.       GetStringData()->Lock();
  536.     }
  537.   }
  538.  
  539.   return *this;
  540. }
  541.  
  542. // assigns a single character
  543. wxString& wxString::operator=(wxChar ch)
  544. {
  545.   if ( !AssignCopy(1, &ch) ) {
  546.     wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
  547.   }
  548.   return *this;
  549. }
  550.  
  551.  
  552. // assigns C string
  553. wxString& wxString::operator=(const wxChar *psz)
  554. {
  555.   if ( !AssignCopy(wxStrlen(psz), psz) ) {
  556.     wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
  557.   }
  558.   return *this;
  559. }
  560.  
  561. #if !wxUSE_UNICODE
  562.  
  563. // same as 'signed char' variant
  564. wxString& wxString::operator=(const unsigned char* psz)
  565. {
  566.   *this = (const char *)psz;
  567.   return *this;
  568. }
  569.  
  570. #if wxUSE_WCHAR_T
  571. wxString& wxString::operator=(const wchar_t *pwz)
  572. {
  573.   wxString str(pwz);
  574.   *this = str;
  575.   return *this;
  576. }
  577. #endif
  578.  
  579. #endif
  580.  
  581. // ---------------------------------------------------------------------------
  582. // string concatenation
  583. // ---------------------------------------------------------------------------
  584.  
  585. // add something to this string
  586. bool wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
  587. {
  588.   STATISTICS_ADD(SummandLength, nSrcLen);
  589.  
  590.   // concatenating an empty string is a NOP
  591.   if ( nSrcLen > 0 ) {
  592.     wxStringData *pData = GetStringData();
  593.     size_t nLen = pData->nDataLength;
  594.     size_t nNewLen = nLen + nSrcLen;
  595.  
  596.     // alloc new buffer if current is too small
  597.     if ( pData->IsShared() ) {
  598.       STATISTICS_ADD(ConcatHit, 0);
  599.  
  600.       // we have to allocate another buffer
  601.       wxStringData* pOldData = GetStringData();
  602.       if ( !AllocBuffer(nNewLen) ) {
  603.           // allocation failure handled by caller
  604.           return FALSE;
  605.       }
  606.       memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
  607.       pOldData->Unlock();
  608.     }
  609.     else if ( nNewLen > pData->nAllocLength ) {
  610.       STATISTICS_ADD(ConcatHit, 0);
  611.  
  612.       // we have to grow the buffer
  613.       if ( !Alloc(nNewLen) ) {
  614.           // allocation failure handled by caller
  615.           return FALSE;
  616.       }
  617.     }
  618.     else {
  619.       STATISTICS_ADD(ConcatHit, 1);
  620.  
  621.       // the buffer is already big enough
  622.     }
  623.  
  624.     // should be enough space
  625.     wxASSERT( nNewLen <= GetStringData()->nAllocLength );
  626.  
  627.     // fast concatenation - all is done in our buffer
  628.     memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar));
  629.  
  630.     m_pchData[nNewLen] = wxT('\0');          // put terminating '\0'
  631.     GetStringData()->nDataLength = nNewLen; // and fix the length
  632.   }
  633.   //else: the string to append was empty
  634.   return TRUE;
  635. }
  636.  
  637. /*
  638.  * concatenation functions come in 5 flavours:
  639.  *  string + string
  640.  *  char   + string      and      string + char
  641.  *  C str  + string      and      string + C str
  642.  */
  643.  
  644. wxString operator+(const wxString& str1, const wxString& str2)
  645. {
  646.   wxASSERT( str1.GetStringData()->IsValid() );
  647.   wxASSERT( str2.GetStringData()->IsValid() );
  648.  
  649.   wxString s = str1;
  650.   s += str2;
  651.  
  652.   return s;
  653. }
  654.  
  655. wxString operator+(const wxString& str, wxChar ch)
  656. {
  657.   wxASSERT( str.GetStringData()->IsValid() );
  658.  
  659.   wxString s = str;
  660.   s += ch;
  661.  
  662.   return s;
  663. }
  664.  
  665. wxString operator+(wxChar ch, const wxString& str)
  666. {
  667.   wxASSERT( str.GetStringData()->IsValid() );
  668.  
  669.   wxString s = ch;
  670.   s += str;
  671.  
  672.   return s;
  673. }
  674.  
  675. wxString operator+(const wxString& str, const wxChar *psz)
  676. {
  677.   wxASSERT( str.GetStringData()->IsValid() );
  678.  
  679.   wxString s;
  680.   if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
  681.     wxFAIL_MSG( _T("out of memory in wxString::operator+") );
  682.   }
  683.   s = str;
  684.   s += psz;
  685.  
  686.   return s;
  687. }
  688.  
  689. wxString operator+(const wxChar *psz, const wxString& str)
  690. {
  691.   wxASSERT( str.GetStringData()->IsValid() );
  692.  
  693.   wxString s;
  694.   if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
  695.     wxFAIL_MSG( _T("out of memory in wxString::operator+") );
  696.   }
  697.   s = psz;
  698.   s += str;
  699.  
  700.   return s;
  701. }
  702.  
  703. // ===========================================================================
  704. // other common string functions
  705. // ===========================================================================
  706.  
  707. #if wxUSE_UNICODE
  708.  
  709. wxString wxString::FromAscii(const char *ascii)
  710. {
  711.     if (!ascii)
  712.        return wxEmptyString;
  713.  
  714.     size_t len = strlen( ascii );
  715.     wxString res;
  716.  
  717.     if ( len )
  718.     {
  719.         wxStringBuffer buf(res, len);
  720.  
  721.         wchar_t *dest = buf;
  722.  
  723.         for ( ;; )
  724.         {
  725.            if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
  726.                break;
  727.         }
  728.     }
  729.  
  730.     return res;
  731. }
  732.  
  733. const wxCharBuffer wxString::ToAscii() const
  734. {
  735.     // this will allocate enough space for the terminating NUL too
  736.     wxCharBuffer buffer(length());
  737.  
  738.     signed char *dest = (signed char *)buffer.data();
  739.  
  740.     const wchar_t *pwc = c_str();
  741.     for ( ;; )
  742.     {
  743.         *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
  744.  
  745.         // the output string can't have embedded NULs anyhow, so we can safely
  746.         // stop at first of them even if we do have any
  747.         if ( !*pwc++ )
  748.             break;
  749.     }
  750.  
  751.     return buffer;
  752. }
  753.  
  754. #endif // Unicode
  755.  
  756. // ---------------------------------------------------------------------------
  757. // simple sub-string extraction
  758. // ---------------------------------------------------------------------------
  759.  
  760. // helper function: clone the data attached to this string
  761. bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
  762. {
  763.   if ( nCopyLen == 0 ) {
  764.     dest.Init();
  765.   }
  766.   else {
  767.     if ( !dest.AllocBuffer(nCopyLen) ) {
  768.       // allocation failure handled by caller
  769.       return FALSE;
  770.     }
  771.     memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
  772.   }
  773.   return TRUE;
  774. }
  775.  
  776. // extract string of length nCount starting at nFirst
  777. wxString wxString::Mid(size_t nFirst, size_t nCount) const
  778. {
  779.   wxStringData *pData = GetStringData();
  780.   size_t nLen = pData->nDataLength;
  781.  
  782.   // default value of nCount is wxSTRING_MAXLEN and means "till the end"
  783.   if ( nCount == wxSTRING_MAXLEN )
  784.   {
  785.     nCount = nLen - nFirst;
  786.   }
  787.  
  788.   // out-of-bounds requests return sensible things
  789.   if ( nFirst + nCount > nLen )
  790.   {
  791.     nCount = nLen - nFirst;
  792.   }
  793.  
  794.   if ( nFirst > nLen )
  795.   {
  796.     // AllocCopy() will return empty string
  797.     nCount = 0;
  798.   }
  799.  
  800.   wxString dest;
  801.   if ( !AllocCopy(dest, nCount, nFirst) ) {
  802.       wxFAIL_MSG( _T("out of memory in wxString::Mid") );
  803.   }
  804.  
  805.   return dest;
  806. }
  807.  
  808. // check that the tring starts with prefix and return the rest of the string
  809. // in the provided pointer if it is not NULL, otherwise return FALSE
  810. bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const
  811. {
  812.     wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") );
  813.  
  814.     // first check if the beginning of the string matches the prefix: note
  815.     // that we don't have to check that we don't run out of this string as
  816.     // when we reach the terminating NUL, either prefix string ends too (and
  817.     // then it's ok) or we break out of the loop because there is no match
  818.     const wxChar *p = c_str();
  819.     while ( *prefix )
  820.     {
  821.         if ( *prefix++ != *p++ )
  822.         {
  823.             // no match
  824.             return FALSE;
  825.         }
  826.     }
  827.  
  828.     if ( rest )
  829.     {
  830.         // put the rest of the string into provided pointer
  831.         *rest = p;
  832.     }
  833.  
  834.     return TRUE;
  835. }
  836.  
  837. // extract nCount last (rightmost) characters
  838. wxString wxString::Right(size_t nCount) const
  839. {
  840.   if ( nCount > (size_t)GetStringData()->nDataLength )
  841.     nCount = GetStringData()->nDataLength;
  842.  
  843.   wxString dest;
  844.   if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
  845.     wxFAIL_MSG( _T("out of memory in wxString::Right") );
  846.   }
  847.   return dest;
  848. }
  849.  
  850. // get all characters after the last occurence of ch
  851. // (returns the whole string if ch not found)
  852. wxString wxString::AfterLast(wxChar ch) const
  853. {
  854.   wxString str;
  855.   int iPos = Find(ch, TRUE);
  856.   if ( iPos == wxNOT_FOUND )
  857.     str = *this;
  858.   else
  859.     str = c_str() + iPos + 1;
  860.  
  861.   return str;
  862. }
  863.  
  864. // extract nCount first (leftmost) characters
  865. wxString wxString::Left(size_t nCount) const
  866. {
  867.   if ( nCount > (size_t)GetStringData()->nDataLength )
  868.     nCount = GetStringData()->nDataLength;
  869.  
  870.   wxString dest;
  871.   if ( !AllocCopy(dest, nCount, 0) ) {
  872.     wxFAIL_MSG( _T("out of memory in wxString::Left") );
  873.   }
  874.   return dest;
  875. }
  876.  
  877. // get all characters before the first occurence of ch
  878. // (returns the whole string if ch not found)
  879. wxString wxString::BeforeFirst(wxChar ch) const
  880. {
  881.   wxString str;
  882.   for ( const wxChar *pc = m_pchData; *pc != wxT('\0') && *pc != ch; pc++ )
  883.     str += *pc;
  884.  
  885.   return str;
  886. }
  887.  
  888. /// get all characters before the last occurence of ch
  889. /// (returns empty string if ch not found)
  890. wxString wxString::BeforeLast(wxChar ch) const
  891. {
  892.   wxString str;
  893.   int iPos = Find(ch, TRUE);
  894.   if ( iPos != wxNOT_FOUND && iPos != 0 )
  895.     str = wxString(c_str(), iPos);
  896.  
  897.   return str;
  898. }
  899.  
  900. /// get all characters after the first occurence of ch
  901. /// (returns empty string if ch not found)
  902. wxString wxString::AfterFirst(wxChar ch) const
  903. {
  904.   wxString str;
  905.   int iPos = Find(ch);
  906.   if ( iPos != wxNOT_FOUND )
  907.     str = c_str() + iPos + 1;
  908.  
  909.   return str;
  910. }
  911.  
  912. // replace first (or all) occurences of some substring with another one
  913. size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll)
  914. {
  915.   size_t uiCount = 0;   // count of replacements made
  916.  
  917.   size_t uiOldLen = wxStrlen(szOld);
  918.  
  919.   wxString strTemp;
  920.   const wxChar *pCurrent = m_pchData;
  921.   const wxChar *pSubstr;
  922.   while ( *pCurrent != wxT('\0') ) {
  923.     pSubstr = wxStrstr(pCurrent, szOld);
  924.     if ( pSubstr == NULL ) {
  925.       // strTemp is unused if no replacements were made, so avoid the copy
  926.       if ( uiCount == 0 )
  927.         return 0;
  928.  
  929.       strTemp += pCurrent;    // copy the rest
  930.       break;                  // exit the loop
  931.     }
  932.     else {
  933.       // take chars before match
  934.       if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
  935.         wxFAIL_MSG( _T("out of memory in wxString::Replace") );
  936.         return 0;
  937.       }
  938.       strTemp += szNew;
  939.       pCurrent = pSubstr + uiOldLen;  // restart after match
  940.  
  941.       uiCount++;
  942.  
  943.       // stop now?
  944.       if ( !bReplaceAll ) {
  945.         strTemp += pCurrent;    // copy the rest
  946.         break;                  // exit the loop
  947.       }
  948.     }
  949.   }
  950.  
  951.   // only done if there were replacements, otherwise would have returned above
  952.   *this = strTemp;
  953.  
  954.   return uiCount;
  955. }
  956.  
  957. bool wxString::IsAscii() const
  958. {
  959.   const wxChar *s = (const wxChar*) *this;
  960.   while(*s){
  961.     if(!isascii(*s)) return(FALSE);
  962.     s++;
  963.   }
  964.   return(TRUE);
  965. }
  966.  
  967. bool wxString::IsWord() const
  968. {
  969.   const wxChar *s = (const wxChar*) *this;
  970.   while(*s){
  971.     if(!wxIsalpha(*s)) return(FALSE);
  972.     s++;
  973.   }
  974.   return(TRUE);
  975. }
  976.  
  977. bool wxString::IsNumber() const
  978. {
  979.   const wxChar *s = (const wxChar*) *this;
  980.   if (wxStrlen(s))
  981.      if ((s[0] == '-') || (s[0] == '+')) s++;
  982.   while(*s){
  983.     if(!wxIsdigit(*s)) return(FALSE);
  984.     s++;
  985.   }
  986.   return(TRUE);
  987. }
  988.  
  989. wxString wxString::Strip(stripType w) const
  990. {
  991.     wxString s = *this;
  992.     if ( w & leading ) s.Trim(FALSE);
  993.     if ( w & trailing ) s.Trim(TRUE);
  994.     return s;
  995. }
  996.  
  997. // ---------------------------------------------------------------------------
  998. // case conversion
  999. // ---------------------------------------------------------------------------
  1000.  
  1001. wxString& wxString::MakeUpper()
  1002. {
  1003.   if ( !CopyBeforeWrite() ) {
  1004.     wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
  1005.     return *this;
  1006.   }
  1007.  
  1008.   for ( wxChar *p = m_pchData; *p; p++ )
  1009.     *p = (wxChar)wxToupper(*p);
  1010.  
  1011.   return *this;
  1012. }
  1013.  
  1014. wxString& wxString::MakeLower()
  1015. {
  1016.   if ( !CopyBeforeWrite() ) {
  1017.     wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
  1018.     return *this;
  1019.   }
  1020.  
  1021.   for ( wxChar *p = m_pchData; *p; p++ )
  1022.     *p = (wxChar)wxTolower(*p);
  1023.  
  1024.   return *this;
  1025. }
  1026.  
  1027. // ---------------------------------------------------------------------------
  1028. // trimming and padding
  1029. // ---------------------------------------------------------------------------
  1030.  
  1031. // some compilers (VC++ 6.0 not to name them) return TRUE for a call to
  1032. // isspace('Ω') in the C locale which seems to be broken to me, but we have to
  1033. // live with this by checking that the character is a 7 bit one - even if this
  1034. // may fail to detect some spaces (I don't know if Unicode doesn't have
  1035. // space-like symbols somewhere except in the first 128 chars), it is arguably
  1036. // still better than trimming away accented letters
  1037. inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
  1038.  
  1039. // trims spaces (in the sense of isspace) from left or right side
  1040. wxString& wxString::Trim(bool bFromRight)
  1041. {
  1042.   // first check if we're going to modify the string at all
  1043.   if ( !IsEmpty() &&
  1044.        (
  1045.         (bFromRight && wxSafeIsspace(GetChar(Len() - 1))) ||
  1046.         (!bFromRight && wxSafeIsspace(GetChar(0u)))
  1047.        )
  1048.      )
  1049.   {
  1050.     // ok, there is at least one space to trim
  1051.     if ( !CopyBeforeWrite() ) {
  1052.       wxFAIL_MSG( _T("out of memory in wxString::Trim") );
  1053.       return *this;
  1054.     }
  1055.  
  1056.     if ( bFromRight )
  1057.     {
  1058.       // find last non-space character
  1059.       wxChar *psz = m_pchData + GetStringData()->nDataLength - 1;
  1060.       while ( wxSafeIsspace(*psz) && (psz >= m_pchData) )
  1061.         psz--;
  1062.  
  1063.       // truncate at trailing space start
  1064.       *++psz = wxT('\0');
  1065.       GetStringData()->nDataLength = psz - m_pchData;
  1066.     }
  1067.     else
  1068.     {
  1069.       // find first non-space character
  1070.       const wxChar *psz = m_pchData;
  1071.       while ( wxSafeIsspace(*psz) )
  1072.         psz++;
  1073.  
  1074.       // fix up data and length
  1075.       int nDataLength = GetStringData()->nDataLength - (psz - (const wxChar*) m_pchData);
  1076.       memmove(m_pchData, psz, (nDataLength + 1)*sizeof(wxChar));
  1077.       GetStringData()->nDataLength = nDataLength;
  1078.     }
  1079.   }
  1080.  
  1081.   return *this;
  1082. }
  1083.  
  1084. // adds nCount characters chPad to the string from either side
  1085. wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
  1086. {
  1087.   wxString s(chPad, nCount);
  1088.  
  1089.   if ( bFromRight )
  1090.     *this += s;
  1091.   else
  1092.   {
  1093.     s += *this;
  1094.     *this = s;
  1095.   }
  1096.  
  1097.   return *this;
  1098. }
  1099.  
  1100. // truncate the string
  1101. wxString& wxString::Truncate(size_t uiLen)
  1102. {
  1103.   if ( uiLen < Len() ) {
  1104.     if ( !CopyBeforeWrite() ) {
  1105.       wxFAIL_MSG( _T("out of memory in wxString::Truncate") );
  1106.       return *this;
  1107.     }
  1108.  
  1109.     *(m_pchData + uiLen) = wxT('\0');
  1110.     GetStringData()->nDataLength = uiLen;
  1111.   }
  1112.   //else: nothing to do, string is already short enough
  1113.  
  1114.   return *this;
  1115. }
  1116.  
  1117. // ---------------------------------------------------------------------------
  1118. // finding (return wxNOT_FOUND if not found and index otherwise)
  1119. // ---------------------------------------------------------------------------
  1120.  
  1121. // find a character
  1122. int wxString::Find(wxChar ch, bool bFromEnd) const
  1123. {
  1124.   const wxChar *psz = bFromEnd ? wxStrrchr(m_pchData, ch) : wxStrchr(m_pchData, ch);
  1125.  
  1126.   return (psz == NULL) ? wxNOT_FOUND : psz - (const wxChar*) m_pchData;
  1127. }
  1128.  
  1129. // find a sub-string (like strstr)
  1130. int wxString::Find(const wxChar *pszSub) const
  1131. {
  1132.   const wxChar *psz = wxStrstr(m_pchData, pszSub);
  1133.  
  1134.   return (psz == NULL) ? wxNOT_FOUND : psz - (const wxChar*) m_pchData;
  1135. }
  1136.  
  1137. // ----------------------------------------------------------------------------
  1138. // conversion to numbers
  1139. // ----------------------------------------------------------------------------
  1140.  
  1141. bool wxString::ToLong(long *val, int base) const
  1142. {
  1143.     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
  1144.     wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
  1145.  
  1146.     const wxChar *start = c_str();
  1147.     wxChar *end;
  1148.     *val = wxStrtol(start, &end, base);
  1149.  
  1150.     // return TRUE only if scan was stopped by the terminating NUL and if the
  1151.     // string was not empty to start with
  1152.     return !*end && (end != start);
  1153. }
  1154.  
  1155. bool wxString::ToULong(unsigned long *val, int base) const
  1156. {
  1157.     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
  1158.     wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
  1159.  
  1160.     const wxChar *start = c_str();
  1161.     wxChar *end;
  1162.     *val = wxStrtoul(start, &end, base);
  1163.  
  1164.     // return TRUE only if scan was stopped by the terminating NUL and if the
  1165.     // string was not empty to start with
  1166.     return !*end && (end != start);
  1167. }
  1168.  
  1169. bool wxString::ToDouble(double *val) const
  1170. {
  1171.     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToDouble") );
  1172.  
  1173.     const wxChar *start = c_str();
  1174.     wxChar *end;
  1175.     *val = wxStrtod(start, &end);
  1176.  
  1177.     // return TRUE only if scan was stopped by the terminating NUL and if the
  1178.     // string was not empty to start with
  1179.     return !*end && (end != start);
  1180. }
  1181.  
  1182. // ---------------------------------------------------------------------------
  1183. // formatted output
  1184. // ---------------------------------------------------------------------------
  1185.  
  1186. /* static */
  1187. wxString wxString::Format(const wxChar *pszFormat, ...)
  1188. {
  1189.     va_list argptr;
  1190.     va_start(argptr, pszFormat);
  1191.  
  1192.     wxString s;
  1193.     s.PrintfV(pszFormat, argptr);
  1194.  
  1195.     va_end(argptr);
  1196.  
  1197.     return s;
  1198. }
  1199.  
  1200. /* static */
  1201. wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
  1202. {
  1203.     wxString s;
  1204.     s.PrintfV(pszFormat, argptr);
  1205.     return s;
  1206. }
  1207.  
  1208. int wxString::Printf(const wxChar *pszFormat, ...)
  1209. {
  1210.   va_list argptr;
  1211.   va_start(argptr, pszFormat);
  1212.  
  1213.   int iLen = PrintfV(pszFormat, argptr);
  1214.  
  1215.   va_end(argptr);
  1216.  
  1217.   return iLen;
  1218. }
  1219.  
  1220. int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
  1221. {
  1222.     int size = 1024;
  1223.     for ( ;; )
  1224.     {
  1225.         wxChar *buf = GetWriteBuf(size + 1);
  1226.         if ( !buf )
  1227.         {
  1228.             // out of memory
  1229.             return -1;
  1230.         }
  1231.  
  1232.         int len = wxVsnprintf(buf, size, pszFormat, argptr);
  1233.  
  1234.         // some implementations of vsnprintf() don't NUL terminate the string
  1235.         // if there is not enough space for it so always do it manually
  1236.         buf[size] = _T('\0');
  1237.  
  1238.         UngetWriteBuf();
  1239.  
  1240.         if ( len >= 0 )
  1241.         {
  1242.             // ok, there was enough space
  1243.             break;
  1244.         }
  1245.  
  1246.         // still not enough, double it again
  1247.         size *= 2;
  1248.     }
  1249.  
  1250.     // we could have overshot
  1251.     Shrink();
  1252.  
  1253.     return Len();
  1254. }
  1255.  
  1256. // ----------------------------------------------------------------------------
  1257. // misc other operations
  1258. // ----------------------------------------------------------------------------
  1259.  
  1260. // returns TRUE if the string matches the pattern which may contain '*' and
  1261. // '?' metacharacters (as usual, '?' matches any character and '*' any number
  1262. // of them)
  1263. bool wxString::Matches(const wxChar *pszMask) const
  1264. {
  1265.     // I disable this code as it doesn't seem to be faster (in fact, it seems
  1266.     // to be much slower) than the old, hand-written code below and using it
  1267.     // here requires always linking with libregex even if the user code doesn't
  1268.     // use it
  1269. #if 0 // wxUSE_REGEX
  1270.     // first translate the shell-like mask into a regex
  1271.     wxString pattern;
  1272.     pattern.reserve(wxStrlen(pszMask));
  1273.  
  1274.     pattern += _T('^');
  1275.     while ( *pszMask )
  1276.     {
  1277.         switch ( *pszMask )
  1278.         {
  1279.             case _T('?'):
  1280.                 pattern += _T('.');
  1281.                 break;
  1282.  
  1283.             case _T('*'):
  1284.                 pattern += _T(".*");
  1285.                 break;
  1286.  
  1287.             case _T('^'):
  1288.             case _T('.'):
  1289.             case _T('$'):
  1290.             case _T('('):
  1291.             case _T(')'):
  1292.             case _T('|'):
  1293.             case _T('+'):
  1294.             case _T('\\'):
  1295.                 // these characters are special in a RE, quote them
  1296.                 // (however note that we don't quote '[' and ']' to allow
  1297.                 // using them for Unix shell like matching)
  1298.                 pattern += _T('\\');
  1299.                 // fall through
  1300.  
  1301.             default:
  1302.                 pattern += *pszMask;
  1303.         }
  1304.  
  1305.         pszMask++;
  1306.     }
  1307.     pattern += _T('$');
  1308.  
  1309.     // and now use it
  1310.     return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str());
  1311. #else // !wxUSE_REGEX
  1312.   // TODO: this is, of course, awfully inefficient...
  1313.  
  1314.   // the char currently being checked
  1315.   const wxChar *pszTxt = c_str();
  1316.  
  1317.   // the last location where '*' matched
  1318.   const wxChar *pszLastStarInText = NULL;
  1319.   const wxChar *pszLastStarInMask = NULL;
  1320.  
  1321. match:
  1322.   for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) {
  1323.     switch ( *pszMask ) {
  1324.       case wxT('?'):
  1325.         if ( *pszTxt == wxT('\0') )
  1326.           return FALSE;
  1327.  
  1328.         // pszTxt and pszMask will be incremented in the loop statement
  1329.  
  1330.         break;
  1331.  
  1332.       case wxT('*'):
  1333.         {
  1334.           // remember where we started to be able to backtrack later
  1335.           pszLastStarInText = pszTxt;
  1336.           pszLastStarInMask = pszMask;
  1337.  
  1338.           // ignore special chars immediately following this one
  1339.           // (should this be an error?)
  1340.           while ( *pszMask == wxT('*') || *pszMask == wxT('?') )
  1341.             pszMask++;
  1342.  
  1343.           // if there is nothing more, match
  1344.           if ( *pszMask == wxT('\0') )
  1345.             return TRUE;
  1346.  
  1347.           // are there any other metacharacters in the mask?
  1348.           size_t uiLenMask;
  1349.           const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?"));
  1350.  
  1351.           if ( pEndMask != NULL ) {
  1352.             // we have to match the string between two metachars
  1353.             uiLenMask = pEndMask - pszMask;
  1354.           }
  1355.           else {
  1356.             // we have to match the remainder of the string
  1357.             uiLenMask = wxStrlen(pszMask);
  1358.           }
  1359.  
  1360.           wxString strToMatch(pszMask, uiLenMask);
  1361.           const wxChar* pMatch = wxStrstr(pszTxt, strToMatch);
  1362.           if ( pMatch == NULL )
  1363.             return FALSE;
  1364.  
  1365.           // -1 to compensate "++" in the loop
  1366.           pszTxt = pMatch + uiLenMask - 1;
  1367.           pszMask += uiLenMask - 1;
  1368.         }
  1369.         break;
  1370.  
  1371.       default:
  1372.         if ( *pszMask != *pszTxt )
  1373.           return FALSE;
  1374.         break;
  1375.     }
  1376.   }
  1377.  
  1378.   // match only if nothing left
  1379.   if ( *pszTxt == wxT('\0') )
  1380.     return TRUE;
  1381.  
  1382.   // if we failed to match, backtrack if we can
  1383.   if ( pszLastStarInText ) {
  1384.     pszTxt = pszLastStarInText + 1;
  1385.     pszMask = pszLastStarInMask;
  1386.  
  1387.     pszLastStarInText = NULL;
  1388.  
  1389.     // don't bother resetting pszLastStarInMask, it's unnecessary
  1390.  
  1391.     goto match;
  1392.   }
  1393.  
  1394.   return FALSE;
  1395. #endif // wxUSE_REGEX/!wxUSE_REGEX
  1396. }
  1397.  
  1398. // Count the number of chars
  1399. int wxString::Freq(wxChar ch) const
  1400. {
  1401.     int count = 0;
  1402.     int len = Len();
  1403.     for (int i = 0; i < len; i++)
  1404.     {
  1405.         if (GetChar(i) == ch)
  1406.             count ++;
  1407.     }
  1408.     return count;
  1409. }
  1410.  
  1411. // convert to upper case, return the copy of the string
  1412. wxString wxString::Upper() const
  1413. { wxString s(*this); return s.MakeUpper(); }
  1414.  
  1415. // convert to lower case, return the copy of the string
  1416. wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
  1417.  
  1418. int wxString::sprintf(const wxChar *pszFormat, ...)
  1419.   {
  1420.     va_list argptr;
  1421.     va_start(argptr, pszFormat);
  1422.     int iLen = PrintfV(pszFormat, argptr);
  1423.     va_end(argptr);
  1424.     return iLen;
  1425.   }
  1426.  
  1427. // ---------------------------------------------------------------------------
  1428. // standard C++ library string functions
  1429. // ---------------------------------------------------------------------------
  1430.  
  1431. #ifdef  wxSTD_STRING_COMPATIBILITY
  1432.  
  1433. void wxString::resize(size_t nSize, wxChar ch)
  1434. {
  1435.     size_t len = length();
  1436.  
  1437.     if ( nSize < len )
  1438.     {
  1439.         Truncate(nSize);
  1440.     }
  1441.     else if ( nSize > len )
  1442.     {
  1443.         *this += wxString(ch, nSize - len);
  1444.     }
  1445.     //else: we have exactly the specified length, nothing to do
  1446. }
  1447.  
  1448. void wxString::swap(wxString& str)
  1449. {
  1450.     // this is slightly less efficient than fiddling with m_pchData directly,
  1451.     // but it is still quite efficient as we don't copy the string here because
  1452.     // ref count always stays positive
  1453.     wxString tmp = str;
  1454.     str = *this;
  1455.     *this = tmp;
  1456. }
  1457.  
  1458. wxString& wxString::insert(size_t nPos, const wxString& str)
  1459. {
  1460.   wxASSERT( str.GetStringData()->IsValid() );
  1461.   wxASSERT( nPos <= Len() );
  1462.  
  1463.   if ( !str.IsEmpty() ) {
  1464.     wxString strTmp;
  1465.     wxChar *pc = strTmp.GetWriteBuf(Len() + str.Len());
  1466.     wxStrncpy(pc, c_str(), nPos);
  1467.     wxStrcpy(pc + nPos, str);
  1468.     wxStrcpy(pc + nPos + str.Len(), c_str() + nPos);
  1469.     strTmp.UngetWriteBuf();
  1470.     *this = strTmp;
  1471.   }
  1472.  
  1473.   return *this;
  1474. }
  1475.  
  1476. size_t wxString::find(const wxString& str, size_t nStart) const
  1477. {
  1478.   wxASSERT( str.GetStringData()->IsValid() );
  1479.   wxASSERT( nStart <= Len() );
  1480.  
  1481.   const wxChar *p = wxStrstr(c_str() + nStart, str);
  1482.  
  1483.   return p == NULL ? npos : p - c_str();
  1484. }
  1485.  
  1486. // VC++ 1.5 can't cope with the default argument in the header.
  1487. #if !defined(__VISUALC__) || defined(__WIN32__)
  1488. size_t wxString::find(const wxChar* sz, size_t nStart, size_t n) const
  1489. {
  1490.   return find(wxString(sz, n), nStart);
  1491. }
  1492. #endif // VC++ 1.5
  1493.  
  1494. // Gives a duplicate symbol (presumably a case-insensitivity problem)
  1495. #if !defined(__BORLANDC__)
  1496. size_t wxString::find(wxChar ch, size_t nStart) const
  1497. {
  1498.   wxASSERT( nStart <= Len() );
  1499.  
  1500.   const wxChar *p = wxStrchr(c_str() + nStart, ch);
  1501.  
  1502.   return p == NULL ? npos : p - c_str();
  1503. }
  1504. #endif
  1505.  
  1506. size_t wxString::rfind(const wxString& str, size_t nStart) const
  1507. {
  1508.   wxASSERT( str.GetStringData()->IsValid() );
  1509.   wxASSERT( nStart == npos || nStart <= Len() );
  1510.  
  1511.   // TODO could be made much quicker than that
  1512.   const wxChar *p = c_str() + (nStart == npos ? Len() : nStart);
  1513.   while ( p >= c_str() + str.Len() ) {
  1514.     if ( wxStrncmp(p - str.Len(), str, str.Len()) == 0 )
  1515.       return p - str.Len() - c_str();
  1516.     p--;
  1517.   }
  1518.  
  1519.   return npos;
  1520. }
  1521.  
  1522. // VC++ 1.5 can't cope with the default argument in the header.
  1523. #if !defined(__VISUALC__) || defined(__WIN32__)
  1524. size_t wxString::rfind(const wxChar* sz, size_t nStart, size_t n) const
  1525. {
  1526.     return rfind(wxString(sz, n == npos ? wxSTRING_MAXLEN : n), nStart);
  1527. }
  1528.  
  1529. size_t wxString::rfind(wxChar ch, size_t nStart) const
  1530. {
  1531.     if ( nStart == npos )
  1532.     {
  1533.         nStart = Len();
  1534.     }
  1535.     else
  1536.     {
  1537.         wxASSERT( nStart <= Len() );
  1538.     }
  1539.  
  1540.     const wxChar *p = wxStrrchr(c_str(), ch);
  1541.  
  1542.     if ( p == NULL )
  1543.         return npos;
  1544.  
  1545.     size_t result = p - c_str();
  1546.     return ( result > nStart ) ? npos : result;
  1547. }
  1548. #endif // VC++ 1.5
  1549.  
  1550. size_t wxString::find_first_of(const wxChar* sz, size_t nStart) const
  1551. {
  1552.     const wxChar *start = c_str() + nStart;
  1553.     const wxChar *firstOf = wxStrpbrk(start, sz);
  1554.     if ( firstOf )
  1555.         return firstOf - c_str();
  1556.     else
  1557.         return npos;
  1558. }
  1559.  
  1560. size_t wxString::find_last_of(const wxChar* sz, size_t nStart) const
  1561. {
  1562.     if ( nStart == npos )
  1563.     {
  1564.         nStart = Len();
  1565.     }
  1566.     else
  1567.     {
  1568.         wxASSERT( nStart <= Len() );
  1569.     }
  1570.  
  1571.     for ( const wxChar *p = c_str() + length() - 1; p >= c_str(); p-- )
  1572.     {
  1573.         if ( wxStrchr(sz, *p) )
  1574.             return p - c_str();
  1575.     }
  1576.  
  1577.     return npos;
  1578. }
  1579.  
  1580. size_t wxString::find_first_not_of(const wxChar* sz, size_t nStart) const
  1581. {
  1582.     if ( nStart == npos )
  1583.     {
  1584.         nStart = Len();
  1585.     }
  1586.     else
  1587.     {
  1588.         wxASSERT( nStart <= Len() );
  1589.     }
  1590.  
  1591.     size_t nAccept = wxStrspn(c_str() + nStart, sz);
  1592.     if ( nAccept >= length() - nStart )
  1593.         return npos;
  1594.     else
  1595.         return nAccept;
  1596. }
  1597.  
  1598. size_t wxString::find_first_not_of(wxChar ch, size_t nStart) const
  1599. {
  1600.     wxASSERT( nStart <= Len() );
  1601.  
  1602.     for ( const wxChar *p = c_str() + nStart; *p; p++ )
  1603.     {
  1604.         if ( *p != ch )
  1605.             return p - c_str();
  1606.     }
  1607.  
  1608.     return npos;
  1609. }
  1610.  
  1611. size_t wxString::find_last_not_of(const wxChar* sz, size_t nStart) const
  1612. {
  1613.     if ( nStart == npos )
  1614.     {
  1615.         nStart = Len();
  1616.     }
  1617.     else
  1618.     {
  1619.         wxASSERT( nStart <= Len() );
  1620.     }
  1621.  
  1622.     for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
  1623.     {
  1624.         if ( !wxStrchr(sz, *p) )
  1625.             return p - c_str();
  1626.     }
  1627.  
  1628.     return npos;
  1629. }
  1630.  
  1631. size_t wxString::find_last_not_of(wxChar ch, size_t nStart) const
  1632. {
  1633.     if ( nStart == npos )
  1634.     {
  1635.         nStart = Len();
  1636.     }
  1637.     else
  1638.     {
  1639.         wxASSERT( nStart <= Len() );
  1640.     }
  1641.  
  1642.     for ( const wxChar *p = c_str() + nStart - 1; p >= c_str(); p-- )
  1643.     {
  1644.         if ( *p != ch )
  1645.             return p - c_str();
  1646.     }
  1647.  
  1648.     return npos;
  1649. }
  1650.  
  1651. wxString& wxString::erase(size_t nStart, size_t nLen)
  1652. {
  1653.   wxString strTmp(c_str(), nStart);
  1654.   if ( nLen != npos ) {
  1655.     wxASSERT( nStart + nLen <= Len() );
  1656.  
  1657.     strTmp.append(c_str() + nStart + nLen);
  1658.   }
  1659.  
  1660.   *this = strTmp;
  1661.   return *this;
  1662. }
  1663.  
  1664. wxString& wxString::replace(size_t nStart, size_t nLen, const wxChar *sz)
  1665. {
  1666.   wxASSERT_MSG( nStart + nLen <= Len(),
  1667.                 _T("index out of bounds in wxString::replace") );
  1668.  
  1669.   wxString strTmp;
  1670.   strTmp.Alloc(Len());      // micro optimisation to avoid multiple mem allocs
  1671.  
  1672.   if ( nStart != 0 )
  1673.     strTmp.append(c_str(), nStart);
  1674.   strTmp << sz << c_str() + nStart + nLen;
  1675.  
  1676.   *this = strTmp;
  1677.   return *this;
  1678. }
  1679.  
  1680. wxString& wxString::replace(size_t nStart, size_t nLen, size_t nCount, wxChar ch)
  1681. {
  1682.   return replace(nStart, nLen, wxString(ch, nCount));
  1683. }
  1684.  
  1685. wxString& wxString::replace(size_t nStart, size_t nLen,
  1686.                             const wxString& str, size_t nStart2, size_t nLen2)
  1687. {
  1688.   return replace(nStart, nLen, str.substr(nStart2, nLen2));
  1689. }
  1690.  
  1691. wxString& wxString::replace(size_t nStart, size_t nLen,
  1692.                         const wxChar* sz, size_t nCount)
  1693. {
  1694.   return replace(nStart, nLen, wxString(sz, nCount));
  1695. }
  1696.  
  1697. #endif  //std::string compatibility
  1698.  
  1699. // ============================================================================
  1700. // ArrayString
  1701. // ============================================================================
  1702.  
  1703. // size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
  1704. #define   ARRAY_MAXSIZE_INCREMENT       4096
  1705.  
  1706. #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h
  1707. #define   ARRAY_DEFAULT_INITIAL_SIZE    (16)
  1708. #endif
  1709.  
  1710. #define   STRING(p)   ((wxString *)(&(p)))
  1711.  
  1712. // ctor
  1713. void wxArrayString::Init(bool autoSort)
  1714. {
  1715.   m_nSize  =
  1716.   m_nCount = 0;
  1717.   m_pItems = (wxChar **) NULL;
  1718.   m_autoSort = autoSort;
  1719. }
  1720.  
  1721. // copy ctor
  1722. wxArrayString::wxArrayString(const wxArrayString& src)
  1723. {
  1724.   Init(src.m_autoSort);
  1725.  
  1726.   *this = src;
  1727. }
  1728.  
  1729. // assignment operator
  1730. wxArrayString& wxArrayString::operator=(const wxArrayString& src)
  1731. {
  1732.   if ( m_nSize > 0 )
  1733.     Clear();
  1734.  
  1735.   Copy(src);
  1736.  
  1737.   m_autoSort = src.m_autoSort;
  1738.  
  1739.   return *this;
  1740. }
  1741.  
  1742. void wxArrayString::Copy(const wxArrayString& src)
  1743. {
  1744.   if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE )
  1745.     Alloc(src.m_nCount);
  1746.  
  1747.   for ( size_t n = 0; n < src.m_nCount; n++ )
  1748.     Add(src[n]);
  1749. }
  1750.  
  1751. // grow the array
  1752. void wxArrayString::Grow(size_t nIncrement)
  1753. {
  1754.   // only do it if no more place
  1755.   if ( m_nCount == m_nSize ) {
  1756.     // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would
  1757.     // be never resized!
  1758.     #if ARRAY_DEFAULT_INITIAL_SIZE == 0
  1759.       #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!"
  1760.     #endif
  1761.  
  1762.     if ( m_nSize == 0 ) {
  1763.       // was empty, alloc some memory
  1764.       m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
  1765.       m_pItems = new wxChar *[m_nSize];
  1766.     }
  1767.     else {
  1768.       // otherwise when it's called for the first time, nIncrement would be 0
  1769.       // and the array would never be expanded
  1770.       // add 50% but not too much
  1771.       size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
  1772.                           ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
  1773.       if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
  1774.         ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
  1775.       if ( nIncrement < ndefIncrement )
  1776.         nIncrement = ndefIncrement;
  1777.       m_nSize += nIncrement;
  1778.       wxChar **pNew = new wxChar *[m_nSize];
  1779.  
  1780.       // copy data to new location
  1781.       memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
  1782.  
  1783.       // delete old memory (but do not release the strings!)
  1784.       wxDELETEA(m_pItems);
  1785.  
  1786.       m_pItems = pNew;
  1787.     }
  1788.   }
  1789. }
  1790.  
  1791. void wxArrayString::Free()
  1792. {
  1793.   for ( size_t n = 0; n < m_nCount; n++ ) {
  1794.     STRING(m_pItems[n])->GetStringData()->Unlock();
  1795.   }
  1796. }
  1797.  
  1798. // deletes all the strings from the list
  1799. void wxArrayString::Empty()
  1800. {
  1801.   Free();
  1802.  
  1803.   m_nCount = 0;
  1804. }
  1805.  
  1806. // as Empty, but also frees memory
  1807. void wxArrayString::Clear()
  1808. {
  1809.   Free();
  1810.  
  1811.   m_nSize  =
  1812.   m_nCount = 0;
  1813.  
  1814.   wxDELETEA(m_pItems);
  1815. }
  1816.  
  1817. // dtor
  1818. wxArrayString::~wxArrayString()
  1819. {
  1820.   Free();
  1821.  
  1822.   wxDELETEA(m_pItems);
  1823. }
  1824.  
  1825. // pre-allocates memory (frees the previous data!)
  1826. void wxArrayString::Alloc(size_t nSize)
  1827. {
  1828.   // only if old buffer was not big enough
  1829.   if ( nSize > m_nSize ) {
  1830.     Free();
  1831.     wxDELETEA(m_pItems);
  1832.     m_pItems = new wxChar *[nSize];
  1833.     m_nSize  = nSize;
  1834.   }
  1835.  
  1836.   m_nCount = 0;
  1837. }
  1838.  
  1839. // minimizes the memory usage by freeing unused memory
  1840. void wxArrayString::Shrink()
  1841. {
  1842.   // only do it if we have some memory to free
  1843.   if( m_nCount < m_nSize ) {
  1844.     // allocates exactly as much memory as we need
  1845.     wxChar **pNew = new wxChar *[m_nCount];
  1846.  
  1847.     // copy data to new location
  1848.     memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
  1849.     delete [] m_pItems;
  1850.     m_pItems = pNew;
  1851.   }
  1852. }
  1853.  
  1854. // return a wxString[] as required for some control ctors.
  1855. wxString* wxArrayString::GetStringArray() const
  1856. {
  1857.     wxString *array = 0;
  1858.  
  1859.     if( m_nCount > 0 )
  1860.     {
  1861.         array = new wxString[m_nCount];
  1862.         for( size_t i = 0; i < m_nCount; i++ )
  1863.             array[i] = m_pItems[i];
  1864.     }
  1865.  
  1866.     return array;
  1867. }
  1868.  
  1869. // searches the array for an item (forward or backwards)
  1870. int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
  1871. {
  1872.   if ( m_autoSort ) {
  1873.     // use binary search in the sorted array
  1874.     wxASSERT_MSG( bCase && !bFromEnd,
  1875.                   wxT("search parameters ignored for auto sorted array") );
  1876.  
  1877.     size_t i,
  1878.            lo = 0,
  1879.            hi = m_nCount;
  1880.     int res;
  1881.     while ( lo < hi ) {
  1882.       i = (lo + hi)/2;
  1883.  
  1884.       res = wxStrcmp(sz, m_pItems[i]);
  1885.       if ( res < 0 )
  1886.         hi = i;
  1887.       else if ( res > 0 )
  1888.         lo = i + 1;
  1889.       else
  1890.         return i;
  1891.     }
  1892.  
  1893.     return wxNOT_FOUND;
  1894.   }
  1895.   else {
  1896.     // use linear search in unsorted array
  1897.     if ( bFromEnd ) {
  1898.       if ( m_nCount > 0 ) {
  1899.         size_t ui = m_nCount;
  1900.         do {
  1901.           if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
  1902.             return ui;
  1903.         }
  1904.         while ( ui != 0 );
  1905.       }
  1906.     }
  1907.     else {
  1908.       for( size_t ui = 0; ui < m_nCount; ui++ ) {
  1909.         if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
  1910.           return ui;
  1911.       }
  1912.     }
  1913.   }
  1914.  
  1915.   return wxNOT_FOUND;
  1916. }
  1917.  
  1918. // add item at the end
  1919. size_t wxArrayString::Add(const wxString& str, size_t nInsert)
  1920. {
  1921.   if ( m_autoSort ) {
  1922.     // insert the string at the correct position to keep the array sorted
  1923.     size_t i,
  1924.            lo = 0,
  1925.            hi = m_nCount;
  1926.     int res;
  1927.     while ( lo < hi ) {
  1928.       i = (lo + hi)/2;
  1929.  
  1930.       res = wxStrcmp(str, m_pItems[i]);
  1931.       if ( res < 0 )
  1932.         hi = i;
  1933.       else if ( res > 0 )
  1934.         lo = i + 1;
  1935.       else {
  1936.         lo = hi = i;
  1937.         break;
  1938.       }
  1939.     }
  1940.  
  1941.     wxASSERT_MSG( lo == hi, wxT("binary search broken") );
  1942.  
  1943.     Insert(str, lo, nInsert);
  1944.  
  1945.     return (size_t)lo;
  1946.   }
  1947.   else {
  1948.     wxASSERT( str.GetStringData()->IsValid() );
  1949.  
  1950.     Grow(nInsert);
  1951.  
  1952.     for (size_t i = 0; i < nInsert; i++)
  1953.     {
  1954.         // the string data must not be deleted!
  1955.         str.GetStringData()->Lock();
  1956.  
  1957.         // just append
  1958.         m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
  1959.     }
  1960.     size_t ret = m_nCount;
  1961.     m_nCount += nInsert;
  1962.     return ret;
  1963.   }
  1964. }
  1965.  
  1966. // add item at the given position
  1967. void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
  1968. {
  1969.   wxASSERT( str.GetStringData()->IsValid() );
  1970.  
  1971.   wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
  1972.   wxCHECK_RET( m_nCount <= m_nCount + nInsert,
  1973.                wxT("array size overflow in wxArrayString::Insert") );
  1974.  
  1975.   Grow(nInsert);
  1976.  
  1977.   memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
  1978.           (m_nCount - nIndex)*sizeof(wxChar *));
  1979.  
  1980.   for (size_t i = 0; i < nInsert; i++)
  1981.   {
  1982.       str.GetStringData()->Lock();
  1983.       m_pItems[nIndex + i] = (wxChar *)str.c_str();
  1984.   }
  1985.   m_nCount += nInsert;
  1986. }
  1987.  
  1988. // expand the array
  1989. void wxArrayString::SetCount(size_t count)
  1990. {
  1991.     Alloc(count);
  1992.  
  1993.     wxString s;
  1994.     while ( m_nCount < count )
  1995.         m_pItems[m_nCount++] = (wxChar *)s.c_str();
  1996. }
  1997.  
  1998. // removes item from array (by index)
  1999. void wxArrayString::Remove(size_t nIndex, size_t nRemove)
  2000. {
  2001.   wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
  2002.   wxCHECK_RET( nIndex + nRemove <= m_nCount,
  2003.                wxT("removing too many elements in wxArrayString::Remove") );
  2004.  
  2005.   // release our lock
  2006.   for (size_t i = 0; i < nRemove; i++)
  2007.       Item(nIndex + i).GetStringData()->Unlock();
  2008.  
  2009.   memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
  2010.           (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
  2011.   m_nCount -= nRemove;
  2012. }
  2013.  
  2014. // removes item from array (by value)
  2015. void wxArrayString::Remove(const wxChar *sz)
  2016. {
  2017.   int iIndex = Index(sz);
  2018.  
  2019.   wxCHECK_RET( iIndex != wxNOT_FOUND,
  2020.                wxT("removing inexistent element in wxArrayString::Remove") );
  2021.  
  2022.   Remove(iIndex);
  2023. }
  2024.  
  2025. // ----------------------------------------------------------------------------
  2026. // sorting
  2027. // ----------------------------------------------------------------------------
  2028.  
  2029. // we can only sort one array at a time with the quick-sort based
  2030. // implementation
  2031. #if wxUSE_THREADS
  2032.   // need a critical section to protect access to gs_compareFunction and
  2033.   // gs_sortAscending variables
  2034.   static wxCriticalSection *gs_critsectStringSort = NULL;
  2035.  
  2036.   // call this before the value of the global sort vars is changed/after
  2037.   // you're finished with them
  2038.   #define START_SORT()     wxASSERT( !gs_critsectStringSort );                \
  2039.                            gs_critsectStringSort = new wxCriticalSection;     \
  2040.                            gs_critsectStringSort->Enter()
  2041.   #define END_SORT()       gs_critsectStringSort->Leave();                    \
  2042.                            delete gs_critsectStringSort;                      \
  2043.                            gs_critsectStringSort = NULL
  2044. #else // !threads
  2045.   #define START_SORT()
  2046.   #define END_SORT()
  2047. #endif // wxUSE_THREADS
  2048.  
  2049. // function to use for string comparaison
  2050. static wxArrayString::CompareFunction gs_compareFunction = NULL;
  2051.  
  2052. // if we don't use the compare function, this flag tells us if we sort the
  2053. // array in ascending or descending order
  2054. static bool gs_sortAscending = TRUE;
  2055.  
  2056. // function which is called by quick sort
  2057. extern "C" int LINKAGEMODE
  2058. wxStringCompareFunction(const void *first, const void *second)
  2059. {
  2060.   wxString *strFirst = (wxString *)first;
  2061.   wxString *strSecond = (wxString *)second;
  2062.  
  2063.   if ( gs_compareFunction ) {
  2064.     return gs_compareFunction(*strFirst, *strSecond);
  2065.   }
  2066.   else {
  2067.     // maybe we should use wxStrcoll
  2068.     int result = wxStrcmp(strFirst->c_str(), strSecond->c_str());
  2069.  
  2070.     return gs_sortAscending ? result : -result;
  2071.   }
  2072. }
  2073.  
  2074. // sort array elements using passed comparaison function
  2075. void wxArrayString::Sort(CompareFunction compareFunction)
  2076. {
  2077.   START_SORT();
  2078.  
  2079.   wxASSERT( !gs_compareFunction );  // must have been reset to NULL
  2080.   gs_compareFunction = compareFunction;
  2081.  
  2082.   DoSort();
  2083.  
  2084.   // reset it to NULL so that Sort(bool) will work the next time
  2085.   gs_compareFunction = NULL;
  2086.  
  2087.   END_SORT();
  2088. }
  2089.  
  2090. void wxArrayString::Sort(bool reverseOrder)
  2091. {
  2092.   START_SORT();
  2093.  
  2094.   wxASSERT( !gs_compareFunction );  // must have been reset to NULL
  2095.   gs_sortAscending = !reverseOrder;
  2096.  
  2097.   DoSort();
  2098.  
  2099.   END_SORT();
  2100. }
  2101.  
  2102. void wxArrayString::DoSort()
  2103. {
  2104.   wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
  2105.  
  2106.   // just sort the pointers using qsort() - of course it only works because
  2107.   // wxString() *is* a pointer to its data
  2108.   qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
  2109. }
  2110.  
  2111. bool wxArrayString::operator==(const wxArrayString& a) const
  2112. {
  2113.     if ( m_nCount != a.m_nCount )
  2114.         return FALSE;
  2115.  
  2116.     for ( size_t n = 0; n < m_nCount; n++ )
  2117.     {
  2118.         if ( Item(n) != a[n] )
  2119.             return FALSE;
  2120.     }
  2121.  
  2122.     return TRUE;
  2123. }
  2124.  
  2125.