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