]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
corrected name of wxWS_EX_PROCESS_UI_UPDATES style (part of patch 1686335)
[wxWidgets.git] / src / common / string.cpp
index 04969d3246ef660245d303f0a5c9b27e91dbc165..f26486112aaee9a34233162cf96f6271a4f60495 100644 (file)
 #endif
 
 #include <ctype.h>
+
+#ifndef __WXWINCE__
+    #include <errno.h>
+#endif
+
 #include <string.h>
 #include <stdlib.h>
 
@@ -51,7 +56,7 @@
 // static class variables definition
 // ---------------------------------------------------------------------------
 
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
   //According to STL _must_ be a -1 size_t
   const size_t wxStringBase::npos = (size_t) -1;
 #endif
@@ -60,7 +65,7 @@
 // static data
 // ----------------------------------------------------------------------------
 
-#if wxUSE_STL
+#if wxUSE_STL_BASED_WXSTRING
 
 extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T("");
 
@@ -86,52 +91,20 @@ extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy;
 
 #if wxUSE_STD_IOSTREAM
 
-// MS Visual C++ version 5.0 provides the new STL headers as well as the old
-// iostream ones.
-//
-// ATTN: you can _not_ use both of these in the same program!
-
 #include <iostream>
 
-wxSTD istream& operator>>(wxSTD istream& is, wxString& WXUNUSED(str))
-{
-#if 0
-  int w = is.width(0);
-  if ( is.ipfx(0) ) {
-    streambuf *sb = is.rdbuf();
-    str.erase();
-    while ( true ) {
-      int ch = sb->sbumpc ();
-      if ( ch == EOF ) {
-        is.setstate(ios::eofbit);
-        break;
-      }
-      else if ( isspace(ch) ) {
-        sb->sungetc();
-        break;
-      }
-
-      str += ch;
-      if ( --w == 1 )
-        break;
-    }
-  }
-
-  is.isfx();
-  if ( str.length() == 0 )
-    is.setstate(ios::failbit);
-#endif
-  return is;
+wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
+{
+    return os << str.c_str();
 }
 
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
+wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
 {
-#ifdef __BORLANDC__
-    os << str.mb_str();
+#if wxUSE_UNICODE && !defined(__BORLANDC__)
+    return os << str.AsWChar();
 #else
-    os << str.c_str();
+    return os << str.AsChar();
 #endif
-    return os;
 }
 
 #endif // wxUSE_STD_IOSTREAM
@@ -165,7 +138,7 @@ wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
   #define STATISTICS_ADD(av, val)
 #endif // WXSTRING_STATISTICS
 
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
 
 // ===========================================================================
 // wxStringData class deallocation
@@ -210,11 +183,19 @@ void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength)
 // poor man's iterators are "void *" pointers
 wxStringBase::wxStringBase(const void *pStart, const void *pEnd)
 {
-  InitWith((const wxChar *)pStart, 0,
-           (const wxChar *)pEnd - (const wxChar *)pStart);
+  if ( pEnd >= pStart )
+  {
+    InitWith((const wxChar *)pStart, 0,
+             (const wxChar *)pEnd - (const wxChar *)pStart);
+  }
+  else
+  {
+    wxFAIL_MSG( _T("pStart is not before pEnd") );
+    Init();
+  }
 }
 
-wxStringBase::wxStringBase(size_type n, wxChar ch)
+wxStringBase::wxStringBase(size_type n, wxUniChar ch)
 {
   Init();
   append(n, ch);
@@ -323,7 +304,7 @@ bool wxStringBase::AllocBeforeWrite(size_t nLen)
   return true;
 }
 
-wxStringBase& wxStringBase::append(size_t n, wxChar ch)
+wxStringBase& wxStringBase::append(size_t n, wxUniChar ch)
 {
     size_type len = length();
 
@@ -337,7 +318,7 @@ wxStringBase& wxStringBase::append(size_t n, wxChar ch)
     return *this;
 }
 
-void wxStringBase::resize(size_t nSize, wxChar ch)
+void wxStringBase::resize(size_t nSize, wxUniChar ch)
 {
     size_t len = length();
 
@@ -470,36 +451,47 @@ void wxStringBase::swap(wxStringBase& str)
 
 size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const
 {
+    // deal with the special case of empty string first
+    const size_t nLen = length();
+    const size_t nLenOther = str.length();
+
+    if ( !nLenOther )
+    {
+        // empty string is a substring of anything
+        return 0;
+    }
+
+    if ( !nLen )
+    {
+        // the other string is non empty so can't be our substring
+        return npos;
+    }
+
     wxASSERT( str.GetStringData()->IsValid() );
-    wxASSERT( nStart <= length() );
+    wxASSERT( nStart <= nLen );
+
+    const wxChar * const other = str.c_str();
 
-    //anchor
+    // anchor
     const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart,
-                                               str.c_str()[0],
-                                               length() - nStart);
+                                               *other,
+                                               nLen - nStart);
 
