]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
Font updates
[wxWidgets.git] / src / common / string.cpp
index 9c015019948c344720dbb05cedb433196dede951..77af363cb5f986680d60b0397c4cbf821e48c50c 100644 (file)
@@ -38,8 +38,6 @@
   #include "wx/thread.h"
 #endif
 
-#include "wx/regex.h"   // for wxString::Matches()
-
 #include <ctype.h>
 #include <string.h>
 #include <stdlib.h>
   #include <clib.h>
 #endif
 
-#if wxUSE_WCSRTOMBS
-  #include <wchar.h>    // for wcsrtombs(), see comments where it's used
-#endif // GNU
-
-#ifdef  WXSTRING_IS_WXOBJECT
-  IMPLEMENT_DYNAMIC_CLASS(wxString, wxObject)
-#endif  //WXSTRING_IS_WXOBJECT
-
 #if wxUSE_UNICODE
-#undef wxUSE_EXPERIMENTAL_PRINTF
-#define wxUSE_EXPERIMENTAL_PRINTF 1
+    #undef wxUSE_EXPERIMENTAL_PRINTF
+    #ifndef wvsnprintf
+        #define wxUSE_EXPERIMENTAL_PRINTF 1
+    #endif
 #endif
 
 // allocating extra space for each string consumes more memory but speeds up
 // static class variables definition
 // ---------------------------------------------------------------------------
 
+#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
+// must define this static for VA or else you get multiply defined symbols
+// everywhere
+const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
+#endif // Visual Age
+
 #ifdef  wxSTD_STRING_COMPATIBILITY
   const size_t wxString::npos = wxSTRING_MAXLEN;
 #endif // wxSTD_STRING_COMPATIBILITY
@@ -87,12 +85,6 @@ static const struct
   wxChar dummy;
 } g_strEmpty = { {-1, 0, 0}, wxT('\0') };
 
-#if defined(__VISAGECPP__) && __IBMCPP__ >= 400
-// must define this static for VA or else you get multiply defined symbols
-// everywhere
-const unsigned int wxSTRING_MAXLEN = UINT_MAX - 100;
-#endif // Visual Age
-
 // empty C style string: points to 'string data' byte of g_strEmpty
 extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy;
 
@@ -139,7 +131,7 @@ extern const wxChar WXDLLEXPORT *wxEmptyString = &g_strEmpty.dummy;
     #endif //compiler
 #endif // no vsnprintf
 
-#ifdef _AIX
+#if defined(_AIX)
   // AIX has vsnprintf, but there's no prototype in the system headers.
   extern "C" int vsnprintf(char* str, size_t n, const char* format, va_list ap);
 #endif
@@ -194,46 +186,6 @@ wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
 
 #endif  //std::string compatibility
 
-extern int WXDLLEXPORT wxVsnprintf(wxChar *buf, size_t len,
-                                   const wxChar *format, va_list argptr)
-{
-#if wxUSE_UNICODE
-    // FIXME should use wvsnprintf() or whatever if it's available
-    wxString s;
-    int iLen = s.PrintfV(format, argptr);
-    if ( iLen != -1 )
-    {
-        wxStrncpy(buf, s.c_str(), len);
-        buf[len-1] = wxT('\0');
-    }
-
-    return iLen;
-#else // ANSI
-    // vsnprintf() will not terminate the string with '\0' if there is not
-    // enough place, but we want the string to always be NUL terminated
-    int rc = wxVsnprintfA(buf, len - 1, format, argptr);
-    if ( rc == -1 )
-    {
-        buf[len] = 0;
-    }
-
-    return rc;
-#endif // Unicode/ANSI
-}
-
-extern int WXDLLEXPORT wxSnprintf(wxChar *buf, size_t len,
-                                  const wxChar *format, ...)
-{
-    va_list argptr;
-    va_start(argptr, format);
-
-    int iLen = wxVsnprintf(buf, len, format, argptr);
-
-    va_end(argptr);
-
-    return iLen;
-}
-
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -277,7 +229,10 @@ wxString::wxString(wxChar ch, size_t nLength)
   Init();
 
   if ( nLength > 0 ) {
-    AllocBuffer(nLength);
+    if ( !AllocBuffer(nLength) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+      return;
+    }
 
 #if wxUSE_UNICODE
     // memset only works on char
@@ -304,7 +259,10 @@ void wxString::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
 
   if ( nLength > 0 ) {
     // trailing '\0' is written in AllocBuffer()
-    AllocBuffer(nLength);
+    if ( !AllocBuffer(nLength) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::InitWith") );
+      return;
+    }
     memcpy(m_pchData, psz + nPos, nLength*sizeof(wxChar));
   }
 }
