From 31bccc83b946f0dd2b8cbfe5644d552b41996121 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Tue, 5 Apr 2016 21:55:51 +0200
Subject: [PATCH] fixed locale problems

---
 src/json.hpp      | 64 ++++++++++++++++++++++++-----------------------
 src/json.hpp.re2c | 64 ++++++++++++++++++++++++-----------------------
 test/unit.cpp     | 27 ++++++++++++++++++++
 3 files changed, 93 insertions(+), 62 deletions(-)

diff --git a/src/json.hpp b/src/json.hpp
index 0594b38d..13a6c49a 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -6114,24 +6114,26 @@ class basic_json
 
             case value_t::number_float:
             {
-                // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
-                char buf[263];
-                int len;
-
                 // check if number was parsed from a string
                 if (m_type.bits.parsed)
                 {
                     // check if parsed number had an exponent given
                     if (m_type.bits.has_exp)
                     {
+                        // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
+                        char buf[263];
+                        int len;
+
                         // handle capitalization of the exponent
                         if (m_type.bits.exp_cap)
                         {
-                            len = snprintf(buf, sizeof(buf), "%.*E", m_type.bits.precision, m_value.number_float) + 1;
+                            len = snprintf(buf, sizeof(buf), "%.*E",
+                                           m_type.bits.precision, m_value.number_float) + 1;
                         }
                         else
                         {
-                            len = snprintf(buf, sizeof(buf), "%.*e", m_type.bits.precision, m_value.number_float) + 1;
+                            len = snprintf(buf, sizeof(buf), "%.*e",
+                                           m_type.bits.precision, m_value.number_float) + 1;
                         }
 
                         // remove '+' sign from the exponent if necessary
@@ -6152,40 +6154,40 @@ class basic_json
                                 }
                             }
                         }
+
+                        o << buf;
                     }
                     else
                     {
                         // no exponent - output as a decimal
-                        snprintf(buf, sizeof(buf), "%.*f",
-                                 m_type.bits.precision, m_value.number_float);
+                        std::stringstream ss;
+                        ss.imbue(std::locale("C"));
+                        ss << std::setprecision(m_type.bits.precision)
+                           << std::fixed << m_value.number_float;
+                        o << ss.str();
                     }
                 }
-                else if (m_value.number_float == 0)
-                {
-                    // special case for zero to get "0.0"/"-0.0"
-                    if (std::signbit(m_value.number_float))
-                    {
-                        o << "-0.0";
-                    }
-                    else
-                    {
-                        o << "0.0";
-                    }
-                    return;
-                }
                 else
                 {
-                    // Otherwise 6, 15 or 16 digits of precision allows
-                    // round-trip IEEE 754 string->float->string,
-                    // string->double->string or string->long double->string;
-                    // to be safe, we read this value from
-                    // std::numeric_limits<number_float_t>::digits10
-                    snprintf(buf, sizeof(buf), "%.*g",
-                             std::numeric_limits<double>::digits10,
-                             m_value.number_float);
+                    if (m_value.number_float == 0)
+                    {
+                        // special case for zero to get "0.0"/"-0.0"
+                        o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
+                    }
+                    else
+                    {
+                        // Otherwise 6, 15 or 16 digits of precision allows
+                        // round-trip IEEE 754 string->float->string,
+                        // string->double->string or string->long double->string;
+                        // to be safe, we read this value from
+                        // std::numeric_limits<number_float_t>::digits10
+                        std::stringstream ss;
+                        ss.imbue(std::locale("C"));
+                        ss << std::setprecision(std::numeric_limits<double>::digits10)
+                           << m_value.number_float;
+                        o << ss.str();
+                    }
                 }