-    if(!p)
+    if ( !p )
         return npos;
 
-    while(p - c_str() + str.length() <= length() &&
-          wxTmemcmp(p, str.c_str(), str.length()) )
+    while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) )
     {
-        //Previosly passed as the first argument to wxTmemchr,
-        //but C/C++ standard does not specify evaluation order
-        //of arguments to functions -
-        //http://embedded.com/showArticle.jhtml?articleID=9900607
-        ++p;
-
-        //anchor again
-        p = (const wxChar*)wxTmemchr(p,
-                                     str.c_str()[0],
-                                     length() - (p - c_str()));
-
-        if(!p)
+        p++;
+
+        // anchor again
+        p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str()));
+
+        if ( !p )
             return npos;
     }
 
-    return (p - c_str() + str.length() <= length()) ? p - c_str() : npos;
+    return p - c_str() + nLenOther <= nLen ? p - c_str() : npos;
 }
 
 size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
@@ -507,7 +499,7 @@ size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const
     return find(wxStringBase(sz, n), nStart);
 }
 
-size_t wxStringBase::find(wxChar ch, size_t nStart) const
+size_t wxStringBase::find(wxUniChar ch, size_t nStart) const
 {
     wxASSERT( nStart <= length() );
 
@@ -554,7 +546,7 @@ size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const
     return rfind(wxStringBase(sz, n), nStart);
 }
 
-size_t wxStringBase::rfind(wxChar ch, size_t nStart) const
+size_t wxStringBase::rfind(wxUniChar ch, size_t nStart) const
 {
     if ( nStart == npos )
     {
@@ -662,14 +654,14 @@ size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart,
     return find_first_not_of(wxStringBase(sz, n), nStart);
 }
 
-size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const
+size_t wxStringBase::find_first_not_of(wxUniChar ch, size_t nStart) const
 {
     wxASSERT( nStart <= length() );
 
-    for ( const wxChar *p = c_str() + nStart; *p; p++ )
+    for ( const_iterator p = begin() + nStart; (bool)*p; ++p ) // FIXME-DMARS
     {
         if ( *p != ch )
-            return p - c_str();
+            return p - begin();
     }
 
     return npos;
@@ -703,7 +695,7 @@ size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart,
     return find_last_not_of(wxStringBase(sz, n), nStart);
 }
 
-size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
+size_t wxStringBase::find_last_not_of(wxUniChar ch, size_t nStart) const
 {
     if ( nStart == npos )
     {
@@ -714,10 +706,10 @@ size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const
         wxASSERT( nStart <= length() );
     }
 
-    for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p )
+    for ( const_iterator p = begin() + nStart; p != begin(); --p )
     {
         if ( *p != ch )
-            return p - c_str();
+            return p - begin();
     }
 
     return npos;
@@ -756,7 +748,7 @@ wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
 }
 
 wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen,
-                                    size_t nCount, wxChar ch)
+                                    size_t nCount, wxUniChar ch)
 {
   return replace(nStart, nLen, wxStringBase(nCount, ch).c_str());
 }
@@ -803,9 +795,10 @@ wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc)
 }
 
 // assigns a single character