@@ -334,7 +292,10 @@ wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
 
   // empty?
   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+      return;
+    }
     conv.MB2WC(m_pchData, psz, nLen);
   }
   else {
@@ -346,14 +307,24 @@ wxString::wxString(const char *psz, wxMBConv& conv, size_t nLength)
 
 #if wxUSE_WCHAR_T
 // from wide string
-wxString::wxString(const wchar_t *pwz, wxMBConv& conv)
+wxString::wxString(const wchar_t *pwz, wxMBConv& conv, size_t nLength)
 {
   // first get necessary size
-  size_t nLen = pwz ? conv.WC2MB((char *) NULL, pwz, 0) : 0;
+  size_t nLen = 0;
+  if (pwz)
+  {
+    if (nLength == wxSTRING_MAXLEN)
+      nLen = conv.WC2MB((char *) NULL, pwz, 0);
+    else
+      nLen = nLength;
+  }
 
   // empty?
   if ( (nLen != 0) && (nLen != (size_t)-1) ) {
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::wxString") );
+      return;
+    }
     conv.WC2MB(m_pchData, pwz, nLen);
   }
   else {
@@ -369,7 +340,7 @@ wxString::wxString(const wchar_t *pwz, wxMBConv& conv)
 // ---------------------------------------------------------------------------
 
 // allocates memory needed to store a C string of length nLen
-void wxString::AllocBuffer(size_t nLen)
+bool wxString::AllocBuffer(size_t nLen)
 {
   // allocating 0 sized buffer doesn't make sense, all empty strings should
   // reuse g_strEmpty
@@ -386,30 +357,42 @@ void wxString::AllocBuffer(size_t nLen)
   // 2) sizeof(wxStringData) for housekeeping info
   wxStringData* pData = (wxStringData*)
     malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar));
+
+  if ( pData == NULL ) {
+    // allocation failures are handled by the caller
+    return FALSE;
+  }
+
   pData->nRefs        = 1;
   pData->nDataLength  = nLen;
   pData->nAllocLength = nLen + EXTRA_ALLOC;
   m_pchData           = pData->data();  // data starts after wxStringData
   m_pchData[nLen]     = wxT('\0');
+  return TRUE;
 }
 
 // must be called before changing this string
-void wxString::CopyBeforeWrite()
+bool wxString::CopyBeforeWrite()
 {
   wxStringData* pData = GetStringData();
 
   if ( pData->IsShared() ) {
     pData->Unlock();                // memory not freed because shared
     size_t nLen = pData->nDataLength;
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      // allocation failures are handled by the caller
+      return FALSE;
+    }
     memcpy(m_pchData, pData->data(), nLen*sizeof(wxChar));
   }
 
   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
+
+  return TRUE;
 }
 
 // must be called before replacing contents of this string
