From be230c1a29fd87e6759bdca439598f117aef3c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 17 May 2015 21:23:08 +0200 Subject: [PATCH] Add a version of std::stod which takes locale. We need a string-to-double conversion function which acts the same on all computers, irrespective of which locale is running. We need to guarantee that the function expects '.' as the decimal point, and not ','. The choice of en-US is more or less arbitrary. --- PowerEditor/src/MISC/Common/Common.cpp | 16 ++++++++++++++++ PowerEditor/src/MISC/Common/Common.h | 1 + PowerEditor/src/MISC/Common/Sorters.h | 18 +++++++++++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 37a825c13..e52364751 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -761,4 +761,20 @@ generic_string stringTakeWhileAdmissable(const generic_string& input, const gene { return input.substr(0, idx); } +} + +double stodLocale(const generic_string& str, _locale_t loc, size_t* idx) +{ + // Copied from the std::stod implementation but uses _wcstod_l instead of wcstod. + const wchar_t* ptr = str.c_str(); + errno = 0; + wchar_t* eptr; + double ans = ::_wcstod_l(ptr, &eptr, loc); + if (ptr == eptr) + throw new std::invalid_argument("invalid stod argument"); + if (errno == ERANGE) + throw new std::out_of_range("stod argument out of range"); + if (idx != NULL) + *idx = (size_t)(eptr - ptr); + return ans; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 78180d050..44b1c1ce1 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -191,5 +191,6 @@ generic_string stringReplace(generic_string subject, const generic_string& searc std::vector stringSplit(const generic_string& input, const generic_string& delimiter); generic_string stringJoin(const std::vector& strings, const generic_string& separator); generic_string stringTakeWhileAdmissable(const generic_string& input, const generic_string& admissable); +double stodLocale(const generic_string& str, _locale_t loc, size_t* idx = NULL); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/MISC/Common/Sorters.h b/PowerEditor/src/MISC/Common/Sorters.h index a2d136a8b..2e758772a 100644 --- a/PowerEditor/src/MISC/Common/Sorters.h +++ b/PowerEditor/src/MISC/Common/Sorters.h @@ -79,7 +79,15 @@ template class NumericSorter : public ISorter { public: - NumericSorter(bool isDescending) : ISorter(isDescending) { }; + NumericSorter(bool isDescending) : ISorter(isDescending) + { + _usLocale = ::_wcreate_locale(LC_NUMERIC, TEXT("en-US")); + }; + + ~NumericSorter() + { + ::_free_locale(_usLocale); + } std::vector sort(std::vector lines) override { @@ -151,6 +159,10 @@ protected: // Should convert the input string to a number of the correct type. // If unable to convert, throw either std::invalid_argument or std::out_of_range. virtual T_Num convertStringToNumber(const generic_string& input) = 0; + + // We need a fixed locale so we get the same string-to-double behavior across all computers. + // This is the "enUS" locale. + _locale_t _usLocale; }; // Converts lines to long long before sorting. @@ -186,7 +198,7 @@ protected: double convertStringToNumber(const generic_string& input) override { - return std::stod(input); + return stodLocale(input, _usLocale); } }; @@ -204,7 +216,7 @@ protected: double convertStringToNumber(const generic_string& input) override { - return std::stod(input); + return stodLocale(input, _usLocale); } };