-wxStringBase& wxStringBase::operator=(wxChar ch)
+wxStringBase& wxStringBase::operator=(wxUniChar ch)
 {
-  if ( !AssignCopy(1, &ch) ) {
+  wxChar c(ch);
+  if ( !AssignCopy(1, &c) ) {
     wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") );
   }
   return *this;
@@ -918,11 +911,11 @@ bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const
   return true;
 }
 
-#endif // !wxUSE_STL
+#endif // !wxUSE_STL_BASED_WXSTRING
 
-#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+#if !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE)
 
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
     #define STRINGCLASS wxStringBase
 #else
     #define STRINGCLASS wxString
@@ -992,7 +985,7 @@ int STRINGCLASS::compare(size_t nStart, size_t nLen,
 
 #undef STRINGCLASS
 
-#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE)
+#endif // !wxUSE_STL_BASED_WXSTRING || !defined(HAVE_STD_STRING_COMPARE)
 
 // ===========================================================================
 // wxString class core
@@ -1071,9 +1064,9 @@ bool wxString::Shrink()
   return tmp.length() == length();
 }
 
-#if !wxUSE_STL
+#if !wxUSE_STL_BASED_WXSTRING
 // get the pointer to writable buffer of (at least) nLen bytes
-wxChar *wxString::GetWriteBuf(size_t nLen)
+wxChar *wxString::DoGetWriteBuf(size_t nLen)
 {
   if ( !AllocBeforeWrite(nLen) ) {
     // allocation failure handled by caller
@@ -1087,18 +1080,43 @@ wxChar *wxString::GetWriteBuf(size_t nLen)
 }
 
 // put string back in a reasonable state after GetWriteBuf
+void wxString::DoUngetWriteBuf()
+{
+  DoUngetWriteBuf(wxStrlen(m_pchData));
+}
+
+void wxString::DoUngetWriteBuf(size_t nLen)
+{
+  wxStringData * const pData = GetStringData();
+
+  wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") );
+
+  // the strings we store are always NUL-terminated
+  pData->data()[nLen] = _T('\0');
+  pData->nDataLength = nLen;
+  pData->Validate(true);
+}
+
+// deprecated compatibility code:
+#if WXWIN_COMPATIBILITY_2_8
+wxChar *wxString::GetWriteBuf(size_t nLen)
+{
+    return DoGetWriteBuf(nLen);
+}
+
 void wxString::UngetWriteBuf()
 {
-  GetStringData()->nDataLength = wxStrlen(m_pchData);
-  GetStringData()->Validate(true);
+    DoUngetWriteBuf();
 }
 
 void wxString::UngetWriteBuf(size_t nLen)
 {
-  GetStringData()->nDataLength = nLen;
-  GetStringData()->Validate(true);
+    DoUngetWriteBuf(nLen);
 }
-#endif
+#endif // WXWIN_COMPATIBILITY_2_8
+
+#endif // !wxUSE_STL_BASED_WXSTRING
+
 
 // ---------------------------------------------------------------------------
 // data access
@@ -1139,71 +1157,71 @@ wxString& wxString::operator=(const wchar_t *pwz)
 
 wxString operator+(const wxString& str1, const wxString& str2)
 {
-#if !wxUSE_STL
-  wxASSERT( str1.GetStringData()->IsValid() );
-  wxASSERT( str2.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+    wxASSERT( str1.GetStringData()->IsValid() );
+    wxASSERT( str2.GetStringData()->IsValid() );
 #endif
 
-  wxString s = str1;
-  s += str2;
+    wxString s = str1;
+    s += str2;
 
-  return s;
+    return s;
 }
 
-wxString operator+(const wxString& str, wxChar ch)
+wxString operator+(const wxString& str, wxUniChar ch)
 {
-#if !wxUSE_STL
-  wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+    wxASSERT( str.GetStringData()->IsValid() );
 #endif
 
-  wxString s = str;
-  s += ch;
+    wxString s = str;
+    s += ch;
 
-  return s;
+    return s;
 }
 
-wxString operator+(wxChar ch, const wxString& str)
+wxString operator+(wxUniChar ch, const wxString& str)
 {
-#if !wxUSE_STL
-  wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+    wxASSERT( str.GetStringData()->IsValid() );
 #endif
 
-  wxString s = ch;
-  s += str;
+    wxString s = ch;
+    s += str;
 
-  return s;
+    return s;
 }
 
 wxString operator+(const wxString& str, const wxChar *psz)
 {
-#if !wxUSE_STL
-  wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+    wxASSERT( str.GetStringData()->IsValid() );
 #endif
 
-  wxString s;
-  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
-    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
-  }
-  s += str;
-  s += psz;
+    wxString s;
+    if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
+        wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+    }
+    s += str;
+    s += psz;
 
-  return s;
+    return s;
 }
 
 wxString operator+(const wxChar *psz, const wxString& str)
 {
-#if !wxUSE_STL
-  wxASSERT( str.GetStringData()->IsValid() );
+#if !wxUSE_STL_BASED_WXSTRING
+    wxASSERT( str.GetStringData()->IsValid() );
 #endif
 
-  wxString s;
-  if ( !s.Alloc(wxStrlen(psz) + str.Len()) ) {
-    wxFAIL_MSG( _T("out of memory in wxString::operator+") );
-  }
-  s = psz;
-  s += str;
+    wxString s;
+    if ( !s.Alloc(wxStrlen(psz) + str.length()) ) {
+        wxFAIL_MSG( _T("out of memory in wxString::operator+") );
+    }
+    s = psz;
+    s += str;
 
-  return s;
+    return s;
 }
 
 // ===========================================================================
@@ -1402,7 +1420,7 @@ bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const
     wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") );
 
     int start = length() - wxStrlen(suffix);
-    if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 )
+    if ( start < 0 || wxStrcmp(wx_str() + start, suffix) != 0 )
         return false;
 
     if ( rest )
@@ -1430,14 +1448,14 @@ wxString wxString::Right(size_t nCount) const
 
 // get all characters after the last occurence of ch
 // (returns the whole string if ch not found)
-wxString wxString::AfterLast(wxChar ch) const
+wxString wxString::AfterLast(wxUniChar ch) const
 {
   wxString str;
   int iPos = Find(ch, true);
   if ( iPos == wxNOT_FOUND )
     str = *this;
   else
-    str = c_str() + iPos + 1;
+    str = wx_str() + iPos + 1;
 
   return str;
 }