-void wxString::AllocBeforeWrite(size_t nLen)
+bool wxString::AllocBeforeWrite(size_t nLen)
 {
   wxASSERT( nLen != 0 );  // doesn't make any sense
 
@@ -418,7 +401,10 @@ void wxString::AllocBeforeWrite(size_t nLen)
   if ( pData->IsShared() || pData->IsEmpty() ) {
     // can't work with old buffer, get new one
     pData->Unlock();
-    AllocBuffer(nLen);
+    if ( !AllocBuffer(nLen) ) {
+      // allocation failures are handled by the caller
+      return FALSE;
+    }
   }
   else {
     if ( nLen > pData->nAllocLength ) {
@@ -428,15 +414,13 @@ void wxString::AllocBeforeWrite(size_t nLen)
 
       nLen += EXTRA_ALLOC;
 
-      wxStringData *pDataOld = pData;
       pData = (wxStringData*)
           realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
-      if ( !pData ) {
-        // out of memory
-        free(pDataOld);
 
-        // FIXME we're going to crash...
-        return;
+      if ( pData == NULL ) {
+        // allocation failures are handled by the caller
+        // keep previous data since reallocation failed
+        return FALSE;
       }
 
       pData->nAllocLength = nLen;
@@ -448,10 +432,12 @@ void wxString::AllocBeforeWrite(size_t nLen)
   }
 
   wxASSERT( !GetStringData()->IsShared() );  // we must be the only owner
+
+  return TRUE;
 }
 
 // allocate enough memory for nLen characters
-void wxString::Alloc(size_t nLen)
+bool wxString::Alloc(size_t nLen)
 {
   wxStringData *pData = GetStringData();
   if ( pData->nAllocLength <= nLen ) {
@@ -459,7 +445,13 @@ void wxString::Alloc(size_t nLen)
       nLen += EXTRA_ALLOC;
 
       wxStringData* pData = (wxStringData*)
-        malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+          malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+
+      if ( pData == NULL ) {
+        // allocation failure handled by caller
+        return FALSE;
+      }
+
       pData->nRefs = 1;
       pData->nDataLength = 0;
       pData->nAllocLength = nLen;
@@ -469,56 +461,69 @@ void wxString::Alloc(size_t nLen)
     else if ( pData->IsShared() ) {
       pData->Unlock();                // memory not freed because shared
       size_t nOldLen = pData->nDataLength;
-      AllocBuffer(nLen);
+      if ( !AllocBuffer(nLen) ) {
+        // allocation failure handled by caller
+        return FALSE;
+      }
       memcpy(m_pchData, pData->data(), nOldLen*sizeof(wxChar));
     }
     else {
       nLen += EXTRA_ALLOC;
 
-      wxStringData *pDataOld = pData;
-      wxStringData *p = (wxStringData *)
+      pData = (wxStringData *)
         realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
 
-      if ( p == NULL ) {
-        // don't leak memory
-        free(pDataOld);
-
-        // FIXME what to do on memory error?
-        return;
+      if ( pData == NULL ) {
+        // allocation failure handled by caller
+        // keep previous data since reallocation failed
+        return FALSE;
       }
 
       // it's not important if the pointer changed or not (the check for this
       // is not faster than assigning to m_pchData in all cases)
-      p->nAllocLength = nLen;
-      m_pchData = p->data();
+      pData->nAllocLength = nLen;
+      m_pchData = pData->data();
     }
   }
   //else: we've already got enough
+  return TRUE;
 }
 
 // shrink to minimal size (releasing extra memory)
-void wxString::Shrink()
+bool wxString::Shrink()
 {
   wxStringData *pData = GetStringData();
 
-  // this variable is unused in release build, so avoid the compiler warning
-  // by just not declaring it
-#ifdef __WXDEBUG__
-  void *p =
-#endif
-  realloc(pData, sizeof(wxStringData) + (pData->nDataLength + 1)*sizeof(wxChar));
+  size_t nLen = pData->nDataLength;
+  void *p = realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar));
+
+  if ( p == NULL) {
+      wxFAIL_MSG( _T("out of memory reallocating wxString data") );
+      // keep previous data since reallocation failed
+      return FALSE;
+  }
 
-  // we rely on a reasonable realloc() implementation here - so far I haven't
-  // seen any which wouldn't behave like this
+  if ( p != pData )
+  {
+      // contrary to what one might believe, some realloc() implementation do
+      // move the memory block even when its size is reduced
+      pData = (wxStringData *)p;
+
+      m_pchData = pData->data();
+  }
 
-  wxASSERT( p != NULL );  // can't free memory?
-  wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
+  pData->nAllocLength = nLen;
+
+  return TRUE;
 }
 
 // get the pointer to writable buffer of (at least) nLen bytes
 wxChar *wxString::GetWriteBuf(size_t nLen)
 {
-  AllocBeforeWrite(nLen);
+  if ( !AllocBeforeWrite(nLen) ) {
+    // allocation failure handled by caller
+    return NULL;
+  }
 
   wxASSERT( GetStringData()->nRefs == 1 );
   GetStringData()->Validate(FALSE);
@@ -550,17 +555,21 @@ void wxString::UngetWriteBuf(size_t nLen)
 // ---------------------------------------------------------------------------
 
 // helper function: does real copy
-void wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
+bool wxString::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData)
 {
   if ( nSrcLen == 0 ) {
     Reinit();
   }
   else {
-    AllocBeforeWrite(nSrcLen);
+    if ( !AllocBeforeWrite(nSrcLen) ) {
+      // allocation failure handled by caller
+      return FALSE;
+    }
     memcpy(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar));
     GetStringData()->nDataLength = nSrcLen;
     m_pchData[nSrcLen] = wxT('\0');
   }
+  return TRUE;
 }
 
 // assigns one string to another
