]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
don't allow docks to be resized such that panes overlap
[wxWidgets.git] / src / common / string.cpp
index 84f285410c0efcf1fbfc7ebbedbe7dfa364c5fb7..220df16994c19f153915e6b74bf7d27f52c16e79 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 
 #include <string.h>
 #include <stdlib.h>
 
-#ifdef __SALFORDC__
-    #include <clib.h>
-#endif
-
 #include "wx/hashmap.h"
 #include "wx/hashmap.h"
+#include "wx/vector.h"
+#include "wx/xlocale.h"
 
 // string handling functions used by wxString:
 #if wxUSE_UNICODE_UTF8
 
 // string handling functions used by wxString:
 #if wxUSE_UNICODE_UTF8
     #define wxStringStrlen   wxStrlen
 #endif
 
     #define wxStringStrlen   wxStrlen
 #endif
 
+// ----------------------------------------------------------------------------
+// global variables
+// ----------------------------------------------------------------------------
+
+namespace wxPrivate
+{
+
+static UntypedBufferData s_untypedNullData(NULL, 0);
+
+UntypedBufferData * const untypedNullDataPtr = &s_untypedNullData;
+
+} // namespace wxPrivate
 
 // ---------------------------------------------------------------------------
 // static class variables definition
 
 // ---------------------------------------------------------------------------
 // static class variables definition
 //According to STL _must_ be a -1 size_t
 const size_t wxString::npos = (size_t) -1;
 
 //According to STL _must_ be a -1 size_t
 const size_t wxString::npos = (size_t) -1;
 
+#if wxUSE_STRING_POS_CACHE
+
+#ifdef wxHAS_COMPILER_TLS
+
+wxTLS_TYPE(wxString::Cache) wxString::ms_cache;
+
+#else // !wxHAS_COMPILER_TLS
+
+struct wxStrCacheInitializer
+{
+    wxStrCacheInitializer()
+    {
+        // calling this function triggers s_cache initialization in it, and
+        // from now on it becomes safe to call from multiple threads
+        wxString::GetCache();
+    }
+};
+
+/*
+wxString::Cache& wxString::GetCache()
+{
+    static wxTLS_TYPE(Cache) s_cache;
+
+    return wxTLS_VALUE(s_cache);
+}
+*/
+
+static wxStrCacheInitializer gs_stringCacheInit;
+
+#endif // wxHAS_COMPILER_TLS/!wxHAS_COMPILER_TLS
+
+// gdb seems to be unable to display thread-local variables correctly, at least
+// not my 6.4.98 version under amd64, so provide this debugging helper to do it
+#if wxDEBUG_LEVEL >= 2
+
+struct wxStrCacheDumper
+{
+    static void ShowAll()
+    {
+        puts("*** wxString cache dump:");
+        for ( unsigned n = 0; n < wxString::Cache::SIZE; n++ )
+        {
+            const wxString::Cache::Element&
+                c = wxString::GetCacheBegin()[n];
+
+            printf("\t%u%s\t%p: pos=(%lu, %lu), len=%ld\n",
+                   n,
+                   n == wxString::LastUsedCacheElement() ? " [*]" : "",
+                   c.str,
+                   (unsigned long)c.pos,
+                   (unsigned long)c.impl,
+                   (long)c.len);
+        }
+    }
+};
+
+void wxDumpStrCache() { wxStrCacheDumper::ShowAll(); }
+
+#endif // wxDEBUG_LEVEL >= 2
+
+#ifdef wxPROFILE_STRING_CACHE
+
+wxString::CacheStats wxString::ms_cacheStats;
+
+struct wxStrCacheStatsDumper
+{
+    ~wxStrCacheStatsDumper()
+    {
+        const wxString::CacheStats& stats = wxString::ms_cacheStats;
+
+        if ( stats.postot )
+        {
+            puts("*** wxString cache statistics:");
+            printf("\tTotal non-trivial calls to PosToImpl(): %u\n",
+                   stats.postot);
+            printf("\tHits %u (of which %u not used) or %.2f%%\n",
+                   stats.poshits,
+                   stats.mishits,
+                   100.*float(stats.poshits - stats.mishits)/stats.postot);
+            printf("\tAverage position requested: %.2f\n",
+                   float(stats.sumpos) / stats.postot);
+            printf("\tAverage offset after cached hint: %.2f\n",
+                   float(stats.sumofs) / stats.postot);
+        }
+
+        if ( stats.lentot )
+        {
+            printf("\tNumber of calls to length(): %u, hits=%.2f%%\n",
+                   stats.lentot, 100.*float(stats.lenhits)/stats.lentot);
+        }
+    }
+};
+
+static wxStrCacheStatsDumper s_showCacheStats;
+
+#endif // wxPROFILE_STRING_CACHE
+
+#endif // wxUSE_STRING_POS_CACHE
+
 // ----------------------------------------------------------------------------
 // global functions
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // global functions
 // ----------------------------------------------------------------------------
