Bugfix: when working with C formatting functions we need to query C locales (localeconv) rather than std::locale
This commit is contained in:
parent
82b82fd487
commit
738d462955
2 changed files with 72 additions and 46 deletions
59
src/json.hpp
59
src/json.hpp
|
@ -6419,11 +6419,14 @@ class basic_json
|
|||
|
||||
private:
|
||||
static constexpr size_t s_capacity = 30;
|
||||
std::array<char, s_capacity + 2> m_buf{};
|
||||
std::array<char, s_capacity + 2> m_buf{}; // +2 for leading '-'
|
||||
// and trailing '\0'
|
||||
|
||||
template<typename T>
|
||||
void x_write(T x, std::true_type)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::digits10 <= s_capacity, "");
|
||||
|
||||
const bool is_neg = x < 0;
|
||||
size_t i = 0;
|
||||
|
||||
|
@ -6433,12 +6436,7 @@ class basic_json
|
|||
x /= 10;
|
||||
}
|
||||
|
||||
if(i == s_capacity)
|
||||
{
|
||||
std::runtime_error(
|
||||
"Number is unexpectedly long: "
|
||||
+ std::to_string(x));
|
||||
}
|
||||
assert(i < s_capacity);
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
|
@ -6478,34 +6476,49 @@ class basic_json
|
|||
|
||||
snprintf(m_buf.data(), m_buf.size(), fmt, x);
|
||||
|
||||
#if 0
|
||||
// C locales and C++ locales are similar but
|
||||
// different.
|
||||
//
|
||||
// If working with C++ streams we'd've used
|
||||
// these, but for C formatting functions we
|
||||
// have to use C locales (setlocale / localeconv),
|
||||
// rather than C++ locales (std::locale installed
|
||||
// by std::locale::global()).
|
||||
const std::locale loc;
|
||||
|
||||
// erase thousands separator
|
||||
{
|
||||
const char sep =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).thousands_sep();
|
||||
const char thousands_sep =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).thousands_sep();
|
||||
|
||||
const char decimal_point =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).decimal_point();
|
||||
#else
|
||||
const auto loc = localeconv();
|
||||
assert(loc != nullptr);
|
||||
const char thousands_sep = !loc->thousands_sep ? '\0'
|
||||
: loc->thousands_sep[0];
|
||||
|
||||
const char decimal_point = !loc->decimal_point ? '\0'
|
||||
: loc->decimal_point[0];
|
||||
#endif
|
||||
|
||||
// erase thousands separator
|
||||
if (thousands_sep) {
|
||||
auto end = std::remove(m_buf.begin(),
|
||||
m_buf.end(),
|
||||
sep);
|
||||
thousands_sep);
|
||||
|
||||
std::fill(end, m_buf.end(), '\0');
|
||||
}
|
||||
|
||||
// convert decimal point to '.'
|
||||
if (decimal_point and decimal_point != '.')
|
||||
{
|
||||
const char decimal_point =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).decimal_point();
|
||||
|
||||
for(auto& c : m_buf)
|
||||
for (auto& c : m_buf)
|
||||
{
|
||||
if(decimal_point == '.') {
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == decimal_point)
|
||||
if (c == decimal_point)
|
||||
{
|
||||
c = '.';
|
||||
break;
|
||||
|
|
|
@ -6419,11 +6419,14 @@ class basic_json
|
|||
|
||||
private:
|
||||
static constexpr size_t s_capacity = 30;
|
||||
std::array<char, s_capacity + 2> m_buf{};
|
||||
std::array<char, s_capacity + 2> m_buf{}; // +2 for leading '-'
|
||||
// and trailing '\0'
|
||||
|
||||
template<typename T>
|
||||
void x_write(T x, std::true_type)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::digits10 <= s_capacity, "");
|
||||
|
||||
const bool is_neg = x < 0;
|
||||
size_t i = 0;
|
||||
|
||||
|
@ -6433,12 +6436,7 @@ class basic_json
|
|||
x /= 10;
|
||||
}
|
||||
|
||||
if(i == s_capacity)
|
||||
{
|
||||
std::runtime_error(
|
||||
"Number is unexpectedly long: "
|
||||
+ std::to_string(x));
|
||||
}
|
||||
assert(i < s_capacity);
|
||||
|
||||
if(i == 0)
|
||||
{
|
||||
|
@ -6478,34 +6476,49 @@ class basic_json
|
|||
|
||||
snprintf(m_buf.data(), m_buf.size(), fmt, x);
|
||||
|
||||
#if 0
|
||||
// C locales and C++ locales are similar but
|
||||
// different.
|
||||
//
|
||||
// If working with C++ streams we'd've used
|
||||
// these, but for C formatting functions we
|
||||
// have to use C locales (setlocale / localeconv),
|
||||
// rather than C++ locales (std::locale installed
|
||||
// by std::locale::global()).
|
||||
const std::locale loc;
|
||||
|
||||
// erase thousands separator
|
||||
{
|
||||
const char sep =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).thousands_sep();
|
||||
const char thousands_sep =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).thousands_sep();
|
||||
|
||||
const char decimal_point =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).decimal_point();
|
||||
#else
|
||||
const auto loc = localeconv();
|
||||
assert(loc != nullptr);
|
||||
const char thousands_sep = !loc->thousands_sep ? '\0'
|
||||
: loc->thousands_sep[0];
|
||||
|
||||
const char decimal_point = !loc->decimal_point ? '\0'
|
||||
: loc->decimal_point[0];
|
||||
#endif
|
||||
|
||||
// erase thousands separator
|
||||
if (thousands_sep) {
|
||||
auto end = std::remove(m_buf.begin(),
|
||||
m_buf.end(),
|
||||
sep);
|
||||
thousands_sep);
|
||||
|
||||
std::fill(end, m_buf.end(), '\0');
|
||||
}
|
||||
|
||||
// convert decimal point to '.'
|
||||
if (decimal_point and decimal_point != '.')
|
||||
{
|
||||
const char decimal_point =
|
||||
std::use_facet< std::numpunct<char> >(
|
||||
loc).decimal_point();
|
||||
|
||||
for(auto& c : m_buf)
|
||||
for (auto& c : m_buf)
|
||||
{
|
||||
if(decimal_point == '.') {
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == decimal_point)
|
||||
if (c == decimal_point)
|
||||
{
|
||||
c = '.';
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue