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); } };