-
-                o << buf;
                 return;
             }
 
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index f4ddacf7..70079144 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -6114,24 +6114,26 @@ class basic_json
 
             case value_t::number_float:
             {
-                // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
-                char buf[263];
-                int len;
-
                 // check if number was parsed from a string
                 if (m_type.bits.parsed)
                 {
                     // check if parsed number had an exponent given
                     if (m_type.bits.has_exp)
                     {
+                        // buffer size: precision (2^8-1 = 255) + other ('-.e-xxx' = 7) + null (1)
+                        char buf[263];
+                        int len;
+
                         // handle capitalization of the exponent
                         if (m_type.bits.exp_cap)
                         {
-                            len = snprintf(buf, sizeof(buf), "%.*E", m_type.bits.precision, m_value.number_float) + 1;
+                            len = snprintf(buf, sizeof(buf), "%.*E",
+                                           m_type.bits.precision, m_value.number_float) + 1;
                         }
                         else
                         {
-                            len = snprintf(buf, sizeof(buf), "%.*e", m_type.bits.precision, m_value.number_float) + 1;
+                            len = snprintf(buf, sizeof(buf), "%.*e",
+                                           m_type.bits.precision, m_value.number_float) + 1;
                         }
 
                         // remove '+' sign from the exponent if necessary
@@ -6152,40 +6154,40 @@ class basic_json
                                 }
                             }
                         }
+
+                        o << buf;
                     }
                     else
                     {
                         // no exponent - output as a decimal
-                        snprintf(buf, sizeof(buf), "%.*f",
-                                 m_type.bits.precision, m_value.number_float);
+                        std::stringstream ss;
+                        ss.imbue(std::locale("C"));  // fix locale problems
+                        ss << std::setprecision(m_type.bits.precision)
+                           << std::fixed << m_value.number_float;
+                        o << ss.str();
                     }
                 }
-                else if (m_value.number_float == 0)
-                {
-                    // special case for zero to get "0.0"/"-0.0"
-                    if (std::signbit(m_value.number_float))
-                    {
-                        o << "-0.0";
-                    }
-                    else
-                    {
-                        o << "0.0";
-                    }
-                    return;
-                }
                 else
                 {
-                    // Otherwise 6, 15 or 16 digits of precision allows
-                    // round-trip IEEE 754 string->float->string,
-                    // string->double->string or string->long double->string;
-                    // to be safe, we read this value from
-                    // std::numeric_limits<number_float_t>::digits10
-                    snprintf(buf, sizeof(buf), "%.*g",
-                             std::numeric_limits<double>::digits10,
-                             m_value.number_float);
+                    if (m_value.number_float == 0)
+                    {
+                        // special case for zero to get "0.0"/"-0.0"
+                        o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
+                    }
+                    else
+                    {
+                        // Otherwise 6, 15 or 16 digits of precision allows
+                        // round-trip IEEE 754 string->float->string,
+                        // string->double->string or string->long double->string;
+                        // to be safe, we read this value from
+                        // std::numeric_limits<number_float_t>::digits10
+                        std::stringstream ss;
+                        ss.imbue(std::locale("C"));  // fix locale problems
+                        ss << std::setprecision(std::numeric_limits<double>::digits10)
+                           << m_value.number_float;
+                        o << ss.str();
+                    }
                 }
-
-                o << buf;
                 return;
             }
 
diff --git a/test/unit.cpp b/test/unit.cpp
index b440a28b..85f8b229 100644
--- a/test/unit.cpp
+++ b/test/unit.cpp
@@ -12369,5 +12369,32 @@ TEST_CASE("regression tests")
         j_long_double = 1.23e45L;
         CHECK(j_long_double.get<long double>() == 1.23e45L);
     }
+
+    SECTION("issue #228 - double values are serialized with commas as decimal points")
+    {
+        json j1a = 23.42;
+        json j1b = json::parse("23.42");
+
+        json j2a = 2342e-2;
+        //issue #230
+        //json j2b = json::parse("2342e-2");
+
+        json j3a = 10E3;
+        json j3b = json::parse("10E3");
+        json j3c = json::parse("10e3");
+
+        std::locale::global(std::locale("de_DE"));
+
+        CHECK(j1a.dump() == "23.42");
+        CHECK(j1b.dump() == "23.42");
+
+        CHECK(j2a.dump() == "23.42");
+        //issue #230
+        //CHECK(j2b.dump() == "23.42");
+
+        CHECK(j3a.dump() == "10000");
+        CHECK(j3b.dump() == "1E04");
+        CHECK(j3c.dump() == "1e04");
+    }
 }