@@ -1457,7 +1475,7 @@ wxString wxString::Left(size_t nCount) const
 
 // get all characters before the first occurence of ch
 // (returns the whole string if ch not found)
-wxString wxString::BeforeFirst(wxChar ch) const
+wxString wxString::BeforeFirst(wxUniChar ch) const
 {
   int iPos = Find(ch);
   if ( iPos == wxNOT_FOUND ) iPos = length();
@@ -1466,7 +1484,7 @@ wxString wxString::BeforeFirst(wxChar ch) const
 
 /// get all characters before the last occurence of ch
 /// (returns empty string if ch not found)
-wxString wxString::BeforeLast(wxChar ch) const
+wxString wxString::BeforeLast(wxUniChar ch) const
 {
   wxString str;
   int iPos = Find(ch, true);
@@ -1478,12 +1496,12 @@ wxString wxString::BeforeLast(wxChar ch) const
 
 /// get all characters after the first occurence of ch
 /// (returns empty string if ch not found)
-wxString wxString::AfterFirst(wxChar ch) const
+wxString wxString::AfterFirst(wxUniChar ch) const
 {
   wxString str;
   int iPos = Find(ch);
   if ( iPos != wxNOT_FOUND )
-    str = c_str() + iPos + 1;
+    str = wx_str() + iPos + 1;
 
   return str;
 }
@@ -1606,65 +1624,65 @@ inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
 // trims spaces (in the sense of isspace) from left or right side
 wxString& wxString::Trim(bool bFromRight)
 {
-  // first check if we're going to modify the string at all
-  if ( !empty() &&
-       (
-        (bFromRight && wxSafeIsspace(GetChar(Len() - 1))) ||
-        (!bFromRight && wxSafeIsspace(GetChar(0u)))
+    // first check if we're going to modify the string at all
+    if ( !empty() &&
+         (
+          (bFromRight && wxSafeIsspace(GetChar(length() - 1))) ||
+          (!bFromRight && wxSafeIsspace(GetChar(0u)))
+         )
        )
-     )
-  {
-    if ( bFromRight )
     {
-      // find last non-space character
-      iterator psz = begin() + length() - 1;
-      while ( wxSafeIsspace(*psz) && (psz >= begin()) )
-        psz--;
+        if ( bFromRight )
+        {
+            // find last non-space character
+            reverse_iterator psz = rbegin();
+            while ( (psz != rend()) && wxSafeIsspace(*psz) )
+                psz++;
 
-      // truncate at trailing space start
-      *++psz = wxT('\0');
-      erase(psz, end());
-    }
-    else
-    {
-      // find first non-space character
-      iterator psz = begin();
-      while ( wxSafeIsspace(*psz) )
-        psz++;
+            // truncate at trailing space start
+            erase(psz.base(), end());
+        }
+        else
+        {
+            // find first non-space character
+            iterator psz = begin();
+            while ( (psz != end()) && wxSafeIsspace(*psz) )
+                psz++;
 
-      // fix up data and length
-      erase(begin(), psz);
+            // fix up data and length
+            erase(begin(), psz);
+        }
     }
-  }
 
-  return *this;
+    return *this;
 }
 
 // adds nCount characters chPad to the string from either side
-wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight)
+wxString& wxString::Pad(size_t nCount, wxUniChar chPad, bool bFromRight)
 {
-  wxString s(chPad, nCount);
+    wxString s(chPad, nCount);
 
-  if ( bFromRight )
-    *this += s;
-  else
-  {
-    s += *this;
-    swap(s);
-  }
+    if ( bFromRight )
+        *this += s;
+    else
+    {
+        s += *this;
+        swap(s);
+    }
 
-  return *this;
+    return *this;
 }
 
 // truncate the string
 wxString& wxString::Truncate(size_t uiLen)
 {
-  if ( uiLen < Len() ) {
-    erase(begin() + uiLen, end());
-  }
-  //else: nothing to do, string is already short enough
+    if ( uiLen < length() )
+    {
+        erase(begin() + uiLen, end());
+    }
+    //else: nothing to do, string is already short enough
 
-  return *this;
+    return *this;
 }
 
 // ---------------------------------------------------------------------------
@@ -1672,64 +1690,106 @@ wxString& wxString::Truncate(size_t uiLen)
 // ---------------------------------------------------------------------------
 
 // find a character
-int wxString::Find(wxChar ch, bool bFromEnd) const
+int wxString::Find(wxUniChar ch, bool bFromEnd) const
 {
-  size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
+    size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch);
 
-  return (idx == npos) ? wxNOT_FOUND : (int)idx;
+    return (idx == npos) ? wxNOT_FOUND : (int)idx;
 }
 
 // find a sub-string (like strstr)
 int wxString::Find(const wxChar *pszSub) const
 {
-  size_type idx = find(pszSub);
+    size_type idx = find(pszSub);
 
-  return (idx == npos) ? wxNOT_FOUND : (int)idx;
+    return (idx == npos) ? wxNOT_FOUND : (int)idx;
 }
 
 // ----------------------------------------------------------------------------
 // conversion to numbers
 // ----------------------------------------------------------------------------
 
-bool wxString::ToLong(long *val, int base) const
+// the implementation of all the functions below is exactly the same so factor
+// it out
+
+template <typename T, typename F>
+bool wxStringToIntType(const wxChar *start,
+                       T *val,
+                       int base,
+                       F func)
 {
-    wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToLong") );
+    wxCHECK_MSG( val, false, _T("NULL output pointer") );
     wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
-    const wxChar *start = c_str();
+#ifndef __WXWINCE__
+    errno = 0;
+#endif
+
     wxChar *end;
-    *val = wxStrtol(start, &end, base);
+    *val = (*func)(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);
+    // string was not empty to start with and no under/overflow occurred
+    return !*end && (end != start)
+#ifndef __WXWINCE__
+        && (errno != ERANGE)
+#endif
+    ;
+}
+
+bool wxString::ToLong(long *val, int base) const
+{
+    return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtol);
 }
 
 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") );