@@ -73,7 +182,13 @@ const size_t wxString::npos = (size_t) -1;
 wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
 {
 #if wxUSE_UNICODE && !wxUSE_UNICODE_UTF8
 wxSTD ostream& operator<<(wxSTD ostream& os, const wxCStrData& str)
 {
 #if wxUSE_UNICODE && !wxUSE_UNICODE_UTF8
-    return os << (const char *)str.AsCharBuf();
+    const wxScopedCharBuffer buf(str.AsCharBuf());
+    if ( !buf )
+        os.clear(wxSTD ios_base::failbit);
+    else
+        os << buf.data();
+
+    return os;
 #else
     return os << str.AsInternal();
 #endif
 #else
     return os << str.AsInternal();
 #endif
@@ -84,13 +199,13 @@ wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str)
     return os << str.c_str();
 }
 
     return os << str.c_str();
 }
 
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxCharBuffer& str)
+wxSTD ostream& operator<<(wxSTD ostream& os, const wxScopedCharBuffer& str)
 {
     return os << str.data();
 }
 
 #ifndef __BORLANDC__
 {
     return os << str.data();
 }
 
 #ifndef __BORLANDC__
-wxSTD ostream& operator<<(wxSTD ostream& os, const wxWCharBuffer& str)
+wxSTD ostream& operator<<(wxSTD ostream& os, const wxScopedWCharBuffer& str)
 {
     return os << str.data();
 }
 {
     return os << str.data();
 }
@@ -108,7 +223,7 @@ wxSTD wostream& operator<<(wxSTD wostream& wos, const wxCStrData& str)
     return wos << str.AsWChar();
 }
 
     return wos << str.AsWChar();
 }
 
-wxSTD wostream& operator<<(wxSTD wostream& wos, const wxWCharBuffer& str)
+wxSTD wostream& operator<<(wxSTD wostream& wos, const wxScopedWCharBuffer& str)
 {
     return wos << str.data();
 }
 {
     return wos << str.data();
 }
@@ -127,22 +242,30 @@ void wxString::PosLenToImpl(size_t pos, size_t len,
                             size_t *implPos, size_t *implLen) const
 {
     if ( pos == npos )
                             size_t *implPos, size_t *implLen) const
 {
     if ( pos == npos )
+    {
         *implPos = npos;
         *implPos = npos;
-    else
+    }
+    else // have valid start position
     {
     {
-        const_iterator i = begin() + pos;
-        *implPos = wxStringImpl::const_iterator(i.impl()) - m_impl.begin();
+        const const_iterator b = GetIterForNthChar(pos);
+        *implPos = wxStringImpl::const_iterator(b.impl()) - m_impl.begin();
         if ( len == npos )
         if ( len == npos )
+        {
             *implLen = npos;
             *implLen = npos;
-        else
+        }
+        else // have valid length too
         {
         {
-            // too large length is interpreted as "to the end of the string"
-            // FIXME-UTF8: verify this is the case in std::string, assert
-            // otherwise
-            if ( pos + len > length() )
-                len = length() - pos;
-
-            *implLen = (i + len).impl() - i.impl();
+            // we need to handle the case of length specifying a substring
+            // going beyond the end of the string, just as std::string does
+            const const_iterator e(end());
+            const_iterator i(b);
+            while ( len && i <= e )
+            {
+                ++i;
+                --len;
+            }
+
+            *implLen = i.impl() - b.impl();
         }
     }
 }
         }
     }
 }
@@ -272,7 +395,7 @@ const char* wxCStrData::AsChar() const
     //             adding more fields to wxString and require profiling results
     //             to be sure that we really gain enough from them to justify
     //             doing it.
     //             adding more fields to wxString and require profiling results
     //             to be sure that we really gain enough from them to justify
     //             doing it.
-    wxCharBuffer buf(str->mb_str());
+    wxScopedCharBuffer buf(str->mb_str());
 
     // if it failed, return empty string and not NULL to avoid crashes in code
     // written with either wxWidgets 2 wxString or std::string behaviour in
 
     // if it failed, return empty string and not NULL to avoid crashes in code
     // written with either wxWidgets 2 wxString or std::string behaviour in
@@ -303,7 +426,7 @@ const wchar_t* wxCStrData::AsWChar() const
     wxString *str = wxConstCast(m_str, wxString);
 
     // convert the string:
     wxString *str = wxConstCast(m_str, wxString);
 
     // convert the string:
