]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/msgfmt.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / i18n / msgfmt.cpp
index 94a0286196a92b80c4d62dd01bde8f5d6b728dde..3ca368ef954846521a37d0fb3ff744d48397427e 100644 (file)
@@ -31,6 +31,7 @@
 #include "unicode/decimfmt.h"
 #include "unicode/localpointer.h"
 #include "unicode/msgfmt.h"
+#include "unicode/numberformatter.h"
 #include "unicode/plurfmt.h"
 #include "unicode/rbnf.h"
 #include "unicode/selfmt.h"
@@ -48,7 +49,7 @@
 #include "ustrfmt.h"
 #include "util.h"
 #include "uvector.h"
-#include "visibledigits.h"
+#include "number_decimalquantity.h"
 
 // *****************************************************************************
 // class MessageFormat
@@ -435,7 +436,7 @@ MessageFormat::operator==(const Format& rhs) const
 // -------------------------------------
 // Creates a copy of this MessageFormat, the caller owns the copy.
 
-Format*
+MessageFormat*
 MessageFormat::clone() const
 {
     return new MessageFormat(*this);
@@ -809,26 +810,31 @@ MessageFormat::getFormats(int32_t& cnt) const
     // method on this object.  We construct and resize an array
     // on demand that contains aliases to the subformats[i].format
     // pointers.
+
+    // Get total required capacity first (it's refreshed on each call).
+    int32_t totalCapacity = 0;
+    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {}
+
     MessageFormat* t = const_cast<MessageFormat*> (this);
     cnt = 0;
-    if (formatAliases == NULL) {
-        t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount;
+    if (formatAliases == nullptr) {
+        t->formatAliasesCapacity = totalCapacity;
         Format** a = (Format**)
             uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
-        if (a == NULL) {
+        if (a == nullptr) {
             t->formatAliasesCapacity = 0;
-            return NULL;
+            return nullptr;
         }
         t->formatAliases = a;
-    } else if (argTypeCount > formatAliasesCapacity) {
+    } else if (totalCapacity > formatAliasesCapacity) {
         Format** a = (Format**)
-            uprv_realloc(formatAliases, sizeof(Format*) * argTypeCount);
-        if (a == NULL) {
+            uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity);
+        if (a == nullptr) {
             t->formatAliasesCapacity = 0;
-            return NULL;
+            return nullptr;
         }
         t->formatAliases = a;
-        t->formatAliasesCapacity = argTypeCount;
+        t->formatAliasesCapacity = totalCapacity;
     }
 
     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
@@ -1077,7 +1083,7 @@ void MessageFormat::format(int32_t msgStart, const void *plNumber,
                 // that formats the number without subtracting the offset.
                 appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
             }
-        } else if ((formatter = getCachedFormatter(i -2))) {
+        } else if ((formatter = getCachedFormatter(i -2)) != 0) {
             // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
             if (dynamic_cast<const ChoiceFormat*>(formatter) ||
                 dynamic_cast<const PluralFormat*>(formatter) ||
@@ -1672,7 +1678,6 @@ void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
     }
 }
 
-
 Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
                                                Formattable::Type& formattableType, UParseError& parseError,
                                                UErrorCode& ec) {
@@ -1682,6 +1687,7 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
     Format* fmt = NULL;
     int32_t typeID, styleID;
     DateFormat::EStyle date_style;
+    int32_t firstNonSpace;
 
     switch (typeID = findKeyword(type, TYPE_IDS)) {
     case 0: // number
@@ -1700,12 +1706,20 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
             formattableType = Formattable::kLong;
             fmt = createIntegerFormat(fLocale, ec);
             break;
-        default: // pattern
-            fmt = NumberFormat::createInstance(fLocale, ec);
-            if (fmt) {
-                DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt);
-                if (decfmt != NULL) {
-                    decfmt->applyPattern(style,parseError,ec);
+        default: // pattern or skeleton
+            firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
+            if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
+                // Skeleton
+                UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
+                fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
+            } else {
+                // Pattern
+                fmt = NumberFormat::createInstance(fLocale, ec);
+                if (fmt) {
+                    auto* decfmt = dynamic_cast<DecimalFormat*>(fmt);
+                    if (decfmt != nullptr) {
+                        decfmt->applyPattern(style, parseError, ec);
+                    }
                 }
             }
             break;
@@ -1715,19 +1729,27 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
     case 1: // date
     case 2: // time
         formattableType = Formattable::kDate;
-        styleID = findKeyword(style, DATE_STYLE_IDS);
-        date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
-
-        if (typeID == 1) {
-            fmt = DateFormat::createDateInstance(date_style, fLocale);
+        firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
+        if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
+            // Skeleton
+            UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
+            fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
         } else {
-            fmt = DateFormat::createTimeInstance(date_style, fLocale);
-        }
+            // Pattern
+            styleID = findKeyword(style, DATE_STYLE_IDS);
+            date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
 
-        if (styleID < 0 && fmt != NULL) {
-            SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
-            if (sdtfmt != NULL) {
-                sdtfmt->applyPattern(style);
+            if (typeID == 1) {
+                fmt = DateFormat::createDateInstance(date_style, fLocale);
+            } else {
+                fmt = DateFormat::createTimeInstance(date_style, fLocale);
+            }
+
+            if (styleID < 0 && fmt != NULL) {
+                SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
+                if (sdtfmt != NULL) {
+                    sdtfmt->applyPattern(style);
+                }
             }
         }
         break;
@@ -1851,7 +1873,7 @@ UBool MessageFormat::DummyFormat::operator==(const Format&) const {
     return TRUE;
 }
 
-Format* MessageFormat::DummyFormat::clone() const {
+MessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const {
     return new DummyFormat();
 }
 
@@ -1954,16 +1976,19 @@ UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double nu
         context.formatter = msgFormat.getDefaultNumberFormat(ec);
         context.forReplaceNumber = TRUE;
     }
-    U_ASSERT(context.number.getDouble(ec) == number);  // argument number minus the offset
+    if (context.number.getDouble(ec) != number) {
+        ec = U_INTERNAL_PROGRAM_ERROR;
+        return UnicodeString(FALSE, OTHER_STRING, 5);
+    }
     context.formatter->format(context.number, context.numberString, ec);
-    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
+    auto* decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
     if(decFmt != NULL) {
-        VisibleDigitsWithExponent digits;
-        decFmt->initVisibleDigitsWithExponent(context.number, digits, ec);
+        number::impl::DecimalQuantity dq;
+        decFmt->formatToDecimalQuantity(context.number, dq, ec);
         if (U_FAILURE(ec)) {
             return UnicodeString(FALSE, OTHER_STRING, 5);
         }
-        return rules->select(digits);
+        return rules->select(dq);
     } else {
         return rules->select(number);
     }