@@ -587,7 +596,9 @@ wxString& wxString::operator=(const wxString& stringSrc)
 // assigns a single character
 wxString& wxString::operator=(wxChar ch)
 {
-  AssignCopy(1, &ch);
+  if ( !AssignCopy(1, &ch) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator=(wxChar)") );
+  }
   return *this;
 }
 
@@ -595,7 +606,9 @@ wxString& wxString::operator=(wxChar ch)
 // assigns C string
 wxString& wxString::operator=(const wxChar *psz)
 {
-  AssignCopy(wxStrlen(psz), psz);
+  if ( !AssignCopy(wxStrlen(psz), psz) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator=(const wxChar *)") );
+  }
   return *this;
 }
 
@@ -624,7 +637,7 @@ wxString& wxString::operator=(const wchar_t *pwz)
 // ---------------------------------------------------------------------------
 
 // add something to this string
-void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
+bool wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
 {
   STATISTICS_ADD(SummandLength, nSrcLen);
 
@@ -640,7 +653,10 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
 
       // we have to allocate another buffer
       wxStringData* pOldData = GetStringData();
-      AllocBuffer(nNewLen);
+      if ( !AllocBuffer(nNewLen) ) {
+          // allocation failure handled by caller
+          return FALSE;
+      }
       memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar));
       pOldData->Unlock();
     }
@@ -648,7 +664,10 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
       STATISTICS_ADD(ConcatHit, 0);
 
       // we have to grow the buffer
-      Alloc(nNewLen);
+      if ( !Alloc(nNewLen) ) {
+          // allocation failure handled by caller
+          return FALSE;
+      }
     }
     else {
       STATISTICS_ADD(ConcatHit, 1);
@@ -666,6 +685,7 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
     GetStringData()->nDataLength = nNewLen; // and fix the length
   }
   //else: the string to append was empty
+  return TRUE;
 }
 
 /*
@@ -675,57 +695,61 @@ void wxString::ConcatSelf(int nSrcLen, const wxChar *pszSrcData)
  *  C str  + string      and      string + C str
  */
 
-wxString operator+(const wxString& string1, const wxString& string2)
+wxString operator+(const wxString& str1, const wxString& str2)
 {
-  wxASSERT( string1.GetStringData()->IsValid() );
-  wxASSERT( string2.GetStringData()->IsValid() );
+  wxASSERT( str1.GetStringData()->IsValid() );
+  wxASSERT( str2.GetStringData()->IsValid() );
 
-  wxString s = string1;
-  s += string2;
+  wxString s = str1;
+  s += str2;
 
   return s;
 }
 
-wxString operator+(const wxString& string, wxChar ch)
+wxString operator+(const wxString& str, wxChar ch)
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
-  wxString s = string;
+  wxString s = str;
   s += ch;
 
   return s;
 }
 