-    wxWCharBuffer buf(str->wc_str());
+    wxScopedWCharBuffer buf(str->wc_str());
 
     // notice that here, unlike above in AsChar(), conversion can't fail as our
     // internal UTF-8 is always well-formed -- or the string was corrupted and
 
     // notice that here, unlike above in AsChar(), conversion can't fail as our
     // internal UTF-8 is always well-formed -- or the string was corrupted and
@@ -342,15 +465,15 @@ wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
 {
     // anything to do?
     if ( !psz || nLength == 0 )
 {
     // anything to do?
     if ( !psz || nLength == 0 )
-        return SubstrBufFromMB(L"", 0);
+        return SubstrBufFromMB(wxWCharBuffer(L""), 0);
 
     if ( nLength == npos )
         nLength = wxNO_LEN;
 
     size_t wcLen;
 
     if ( nLength == npos )
         nLength = wxNO_LEN;
 
     size_t wcLen;
-    wxWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
+    wxScopedWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
     if ( !wcLen )
     if ( !wcLen )
-        return SubstrBufFromMB(_T(""), 0);
+        return SubstrBufFromMB(wxWCharBuffer(L""), 0);
     else
         return SubstrBufFromMB(wcBuf, wcLen);
 }
     else
         return SubstrBufFromMB(wcBuf, wcLen);
 }
@@ -363,7 +486,7 @@ wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
 {
     // anything to do?
     if ( !psz || nLength == 0 )
 {
     // anything to do?
     if ( !psz || nLength == 0 )
-        return SubstrBufFromMB("", 0);
+        return SubstrBufFromMB(wxCharBuffer(""), 0);
 
     // if psz is already in UTF-8, we don't have to do the roundtrip to
     // wchar_t* and back:
 
     // if psz is already in UTF-8, we don't have to do the roundtrip to
     // wchar_t* and back:
@@ -373,7 +496,11 @@ wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
         // UTF-8 sequence and psz may be invalid:
         if ( wxStringOperations::IsValidUtf8String(psz, nLength) )
         {
         // UTF-8 sequence and psz may be invalid:
         if ( wxStringOperations::IsValidUtf8String(psz, nLength) )
         {
-            return SubstrBufFromMB(wxCharBuffer::CreateNonOwned(psz), nLength);
+            // we must pass the real string length to SubstrBufFromMB ctor
+            if ( nLength == npos )
+                nLength = psz ? strlen(psz) : 0;
+            return SubstrBufFromMB(wxScopedCharBuffer::CreateNonOwned(psz, nLength),
+                                   nLength);
         }
         // else: do the roundtrip through wchar_t*
     }
         }
         // else: do the roundtrip through wchar_t*
     }
