]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
Handle hot spots in wxImage::Rotate90().
[wxWidgets.git] / src / common / string.cpp
index dcac014916affa78c76d317829b52d2a74ced9d3..e5db843659ab227454fe1ce824505428a1fe694b 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef WX_PRECOMP
     #include "wx/string.h"
     #include "wx/wxcrtvararg.h"
+    #include "wx/intl.h"
     #include "wx/log.h"
 #endif
 
     #include "wx/msw/wrapwin.h"
 #endif // __WXMSW__
 
+#if wxUSE_STD_IOSTREAM
+    #include <sstream>
+#endif
+
 // string handling functions used by wxString:
 #if wxUSE_UNICODE_UTF8
     #define wxStringMemcpy   memcpy
@@ -1078,34 +1083,63 @@ size_t wxString::find_last_not_of(const wxOtherCharType* sz, size_t nStart,
 
 int wxString::CmpNoCase(const wxString& s) const
 {
-#if defined(__WXMSW__) && !wxUSE_UNICODE_UTF8
-    // prefer to use CompareString() if available as it's more efficient than
-    // doing it manual or even using wxStricmp() (see #10375)
-    switch ( ::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
-                             m_impl.c_str(), m_impl.length(),
-                             s.m_impl.c_str(), s.m_impl.length()) )
+#if !wxUSE_UNICODE_UTF8
+    // We compare NUL-delimited chunks of the strings inside the loop. We will
+    // do as many iterations as there are embedded NULs in the string, i.e.
+    // usually we will run it just once.
+
+    typedef const wxStringImpl::value_type *pchar_type;
+    const pchar_type thisBegin = m_impl.c_str();
+    const pchar_type thatBegin = s.m_impl.c_str();
+
+    const pchar_type thisEnd = thisBegin + m_impl.length();
+    const pchar_type thatEnd = thatBegin + s.m_impl.length();
+
+    pchar_type thisCur = thisBegin;
+    pchar_type thatCur = thatBegin;
+
+    int rc;
+    for ( ;; )
     {
-        case CSTR_LESS_THAN:
-            return -1;
+        // Compare until the next NUL, if the strings differ this is the final
+        // result.
+        rc = wxStricmp(thisCur, thatCur);
+        if ( rc )
+            break;
 
-        case CSTR_EQUAL:
-            return 0;
+        const size_t lenChunk = wxStrlen(thisCur);
+        thisCur += lenChunk;
+        thatCur += lenChunk;
 
-        case CSTR_GREATER_THAN:
-            return 1;
+        // Skip all the NULs as wxStricmp() doesn't handle them.
+        for ( ; !*thisCur; thisCur++, thatCur++ )
+        {
+            // Check if we exhausted either of the strings.
+            if ( thisCur == thisEnd )
+            {
+                // This one is exhausted, is the other one too?
+                return thatCur == thatEnd ? 0 : -1;
+            }
 
-        default:
-            wxFAIL_MSG( "unexpected CompareString() return value" );
-            // fall through
+            if ( thatCur == thatEnd )
+            {
+                // Because of the test above we know that this one is not
+                // exhausted yet so it's greater than the other one that is.
+                return 1;
+            }
 
-        case 0:
-            wxLogLastError("CompareString");
-            // use generic code below
+            if ( *thatCur )
+            {
+                // Anything non-NUL is greater than NUL.
+                return -1;
+            }
+        }
     }
-#endif // __WXMSW__ && !wxUSE_UNICODE_UTF8
 
-    // do the comparison manually: notice that we can't use wxStricmp() as it
-    // doesn't handle embedded NULs
+    return rc;
+#else // wxUSE_UNICODE_UTF8
+    // CRT functions can't be used for case-insensitive comparison of UTF-8
+    // strings so do it in the naive, simple and inefficient way.
 
     // FIXME-UTF8: use wxUniChar::ToLower/ToUpper once added
     const_iterator i1 = begin();
@@ -1129,6 +1163,7 @@ int wxString::CmpNoCase(const wxString& s) const
     else if ( len1 > len2 )
         return 1;
     return 0;
+#endif // !wxUSE_UNICODE_UTF8/wxUSE_UNICODE_UTF8
 }
 
 
@@ -1314,22 +1349,43 @@ wxString wxString::Left(size_t nCount) const
 
 // get all characters before the first occurrence of ch
 // (returns the whole string if ch not found)
