Browse Source

Include <xlocale.h> before <stdlib.h>

I think that on macOS <xlocale.h> defines a macro, which is used by <stdlib.h> to
make the extended strtoX_l() functions available. This means that the inclusion
order is important. (+7 squashed commits)
Squashed commits:
[54ddbe6] Include stdlib.h on macOS too.
[cd1845f] Fix the macOS build.

On macOS, one should include <xlocale.h> in addition to <locale.h>.
[a7d757f] Overlooked one strtod() call.
[62a8f53] Include <locale.h> to fix the Windows build.
[f621cda] Fix Windows build.

Windows has a _create_locale() function instead of newlocale().
[65c4164] Fix Windows build.

Windows has _strtod_l(). Note the leading underscore.
[97e54e4] Make string to floating-point conversion independent from locale.

Instead of using strtod() for converting strings to doubles, use strtod_l()
with an explicit "C" locale. The problem of strtod() is that the decimal
separator changes with the locale. So an XML written on an English system
cannot be read on a German system, for example.

Using strtod_l() + "C" locale uses a dot as separator all the time (locale-independent).
Manuel Freiberger 8 years ago
parent
commit
e0e0dcb928
1 changed files with 114 additions and 67 deletions
  1. 114 67
      Source/Atomic/Core/StringUtils.cpp

+ 114 - 67
Source/Atomic/Core/StringUtils.cpp

@@ -28,6 +28,53 @@
 
 #include "../DebugNew.h"
 
+
+// The built-in strtod() function uses the current locale for parsing strings. On certain
+// locales (German, Swedish, ...) a comma is used as decimal separator. For portable XMLs,
+// we need to parse floating point values the same way on all platforms no matter what
+// locale is set. The strtod_c_locale() is a workaround using the "C" locale explicitly,
+// which uses a dot as decimal separator.
+
+#include <locale.h>
+#ifdef __APPLE__
+#include <xlocale.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef _WIN32
+
+static
+_locale_t get_c_locale()
+{
+    static _locale_t loc = _create_locale(LC_ALL, "C");
+    return loc;
+}
+
+static
+double strtod_c_locale(const char* nptr, char** endptr)
+{
+    return _strtod_l(nptr, endptr, get_c_locale());
+}
+
+#else
+
+static
+locale_t get_c_locale()
+{
+    static locale_t loc = newlocale(LC_ALL_MASK, "C", NULL);
+    return loc;
+}
+
+static
+double strtod_c_locale(const char* nptr, char** endptr)
+{
+    return strtod_l(nptr, endptr, get_c_locale());
+}
+
+#endif // _WIN32
+
+
 namespace Atomic
 {
 
@@ -146,7 +193,7 @@ float ToFloat(const char* source)
     if (!source)
         return 0;
 
-    return (float)strtod(source, 0);
+    return (float)strtod_c_locale(source, 0);
 }
 
 double ToDouble(const String& source)
@@ -159,7 +206,7 @@ double ToDouble(const char* source)
     if (!source)
         return 0;
 
-    return strtod(source, 0);
+    return strtod_c_locale(source, 0);
 }
 
 Color ToColor(const String& source)
@@ -176,11 +223,11 @@ Color ToColor(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.r_ = (float)strtod(ptr, &ptr);
-    ret.g_ = (float)strtod(ptr, &ptr);
-    ret.b_ = (float)strtod(ptr, &ptr);
+    ret.r_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.g_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.b_ = (float)strtod_c_locale(ptr, &ptr);
     if (elements > 3)
-        ret.a_ = (float)strtod(ptr, &ptr);
+        ret.a_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }
@@ -241,10 +288,10 @@ Rect ToRect(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.min_.x_ = (float)strtod(ptr, &ptr);
-    ret.min_.y_ = (float)strtod(ptr, &ptr);
-    ret.max_.x_ = (float)strtod(ptr, &ptr);
-    ret.max_.y_ = (float)strtod(ptr, &ptr);
+    ret.min_.x_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.min_.y_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.max_.x_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.max_.y_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }
@@ -265,9 +312,9 @@ Quaternion ToQuaternion(const char* source)
     {
         // 3 coords specified: conversion from Euler angles
         float x, y, z;
-        x = (float)strtod(ptr, &ptr);
-        y = (float)strtod(ptr, &ptr);
-        z = (float)strtod(ptr, &ptr);
+        x = (float)strtod_c_locale(ptr, &ptr);
+        y = (float)strtod_c_locale(ptr, &ptr);
+        z = (float)strtod_c_locale(ptr, &ptr);
 
         return Quaternion(x, y, z);
     }
@@ -275,10 +322,10 @@ Quaternion ToQuaternion(const char* source)
     {
         // 4 coords specified: full quaternion
         Quaternion ret;
-        ret.w_ = (float)strtod(ptr, &ptr);
-        ret.x_ = (float)strtod(ptr, &ptr);
-        ret.y_ = (float)strtod(ptr, &ptr);
-        ret.z_ = (float)strtod(ptr, &ptr);
+        ret.w_ = (float)strtod_c_locale(ptr, &ptr);
+        ret.x_ = (float)strtod_c_locale(ptr, &ptr);
+        ret.y_ = (float)strtod_c_locale(ptr, &ptr);
+        ret.z_ = (float)strtod_c_locale(ptr, &ptr);
 
         return ret;
     }
