Imported Upstream version 58.1
[platform/upstream/icu.git] / source / i18n / digitlst.cpp
index 16b9dc3..a3b3406 100644 (file)
@@ -1,3 +1,5 @@
+// Copyright (C) 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 **********************************************************************
 *   Copyright (C) 1997-2015, International Business Machines
 ******************************************************************************
 */
 
+#if defined(__CYGWIN__) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
 #include "digitlst.h"
 
 #if !UCONFIG_NO_FORMATTING
+
 #include "unicode/putil.h"
 #include "charstr.h"
 #include "cmemory.h"
 #include "putilimp.h"
 #include "uassert.h"
 #include "digitinterval.h" 
+#include "ucln_in.h"
+#include "umutex.h"
 #include <stdlib.h>
 #include <limits.h>
 #include <string.h>
 #include <stdio.h>
 #include <limits>
 
+#if !defined(U_USE_STRTOD_L)
+# if U_PLATFORM_USES_ONLY_WIN32_API
+#   define U_USE_STRTOD_L 1
+# elif defined(U_HAVE_STRTOD_L)
+#   define U_USE_STRTOD_L U_HAVE_STRTOD_L
+# else
+#   define U_USE_STRTOD_L 0
+# endif
+#endif
+
+#if U_USE_STRTOD_L && !U_PLATFORM_USES_ONLY_WIN32_API
+# if U_PLATFORM == U_PF_CYGWIN
+#   include <locale.h>
+# else
+#   include <xlocale.h>
+# endif
+#endif
+
 // ***************************************************************************
 // class DigitList
 //    A wrapper onto decNumber.
@@ -395,27 +422,6 @@ DigitList::append(char digit)
     internalClear();
 }
 
-char DigitList::getStrtodDecimalSeparator() {
-    // TODO: maybe use andy's pthread once.
-    static char gDecimal = 0;
-    char result;
-    {
-        Mutex mutex;
-        result = gDecimal;;
-        if (result == 0) {
-            // We need to know the decimal separator character that will be used with strtod().
-            // Depends on the C runtime global locale.
-            // Most commonly is '.'
-            // TODO: caching could fail if the global locale is changed on the fly.
-            char rep[MAX_DIGITS];
-            sprintf(rep, "%+1.1f", 1.0);
-            result = rep[2];
-            gDecimal = result;;
-        }
-    }
-    return result;
-}
-
 // -------------------------------------
 
 /**
@@ -428,24 +434,11 @@ char DigitList::getStrtodDecimalSeparator() {
 double
 DigitList::getDouble() const
 {
-    static char gDecimal = 0;
-    char decimalSeparator;
     {
         Mutex mutex;
         if (fHave == kDouble) {
             return fUnion.fDouble;
         }
-        decimalSeparator = gDecimal;
-    }
-
-    if (decimalSeparator == 0) {
-        // We need to know the decimal separator character that will be used with strtod().
-        // Depends on the C runtime global locale.
-        // Most commonly is '.'
-        // TODO: caching could fail if the global locale is changed on the fly.
-        char rep[MAX_DIGITS];
-        sprintf(rep, "%+1.1f", 1.0);
-        decimalSeparator = rep[2];
     }
 
     double tDouble = 0.0;
@@ -482,25 +475,72 @@ DigitList::getDouble() const
             uprv_decNumberToString(this->fDecNumber, s.getAlias());
         }
         U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
-        
-        if (decimalSeparator != '.') {
-            char *decimalPt = strchr(s.getAlias(), '.');
-            if (decimalPt != NULL) {
-                *decimalPt = decimalSeparator;
-            }
-        }
+
         char *end = NULL;
-        tDouble = uprv_strtod(s.getAlias(), &end);
+        tDouble = decimalStrToDouble(s.getAlias(), &end);
     }
     {
         Mutex mutex;
         DigitList *nonConstThis = const_cast<DigitList *>(this);
         nonConstThis->internalSetDouble(tDouble);
-        gDecimal = decimalSeparator;
     }
     return tDouble;
 }
 
+#if U_USE_STRTOD_L && U_PLATFORM_USES_ONLY_WIN32_API
+# define locale_t _locale_t
+# define freelocale _free_locale
+# define strtod_l _strtod_l
+#endif
+
+#if U_USE_STRTOD_L
+static locale_t gCLocale = (locale_t)0;
+#endif
+static icu::UInitOnce gCLocaleInitOnce = U_INITONCE_INITIALIZER;
+
+U_CDECL_BEGIN
+// Cleanup callback func
+static UBool U_CALLCONV digitList_cleanup(void)
+{
+#if U_USE_STRTOD_L
+    if (gCLocale != (locale_t)0) {
+        freelocale(gCLocale);
+    }
+#endif
+    return TRUE;
+}
+// C Locale initialization func
+static void U_CALLCONV initCLocale(void) {
+    ucln_i18n_registerCleanup(UCLN_I18N_DIGITLIST, digitList_cleanup);
+#if U_USE_STRTOD_L
+# if U_PLATFORM_USES_ONLY_WIN32_API
+    gCLocale = _create_locale(LC_ALL, "C");
+# else
+    gCLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
+# endif
+#endif
+}
+U_CDECL_END
+
+double
+DigitList::decimalStrToDouble(char *decstr, char **end) {
+    umtx_initOnce(gCLocaleInitOnce, &initCLocale);
+#if U_USE_STRTOD_L
+    return strtod_l(decstr, end, gCLocale);
+#else
+    char *decimalPt = strchr(decstr, '.');
+    if (decimalPt) {
+        // We need to know the decimal separator character that will be used with strtod().
+        // Depends on the C runtime global locale.
+        // Most commonly is '.'
+        char rep[MAX_DIGITS];
+        sprintf(rep, "%+1.1f", 1.0);
+        *decimalPt = rep[2];
+    }
+    return uprv_strtod(decstr, end);
+#endif
+}
+
 // -------------------------------------
 
 /**
@@ -734,7 +774,7 @@ DigitList::set(int64_t source)
  * be acceptable for a public API.
  */
 void
-DigitList::set(const StringPiece &source, UErrorCode &status, uint32_t /*fastpathBits*/) {
+DigitList::set(StringPiece source, UErrorCode &status, uint32_t /*fastpathBits*/) {
     if (U_FAILURE(status)) {
         return;
     }