@@ -383,9 +510,9 @@ wxString::SubstrBufFromMB wxString::ConvertStr(const char *psz, size_t nLength,
 
     // first convert to wide string:
     size_t wcLen;
 
     // first convert to wide string:
     size_t wcLen;
-    wxWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
+    wxScopedWCharBuffer wcBuf(conv.cMB2WC(psz, nLength, &wcLen));
     if ( !wcLen )
     if ( !wcLen )
-        return SubstrBufFromMB("", 0);
+        return SubstrBufFromMB(wxCharBuffer(""), 0);
 
     // and then to UTF-8:
     SubstrBufFromMB buf(ConvertStr(wcBuf, wcLen, wxMBConvStrictUTF8()));
 
     // and then to UTF-8:
     SubstrBufFromMB buf(ConvertStr(wcBuf, wcLen, wxMBConvStrictUTF8()));
@@ -403,15 +530,15 @@ wxString::SubstrBufFromWC wxString::ConvertStr(const wchar_t *pwz, size_t nLengt
 {
     // anything to do?
     if ( !pwz || nLength == 0 )
 {
     // anything to do?
     if ( !pwz || nLength == 0 )
-        return SubstrBufFromWC("", 0);
+        return SubstrBufFromWC(wxCharBuffer(""), 0);
 
     if ( nLength == npos )
         nLength = wxNO_LEN;
 
     size_t mbLen;
 
     if ( nLength == npos )
         nLength = wxNO_LEN;
 
     size_t mbLen;
-    wxCharBuffer mbBuf(conv.cWC2MB(pwz, nLength, &mbLen));
+    wxScopedCharBuffer mbBuf(conv.cWC2MB(pwz, nLength, &mbLen));
     if ( !mbLen )
     if ( !mbLen )
-        return SubstrBufFromWC("", 0);
+        return SubstrBufFromWC(wxCharBuffer(""), 0);
     else
         return SubstrBufFromWC(mbBuf, mbLen);
 }
     else
         return SubstrBufFromWC(mbBuf, mbLen);
 }
@@ -421,50 +548,54 @@ wxString::SubstrBufFromWC wxString::ConvertStr(const wchar_t *pwz, size_t nLengt
 #if wxUSE_UNICODE_WCHAR
 
 //Convert wxString in Unicode mode to a multi-byte string
 #if wxUSE_UNICODE_WCHAR
 
 //Convert wxString in Unicode mode to a multi-byte string
-const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
+const wxScopedCharBuffer wxString::mb_str(const wxMBConv& conv) const
 {
 {
-    return conv.cWC2MB(wx_str(), length() + 1 /* size, not length */, NULL);
+    // NB: Length passed to cWC2MB() doesn't include terminating NUL, it's
+    //     added by it automatically. If we passed length()+1 here, it would
+    //     create a buffer with 2 trailing NULs of length one greater than
+    //     expected.
+    return conv.cWC2MB(wx_str(), length(), NULL);
 }
 
 #elif wxUSE_UNICODE_UTF8
 
 }
 
 #elif wxUSE_UNICODE_UTF8
 
-const wxWCharBuffer wxString::wc_str() const
+const wxScopedWCharBuffer wxString::wc_str() const
 {
 {
+    // NB: Length passed to cMB2WC() doesn't include terminating NUL, it's
+    //     added by it automatically. If we passed length()+1 here, it would
+    //     create a buffer with 2 trailing NULs of length one greater than
+    //     expected.
     return wxMBConvStrictUTF8().cMB2WC
                                 (
                                     m_impl.c_str(),
     return wxMBConvStrictUTF8().cMB2WC
                                 (
                                     m_impl.c_str(),
-                                    m_impl.length() + 1, // size, not length
+                                    m_impl.length(),
                                     NULL
                                 );
 }
 
                                     NULL
                                 );
 }
 
-const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const
+const wxScopedCharBuffer wxString::mb_str(const wxMBConv& conv) const
 {
     if ( conv.IsUTF8() )
 {
     if ( conv.IsUTF8() )
-        return wxCharBuffer::CreateNonOwned(m_impl.c_str());
-
-    // FIXME-UTF8: use wc_str() here once we have buffers with length
+        return wxScopedCharBuffer::CreateNonOwned(m_impl.c_str(), m_impl.length());
 
 
-    size_t wcLen;
-    wxWCharBuffer wcBuf(wxMBConvStrictUTF8().cMB2WC
-                                             (
-                                                m_impl.c_str(),
-                                                m_impl.length() + 1, // size
-                                                &wcLen
-                                             ));
-    if ( !wcLen )
+    wxScopedWCharBuffer wcBuf(wc_str());
+    if ( !wcBuf.length() )
         return wxCharBuffer("");
 
         return wxCharBuffer("");
 
-    return conv.cWC2MB(wcBuf, wcLen+1, NULL);
+    return conv.cWC2MB(wcBuf.data(), wcBuf.length(), NULL);
 }
 
 #else // ANSI
 
 //Converts this string to a wide character string if unicode
 //mode is not enabled and wxUSE_WCHAR_T is enabled
 }
 
 #else // ANSI
 
 //Converts this string to a wide character string if unicode
 //mode is not enabled and wxUSE_WCHAR_T is enabled
-const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const
+const wxScopedWCharBuffer wxString::wc_str(const wxMBConv& conv) const
 {
 {
-    return conv.cMB2WC(wx_str(), length() + 1 /* size, not length */, NULL);
+    // NB: Length passed to cMB2WC() doesn't include terminating NUL, it's
+    //     added by it automatically. If we passed length()+1 here, it would
+    //     create a buffer with 2 trailing NULs of length one greater than
+    //     expected.
+    return conv.cMB2WC(wx_str(), length(), NULL);
 }
 
 #endif // Unicode/ANSI
 }
 
 #endif // Unicode/ANSI
@@ -991,6 +1122,7 @@ size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart,
 
 int wxString::CmpNoCase(const wxString& s) const
 {
 
 int wxString::CmpNoCase(const wxString& s) const
 {
+#if wxUSE_UNICODE_UTF8
     // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
 
     const_iterator i1 = begin();
     // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
 
     const_iterator i1 = begin();
@@ -1014,6 +1146,9 @@ int wxString::CmpNoCase(const wxString& s) const
     else if ( len1 > len2 )
         return 1;
     return 0;
     else if ( len1 > len2 )
         return 1;
     return 0;
+#else // wxUSE_UNICODE_WCHAR or ANSI
+    return wxStricmp(m_impl.c_str(), s.m_impl.c_str());
+#endif
 }
 
 
 }
 
 
@@ -1066,7 +1201,7 @@ wxString wxString::FromAscii(char ascii)
     return wxString(wxUniChar((wchar_t)c));
 }
 
     return wxString(wxUniChar((wchar_t)c));
 }
 
-const wxCharBuffer wxString::ToAscii() const
+const wxScopedCharBuffer wxString::ToAscii() const
 {
     // this will allocate enough space for the terminating NUL too
     wxCharBuffer buffer(length());
 {
     // this will allocate enough space for the terminating NUL too
     wxCharBuffer buffer(length());
@@ -1170,7 +1305,7 @@ wxString wxString::Right(size_t nCount) const
   return dest;
 }
 
   return dest;
 }
 
-// get all characters after the last occurence of ch
+// get all characters after the last occurrence of ch
 // (returns the whole string if ch not found)
 wxString wxString::AfterLast(wxUniChar ch) const
 {
 // (returns the whole string if ch not found)
 wxString wxString::AfterLast(wxUniChar ch) const
 {
@@ -1179,7 +1314,7 @@ wxString wxString::AfterLast(wxUniChar ch) const
   if ( iPos == wxNOT_FOUND )
     str = *this;
   else
   if ( iPos == wxNOT_FOUND )
     str = *this;
   else
-    str = wx_str() + iPos + 1;
+    str.assign(*this, iPos + 1, npos);
 
   return str;
 }
 
   return str;
 }
@@ -1197,16 +1332,17 @@ wxString wxString::Left(size_t nCount) const
   return dest;
 }
 
   return dest;
 }
 