+    return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoul);
+}
 
-    const wxChar *start = c_str();
-    wxChar *end;
-    *val = wxStrtoul(start, &end, base);
+bool wxString::ToLongLong(wxLongLong_t *val, int base) const
+{
+#ifdef wxHAS_STRTOLL
+    return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoll);
+#else
+    // TODO: implement this ourselves
+    wxUnusedVar(val);
+    wxUnusedVar(base);
+    return false;
+#endif // wxHAS_STRTOLL
+}
 
-    // 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::ToULongLong(wxULongLong_t *val, int base) const
+{
+#ifdef wxHAS_STRTOLL
+    return wxStringToIntType((const wxChar*)c_str(), val, base, wxStrtoull);
+#else
+    // TODO: implement this ourselves
+    wxUnusedVar(val);
+    wxUnusedVar(base);
+    return false;
+#endif
 }
 
 bool wxString::ToDouble(double *val) const
 {
     wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
 
+#ifndef __WXWINCE__
+    errno = 0;
+#endif
+
     const wxChar *start = c_str();
     wxChar *end;
     *val = wxStrtod(start, &end);
 
     // 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);
+    // string was not empty to start with and no under/overflow occurred
+    return !*end && (end != start)
+#ifndef __WXWINCE__
+        && (errno != ERANGE)
+#endif
+    ;
 }
 
 // ---------------------------------------------------------------------------
@@ -1737,13 +1797,17 @@ bool wxString::ToDouble(double *val) const
 // ---------------------------------------------------------------------------
 
 /* static */
-wxString wxString::Format(const wxChar *pszFormat, ...)
+#ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
+wxString wxStringPrintfMixinBase::DoFormat(const wxChar *format, ...)
+#else
+wxString wxString::DoFormat(const wxChar *format, ...)
+#endif
 {
     va_list argptr;
-    va_start(argptr, pszFormat);
+    va_start(argptr, format);
 
     wxString s;
-    s.PrintfV(pszFormat, argptr);
+    s.PrintfV(format, argptr);
 
     va_end(argptr);
 
@@ -1751,26 +1815,39 @@ wxString wxString::Format(const wxChar *pszFormat, ...)
 }
 
 /* static */
-wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr)
+wxString wxString::FormatV(const wxString& format, va_list argptr)
 {
     wxString s;
-    s.PrintfV(pszFormat, argptr);
+    s.PrintfV(format, argptr);
     return s;
 }
 
-int wxString::Printf(const wxChar *pszFormat, ...)
+#ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
+int wxStringPrintfMixinBase::DoPrintf(const wxChar *format, ...)
+#else
+int wxString::DoPrintf(const wxChar *format, ...)
+#endif
 {
     va_list argptr;
-    va_start(argptr, pszFormat);
+    va_start(argptr, format);
+
+#ifdef wxNEEDS_WXSTRING_PRINTF_MIXIN
+    // get a pointer to the wxString instance; we have to use dynamic_cast<>
+    // because it's the only cast that works safely for downcasting when
+    // multiple inheritance is used:
+    wxString *str = static_cast<wxString*>(this);
+#else
+    wxString *str = this;
+#endif
 
-    int iLen = PrintfV(pszFormat, argptr);
+    int iLen = str->PrintfV(format, argptr);
 
     va_end(argptr);
 
     return iLen;
 }
 
