From 72448a032a7dfac3013b38f9cf0a942342c6cb4a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 30 Jun 2014 00:27:13 +0000 Subject: [PATCH] Don't use C++ streams in wxString::FromCDouble() implementation. This doesn't work if the global C++ locale had been changed and we can't call imbue(locale::classic()) to ensure that the stream we use here uses the C locale because imbue() is hopelessly broken in some implementations. So just get rid of this code and keep only the hack replacing the decimal separator with the dot explicitly. This is ugly but should always work in practice and is also consistent with ToCDouble(). Closes #16343. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_3_0_BRANCH@76791 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 4 ++++ src/common/string.cpp | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 534c4e2a5e..fd699e54be 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -577,6 +577,10 @@ Major new features in this release 3.0.2: (released 2014-xx-xx) ---------------------------- +All: + +- Make wxString::FromCDouble() work when the global C++ locale is not the C one. + wxMSW: - Fix Cygwin 1.7 build. diff --git a/src/common/string.cpp b/src/common/string.cpp index a2f18a8b49..c2b2292b1c 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1797,6 +1797,8 @@ bool wxString::ToCULong(unsigned long *pVal, int base) const // point which is different in different locales. bool wxString::ToCDouble(double *pVal) const { + // See the explanations in FromCDouble() below for the reasons for all this. + // Create a copy of this string using the decimal point instead of whatever // separator the current locale uses. #if wxUSE_INTL @@ -1854,20 +1856,19 @@ wxString wxString::FromCDouble(double val, int precision) { wxCHECK_MSG( precision >= -1, wxString(), "Invalid negative precision" ); -#if wxUSE_STD_IOSTREAM && wxUSE_STD_STRING - // We assume that we can use the ostream and not wstream for numbers. - wxSTD ostringstream os; - if ( precision != -1 ) - { - os.precision(precision); - os.setf(std::ios::fixed, std::ios::floatfield); - } + // Unfortunately there is no good way to get the number directly in the C + // locale. Some platforms provide special functions to do this (e.g. + // _sprintf_l() in MSVS or sprintf_l() in BSD systems), but some systems we + // still support don't have them and it doesn't seem worth it to have two + // different ways to do the same thing. Also, in principle, using the + // standard C++ streams should allow us to do it, but some implementations + // of them are horribly broken and actually change the global C locale, + // thus randomly affecting the results produced in other threads, when + // imbue() stream method is called (for the record, the latest libstdc++ + // version included in OS X does it and so seem to do the versions + // currently included in Android NDK and both FreeBSD and OpenBSD), so we + // can't do this neither and are reduced to this hack. - 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, precision); #if wxUSE_INTL wxString sep = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, @@ -1881,7 +1882,6 @@ wxString wxString::FromCDouble(double val, int precision) s.Replace(sep, "."); return s; -#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM } // ---------------------------------------------------------------------------