-// get all characters before the first occurence of ch
+// get all characters before the first occurrence of ch
 // (returns the whole string if ch not found)
 wxString wxString::BeforeFirst(wxUniChar ch) const
 {
   int iPos = Find(ch);
 // (returns the whole string if ch not found)
 wxString wxString::BeforeFirst(wxUniChar ch) const
 {
   int iPos = Find(ch);
-  if ( iPos == wxNOT_FOUND ) iPos = length();
+  if ( iPos == wxNOT_FOUND )
+      iPos = length();
   return wxString(*this, 0, iPos);
 }
 
   return wxString(*this, 0, iPos);
 }
 
-/// get all characters before the last occurence of ch
+/// get all characters before the last occurrence of ch
 /// (returns empty string if ch not found)
 wxString wxString::BeforeLast(wxUniChar ch) const
 {
 /// (returns empty string if ch not found)
 wxString wxString::BeforeLast(wxUniChar ch) const
 {
@@ -1218,19 +1354,19 @@ wxString wxString::BeforeLast(wxUniChar ch) const
   return str;
 }
 
   return str;
 }
 
-/// get all characters after the first occurence of ch
+/// get all characters after the first occurrence of ch
 /// (returns empty string if ch not found)
 wxString wxString::AfterFirst(wxUniChar ch) const
 {
   wxString str;
   int iPos = Find(ch);
   if ( iPos != wxNOT_FOUND )
 /// (returns empty string if ch not found)
 wxString wxString::AfterFirst(wxUniChar ch) const
 {
   wxString str;
   int iPos = Find(ch);
   if ( iPos != wxNOT_FOUND )
-    str = wx_str() + iPos + 1;
+      str.assign(*this, iPos + 1, npos);
 
   return str;
 }
 
 
   return str;
 }
 