-int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
+int wxString::PrintfV(const wxString& format, va_list argptr)
 {
     int size = 1024;
 
@@ -1789,7 +1866,7 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
         // only a copy
         va_list argptrcopy;
         wxVaCopy(argptrcopy, argptr);
-        int len = wxVsnprintf(buf, size, pszFormat, argptrcopy);
+        int len = wxVsnprintf(buf, size, format, argptrcopy);
         va_end(argptrcopy);
 
         // some implementations of vsnprintf() don't NUL terminate
@@ -1802,13 +1879,29 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
         // buffer were large enough (newer standards such as Unix98)
         if ( len < 0 )
         {
+#if wxUSE_WXVSNPRINTF
+            // we know that our own implementation of wxVsnprintf() returns -1
+            // only for a format error - thus there's something wrong with
+            // the user's format string
+            return -1;
+#else // assume that system version only returns error if not enough space
             // still not enough, as we don't know how much we need, double the
             // current size of the buffer
             size *= 2;
+#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
         }
-        else if ( len > size )
+        else if ( len >= size )
         {
-            size = len;
+#if wxUSE_WXVSNPRINTF
+            // we know that our own implementation of wxVsnprintf() returns 
+            // size+1 when there's not enough space but that's not the size
+            // of the required buffer!
+            size *= 2;      // so we just double the current size of the buffer
+#else
+            // some vsnprintf() implementations NUL-terminate the buffer and
+            // some don't in len == size case, to be safe always add 1
+            size = len + 1;
+#endif
         }
         else // ok, there was enough space
         {
@@ -1819,7 +1912,7 @@ int wxString::PrintfV(const wxChar* pszFormat, va_list argptr)
     // we could have overshot
     Shrink();
 
-    return Len();
+    return length();
 }
 
 // ----------------------------------------------------------------------------
@@ -1965,10 +2058,10 @@ match:
 }
 
 // Count the number of chars
-int wxString::Freq(wxChar ch) const
+int wxString::Freq(wxUniChar ch) const
 {
     int count = 0;
-    int len = Len();
+    int len = length();
     for (int i = 0; i < len; i++)
     {
         if (GetChar(i) == ch)
@@ -1984,15 +2077,6 @@ wxString wxString::Upper() const
 // convert to lower case, return the copy of the string
 wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
 
-int wxString::sprintf(const wxChar *pszFormat, ...)
-  {
-    va_list argptr;
-    va_start(argptr, pszFormat);
-    int iLen = PrintfV(pszFormat, argptr);
-    va_end(argptr);
-    return iLen;
-  }
-
 // ============================================================================
 // ArrayString
 // ============================================================================
@@ -2026,14 +2110,12 @@ wxArrayString::wxArrayString(size_t sz, const wxString* a)
 #define   ARRAY_DEFAULT_INITIAL_SIZE    (16)
 #endif
 
-#define   STRING(p)   ((wxString *)(&(p)))
-
 // ctor
 void wxArrayString::Init(bool autoSort)
 {
   m_nSize  =
   m_nCount = 0;
-  m_pItems = (wxChar **) NULL;
+  m_pItems = NULL;
   m_autoSort = autoSort;
 }
 
@@ -2083,7 +2165,7 @@ void wxArrayString::Grow(size_t nIncrement)
       m_nSize = ARRAY_DEFAULT_INITIAL_SIZE;
       if (m_nSize < nIncrement)
           m_nSize = nIncrement;
-      m_pItems = new wxChar *[m_nSize];
+      m_pItems = new wxString[m_nSize];
     }
     else {
       // otherwise when it's called for the first time, nIncrement would be 0
@@ -2096,10 +2178,11 @@ void wxArrayString::Grow(size_t nIncrement)
       if ( nIncrement < ndefIncrement )
         nIncrement = ndefIncrement;
       m_nSize += nIncrement;
-      wxChar **pNew = new wxChar *[m_nSize];
+      wxString *pNew = new wxString[m_nSize];
 
       // copy data to new location
-      memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
+      for ( size_t j = 0; j < m_nCount; j++ )
+          pNew[j] = m_pItems[j];
 
       // delete old memory (but do not release the strings!)
       wxDELETEA(m_pItems);
@@ -2109,26 +2192,15 @@ void wxArrayString::Grow(size_t nIncrement)
   }
 }
 