-wxString wxString::BeforeFirst(wxUniChar ch) const
+wxString wxString::BeforeFirst(wxUniChar ch, wxString *rest) const
 {
   int iPos = Find(ch);
   if ( iPos == wxNOT_FOUND )
-      iPos = length();
+  {
+    iPos = length();
+    if ( rest )
+      rest->clear();
+  }
+  else
+  {
+    if ( rest )
+      rest->assign(*this, iPos + 1, npos);
+  }
+
   return wxString(*this, 0, iPos);
 }
 
 /// get all characters before the last occurrence of ch
 /// (returns empty string if ch not found)
-wxString wxString::BeforeLast(wxUniChar ch) const
+wxString wxString::BeforeLast(wxUniChar ch, wxString *rest) const
 {
   wxString str;
   int iPos = Find(ch, true);
-  if ( iPos != wxNOT_FOUND && iPos != 0 )
-    str = wxString(c_str(), iPos);
+  if ( iPos != wxNOT_FOUND )
+  {
+    if ( iPos != 0 )
+      str.assign(*this, 0, iPos);
+
+    if ( rest )
+      rest->assign(*this, iPos + 1, npos);
+  }
+  else
+  {
+    if ( rest )
+      *rest = *this;
+  }
 
   return str;
 }
@@ -1727,7 +1783,87 @@ bool wxString::ToCDouble(double *pVal) const
     WX_STRING_TO_X_TYPE_END
 }
 
-#endif  // wxUSE_XLOCALE
+#else // wxUSE_XLOCALE
+
+// Provide implementation of these functions even when wxUSE_XLOCALE is
+// disabled, we still need them in wxWidgets internal code.
+
+// For integers we just assume the current locale uses the same number
+// representation as the C one as there is nothing else we can do.
+bool wxString::ToCLong(long *pVal, int base) const
+{
+    return ToLong(pVal, base);
+}
+
+bool wxString::ToCULong(unsigned long *pVal, int base) const
+{
+    return ToULong(pVal, base);
+}
+
+// For floating point numbers we have to handle the problem of the decimal
+// point which is different in different locales.
+bool wxString::ToCDouble(double *pVal) const
+{
+    // Create a copy of this string using the decimal point instead of whatever
+    // separator the current locale uses.
+#if wxUSE_INTL
+    wxString sep = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
+                                     wxLOCALE_CAT_NUMBER);
+    if ( sep == "." )
+    {
+        // We can avoid an unnecessary string copy in this case.
+        return ToDouble(pVal);
+    }
+#else // !wxUSE_INTL
+    // We don't know what the current separator is so it might even be a point
+    // already, try to parse the string as a double:
+    if ( ToDouble(pVal) )
+    {
+        // It must have been the point, nothing else to do.
+        return true;
+    }
+
+    // Try to guess the separator, using the most common alternative value.
+    wxString sep(",");
+#endif // wxUSE_INTL/!wxUSE_INTL
+    wxString cstr(*this);
+    cstr.Replace(".", sep);
+
+    return cstr.ToDouble(pVal);
+}
+
+#endif  // wxUSE_XLOCALE/!wxUSE_XLOCALE
+
+// ----------------------------------------------------------------------------
+// number to string conversion
+// ----------------------------------------------------------------------------
+
+/* static */
+wxString wxString::FromCDouble(double val)
+{
+#if wxUSE_STD_IOSTREAM && wxUSE_STD_STRING
+    // We assume that we can use the ostream and not wstream for numbers.
+    wxSTD ostringstream os;
+    os << val;
+    return os.str();
+#else // wxUSE_STD_IOSTREAM
+    // Can't use iostream locale support, fall back to the manual method
+    // instead.
+    wxString s = FromDouble(val);
+#if wxUSE_INTL
+    wxString sep = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
+                                     wxLOCALE_CAT_NUMBER);
+#else // !wxUSE_INTL
+    // As above, this is the most common alternative value. Notice that here it
+    // doesn't matter if we guess wrongly and the current separator is already
+    // ".": we'll just waste a call to Replace() in this case.
+    wxString sep(",");
+#endif // wxUSE_INTL/!wxUSE_INTL
+
+    s.Replace(sep, ".");
+    return s;
+#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM
+}
 
 // ---------------------------------------------------------------------------
 // formatted output
@@ -1897,11 +2033,6 @@ static int DoStringPrintfV(wxString& str,
         if ( !buf )
         {
             // out of memory
-
-            // in UTF-8 build, leaving uninitialized junk in the buffer
-            // could result in invalid non-empty UTF-8 string, so just
-            // reset the string to empty on failure:
-            buf[0] = '\0';
             return -1;
         }