X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/69d31e313035d5e22d9400ec946f6007f710910c..6f3f38980f10a935f3b47dbf0d3b4643e96a4be2:/src/common/string.cpp diff --git a/src/common/string.cpp b/src/common/string.cpp index 9e9ba528fc..e5db843659 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -24,6 +24,7 @@ #ifndef WX_PRECOMP #include "wx/string.h" #include "wx/wxcrtvararg.h" + #include "wx/intl.h" #include "wx/log.h" #endif @@ -44,6 +45,10 @@ #include "wx/msw/wrapwin.h" #endif // __WXMSW__ +#if wxUSE_STD_IOSTREAM + #include +#endif + // string handling functions used by wxString: #if wxUSE_UNICODE_UTF8 #define wxStringMemcpy memcpy @@ -57,16 +62,20 @@ #define wxStringStrlen wxStrlen #endif -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - +// define a function declared in wx/buffer.h here as we don't have buffer.cpp +// and don't want to add it just because of this simple function namespace wxPrivate { -static UntypedBufferData s_untypedNullData(NULL, 0); +// wxXXXBuffer classes can be (implicitly) used during global statics +// initialization so wrap the status UntypedBufferData variable in a function +// to make it safe to access it even before all global statics are initialized +UntypedBufferData *GetUntypedNullData() +{ + static UntypedBufferData s_untypedNullData(NULL, 0); -UntypedBufferData * const untypedNullDataPtr = &s_untypedNullData; + return &s_untypedNullData; +} } // namespace wxPrivate @@ -1074,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(); @@ -1125,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 } @@ -1310,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; } @@ -1723,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 @@ -1893,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; }