@@ -298,8 +345,8 @@ Vector2 ToVector2(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.x_ = (float)strtod(ptr, &ptr);
-    ret.y_ = (float)strtod(ptr, &ptr);
+    ret.x_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.y_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }
@@ -318,9 +365,9 @@ Vector3 ToVector3(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.x_ = (float)strtod(ptr, &ptr);
-    ret.y_ = (float)strtod(ptr, &ptr);
-    ret.z_ = (float)strtod(ptr, &ptr);
+    ret.x_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.y_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.z_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }
@@ -342,23 +389,23 @@ Vector4 ToVector4(const char* source, bool allowMissingCoords)
         if (elements < 4)
             return ret;
 
-        ret.x_ = (float)strtod(ptr, &ptr);
-        ret.y_ = (float)strtod(ptr, &ptr);
-        ret.z_ = (float)strtod(ptr, &ptr);
-        ret.w_ = (float)strtod(ptr, &ptr);
+        ret.x_ = (float)strtod_c_locale(ptr, &ptr);
+        ret.y_ = (float)strtod_c_locale(ptr, &ptr);
+        ret.z_ = (float)strtod_c_locale(ptr, &ptr);
+        ret.w_ = (float)strtod_c_locale(ptr, &ptr);
 
         return ret;
     }
     else
     {
         if (elements > 0)
-            ret.x_ = (float)strtod(ptr, &ptr);
+            ret.x_ = (float)strtod_c_locale(ptr, &ptr);
         if (elements > 1)
-            ret.y_ = (float)strtod(ptr, &ptr);
+            ret.y_ = (float)strtod_c_locale(ptr, &ptr);
         if (elements > 2)
-            ret.z_ = (float)strtod(ptr, &ptr);
+            ret.z_ = (float)strtod_c_locale(ptr, &ptr);
         if (elements > 3)
-            ret.w_ = (float)strtod(ptr, &ptr);
+            ret.w_ = (float)strtod_c_locale(ptr, &ptr);
 
         return ret;
     }
@@ -426,15 +473,15 @@ Matrix3 ToMatrix3(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.m00_ = (float)strtod(ptr, &ptr);
-    ret.m01_ = (float)strtod(ptr, &ptr);
-    ret.m02_ = (float)strtod(ptr, &ptr);
-    ret.m10_ = (float)strtod(ptr, &ptr);
-    ret.m11_ = (float)strtod(ptr, &ptr);
-    ret.m12_ = (float)strtod(ptr, &ptr);
-    ret.m20_ = (float)strtod(ptr, &ptr);
-    ret.m21_ = (float)strtod(ptr, &ptr);
-    ret.m22_ = (float)strtod(ptr, &ptr);
+    ret.m00_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m01_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m02_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m10_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m11_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m12_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m20_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m21_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m22_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }
@@ -453,18 +500,18 @@ Matrix3x4 ToMatrix3x4(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.m00_ = (float)strtod(ptr, &ptr);
-    ret.m01_ = (float)strtod(ptr, &ptr);
-    ret.m02_ = (float)strtod(ptr, &ptr);
-    ret.m03_ = (float)strtod(ptr, &ptr);
-    ret.m10_ = (float)strtod(ptr, &ptr);
-    ret.m11_ = (float)strtod(ptr, &ptr);
-    ret.m12_ = (float)strtod(ptr, &ptr);
-    ret.m13_ = (float)strtod(ptr, &ptr);
-    ret.m20_ = (float)strtod(ptr, &ptr);
-    ret.m21_ = (float)strtod(ptr, &ptr);
-    ret.m22_ = (float)strtod(ptr, &ptr);
-    ret.m23_ = (float)strtod(ptr, &ptr);
+    ret.m00_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m01_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m02_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m03_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m10_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m11_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m12_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m13_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m20_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m21_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m22_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m23_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }
@@ -483,22 +530,22 @@ Matrix4 ToMatrix4(const char* source)
         return ret;
 
     char* ptr = (char*)source;
-    ret.m00_ = (float)strtod(ptr, &ptr);
-    ret.m01_ = (float)strtod(ptr, &ptr);
-    ret.m02_ = (float)strtod(ptr, &ptr);
-    ret.m03_ = (float)strtod(ptr, &ptr);
-    ret.m10_ = (float)strtod(ptr, &ptr);
-    ret.m11_ = (float)strtod(ptr, &ptr);
-    ret.m12_ = (float)strtod(ptr, &ptr);
-    ret.m13_ = (float)strtod(ptr, &ptr);
-    ret.m20_ = (float)strtod(ptr, &ptr);
-    ret.m21_ = (float)strtod(ptr, &ptr);
-    ret.m22_ = (float)strtod(ptr, &ptr);
-    ret.m23_ = (float)strtod(ptr, &ptr);
-    ret.m30_ = (float)strtod(ptr, &ptr);
-    ret.m31_ = (float)strtod(ptr, &ptr);
-    ret.m32_ = (float)strtod(ptr, &ptr);
-    ret.m33_ = (float)strtod(ptr, &ptr);
+    ret.m00_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m01_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m02_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m03_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m10_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m11_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m12_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m13_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m20_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m21_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m22_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m23_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m30_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m31_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m32_ = (float)strtod_c_locale(ptr, &ptr);
+    ret.m33_ = (float)strtod_c_locale(ptr, &ptr);
 
     return ret;
 }