-wxString operator+(wxChar ch, const wxString& string)
+wxString operator+(wxChar ch, const wxString& str)
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
   wxString s = ch;
-  s += string;
+  s += str;
 
   return s;
 }
 
-wxString operator+(const wxString& string, const wxChar *psz)
+wxString operator+(const wxString& str, const wxChar *psz)
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
   wxString s;
-  s.Alloc(wxStrlen(psz) + string.Len());
-  s = string;
+  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+  }
+  s = str;
   s += psz;
 
   return s;
 }
 
-wxString operator+(const wxChar *psz, const wxString& string)
+wxString operator+(const wxChar *psz, const wxString& str)
 {
-  wxASSERT( string.GetStringData()->IsValid() );
+  wxASSERT( str.GetStringData()->IsValid() );
 
   wxString s;
-  s.Alloc(wxStrlen(psz) + string.Len());
+  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+  }
   s = psz;
-  s += string;
+  s += str;
 
   return s;
 }
@@ -734,20 +758,73 @@ wxString operator+(const wxChar *psz, const wxString& string)
 // other common string functions
 // ===========================================================================
 
+#if wxUSE_UNICODE
+
+wxString wxString::FromAscii(const char *ascii)
+{
+    if (!ascii)
+       return wxEmptyString;
+
+    size_t len = strlen( ascii );
+    wxString res;
+
+    if ( len )
+    {
+        wxStringBuffer buf(res, len);
+
+        wchar_t *dest = buf;
+
+        for ( ;; )
+        {
+           if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' )
+               break;
+        }
+    }
+
+    return res;
+}
+
+const wxCharBuffer wxString::ToAscii() const
+{
+    // this will allocate enough space for the terminating NUL too
+    wxCharBuffer buffer(length());
+
+    signed char *dest = (signed char *)buffer.data();
+
+    const wchar_t *pwc = c_str();
+    for ( ;; )
+    {
+        *dest++ = *pwc > SCHAR_MAX ? '_' : *pwc;
+
+        // the output string can't have embedded NULs anyhow, so we can safely
+        // stop at first of them even if we do have any
+        if ( !*pwc++ )
+            break;
+    }
+
+    return buffer;
+}
+
+#endif // Unicode
+
 // ---------------------------------------------------------------------------
 // simple sub-string extraction
 // ---------------------------------------------------------------------------
 
 // helper function: clone the data attached to this string
-void wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
+bool wxString::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
 {
   if ( nCopyLen == 0 ) {
     dest.Init();
   }
   else {
-    dest.AllocBuffer(nCopyLen);
+    if ( !dest.AllocBuffer(nCopyLen) ) {
+      // allocation failure handled by caller
+      return FALSE;
+    }
     memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar));
   }
+  return TRUE;
 }
 
 // extract string of length nCount starting at nFirst
@@ -775,7 +852,9 @@ wxString wxString::Mid(size_t nFirst, size_t nCount) const
   }
 
   wxString dest;
-  AllocCopy(dest, nCount, nFirst);
+  if ( !AllocCopy(dest, nCount, nFirst) ) {
+      wxFAIL_MSG( _T("out of memory in wxString::Mid") );
+  }
 
   return dest;
 }
@@ -816,7 +895,9 @@ wxString wxString::Right(size_t nCount) const
     nCount = GetStringData()->nDataLength;
 
   wxString dest;
-  AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount);
+  if ( !AllocCopy(dest, nCount, GetStringData()->nDataLength - nCount) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::Right") );
+  }
   return dest;
 }
 
@@ -841,7 +922,9 @@ wxString wxString::Left(size_t nCount) const
     nCount = GetStringData()->nDataLength;
 
   wxString dest;
-  AllocCopy(dest, nCount, 0);
+  if ( !AllocCopy(dest, nCount, 0) ) {
+    wxFAIL_MSG( _T("out of memory in wxString::Left") );
+  }
   return dest;
 }
 