-void wxArrayString::Free()
-{
-  for ( size_t n = 0; n < m_nCount; n++ ) {
-    STRING(m_pItems[n])->GetStringData()->Unlock();
-  }
-}
-
 // deletes all the strings from the list
 void wxArrayString::Empty()
 {
-  Free();
-
   m_nCount = 0;
 }
 
 // as Empty, but also frees memory
 void wxArrayString::Clear()
 {
-  Free();
-
   m_nSize  =
   m_nCount = 0;
 
@@ -2138,8 +2210,6 @@ void wxArrayString::Clear()
 // dtor
 wxArrayString::~wxArrayString()
 {
-  Free();
-
   wxDELETEA(m_pItems);
 }
 
@@ -2153,13 +2223,17 @@ void wxArrayString::Alloc(size_t nSize)
 {
   // only if old buffer was not big enough
   if ( nSize > m_nSize ) {
-    Free();
-    wxDELETEA(m_pItems);
-    m_pItems = new wxChar *[nSize];
+    wxString *pNew = new wxString[nSize];
+    if ( !pNew )
+        return;
+
+    for ( size_t j = 0; j < m_nCount; j++ )
+        pNew[j] = m_pItems[j];
+    delete [] m_pItems;
+
+    m_pItems = pNew;
     m_nSize  = nSize;
   }
-
-  m_nCount = 0;
 }
 
 // minimizes the memory usage by freeing unused memory
@@ -2168,39 +2242,16 @@ void wxArrayString::Shrink()
   // only do it if we have some memory to free
   if( m_nCount < m_nSize ) {
     // allocates exactly as much memory as we need
-    wxChar **pNew = new wxChar *[m_nCount];
+    wxString *pNew = new wxString[m_nCount];
 
     // copy data to new location
-    memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *));
+    for ( size_t j = 0; j < m_nCount; j++ )
+        pNew[j] = m_pItems[j];
     delete [] m_pItems;
     m_pItems = pNew;
   }
 }
 
-#if WXWIN_COMPATIBILITY_2_4
-
-// 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;
-}
-
-void wxArrayString::Remove(size_t nIndex, size_t nRemove)
-{
-    RemoveAt(nIndex, nRemove);
-}
-
-#endif // WXWIN_COMPATIBILITY_2_4
-
 // searches the array for an item (forward or backwards)
 int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
 {
@@ -2233,7 +2284,7 @@ int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
       if ( m_nCount > 0 ) {
         size_t ui = m_nCount;
         do {
-          if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) )
+          if ( m_pItems[--ui].IsSameAs(sz, bCase) )
             return ui;
         }
         while ( ui != 0 );
@@ -2241,7 +2292,7 @@ int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const
     }
     else {
       for( size_t ui = 0; ui < m_nCount; ui++ ) {
-        if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) )
+        if( m_pItems[ui].IsSameAs(sz, bCase) )
           return ui;
       }
     }
@@ -2280,17 +2331,12 @@ size_t wxArrayString::Add(const wxString& str, size_t nInsert)
     return (size_t)lo;
   }
   else {
-    wxASSERT( str.GetStringData()->IsValid() );
-
     Grow(nInsert);
 
     for (size_t i = 0; i < nInsert; i++)
     {
-        // the string data must not be deleted!
-        str.GetStringData()->Lock();
-
         // just append
-        m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast
+        m_pItems[m_nCount + i] = str;
     }
     size_t ret = m_nCount;
     m_nCount += nInsert;
@@ -2301,21 +2347,18 @@ size_t wxArrayString::Add(const wxString& str, size_t nInsert)
 // add item at the given position
 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(nInsert);
 
-  memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex],
-          (m_nCount - nIndex)*sizeof(wxChar *));
+  for (int j = m_nCount - nIndex - 1; j >= 0; j--)
+      m_pItems[nIndex + nInsert + j] = m_pItems[nIndex + j];
 
   for (size_t i = 0; i < nInsert; i++)
   {
-      str.GetStringData()->Lock();
-      m_pItems[nIndex + i] = (wxChar *)str.c_str();
+      m_pItems[nIndex + i] = str;
   }
   m_nCount += nInsert;
 }
@@ -2351,7 +2394,7 @@ void wxArrayString::SetCount(size_t count)
 
     wxString s;
     while ( m_nCount < count )
-        m_pItems[m_nCount++] = (wxChar *)s.c_str();
+        m_pItems[m_nCount++] = s;
 }
 
 // removes item from array (by index)
@@ -2361,12 +2404,9 @@ void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove)
   wxCHECK_RET( nIndex + nRemove <= m_nCount,
                wxT("removing too many elements in wxArrayString::Remove") );
 
-  // release our lock
-  for (size_t i = 0; i < nRemove; i++)
-      Item(nIndex + i).GetStringData()->Unlock();
+  for ( size_t j =  0; j < m_nCount - nIndex -nRemove; j++)
+      m_pItems[nIndex + j] = m_pItems[nIndex + nRemove + j];
 
-  memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove],
-          (m_nCount - nIndex - nRemove)*sizeof(wxChar *));
   m_nCount -= nRemove;
 }
 
@@ -2397,19 +2437,7 @@ void wxArrayString::assign(const_iterator first, const_iterator last)
 #if wxUSE_THREADS
   // need a critical section to protect access to gs_compareFunction and
   // gs_sortAscending variables