-// replace first (or all) occurences of some substring with another one
+// replace first (or all) occurrences of some substring with another one
 size_t wxString::Replace(const wxString& strOld,
                          const wxString& strNew, bool bReplaceAll)
 {
 size_t wxString::Replace(const wxString& strOld,
                          const wxString& strNew, bool bReplaceAll)
 {
@@ -1238,36 +1374,92 @@ size_t wxString::Replace(const wxString& strOld,
     wxCHECK_MSG( !strOld.empty(), 0,
                  _T("wxString::Replace(): invalid parameter") );
 
     wxCHECK_MSG( !strOld.empty(), 0,
                  _T("wxString::Replace(): invalid parameter") );
 
+    wxSTRING_INVALIDATE_CACHE();
+
     size_t uiCount = 0;   // count of replacements made
 
     size_t uiCount = 0;   // count of replacements made
 
-    size_t uiOldLen = strOld.length();
-    size_t uiNewLen = strNew.length();
+    // optimize the special common case: replacement of one character by
+    // another one (in UTF-8 case we can only do this for ASCII characters)
+    //
+    // benchmarks show that this special version is around 3 times faster
+    // (depending on the proportion of matching characters and UTF-8/wchar_t
+    // build)
+    if ( strOld.m_impl.length() == 1 && strNew.m_impl.length() == 1 )
+    {
+        const wxStringCharType chOld = strOld.m_impl[0],
+                               chNew = strNew.m_impl[0];
+
+        // this loop is the simplified version of the one below
+        for ( size_t pos = 0; ; )
+        {
+            pos = m_impl.find(chOld, pos);
+            if ( pos == npos )
+                break;
 
 
-    size_t dwPos = 0;
+            m_impl[pos++] = chNew;
 
 
-    while ( (*this)[dwPos] != wxT('\0') )
+            uiCount++;
+
+            if ( !bReplaceAll )
+                break;
+        }
+    }
+    else if ( !bReplaceAll)
     {
     {
-        //DO NOT USE STRSTR HERE
-        //this string can contain embedded null characters,
-        //so strstr will function incorrectly
-        dwPos = find(strOld, dwPos);
-        if ( dwPos == npos )
-            break;                  // exit the loop
-        else
+        size_t pos = m_impl.find(strOld, 0);
+        if ( pos != npos )
         {
         {
-            //replace this occurance of the old string with the new one
-            replace(dwPos, uiOldLen, strNew, uiNewLen);
+            m_impl.replace(pos, strOld.m_impl.length(), strNew.m_impl);
+            uiCount = 1;
+        }
+    }
+    else // replace all occurrences
+    {
+        const size_t uiOldLen = strOld.m_impl.length();
+        const size_t uiNewLen = strNew.m_impl.length();
 
 
-            //move up pos past the string that was replaced
-            dwPos += uiNewLen;
+        // first scan the string to find all positions at which the replacement
+        // should be made
+        wxVector<size_t> replacePositions;
 
 
-            //increase replace count
+        size_t pos;
+        for ( pos = m_impl.find(strOld.m_impl, 0);
+              pos != npos;
+              pos = m_impl.find(strOld.m_impl, pos + uiOldLen))
+        {
+            replacePositions.push_back(pos);
             ++uiCount;
             ++uiCount;
+        }
 
 
-            // stop now?
-            if ( !bReplaceAll )
-                break;                  // exit the loop
+        if ( !uiCount )
+            return 0;
+
+        // allocate enough memory for the whole new string
+        wxString tmp;
+        tmp.m_impl.reserve(m_impl.length() + uiCount*(uiNewLen - uiOldLen));
+
+        // copy this string to tmp doing replacements on the fly
+        size_t replNum = 0;
+        for ( pos = 0; replNum < uiCount; replNum++ )
+        {
+            const size_t nextReplPos = replacePositions[replNum];
+
+            if ( pos != nextReplPos )
+            {
+                tmp.m_impl.append(m_impl, pos, nextReplPos - pos);
+            }
+
+            tmp.m_impl.append(strNew.m_impl);
+            pos = nextReplPos + uiOldLen;
         }
         }
+
+        if ( pos != m_impl.length() )
+        {
+            // append the rest of the string unchanged
+            tmp.m_impl.append(m_impl, pos, m_impl.length() - pos);
+        }
+
+        swap(tmp);
     }
 
     return uiCount;
     }
 
     return uiCount;
@@ -1342,14 +1534,28 @@ wxString& wxString::MakeLower()
   return *this;
 }
 
   return *this;
 }
 
+wxString& wxString::MakeCapitalized()
+{
+    const iterator en = end();
+    iterator it = begin();
+    if ( it != en )
+    {
+        *it = (wxChar)wxToupper(*it);
+        for ( ++it; it != en; ++it )
+            *it = (wxChar)wxTolower(*it);
+    }
+
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 // trimming and padding
 // ---------------------------------------------------------------------------
 
 // some compilers (VC++ 6.0 not to name them) return true for a call to
 // ---------------------------------------------------------------------------
 // trimming and padding
 // ---------------------------------------------------------------------------
 
 // some compilers (VC++ 6.0 not to name them) return true for a call to
-// isspace('ê') in the C locale which seems to be broken to me, but we have to
-// live with this by checking that the character is a 7 bit one - even if this
-// may fail to detect some spaces (I don't know if Unicode doesn't have
+// isspace('\xEA') in the C locale which seems to be broken to me, but we have
+// to live with this by checking that the character is a 7 bit one - even if
+// this may fail to detect some spaces (I don't know if Unicode doesn't have
 // space-like symbols somewhere except in the first 128 chars), it is arguably
 // still better than trimming away accented letters
 inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
 // space-like symbols somewhere except in the first 128 chars), it is arguably
 // still better than trimming away accented letters
 inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); }
@@ -1444,63 +1650,105 @@ int wxString::Find(wxUniChar ch, bool bFromEnd) const
     #define DO_IF_NOT_WINCE(x)
 #endif
 
     #define DO_IF_NOT_WINCE(x)
 #endif
 
-#define WX_STRING_TO_INT_TYPE(val, base, func)                              \
-    wxCHECK_MSG( val, false, _T("NULL output pointer") );                   \
-    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );  \
-                                                                            \
+#define WX_STRING_TO_X_TYPE_START                                           \
+    wxCHECK_MSG( pVal, false, _T("NULL output pointer") );                  \
     DO_IF_NOT_WINCE( errno = 0; )                                           \
     DO_IF_NOT_WINCE( errno = 0; )                                           \
-                                                                            \
     const wxStringCharType *start = wx_str();                               \
     const wxStringCharType *start = wx_str();                               \
-    wxStringCharType *end;                                                  \
-    *val = func(start, &end, base);                                         \
-                                                                            \
+    wxStringCharType *end;
+
+#define WX_STRING_TO_X_TYPE_END                                             \
     /* return true only if scan was stopped by the terminating NUL and */   \
     /* if the string was not empty to start with and no under/overflow */   \
     /* occurred: */                                                         \
     /* return true only if scan was stopped by the terminating NUL and */   \
     /* if the string was not empty to start with and no under/overflow */   \
     /* occurred: */                                                         \
-    return !*end && (end != start)                                          \
-        DO_IF_NOT_WINCE( && (errno != ERANGE) )
+    if ( *end || end == start DO_IF_NOT_WINCE(|| errno == ERANGE) )         \
+        return false;                                                       \
+    *pVal = val;                                                            \
+    return true;
+
+bool wxString::ToLong(long *pVal, int base) const
+{
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
 
-bool wxString::ToLong(long *val, int base) const
+    WX_STRING_TO_X_TYPE_START
+    long val = wxStrtol(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
+}
+
+bool wxString::ToULong(unsigned long *pVal, int base) const
 {
 {
-    WX_STRING_TO_INT_TYPE(val, base, wxStrtol);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    unsigned long val = wxStrtoul(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 }
 
-bool wxString::ToULong(unsigned long *val, int base) const
+bool wxString::ToLongLong(wxLongLong_t *pVal, int base) const
 {
 {
-    WX_STRING_TO_INT_TYPE(val, base, wxStrtoul);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    wxLongLong_t val = wxStrtoll(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 }
 
-bool wxString::ToLongLong(wxLongLong_t *val, int base) const
+bool wxString::ToULongLong(wxULongLong_t *pVal, int base) const
 {
 {
-    WX_STRING_TO_INT_TYPE(val, base, wxStrtoll);
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
+
+    WX_STRING_TO_X_TYPE_START
+    wxULongLong_t val = wxStrtoull(start, &end, base);
+    WX_STRING_TO_X_TYPE_END
 }
 
 }
 
-bool wxString::ToULongLong(wxULongLong_t *val, int base) const
+bool wxString::ToDouble(double *pVal) const
 {
 {
-    WX_STRING_TO_INT_TYPE(val, base, wxStrtoull);
+    WX_STRING_TO_X_TYPE_START
+    double val = wxStrtod(start, &end);
+    WX_STRING_TO_X_TYPE_END
 }
 
 }
 
-bool wxString::ToDouble(double *val) const
+#if wxUSE_XLOCALE
+
+bool wxString::ToCLong(long *pVal, int base) const
 {
 {
-    wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") );
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
 
-#ifndef __WXWINCE__
-    errno = 0;
+    WX_STRING_TO_X_TYPE_START
+#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
+    long val = wxStrtol_lA(start, &end, base, wxCLocale);
+#else
+    long val = wxStrtol_l(start, &end, base, wxCLocale);
 #endif
 #endif
+    WX_STRING_TO_X_TYPE_END
+}
 
 
-    const wxChar *start = c_str();
-    wxChar *end;
-    *val = wxStrtod(start, &end);
+bool wxString::ToCULong(unsigned long *pVal, int base) const
+{
+    wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") );
 
 
-    // return true only if scan was stopped by the terminating NUL and if the
-    // string was not empty to start with and no under/overflow occurred
-    return !*end && (end != start)
-#ifndef __WXWINCE__
-        && (errno != ERANGE)
+    WX_STRING_TO_X_TYPE_START
+#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
+    unsigned long val = wxStrtoul_lA(start, &end, base, wxCLocale);
+#else
+    unsigned long val = wxStrtoul_l(start, &end, base, wxCLocale);
 #endif
 #endif
-    ;
+    WX_STRING_TO_X_TYPE_END
 }
 
 }
 
+bool wxString::ToCDouble(double *pVal) const
+{
+    WX_STRING_TO_X_TYPE_START
+#if wxUSE_UNICODE_UTF8 || !wxUSE_UNICODE
+    double val = wxStrtod_lA(start, &end, wxCLocale);
+#else
+    double val = wxStrtod_l(start, &end, wxCLocale);
+#endif
+    WX_STRING_TO_X_TYPE_END
+}
+
+#endif  // wxUSE_XLOCALE
+
 // ---------------------------------------------------------------------------
 // formatted output
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // formatted output
 // ---------------------------------------------------------------------------
@@ -1603,11 +1851,23 @@ int wxString::DoPrintfUtf8(const char *format, ...)
     and set errno.
 
     What vswprintf sets errno to is undefined but Darwin seems to set it to
     and set errno.
 
     What vswprintf sets errno to is undefined but Darwin seems to set it to
-    EOVERFLOW.  The only expected errno that are defined anywhere are by an
-    addendum indicating that EILSEQ should be set for bad input characters and
-    EINVALID for bad arguments such as a NULL buffer pointer.  It would appear
-    that setting EOVERFLOW is not documented anywhere and has only been at
-    this time observed on Darwin.
+    EOVERFLOW.  The only expected errno are EILSEQ and EINVAL.  Both of
+    those are defined in the standard and backed up by several conformance
+    statements.  Note that ENOMEM mentioned in the manual page does not
+    apply to swprintf, only wprintf and fwprintf.
+
+    Official manual page:
+    http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html
+
+    Some conformance statements (AIX, Solaris):
+    http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3
+    http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10
+
+    Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since
+    EILSEQ and EINVAL are specifically defined to mean the error is other than
+    an undersized buffer and no other errno are defined we treat those two
+    as meaning hard errors and everything else gets the old behavior which
+    is to keep looping and increasing buffer size until the function succeeds.
 
     In practice it's impossible to determine before compilation which behavior
     may be used.  The vswprintf function may have vsnprintf-like behavior or
 
     In practice it's impossible to determine before compilation which behavior
     may be used.  The vswprintf function may have vsnprintf-like behavior or
@@ -1704,22 +1964,21 @@ static int DoStringPrintfV(wxString& str,
             // as we don't know how much we need, double the current size of
             // the buffer
 #ifndef __WXWINCE__
             // as we don't know how much we need, double the current size of
             // the buffer
 #ifndef __WXWINCE__
-            if( (errno == 0) || (errno == EOVERFLOW) )
+            if( (errno == EILSEQ) || (errno == EINVAL) )
+            // If errno was set to one of the two well-known hard errors
+            // then fail immediately to avoid an infinite loop.
+                return -1;
+            else
+#endif // __WXWINCE__
             // still not enough, as we don't know how much we need, double the
             // current size of the buffer
                 size *= 2;
             // still not enough, as we don't know how much we need, double the
             // current size of the buffer
                 size *= 2;
-            else
-            // If errno was set to something else, assume hard failure.
-                return -1;
-#else
-            size *= 2;
-#endif // __WXWINCE__
 #endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
         }
         else if ( len >= size )
         {
 #if wxUSE_WXVSNPRINTF
 #endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF
         }
         else if ( len >= size )
         {
 #if wxUSE_WXVSNPRINTF
-            // we know that our own implementation of wxVsnprintf() returns 
+            // 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
             // 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
@@ -1831,8 +2090,8 @@ bool wxString::Matches(const wxString& mask) const
 
   // FIXME-UTF8: implement using iterators, remove #if
 #if wxUSE_UNICODE_UTF8
 
   // FIXME-UTF8: implement using iterators, remove #if
 #if wxUSE_UNICODE_UTF8
-  wxWCharBuffer maskBuf = mask.wc_str();
-  wxWCharBuffer txtBuf = wc_str();
+  const wxScopedWCharBuffer maskBuf = mask.wc_str();
+  const wxScopedWCharBuffer txtBuf = wc_str();
   const wxChar *pszMask = maskBuf.data();
   const wxChar *pszTxt = txtBuf.data();
 #else
   const wxChar *pszMask = maskBuf.data();
   const wxChar *pszTxt = txtBuf.data();
 #else
@@ -1934,38 +2193,3 @@ int wxString::Freq(wxUniChar ch) const
     return count;
 }
 
     return count;
 }
 
-// convert to upper case, return the copy of the string
-wxString wxString::Upper() const
-{ wxString s(*this); return s.MakeUpper(); }
-
-// convert to lower case, return the copy of the string
-wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
-
-// ----------------------------------------------------------------------------
-// wxUTF8StringBuffer
-// ----------------------------------------------------------------------------
-
-#if wxUSE_UNICODE_WCHAR
-wxUTF8StringBuffer::~wxUTF8StringBuffer()
-{
-    wxMBConvStrictUTF8 conv;
-    size_t wlen = conv.ToWChar(NULL, 0, m_buf);
-    wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" );
-
-    wxStringInternalBuffer wbuf(m_str, wlen);
-    conv.ToWChar(wbuf, wlen, m_buf);
-}
-
-wxUTF8StringBufferLength::~wxUTF8StringBufferLength()
-{
-    wxCHECK_RET(m_lenSet, "length not set");
-
-    wxMBConvStrictUTF8 conv;
-    size_t wlen = conv.ToWChar(NULL, 0, m_buf, m_len);
-    wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" );
-
-    wxStringInternalBufferLength wbuf(m_str, wlen);
-    conv.ToWChar(wbuf, wlen, m_buf, m_len);
-    wbuf.SetLength(wlen);
-}
-#endif // wxUSE_UNICODE_WCHAR