@@ -902,7 +985,10 @@ size_t wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplace
     }
     else {
       // take chars before match
-      strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent);
+      if ( !strTemp.ConcatSelf(pSubstr - pCurrent, pCurrent) ) {
+        wxFAIL_MSG( _T("out of memory in wxString::Replace") );
+        return 0;
+      }
       strTemp += szNew;
       pCurrent = pSubstr + uiOldLen;  // restart after match
 
@@ -968,7 +1054,10 @@ wxString wxString::Strip(stripType w) const
 
 wxString& wxString::MakeUpper()
 {
-  CopyBeforeWrite();
+  if ( !CopyBeforeWrite() ) {
+    wxFAIL_MSG( _T("out of memory in wxString::MakeUpper") );
+    return *this;
+  }
 
   for ( wxChar *p = m_pchData; *p; p++ )
     *p = (wxChar)wxToupper(*p);
@@ -978,7 +1067,10 @@ wxString& wxString::MakeUpper()
 
 wxString& wxString::MakeLower()
 {
-  CopyBeforeWrite();
+  if ( !CopyBeforeWrite() ) {
+    wxFAIL_MSG( _T("out of memory in wxString::MakeLower") );
+    return *this;
+  }
 
   for ( wxChar *p = m_pchData; *p; p++ )
     *p = (wxChar)wxTolower(*p);
@@ -1010,7 +1102,10 @@ wxString& wxString::Trim(bool bFromRight)
      )
   {
     // ok, there is at least one space to trim
-    CopyBeforeWrite();
+    if ( !CopyBeforeWrite() ) {
+      wxFAIL_MSG( _T("out of memory in wxString::Trim") );
+      return *this;
+    }
 
     if ( bFromRight )
     {
@@ -1060,7 +1155,10 @@ wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
 wxString& wxString::Truncate(size_t uiLen)
 {
   if ( uiLen < Len() ) {
-    CopyBeforeWrite();
+    if ( !CopyBeforeWrite() ) {
+      wxFAIL_MSG( _T("out of memory in wxString::Truncate") );
+      return *this;
+    }
 
     *(m_pchData + uiLen) = wxT('\0');
     GetStringData()->nDataLength = uiLen;
@@ -1094,26 +1192,28 @@ int wxString::Find(const wxChar *pszSub) const
 // conversion to numbers
 // ----------------------------------------------------------------------------
 
-bool wxString::ToLong(long *val) const
+bool wxString::ToLong(long *val, int base) const
 {
     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToLong") );
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
     const wxChar *start = c_str();
     wxChar *end;
-    *val = wxStrtol(start, &end, 10);
+    *val = wxStrtol(start, &end, base);
 
     // return TRUE only if scan was stopped by the terminating NUL and if the
     // string was not empty to start with
     return !*end && (end != start);
 }
 
-bool wxString::ToULong(unsigned long *val) const
+bool wxString::ToULong(unsigned long *val, int base) const
 {
     wxCHECK_MSG( val, FALSE, _T("NULL pointer in wxString::ToULong") );
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
     const wxChar *start = c_str();
     wxChar *end;
-    *val = wxStrtoul(start, &end, 10);
+    *val = wxStrtoul(start, &end, base);
 
     // return TRUE only if scan was stopped by the terminating NUL and if the
     // string was not empty to start with
@@ -1459,7 +1559,11 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
 // of them)
 bool wxString::Matches(const wxChar *pszMask) const
 {
-#if wxUSE_REGEX
+    // I disable this code as it doesn't seem to be faster (in fact, it seems
+    // to be much slower) than the old, hand-written code below and using it
+    // here requires always linking with libregex even if the user code doesn't
+    // use it
+#if 0 // wxUSE_REGEX
     // first translate the shell-like mask into a regex
     wxString pattern;
     pattern.reserve(wxStrlen(pszMask));
@@ -1633,7 +1737,7 @@ void wxString::resize(size_t nSize, wxChar ch)
     }
     else if ( nSize > len )
     {
-        *this += wxString(ch, len - nSize);
+        *this += wxString(ch, nSize - len);
     }
     //else: we have exactly the specified length, nothing to do
 }
@@ -1645,7 +1749,7 @@ void wxString::swap(wxString& str)
     // ref count always stays positive
     wxString tmp = str;
     str = *this;
-    *this = str;
+    *this = tmp;
 }
 
 wxString& wxString::insert(size_t nPos, const wxString& str)
@@ -1699,7 +1803,7 @@ size_t wxString::find(wxChar ch, size_t nStart) const
 size_t wxString::rfind(const wxString& str, size_t nStart) const
 {
   wxASSERT( str.GetStringData()->IsValid() );
-  wxASSERT( nStart <= Len() );
+  wxASSERT( nStart == npos || nStart <= Len() );
 
   // TODO could be made much quicker than that
   const wxChar *p = c_str() + (nStart == npos ? Len() : nStart);
@@ -1716,7 +1820,7 @@ size_t wxString::rfind(const wxString& str, size_t nStart) const
 #if !defined(__VISUALC__) || defined(__WIN32__)
 size_t wxString::rfind(const wxChar* sz, size_t nStart, size_t n) const
 {
-    return rfind(wxString(sz, n == npos ? 0 : n), nStart);
+    return rfind(wxString(sz, n == npos ? wxSTRING_MAXLEN : n), nStart);
 }
 
 size_t wxString::rfind(wxChar ch, size_t nStart) const
@@ -1893,16 +1997,17 @@ wxString& wxString::replace(size_t nStart, size_t nLen,
 // ArrayString
 // ============================================================================
 
-// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT)
+// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT)
 #define   ARRAY_MAXSIZE_INCREMENT       4096
+
 #ifndef   ARRAY_DEFAULT_INITIAL_SIZE    // also defined in dynarray.h
-  #define   ARRAY_DEFAULT_INITIAL_SIZE    (16)
+#define   ARRAY_DEFAULT_INITIAL_SIZE    (16)
 #endif
 
 #define   STRING(p)   ((wxString *)(&(p)))
 
 // ctor
-wxArrayString::wxArrayString(bool autoSort)
+void wxArrayString::Init(bool autoSort)
 {
   m_nSize  =
   m_nCount = 0;
@@ -1913,10 +2018,7 @@ wxArrayString::wxArrayString(bool autoSort)
 // copy ctor
 wxArrayString::wxArrayString(const wxArrayString& src)
 {
-  m_nSize  =
-  m_nCount = 0;
-  m_pItems = (wxChar **) NULL;
-  m_autoSort = src.m_autoSort;
+  Init(src.m_autoSort);
 
   *this = src;
 }
@@ -1944,7 +2046,7 @@ void wxArrayString::Copy(const wxArrayString& src)
 }
 
 // grow the array
-void wxArrayString::Grow()
+void wxArrayString::Grow(size_t nIncrement)
 {
   // only do it if no more place
   if ( m_nCount == m_nSize ) {
@@ -1963,10 +2065,12 @@ void wxArrayString::Grow()
       // otherwise when it's called for the first time, nIncrement would be 0
       // and the array would never be expanded
       // add 50% but not too much
-      size_t nIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
+      size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE
                           ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1;
-      if ( nIncrement > ARRAY_MAXSIZE_INCREMENT )
-        nIncrement = ARRAY_MAXSIZE_INCREMENT;
+      if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT )
+        ndefIncrement = ARRAY_MAXSIZE_INCREMENT;
+      if ( nIncrement < ndefIncrement )
+        nIncrement = ndefIncrement;
       m_nSize += nIncrement;
       wxChar **pNew = new wxChar *[m_nSize];
 
@@ -2018,8 +2122,6 @@ wxArrayString::~wxArrayString()
 // pre-allocates memory (frees the previous data!)
 void wxArrayString::Alloc(size_t nSize)
 {
-  wxASSERT( nSize > 0 );
-
   // only if old buffer was not big enough
   if ( nSize > m_nSize ) {
     Free();
@@ -2046,6 +2148,21 @@ void wxArrayString::Shrink()
   }
 }
 
+// return a wxString[] as required for some control ctors.
+wxString* wxArrayString::GetStringArray() const
+{
+    wxString *array = 0;
+
+    if( m_nCount > 0 )
+    {
+        array = new wxString[m_nCount];
+        for( size_t i = 0; i < m_nCount; i++ )
+            array[i] = m_pItems[i];
+    }
+
+    return array;
+}
+
 // searches the array for an item (forward or backwards)
 int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
 {
@@ -2096,7 +2213,7 @@ int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
 }
 
 // add item at the end
-size_t wxArrayString::Add(const wxString& str)
+size_t wxArrayString::Add(const wxString& str, size_t nInsert)
 {
   if ( m_autoSort ) {
     // insert the string at the correct position to keep the array sorted
@@ -2120,54 +2237,75 @@ size_t wxArrayString::Add(const wxString& str)
 
     wxASSERT_MSG( lo == hi, wxT("binary search broken") );
 
-    Insert(str, lo);
+    Insert(str, lo, nInsert);
 
     return (size_t)lo;
   }
   else {
     wxASSERT( str.GetStringData()->IsValid() );
 
-    Grow();
+    Grow(nInsert);
 
-    // the string data must not be deleted!
-    str.GetStringData()->Lock();
-
-    // just append
-    m_pItems[m_nCount] = (wxChar *)str.c_str(); // const_cast
+    for (size_t i = 0; i < nInsert; i++)
+    {
+        // the string data must not be deleted!
+        str.GetStringData()->Lock();
 
-    return m_nCount++;
+        // just append
+        m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
+    }
+    size_t ret = m_nCount;
+    m_nCount += nInsert;
+    return ret;
   }
 }
 
 // add item at the given position
-void wxArrayString::Insert(const wxString& str, size_t nIndex)
+void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert)
 {
   wxASSERT( str.GetStringData()->IsValid() );
 
   wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") );
+  wxCHECK_RET( m_nCount <= m_nCount + nInsert,
+               wxT("array size overflow in wxArrayString::Insert") );
 
-  Grow();
+  Grow(nInsert);
 
-  memmove(&m_pItems[nIndex + 1], &m_pItems[nIndex],
+  memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
           (m_nCount - nIndex)*sizeof(wxChar *));
 
-  str.GetStringData()->Lock();
-  m_pItems[nIndex] = (wxChar *)str.c_str();
+  for (size_t i = 0; i < nInsert; i++)
+  {
+      str.GetStringData()->Lock();
+      m_pItems[nIndex + i] = (wxChar *)str.c_str();
+  }
+  m_nCount += nInsert;
+}
+
+// expand the array
+void wxArrayString::SetCount(size_t count)
+{
+    Alloc(count);
 
-  m_nCount++;
+    wxString s;
+    while ( m_nCount < count )
+        m_pItems[m_nCount++] = (wxChar *)s.c_str();
 }
 
 // removes item from array (by index)
-void wxArrayString::Remove(size_t nIndex)
+void wxArrayString::Remove(size_t nIndex, size_t nRemove)
 {
-  wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Remove") );
+  wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") );
+  wxCHECK_RET( nIndex + nRemove <= m_nCount,
+               wxT("removing too many elements in wxArrayString::Remove") );
 
   // release our lock
-  Item(nIndex).GetStringData()->Unlock();
+  for (size_t i = 0; i < nRemove; i++)
+      Item(nIndex + i).GetStringData()->Unlock();
 
-  memmove(&m_pItems[nIndex], &m_pItems[nIndex + 1],
-          (m_nCount - nIndex - 1)*sizeof(wxChar *));
-  m_nCount--;
+  memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
+          (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
+  m_nCount -= nRemove;
 }
 
 // removes item from array (by value)
@@ -2213,7 +2351,8 @@ static wxArrayString::CompareFunction gs_compareFunction = NULL;
 static bool gs_sortAscending = TRUE;
 
 // function which is called by quick sort
-static int LINKAGEMODE wxStringCompareFunction(const void *first, const void *second)
+extern "C" int LINKAGEMODE
+wxStringCompareFunction(const void *first, const void *second)
 {
   wxString *strFirst = (wxString *)first;
   wxString *strSecond = (wxString *)second;