]> granicus.if.org Git - icu/commitdiff
ICU-8561 DigitList::set(double) breaks in some locales and generates NaN
authorJungshik Shin <jshin@chromium.org>
Tue, 20 Sep 2011 00:12:55 +0000 (00:12 +0000)
committerJungshik Shin <jshin@chromium.org>
Tue, 20 Sep 2011 00:12:55 +0000 (00:12 +0000)
X-SVN-Rev: 30689

icu4c/source/i18n/digitlst.cpp

index 1ae9027c747058bd3b988dac0a8948442bb3f789..d00163ef7721c2765a8edefaad64d59592ddaa9b 100644 (file)
@@ -60,6 +60,18 @@ static const char I64_MIN_REP[] = "9223372036854775808";
 
 U_NAMESPACE_BEGIN
 
+static void
+loadDecimalChar() {
+    if (gDecimal == 0) {
+        char rep[MAX_DIGITS];
+        // For machines that decide to change the decimal on you,
+        // and try to be too smart with localization.
+        // This normally should be just a '.'.
+        sprintf(rep, "%+1.1f", 1.0);
+        gDecimal = rep[2];
+    }
+}
+
 // -------------------------------------
 // default constructor
 
@@ -408,15 +420,6 @@ DigitList::getDouble() const
     }
     DigitList *nonConstThis = const_cast<DigitList *>(this);
 
-    if (gDecimal == 0) {
-        char rep[MAX_DIGITS];
-        // For machines that decide to change the decimal on you,
-        // and try to be too smart with localization.
-        // This normally should be just a '.'.
-        sprintf(rep, "%+1.1f", 1.0);
-        gDecimal = rep[2];
-    }
-
     if (isZero()) {
         nonConstThis->fDouble = 0.0;
         if (decNumberIsNegative(fDecNumber)) {
@@ -451,6 +454,7 @@ DigitList::getDouble() const
         }
         U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
         
+        loadDecimalChar();
         if (gDecimal != '.') {
             char *decimalPt = strchr(s, '.');
             if (decimalPt != NULL) {
@@ -741,6 +745,17 @@ DigitList::set(double source)
     sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
     U_ASSERT(uprv_strlen(rep) < sizeof(rep));
 
+    // uprv_decNumberFromString() will parse the string expecting '.' as a
+    // decimal separator, however sprintf() can use ',' in certain locales.
+    // Overwrite a different decimal separator with '.' here before proceeding.
+    loadDecimalChar();
+    if (gDecimal != '.') {
+        char *decimalPt = strchr(rep, gDecimal);
+        if (decimalPt != NULL) {
+            *decimalPt = '.';
+        }
+    }
+
     // Create a decNumber from the string.
     uprv_decNumberFromString(fDecNumber, rep, &fContext);
     uprv_decNumberTrim(fDecNumber);