-  static wxCriticalSection *gs_critsectStringSort = NULL;
-
-  // call this before the value of the global sort vars is changed/after
-  // you're finished with them
-  #define START_SORT()     wxASSERT( !gs_critsectStringSort );                \
-                           gs_critsectStringSort = new wxCriticalSection;     \
-                           gs_critsectStringSort->Enter()
-  #define END_SORT()       gs_critsectStringSort->Leave();                    \
-                           delete gs_critsectStringSort;                      \
-                           gs_critsectStringSort = NULL
-#else // !threads
-  #define START_SORT()
-  #define END_SORT()
+  static wxCriticalSection gs_critsectStringSort;
 #endif // wxUSE_THREADS
 
 // function to use for string comparaison
@@ -2440,7 +2468,7 @@ wxStringCompareFunction(const void *first, const void *second)
 // sort array elements using passed comparaison function
 void wxArrayString::Sort(CompareFunction compareFunction)
 {
-  START_SORT();
+  wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort);
 
   wxASSERT( !gs_compareFunction );  // must have been reset to NULL
   gs_compareFunction = compareFunction;
@@ -2449,8 +2477,6 @@ void wxArrayString::Sort(CompareFunction compareFunction)
 
   // reset it to NULL so that Sort(bool) will work the next time
   gs_compareFunction = NULL;
-
-  END_SORT();
 }
 
 extern "C"
@@ -2461,7 +2487,7 @@ extern "C"
 
 void wxArrayString::Sort(CompareFunction2 compareFunction)
 {
-  qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction);
+  qsort(m_pItems, m_nCount, sizeof(wxString), (wxStringCompareFn)compareFunction);
 }
 
 void wxArrayString::Sort(bool reverseOrder)
@@ -2473,9 +2499,7 @@ void wxArrayString::DoSort()
 {
   wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") );
 
-  // just sort the pointers using qsort() - of course it only works because
-  // wxString() *is* a pointer to its data
-  qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction);
+  qsort(m_pItems, m_nCount, sizeof(wxString), wxStringCompareFunction);
 }
 
 bool wxArrayString::operator==(const wxArrayString& a) const
@@ -2503,3 +2527,106 @@ int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2)
 {
     return -s1->Cmp(*s2);
 }
+
+
+
+// ===========================================================================
+// wxJoin and wxSplit
+// ===========================================================================
+
+#include "wx/tokenzr.h"
+
+wxString wxJoin(const wxArrayString& arr, const wxChar sep, const wxChar escape)
+{
+    size_t count = arr.size();
+    if ( count == 0 )
+        return wxEmptyString;
+
+    wxString str;
+
+    // pre-allocate memory using the estimation of the average length of the
+    // strings in the given array: this is very imprecise, of course, but
+    // better than nothing
+    str.reserve(count*(arr[0].length() + arr[count-1].length()) / 2);
+
+    if ( escape == wxT('\0') )
+    {
+        // escaping is disabled:
+        for ( size_t i = 0; i < count; i++ )
+        {
+            if ( i )
+                str += sep;
+            str += arr[i];
+        }
+    }
+    else // use escape character
+    {
+        for ( size_t n = 0; n < count; n++ )
+        {
+            if ( n )
+                str += sep;
+
+            for ( wxString::const_iterator i = arr[n].begin(),
+                                         end = arr[n].end();
+                  i != end;
+                  ++i )
+            {
+                const wxChar ch = *i;
+                if ( ch == sep )
+                    str += escape;      // escape this separator
+                str += ch;
+            }
+        }
+    }
+
+    str.Shrink(); // release extra memory if we allocated too much
+    return str;
+}
+
+wxArrayString wxSplit(const wxString& str, const wxChar sep, const wxChar escape)
+{
+    if ( escape == wxT('\0') )
+    {
+        // simple case: we don't need to honour the escape character
+        return wxStringTokenize(str, sep, wxTOKEN_RET_EMPTY_ALL);
+    }
+
+    wxArrayString ret;
+    wxString curr;
+    wxChar prev = wxT('\0');
+
+    for ( wxString::const_iterator i = str.begin(),
+                                 end = str.end();
+          i != end;
+          ++i )
+    {
+        const wxChar ch = *i;
+
+        if ( ch == sep )
+        {
+            if ( prev == escape )
+            {
+                // remove the escape character and don't consider this
+                // occurrence of 'sep' as a real separator
+                *curr.rbegin() = sep;
+            }
+            else // real separator
+            {
+                ret.push_back(curr);
+                curr.clear();
+            }
+        }
+        else // normal character
+        {
+            curr += ch;
+        }
+
+        prev = ch;
+    }
+
+    // add the last token
+    if ( !curr.empty() || prev == sep )
+        ret.Add(curr);
+
+    return ret;
+}