11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci/******************************************************************** 41cb0ef41Sopenharmony_ci * COPYRIGHT: 51cb0ef41Sopenharmony_ci * Copyright (c) 1997-2015, International Business Machines Corporation and 61cb0ef41Sopenharmony_ci * others. All Rights Reserved. 71cb0ef41Sopenharmony_ci ******************************************************************** 81cb0ef41Sopenharmony_ci * 91cb0ef41Sopenharmony_ci * File MSGFMT.CPP 101cb0ef41Sopenharmony_ci * 111cb0ef41Sopenharmony_ci * Modification History: 121cb0ef41Sopenharmony_ci * 131cb0ef41Sopenharmony_ci * Date Name Description 141cb0ef41Sopenharmony_ci * 02/19/97 aliu Converted from java. 151cb0ef41Sopenharmony_ci * 03/20/97 helena Finished first cut of implementation. 161cb0ef41Sopenharmony_ci * 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi. 171cb0ef41Sopenharmony_ci * 06/11/97 helena Fixed addPattern to take the pattern correctly. 181cb0ef41Sopenharmony_ci * 06/17/97 helena Fixed the getPattern to return the correct pattern. 191cb0ef41Sopenharmony_ci * 07/09/97 helena Made ParsePosition into a class. 201cb0ef41Sopenharmony_ci * 02/22/99 stephen Removed character literals for EBCDIC safety 211cb0ef41Sopenharmony_ci * 11/01/09 kirtig Added SelectFormat 221cb0ef41Sopenharmony_ci ********************************************************************/ 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci#include "unicode/utypes.h" 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#if !UCONFIG_NO_FORMATTING 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci#include "unicode/appendable.h" 291cb0ef41Sopenharmony_ci#include "unicode/choicfmt.h" 301cb0ef41Sopenharmony_ci#include "unicode/datefmt.h" 311cb0ef41Sopenharmony_ci#include "unicode/decimfmt.h" 321cb0ef41Sopenharmony_ci#include "unicode/localpointer.h" 331cb0ef41Sopenharmony_ci#include "unicode/msgfmt.h" 341cb0ef41Sopenharmony_ci#include "unicode/numberformatter.h" 351cb0ef41Sopenharmony_ci#include "unicode/plurfmt.h" 361cb0ef41Sopenharmony_ci#include "unicode/rbnf.h" 371cb0ef41Sopenharmony_ci#include "unicode/selfmt.h" 381cb0ef41Sopenharmony_ci#include "unicode/smpdtfmt.h" 391cb0ef41Sopenharmony_ci#include "unicode/umsg.h" 401cb0ef41Sopenharmony_ci#include "unicode/ustring.h" 411cb0ef41Sopenharmony_ci#include "cmemory.h" 421cb0ef41Sopenharmony_ci#include "patternprops.h" 431cb0ef41Sopenharmony_ci#include "messageimpl.h" 441cb0ef41Sopenharmony_ci#include "msgfmt_impl.h" 451cb0ef41Sopenharmony_ci#include "plurrule_impl.h" 461cb0ef41Sopenharmony_ci#include "uassert.h" 471cb0ef41Sopenharmony_ci#include "uelement.h" 481cb0ef41Sopenharmony_ci#include "uhash.h" 491cb0ef41Sopenharmony_ci#include "ustrfmt.h" 501cb0ef41Sopenharmony_ci#include "util.h" 511cb0ef41Sopenharmony_ci#include "uvector.h" 521cb0ef41Sopenharmony_ci#include "number_decimalquantity.h" 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci// ***************************************************************************** 551cb0ef41Sopenharmony_ci// class MessageFormat 561cb0ef41Sopenharmony_ci// ***************************************************************************** 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci#define SINGLE_QUOTE ((char16_t)0x0027) 591cb0ef41Sopenharmony_ci#define COMMA ((char16_t)0x002C) 601cb0ef41Sopenharmony_ci#define LEFT_CURLY_BRACE ((char16_t)0x007B) 611cb0ef41Sopenharmony_ci#define RIGHT_CURLY_BRACE ((char16_t)0x007D) 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci//--------------------------------------- 641cb0ef41Sopenharmony_ci// static data 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_cistatic const char16_t ID_NUMBER[] = { 671cb0ef41Sopenharmony_ci 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */ 681cb0ef41Sopenharmony_ci}; 691cb0ef41Sopenharmony_cistatic const char16_t ID_DATE[] = { 701cb0ef41Sopenharmony_ci 0x64, 0x61, 0x74, 0x65, 0 /* "date" */ 711cb0ef41Sopenharmony_ci}; 721cb0ef41Sopenharmony_cistatic const char16_t ID_TIME[] = { 731cb0ef41Sopenharmony_ci 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */ 741cb0ef41Sopenharmony_ci}; 751cb0ef41Sopenharmony_cistatic const char16_t ID_SPELLOUT[] = { 761cb0ef41Sopenharmony_ci 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */ 771cb0ef41Sopenharmony_ci}; 781cb0ef41Sopenharmony_cistatic const char16_t ID_ORDINAL[] = { 791cb0ef41Sopenharmony_ci 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */ 801cb0ef41Sopenharmony_ci}; 811cb0ef41Sopenharmony_cistatic const char16_t ID_DURATION[] = { 821cb0ef41Sopenharmony_ci 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */ 831cb0ef41Sopenharmony_ci}; 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci// MessageFormat Type List Number, Date, Time or Choice 861cb0ef41Sopenharmony_cistatic const char16_t * const TYPE_IDS[] = { 871cb0ef41Sopenharmony_ci ID_NUMBER, 881cb0ef41Sopenharmony_ci ID_DATE, 891cb0ef41Sopenharmony_ci ID_TIME, 901cb0ef41Sopenharmony_ci ID_SPELLOUT, 911cb0ef41Sopenharmony_ci ID_ORDINAL, 921cb0ef41Sopenharmony_ci ID_DURATION, 931cb0ef41Sopenharmony_ci nullptr, 941cb0ef41Sopenharmony_ci}; 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_cistatic const char16_t ID_EMPTY[] = { 971cb0ef41Sopenharmony_ci 0 /* empty string, used for default so that null can mark end of list */ 981cb0ef41Sopenharmony_ci}; 991cb0ef41Sopenharmony_cistatic const char16_t ID_CURRENCY[] = { 1001cb0ef41Sopenharmony_ci 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */ 1011cb0ef41Sopenharmony_ci}; 1021cb0ef41Sopenharmony_cistatic const char16_t ID_PERCENT[] = { 1031cb0ef41Sopenharmony_ci 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */ 1041cb0ef41Sopenharmony_ci}; 1051cb0ef41Sopenharmony_cistatic const char16_t ID_INTEGER[] = { 1061cb0ef41Sopenharmony_ci 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */ 1071cb0ef41Sopenharmony_ci}; 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci// NumberFormat modifier list, default, currency, percent or integer 1101cb0ef41Sopenharmony_cistatic const char16_t * const NUMBER_STYLE_IDS[] = { 1111cb0ef41Sopenharmony_ci ID_EMPTY, 1121cb0ef41Sopenharmony_ci ID_CURRENCY, 1131cb0ef41Sopenharmony_ci ID_PERCENT, 1141cb0ef41Sopenharmony_ci ID_INTEGER, 1151cb0ef41Sopenharmony_ci nullptr, 1161cb0ef41Sopenharmony_ci}; 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_cistatic const char16_t ID_SHORT[] = { 1191cb0ef41Sopenharmony_ci 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */ 1201cb0ef41Sopenharmony_ci}; 1211cb0ef41Sopenharmony_cistatic const char16_t ID_MEDIUM[] = { 1221cb0ef41Sopenharmony_ci 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */ 1231cb0ef41Sopenharmony_ci}; 1241cb0ef41Sopenharmony_cistatic const char16_t ID_LONG[] = { 1251cb0ef41Sopenharmony_ci 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */ 1261cb0ef41Sopenharmony_ci}; 1271cb0ef41Sopenharmony_cistatic const char16_t ID_FULL[] = { 1281cb0ef41Sopenharmony_ci 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */ 1291cb0ef41Sopenharmony_ci}; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci// DateFormat modifier list, default, short, medium, long or full 1321cb0ef41Sopenharmony_cistatic const char16_t * const DATE_STYLE_IDS[] = { 1331cb0ef41Sopenharmony_ci ID_EMPTY, 1341cb0ef41Sopenharmony_ci ID_SHORT, 1351cb0ef41Sopenharmony_ci ID_MEDIUM, 1361cb0ef41Sopenharmony_ci ID_LONG, 1371cb0ef41Sopenharmony_ci ID_FULL, 1381cb0ef41Sopenharmony_ci nullptr, 1391cb0ef41Sopenharmony_ci}; 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_cistatic const icu::DateFormat::EStyle DATE_STYLES[] = { 1421cb0ef41Sopenharmony_ci icu::DateFormat::kDefault, 1431cb0ef41Sopenharmony_ci icu::DateFormat::kShort, 1441cb0ef41Sopenharmony_ci icu::DateFormat::kMedium, 1451cb0ef41Sopenharmony_ci icu::DateFormat::kLong, 1461cb0ef41Sopenharmony_ci icu::DateFormat::kFull, 1471cb0ef41Sopenharmony_ci}; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_cistatic const int32_t DEFAULT_INITIAL_CAPACITY = 10; 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_cistatic const char16_t NULL_STRING[] = { 1521cb0ef41Sopenharmony_ci 0x6E, 0x75, 0x6C, 0x6C, 0 // "null" 1531cb0ef41Sopenharmony_ci}; 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_cistatic const char16_t OTHER_STRING[] = { 1561cb0ef41Sopenharmony_ci 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other" 1571cb0ef41Sopenharmony_ci}; 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ciU_CDECL_BEGIN 1601cb0ef41Sopenharmony_cistatic UBool U_CALLCONV equalFormatsForHash(const UHashTok key1, 1611cb0ef41Sopenharmony_ci const UHashTok key2) { 1621cb0ef41Sopenharmony_ci return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer); 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ciU_CDECL_END 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci// ------------------------------------- 1701cb0ef41Sopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat) 1711cb0ef41Sopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration) 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci//-------------------------------------------------------------------- 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci/** 1761cb0ef41Sopenharmony_ci * Convert an integer value to a string and append the result to 1771cb0ef41Sopenharmony_ci * the given UnicodeString. 1781cb0ef41Sopenharmony_ci */ 1791cb0ef41Sopenharmony_cistatic UnicodeString& itos(int32_t i, UnicodeString& appendTo) { 1801cb0ef41Sopenharmony_ci char16_t temp[16]; 1811cb0ef41Sopenharmony_ci uprv_itou(temp,16,i,10,0); // 10 == radix 1821cb0ef41Sopenharmony_ci appendTo.append(temp, -1); 1831cb0ef41Sopenharmony_ci return appendTo; 1841cb0ef41Sopenharmony_ci} 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci// AppendableWrapper: encapsulates the result of formatting, keeping track 1881cb0ef41Sopenharmony_ci// of the string and its length. 1891cb0ef41Sopenharmony_ciclass AppendableWrapper : public UMemory { 1901cb0ef41Sopenharmony_cipublic: 1911cb0ef41Sopenharmony_ci AppendableWrapper(Appendable& appendable) : app(appendable), len(0) { 1921cb0ef41Sopenharmony_ci } 1931cb0ef41Sopenharmony_ci void append(const UnicodeString& s) { 1941cb0ef41Sopenharmony_ci app.appendString(s.getBuffer(), s.length()); 1951cb0ef41Sopenharmony_ci len += s.length(); 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci void append(const char16_t* s, const int32_t sLength) { 1981cb0ef41Sopenharmony_ci app.appendString(s, sLength); 1991cb0ef41Sopenharmony_ci len += sLength; 2001cb0ef41Sopenharmony_ci } 2011cb0ef41Sopenharmony_ci void append(const UnicodeString& s, int32_t start, int32_t length) { 2021cb0ef41Sopenharmony_ci append(s.tempSubString(start, length)); 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) { 2051cb0ef41Sopenharmony_ci UnicodeString s; 2061cb0ef41Sopenharmony_ci formatter->format(arg, s, ec); 2071cb0ef41Sopenharmony_ci if (U_SUCCESS(ec)) { 2081cb0ef41Sopenharmony_ci append(s); 2091cb0ef41Sopenharmony_ci } 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci void formatAndAppend(const Format* formatter, const Formattable& arg, 2121cb0ef41Sopenharmony_ci const UnicodeString &argString, UErrorCode& ec) { 2131cb0ef41Sopenharmony_ci if (!argString.isEmpty()) { 2141cb0ef41Sopenharmony_ci if (U_SUCCESS(ec)) { 2151cb0ef41Sopenharmony_ci append(argString); 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci } else { 2181cb0ef41Sopenharmony_ci formatAndAppend(formatter, arg, ec); 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci int32_t length() { 2221cb0ef41Sopenharmony_ci return len; 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ciprivate: 2251cb0ef41Sopenharmony_ci Appendable& app; 2261cb0ef41Sopenharmony_ci int32_t len; 2271cb0ef41Sopenharmony_ci}; 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci// ------------------------------------- 2311cb0ef41Sopenharmony_ci// Creates a MessageFormat instance based on the pattern. 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ciMessageFormat::MessageFormat(const UnicodeString& pattern, 2341cb0ef41Sopenharmony_ci UErrorCode& success) 2351cb0ef41Sopenharmony_ci: fLocale(Locale::getDefault()), // Uses the default locale 2361cb0ef41Sopenharmony_ci msgPattern(success), 2371cb0ef41Sopenharmony_ci formatAliases(nullptr), 2381cb0ef41Sopenharmony_ci formatAliasesCapacity(0), 2391cb0ef41Sopenharmony_ci argTypes(nullptr), 2401cb0ef41Sopenharmony_ci argTypeCount(0), 2411cb0ef41Sopenharmony_ci argTypeCapacity(0), 2421cb0ef41Sopenharmony_ci hasArgTypeConflicts(false), 2431cb0ef41Sopenharmony_ci defaultNumberFormat(nullptr), 2441cb0ef41Sopenharmony_ci defaultDateFormat(nullptr), 2451cb0ef41Sopenharmony_ci cachedFormatters(nullptr), 2461cb0ef41Sopenharmony_ci customFormatArgStarts(nullptr), 2471cb0ef41Sopenharmony_ci pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 2481cb0ef41Sopenharmony_ci ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 2491cb0ef41Sopenharmony_ci{ 2501cb0ef41Sopenharmony_ci setLocaleIDs(fLocale.getName(), fLocale.getName()); 2511cb0ef41Sopenharmony_ci applyPattern(pattern, success); 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ciMessageFormat::MessageFormat(const UnicodeString& pattern, 2551cb0ef41Sopenharmony_ci const Locale& newLocale, 2561cb0ef41Sopenharmony_ci UErrorCode& success) 2571cb0ef41Sopenharmony_ci: fLocale(newLocale), 2581cb0ef41Sopenharmony_ci msgPattern(success), 2591cb0ef41Sopenharmony_ci formatAliases(nullptr), 2601cb0ef41Sopenharmony_ci formatAliasesCapacity(0), 2611cb0ef41Sopenharmony_ci argTypes(nullptr), 2621cb0ef41Sopenharmony_ci argTypeCount(0), 2631cb0ef41Sopenharmony_ci argTypeCapacity(0), 2641cb0ef41Sopenharmony_ci hasArgTypeConflicts(false), 2651cb0ef41Sopenharmony_ci defaultNumberFormat(nullptr), 2661cb0ef41Sopenharmony_ci defaultDateFormat(nullptr), 2671cb0ef41Sopenharmony_ci cachedFormatters(nullptr), 2681cb0ef41Sopenharmony_ci customFormatArgStarts(nullptr), 2691cb0ef41Sopenharmony_ci pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 2701cb0ef41Sopenharmony_ci ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 2711cb0ef41Sopenharmony_ci{ 2721cb0ef41Sopenharmony_ci setLocaleIDs(fLocale.getName(), fLocale.getName()); 2731cb0ef41Sopenharmony_ci applyPattern(pattern, success); 2741cb0ef41Sopenharmony_ci} 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ciMessageFormat::MessageFormat(const UnicodeString& pattern, 2771cb0ef41Sopenharmony_ci const Locale& newLocale, 2781cb0ef41Sopenharmony_ci UParseError& parseError, 2791cb0ef41Sopenharmony_ci UErrorCode& success) 2801cb0ef41Sopenharmony_ci: fLocale(newLocale), 2811cb0ef41Sopenharmony_ci msgPattern(success), 2821cb0ef41Sopenharmony_ci formatAliases(nullptr), 2831cb0ef41Sopenharmony_ci formatAliasesCapacity(0), 2841cb0ef41Sopenharmony_ci argTypes(nullptr), 2851cb0ef41Sopenharmony_ci argTypeCount(0), 2861cb0ef41Sopenharmony_ci argTypeCapacity(0), 2871cb0ef41Sopenharmony_ci hasArgTypeConflicts(false), 2881cb0ef41Sopenharmony_ci defaultNumberFormat(nullptr), 2891cb0ef41Sopenharmony_ci defaultDateFormat(nullptr), 2901cb0ef41Sopenharmony_ci cachedFormatters(nullptr), 2911cb0ef41Sopenharmony_ci customFormatArgStarts(nullptr), 2921cb0ef41Sopenharmony_ci pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 2931cb0ef41Sopenharmony_ci ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 2941cb0ef41Sopenharmony_ci{ 2951cb0ef41Sopenharmony_ci setLocaleIDs(fLocale.getName(), fLocale.getName()); 2961cb0ef41Sopenharmony_ci applyPattern(pattern, parseError, success); 2971cb0ef41Sopenharmony_ci} 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ciMessageFormat::MessageFormat(const MessageFormat& that) 3001cb0ef41Sopenharmony_ci: 3011cb0ef41Sopenharmony_ci Format(that), 3021cb0ef41Sopenharmony_ci fLocale(that.fLocale), 3031cb0ef41Sopenharmony_ci msgPattern(that.msgPattern), 3041cb0ef41Sopenharmony_ci formatAliases(nullptr), 3051cb0ef41Sopenharmony_ci formatAliasesCapacity(0), 3061cb0ef41Sopenharmony_ci argTypes(nullptr), 3071cb0ef41Sopenharmony_ci argTypeCount(0), 3081cb0ef41Sopenharmony_ci argTypeCapacity(0), 3091cb0ef41Sopenharmony_ci hasArgTypeConflicts(that.hasArgTypeConflicts), 3101cb0ef41Sopenharmony_ci defaultNumberFormat(nullptr), 3111cb0ef41Sopenharmony_ci defaultDateFormat(nullptr), 3121cb0ef41Sopenharmony_ci cachedFormatters(nullptr), 3131cb0ef41Sopenharmony_ci customFormatArgStarts(nullptr), 3141cb0ef41Sopenharmony_ci pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 3151cb0ef41Sopenharmony_ci ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 3161cb0ef41Sopenharmony_ci{ 3171cb0ef41Sopenharmony_ci // This will take care of creating the hash tables (since they are nullptr). 3181cb0ef41Sopenharmony_ci UErrorCode ec = U_ZERO_ERROR; 3191cb0ef41Sopenharmony_ci copyObjects(that, ec); 3201cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 3211cb0ef41Sopenharmony_ci resetPattern(); 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci} 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ciMessageFormat::~MessageFormat() 3261cb0ef41Sopenharmony_ci{ 3271cb0ef41Sopenharmony_ci uhash_close(cachedFormatters); 3281cb0ef41Sopenharmony_ci uhash_close(customFormatArgStarts); 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_ci uprv_free(argTypes); 3311cb0ef41Sopenharmony_ci uprv_free(formatAliases); 3321cb0ef41Sopenharmony_ci delete defaultNumberFormat; 3331cb0ef41Sopenharmony_ci delete defaultDateFormat; 3341cb0ef41Sopenharmony_ci} 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci//-------------------------------------------------------------------- 3371cb0ef41Sopenharmony_ci// Variable-size array management 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci/** 3401cb0ef41Sopenharmony_ci * Allocate argTypes[] to at least the given capacity and return 3411cb0ef41Sopenharmony_ci * true if successful. If not, leave argTypes[] unchanged. 3421cb0ef41Sopenharmony_ci * 3431cb0ef41Sopenharmony_ci * If argTypes is nullptr, allocate it. If it is not nullptr, enlarge it 3441cb0ef41Sopenharmony_ci * if necessary to be at least as large as specified. 3451cb0ef41Sopenharmony_ci */ 3461cb0ef41Sopenharmony_ciUBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) { 3471cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 3481cb0ef41Sopenharmony_ci return false; 3491cb0ef41Sopenharmony_ci } 3501cb0ef41Sopenharmony_ci if (argTypeCapacity >= capacity) { 3511cb0ef41Sopenharmony_ci return true; 3521cb0ef41Sopenharmony_ci } 3531cb0ef41Sopenharmony_ci if (capacity < DEFAULT_INITIAL_CAPACITY) { 3541cb0ef41Sopenharmony_ci capacity = DEFAULT_INITIAL_CAPACITY; 3551cb0ef41Sopenharmony_ci } else if (capacity < 2*argTypeCapacity) { 3561cb0ef41Sopenharmony_ci capacity = 2*argTypeCapacity; 3571cb0ef41Sopenharmony_ci } 3581cb0ef41Sopenharmony_ci Formattable::Type* a = (Formattable::Type*) 3591cb0ef41Sopenharmony_ci uprv_realloc(argTypes, sizeof(*argTypes) * capacity); 3601cb0ef41Sopenharmony_ci if (a == nullptr) { 3611cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 3621cb0ef41Sopenharmony_ci return false; 3631cb0ef41Sopenharmony_ci } 3641cb0ef41Sopenharmony_ci argTypes = a; 3651cb0ef41Sopenharmony_ci argTypeCapacity = capacity; 3661cb0ef41Sopenharmony_ci return true; 3671cb0ef41Sopenharmony_ci} 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ci// ------------------------------------- 3701cb0ef41Sopenharmony_ci// assignment operator 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ciconst MessageFormat& 3731cb0ef41Sopenharmony_ciMessageFormat::operator=(const MessageFormat& that) 3741cb0ef41Sopenharmony_ci{ 3751cb0ef41Sopenharmony_ci if (this != &that) { 3761cb0ef41Sopenharmony_ci // Calls the super class for assignment first. 3771cb0ef41Sopenharmony_ci Format::operator=(that); 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci setLocale(that.fLocale); 3801cb0ef41Sopenharmony_ci msgPattern = that.msgPattern; 3811cb0ef41Sopenharmony_ci hasArgTypeConflicts = that.hasArgTypeConflicts; 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci UErrorCode ec = U_ZERO_ERROR; 3841cb0ef41Sopenharmony_ci copyObjects(that, ec); 3851cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 3861cb0ef41Sopenharmony_ci resetPattern(); 3871cb0ef41Sopenharmony_ci } 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci return *this; 3901cb0ef41Sopenharmony_ci} 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_cibool 3931cb0ef41Sopenharmony_ciMessageFormat::operator==(const Format& rhs) const 3941cb0ef41Sopenharmony_ci{ 3951cb0ef41Sopenharmony_ci if (this == &rhs) return true; 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci // Check class ID before checking MessageFormat members 3981cb0ef41Sopenharmony_ci if (!Format::operator==(rhs)) return false; 3991cb0ef41Sopenharmony_ci 4001cb0ef41Sopenharmony_ci const MessageFormat& that = static_cast<const MessageFormat&>(rhs); 4011cb0ef41Sopenharmony_ci if (msgPattern != that.msgPattern || 4021cb0ef41Sopenharmony_ci fLocale != that.fLocale) { 4031cb0ef41Sopenharmony_ci return false; 4041cb0ef41Sopenharmony_ci } 4051cb0ef41Sopenharmony_ci 4061cb0ef41Sopenharmony_ci // Compare hashtables. 4071cb0ef41Sopenharmony_ci if ((customFormatArgStarts == nullptr) != (that.customFormatArgStarts == nullptr)) { 4081cb0ef41Sopenharmony_ci return false; 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci if (customFormatArgStarts == nullptr) { 4111cb0ef41Sopenharmony_ci return true; 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci 4141cb0ef41Sopenharmony_ci UErrorCode ec = U_ZERO_ERROR; 4151cb0ef41Sopenharmony_ci const int32_t count = uhash_count(customFormatArgStarts); 4161cb0ef41Sopenharmony_ci const int32_t rhs_count = uhash_count(that.customFormatArgStarts); 4171cb0ef41Sopenharmony_ci if (count != rhs_count) { 4181cb0ef41Sopenharmony_ci return false; 4191cb0ef41Sopenharmony_ci } 4201cb0ef41Sopenharmony_ci int32_t idx = 0, rhs_idx = 0, pos = UHASH_FIRST, rhs_pos = UHASH_FIRST; 4211cb0ef41Sopenharmony_ci for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) { 4221cb0ef41Sopenharmony_ci const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos); 4231cb0ef41Sopenharmony_ci const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos); 4241cb0ef41Sopenharmony_ci if (cur->key.integer != rhs_cur->key.integer) { 4251cb0ef41Sopenharmony_ci return false; 4261cb0ef41Sopenharmony_ci } 4271cb0ef41Sopenharmony_ci const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer); 4281cb0ef41Sopenharmony_ci const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer); 4291cb0ef41Sopenharmony_ci if (*format != *rhs_format) { 4301cb0ef41Sopenharmony_ci return false; 4311cb0ef41Sopenharmony_ci } 4321cb0ef41Sopenharmony_ci } 4331cb0ef41Sopenharmony_ci return true; 4341cb0ef41Sopenharmony_ci} 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ci// ------------------------------------- 4371cb0ef41Sopenharmony_ci// Creates a copy of this MessageFormat, the caller owns the copy. 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ciMessageFormat* 4401cb0ef41Sopenharmony_ciMessageFormat::clone() const 4411cb0ef41Sopenharmony_ci{ 4421cb0ef41Sopenharmony_ci return new MessageFormat(*this); 4431cb0ef41Sopenharmony_ci} 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_ci// ------------------------------------- 4461cb0ef41Sopenharmony_ci// Sets the locale of this MessageFormat object to theLocale. 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_civoid 4491cb0ef41Sopenharmony_ciMessageFormat::setLocale(const Locale& theLocale) 4501cb0ef41Sopenharmony_ci{ 4511cb0ef41Sopenharmony_ci if (fLocale != theLocale) { 4521cb0ef41Sopenharmony_ci delete defaultNumberFormat; 4531cb0ef41Sopenharmony_ci defaultNumberFormat = nullptr; 4541cb0ef41Sopenharmony_ci delete defaultDateFormat; 4551cb0ef41Sopenharmony_ci defaultDateFormat = nullptr; 4561cb0ef41Sopenharmony_ci fLocale = theLocale; 4571cb0ef41Sopenharmony_ci setLocaleIDs(fLocale.getName(), fLocale.getName()); 4581cb0ef41Sopenharmony_ci pluralProvider.reset(); 4591cb0ef41Sopenharmony_ci ordinalProvider.reset(); 4601cb0ef41Sopenharmony_ci } 4611cb0ef41Sopenharmony_ci} 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci// ------------------------------------- 4641cb0ef41Sopenharmony_ci// Gets the locale of this MessageFormat object. 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ciconst Locale& 4671cb0ef41Sopenharmony_ciMessageFormat::getLocale() const 4681cb0ef41Sopenharmony_ci{ 4691cb0ef41Sopenharmony_ci return fLocale; 4701cb0ef41Sopenharmony_ci} 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_civoid 4731cb0ef41Sopenharmony_ciMessageFormat::applyPattern(const UnicodeString& newPattern, 4741cb0ef41Sopenharmony_ci UErrorCode& status) 4751cb0ef41Sopenharmony_ci{ 4761cb0ef41Sopenharmony_ci UParseError parseError; 4771cb0ef41Sopenharmony_ci applyPattern(newPattern,parseError,status); 4781cb0ef41Sopenharmony_ci} 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci// ------------------------------------- 4821cb0ef41Sopenharmony_ci// Applies the new pattern and returns an error if the pattern 4831cb0ef41Sopenharmony_ci// is not correct. 4841cb0ef41Sopenharmony_civoid 4851cb0ef41Sopenharmony_ciMessageFormat::applyPattern(const UnicodeString& pattern, 4861cb0ef41Sopenharmony_ci UParseError& parseError, 4871cb0ef41Sopenharmony_ci UErrorCode& ec) 4881cb0ef41Sopenharmony_ci{ 4891cb0ef41Sopenharmony_ci if(U_FAILURE(ec)) { 4901cb0ef41Sopenharmony_ci return; 4911cb0ef41Sopenharmony_ci } 4921cb0ef41Sopenharmony_ci msgPattern.parse(pattern, &parseError, ec); 4931cb0ef41Sopenharmony_ci cacheExplicitFormats(ec); 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 4961cb0ef41Sopenharmony_ci resetPattern(); 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci} 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_civoid MessageFormat::resetPattern() { 5011cb0ef41Sopenharmony_ci msgPattern.clear(); 5021cb0ef41Sopenharmony_ci uhash_close(cachedFormatters); 5031cb0ef41Sopenharmony_ci cachedFormatters = nullptr; 5041cb0ef41Sopenharmony_ci uhash_close(customFormatArgStarts); 5051cb0ef41Sopenharmony_ci customFormatArgStarts = nullptr; 5061cb0ef41Sopenharmony_ci argTypeCount = 0; 5071cb0ef41Sopenharmony_ci hasArgTypeConflicts = false; 5081cb0ef41Sopenharmony_ci} 5091cb0ef41Sopenharmony_ci 5101cb0ef41Sopenharmony_civoid 5111cb0ef41Sopenharmony_ciMessageFormat::applyPattern(const UnicodeString& pattern, 5121cb0ef41Sopenharmony_ci UMessagePatternApostropheMode aposMode, 5131cb0ef41Sopenharmony_ci UParseError* parseError, 5141cb0ef41Sopenharmony_ci UErrorCode& status) { 5151cb0ef41Sopenharmony_ci if (aposMode != msgPattern.getApostropheMode()) { 5161cb0ef41Sopenharmony_ci msgPattern.clearPatternAndSetApostropheMode(aposMode); 5171cb0ef41Sopenharmony_ci } 5181cb0ef41Sopenharmony_ci UParseError tempParseError; 5191cb0ef41Sopenharmony_ci applyPattern(pattern, (parseError == nullptr) ? tempParseError : *parseError, status); 5201cb0ef41Sopenharmony_ci} 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_ci// ------------------------------------- 5231cb0ef41Sopenharmony_ci// Converts this MessageFormat instance to a pattern. 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ciUnicodeString& 5261cb0ef41Sopenharmony_ciMessageFormat::toPattern(UnicodeString& appendTo) const { 5271cb0ef41Sopenharmony_ci if ((customFormatArgStarts != nullptr && 0 != uhash_count(customFormatArgStarts)) || 5281cb0ef41Sopenharmony_ci 0 == msgPattern.countParts() 5291cb0ef41Sopenharmony_ci ) { 5301cb0ef41Sopenharmony_ci appendTo.setToBogus(); 5311cb0ef41Sopenharmony_ci return appendTo; 5321cb0ef41Sopenharmony_ci } 5331cb0ef41Sopenharmony_ci return appendTo.append(msgPattern.getPatternString()); 5341cb0ef41Sopenharmony_ci} 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ciint32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const { 5371cb0ef41Sopenharmony_ci if (partIndex != 0) { 5381cb0ef41Sopenharmony_ci partIndex = msgPattern.getLimitPartIndex(partIndex); 5391cb0ef41Sopenharmony_ci } 5401cb0ef41Sopenharmony_ci for (;;) { 5411cb0ef41Sopenharmony_ci UMessagePatternPartType type = msgPattern.getPartType(++partIndex); 5421cb0ef41Sopenharmony_ci if (type == UMSGPAT_PART_TYPE_ARG_START) { 5431cb0ef41Sopenharmony_ci return partIndex; 5441cb0ef41Sopenharmony_ci } 5451cb0ef41Sopenharmony_ci if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { 5461cb0ef41Sopenharmony_ci return -1; 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci } 5491cb0ef41Sopenharmony_ci} 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_civoid MessageFormat::setArgStartFormat(int32_t argStart, 5521cb0ef41Sopenharmony_ci Format* formatter, 5531cb0ef41Sopenharmony_ci UErrorCode& status) { 5541cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 5551cb0ef41Sopenharmony_ci delete formatter; 5561cb0ef41Sopenharmony_ci return; 5571cb0ef41Sopenharmony_ci } 5581cb0ef41Sopenharmony_ci if (cachedFormatters == nullptr) { 5591cb0ef41Sopenharmony_ci cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong, 5601cb0ef41Sopenharmony_ci equalFormatsForHash, &status); 5611cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 5621cb0ef41Sopenharmony_ci delete formatter; 5631cb0ef41Sopenharmony_ci return; 5641cb0ef41Sopenharmony_ci } 5651cb0ef41Sopenharmony_ci uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject); 5661cb0ef41Sopenharmony_ci } 5671cb0ef41Sopenharmony_ci if (formatter == nullptr) { 5681cb0ef41Sopenharmony_ci formatter = new DummyFormat(); 5691cb0ef41Sopenharmony_ci } 5701cb0ef41Sopenharmony_ci uhash_iput(cachedFormatters, argStart, formatter, &status); 5711cb0ef41Sopenharmony_ci} 5721cb0ef41Sopenharmony_ci 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ciUBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) { 5751cb0ef41Sopenharmony_ci const MessagePattern::Part& part = msgPattern.getPart(partIndex); 5761cb0ef41Sopenharmony_ci return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ? 5771cb0ef41Sopenharmony_ci msgPattern.partSubstringMatches(part, argName) : 5781cb0ef41Sopenharmony_ci part.getValue() == argNumber; // ARG_NUMBER 5791cb0ef41Sopenharmony_ci} 5801cb0ef41Sopenharmony_ci 5811cb0ef41Sopenharmony_ci// Sets a custom formatter for a MessagePattern ARG_START part index. 5821cb0ef41Sopenharmony_ci// "Custom" formatters are provided by the user via setFormat() or similar APIs. 5831cb0ef41Sopenharmony_civoid MessageFormat::setCustomArgStartFormat(int32_t argStart, 5841cb0ef41Sopenharmony_ci Format* formatter, 5851cb0ef41Sopenharmony_ci UErrorCode& status) { 5861cb0ef41Sopenharmony_ci setArgStartFormat(argStart, formatter, status); 5871cb0ef41Sopenharmony_ci if (customFormatArgStarts == nullptr) { 5881cb0ef41Sopenharmony_ci customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong, 5891cb0ef41Sopenharmony_ci nullptr, &status); 5901cb0ef41Sopenharmony_ci } 5911cb0ef41Sopenharmony_ci uhash_iputi(customFormatArgStarts, argStart, 1, &status); 5921cb0ef41Sopenharmony_ci} 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ciFormat* MessageFormat::getCachedFormatter(int32_t argumentNumber) const { 5951cb0ef41Sopenharmony_ci if (cachedFormatters == nullptr) { 5961cb0ef41Sopenharmony_ci return nullptr; 5971cb0ef41Sopenharmony_ci } 5981cb0ef41Sopenharmony_ci void* ptr = uhash_iget(cachedFormatters, argumentNumber); 5991cb0ef41Sopenharmony_ci if (ptr != nullptr && dynamic_cast<DummyFormat*>((Format*)ptr) == nullptr) { 6001cb0ef41Sopenharmony_ci return (Format*) ptr; 6011cb0ef41Sopenharmony_ci } else { 6021cb0ef41Sopenharmony_ci // Not cached, or a DummyFormat representing setFormat(nullptr). 6031cb0ef41Sopenharmony_ci return nullptr; 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci} 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_ci// ------------------------------------- 6081cb0ef41Sopenharmony_ci// Adopts the new formats array and updates the array count. 6091cb0ef41Sopenharmony_ci// This MessageFormat instance owns the new formats. 6101cb0ef41Sopenharmony_civoid 6111cb0ef41Sopenharmony_ciMessageFormat::adoptFormats(Format** newFormats, 6121cb0ef41Sopenharmony_ci int32_t count) { 6131cb0ef41Sopenharmony_ci if (newFormats == nullptr || count < 0) { 6141cb0ef41Sopenharmony_ci return; 6151cb0ef41Sopenharmony_ci } 6161cb0ef41Sopenharmony_ci // Throw away any cached formatters. 6171cb0ef41Sopenharmony_ci if (cachedFormatters != nullptr) { 6181cb0ef41Sopenharmony_ci uhash_removeAll(cachedFormatters); 6191cb0ef41Sopenharmony_ci } 6201cb0ef41Sopenharmony_ci if (customFormatArgStarts != nullptr) { 6211cb0ef41Sopenharmony_ci uhash_removeAll(customFormatArgStarts); 6221cb0ef41Sopenharmony_ci } 6231cb0ef41Sopenharmony_ci 6241cb0ef41Sopenharmony_ci int32_t formatNumber = 0; 6251cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 6261cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; 6271cb0ef41Sopenharmony_ci formatNumber < count && U_SUCCESS(status) && 6281cb0ef41Sopenharmony_ci (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 6291cb0ef41Sopenharmony_ci setCustomArgStartFormat(partIndex, newFormats[formatNumber], status); 6301cb0ef41Sopenharmony_ci ++formatNumber; 6311cb0ef41Sopenharmony_ci } 6321cb0ef41Sopenharmony_ci // Delete those that didn't get used (if any). 6331cb0ef41Sopenharmony_ci for (; formatNumber < count; ++formatNumber) { 6341cb0ef41Sopenharmony_ci delete newFormats[formatNumber]; 6351cb0ef41Sopenharmony_ci } 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci} 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_ci// ------------------------------------- 6401cb0ef41Sopenharmony_ci// Sets the new formats array and updates the array count. 6411cb0ef41Sopenharmony_ci// This MessageFormat instance makes a copy of the new formats. 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_civoid 6441cb0ef41Sopenharmony_ciMessageFormat::setFormats(const Format** newFormats, 6451cb0ef41Sopenharmony_ci int32_t count) { 6461cb0ef41Sopenharmony_ci if (newFormats == nullptr || count < 0) { 6471cb0ef41Sopenharmony_ci return; 6481cb0ef41Sopenharmony_ci } 6491cb0ef41Sopenharmony_ci // Throw away any cached formatters. 6501cb0ef41Sopenharmony_ci if (cachedFormatters != nullptr) { 6511cb0ef41Sopenharmony_ci uhash_removeAll(cachedFormatters); 6521cb0ef41Sopenharmony_ci } 6531cb0ef41Sopenharmony_ci if (customFormatArgStarts != nullptr) { 6541cb0ef41Sopenharmony_ci uhash_removeAll(customFormatArgStarts); 6551cb0ef41Sopenharmony_ci } 6561cb0ef41Sopenharmony_ci 6571cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 6581cb0ef41Sopenharmony_ci int32_t formatNumber = 0; 6591cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; 6601cb0ef41Sopenharmony_ci formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 6611cb0ef41Sopenharmony_ci Format* newFormat = nullptr; 6621cb0ef41Sopenharmony_ci if (newFormats[formatNumber] != nullptr) { 6631cb0ef41Sopenharmony_ci newFormat = newFormats[formatNumber]->clone(); 6641cb0ef41Sopenharmony_ci if (newFormat == nullptr) { 6651cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 6661cb0ef41Sopenharmony_ci } 6671cb0ef41Sopenharmony_ci } 6681cb0ef41Sopenharmony_ci setCustomArgStartFormat(partIndex, newFormat, status); 6691cb0ef41Sopenharmony_ci ++formatNumber; 6701cb0ef41Sopenharmony_ci } 6711cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 6721cb0ef41Sopenharmony_ci resetPattern(); 6731cb0ef41Sopenharmony_ci } 6741cb0ef41Sopenharmony_ci} 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci// ------------------------------------- 6771cb0ef41Sopenharmony_ci// Adopt a single format by format number. 6781cb0ef41Sopenharmony_ci// Do nothing if the format number is not less than the array count. 6791cb0ef41Sopenharmony_ci 6801cb0ef41Sopenharmony_civoid 6811cb0ef41Sopenharmony_ciMessageFormat::adoptFormat(int32_t n, Format *newFormat) { 6821cb0ef41Sopenharmony_ci LocalPointer<Format> p(newFormat); 6831cb0ef41Sopenharmony_ci if (n >= 0) { 6841cb0ef41Sopenharmony_ci int32_t formatNumber = 0; 6851cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 6861cb0ef41Sopenharmony_ci if (n == formatNumber) { 6871cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 6881cb0ef41Sopenharmony_ci setCustomArgStartFormat(partIndex, p.orphan(), status); 6891cb0ef41Sopenharmony_ci return; 6901cb0ef41Sopenharmony_ci } 6911cb0ef41Sopenharmony_ci ++formatNumber; 6921cb0ef41Sopenharmony_ci } 6931cb0ef41Sopenharmony_ci } 6941cb0ef41Sopenharmony_ci} 6951cb0ef41Sopenharmony_ci 6961cb0ef41Sopenharmony_ci// ------------------------------------- 6971cb0ef41Sopenharmony_ci// Adopt a single format by format name. 6981cb0ef41Sopenharmony_ci// Do nothing if there is no match of formatName. 6991cb0ef41Sopenharmony_civoid 7001cb0ef41Sopenharmony_ciMessageFormat::adoptFormat(const UnicodeString& formatName, 7011cb0ef41Sopenharmony_ci Format* formatToAdopt, 7021cb0ef41Sopenharmony_ci UErrorCode& status) { 7031cb0ef41Sopenharmony_ci LocalPointer<Format> p(formatToAdopt); 7041cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 7051cb0ef41Sopenharmony_ci return; 7061cb0ef41Sopenharmony_ci } 7071cb0ef41Sopenharmony_ci int32_t argNumber = MessagePattern::validateArgumentName(formatName); 7081cb0ef41Sopenharmony_ci if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) { 7091cb0ef41Sopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 7101cb0ef41Sopenharmony_ci return; 7111cb0ef41Sopenharmony_ci } 7121cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; 7131cb0ef41Sopenharmony_ci (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status); 7141cb0ef41Sopenharmony_ci ) { 7151cb0ef41Sopenharmony_ci if (argNameMatches(partIndex + 1, formatName, argNumber)) { 7161cb0ef41Sopenharmony_ci Format* f; 7171cb0ef41Sopenharmony_ci if (p.isValid()) { 7181cb0ef41Sopenharmony_ci f = p.orphan(); 7191cb0ef41Sopenharmony_ci } else if (formatToAdopt == nullptr) { 7201cb0ef41Sopenharmony_ci f = nullptr; 7211cb0ef41Sopenharmony_ci } else { 7221cb0ef41Sopenharmony_ci f = formatToAdopt->clone(); 7231cb0ef41Sopenharmony_ci if (f == nullptr) { 7241cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 7251cb0ef41Sopenharmony_ci return; 7261cb0ef41Sopenharmony_ci } 7271cb0ef41Sopenharmony_ci } 7281cb0ef41Sopenharmony_ci setCustomArgStartFormat(partIndex, f, status); 7291cb0ef41Sopenharmony_ci } 7301cb0ef41Sopenharmony_ci } 7311cb0ef41Sopenharmony_ci} 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_ci// ------------------------------------- 7341cb0ef41Sopenharmony_ci// Set a single format. 7351cb0ef41Sopenharmony_ci// Do nothing if the variable is not less than the array count. 7361cb0ef41Sopenharmony_civoid 7371cb0ef41Sopenharmony_ciMessageFormat::setFormat(int32_t n, const Format& newFormat) { 7381cb0ef41Sopenharmony_ci 7391cb0ef41Sopenharmony_ci if (n >= 0) { 7401cb0ef41Sopenharmony_ci int32_t formatNumber = 0; 7411cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; 7421cb0ef41Sopenharmony_ci (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 7431cb0ef41Sopenharmony_ci if (n == formatNumber) { 7441cb0ef41Sopenharmony_ci Format* new_format = newFormat.clone(); 7451cb0ef41Sopenharmony_ci if (new_format) { 7461cb0ef41Sopenharmony_ci UErrorCode status = U_ZERO_ERROR; 7471cb0ef41Sopenharmony_ci setCustomArgStartFormat(partIndex, new_format, status); 7481cb0ef41Sopenharmony_ci } 7491cb0ef41Sopenharmony_ci return; 7501cb0ef41Sopenharmony_ci } 7511cb0ef41Sopenharmony_ci ++formatNumber; 7521cb0ef41Sopenharmony_ci } 7531cb0ef41Sopenharmony_ci } 7541cb0ef41Sopenharmony_ci} 7551cb0ef41Sopenharmony_ci 7561cb0ef41Sopenharmony_ci// ------------------------------------- 7571cb0ef41Sopenharmony_ci// Get a single format by format name. 7581cb0ef41Sopenharmony_ci// Do nothing if the variable is not less than the array count. 7591cb0ef41Sopenharmony_ciFormat * 7601cb0ef41Sopenharmony_ciMessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) { 7611cb0ef41Sopenharmony_ci if (U_FAILURE(status) || cachedFormatters == nullptr) return nullptr; 7621cb0ef41Sopenharmony_ci 7631cb0ef41Sopenharmony_ci int32_t argNumber = MessagePattern::validateArgumentName(formatName); 7641cb0ef41Sopenharmony_ci if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) { 7651cb0ef41Sopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 7661cb0ef41Sopenharmony_ci return nullptr; 7671cb0ef41Sopenharmony_ci } 7681cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 7691cb0ef41Sopenharmony_ci if (argNameMatches(partIndex + 1, formatName, argNumber)) { 7701cb0ef41Sopenharmony_ci return getCachedFormatter(partIndex); 7711cb0ef41Sopenharmony_ci } 7721cb0ef41Sopenharmony_ci } 7731cb0ef41Sopenharmony_ci return nullptr; 7741cb0ef41Sopenharmony_ci} 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci// ------------------------------------- 7771cb0ef41Sopenharmony_ci// Set a single format by format name 7781cb0ef41Sopenharmony_ci// Do nothing if the variable is not less than the array count. 7791cb0ef41Sopenharmony_civoid 7801cb0ef41Sopenharmony_ciMessageFormat::setFormat(const UnicodeString& formatName, 7811cb0ef41Sopenharmony_ci const Format& newFormat, 7821cb0ef41Sopenharmony_ci UErrorCode& status) { 7831cb0ef41Sopenharmony_ci if (U_FAILURE(status)) return; 7841cb0ef41Sopenharmony_ci 7851cb0ef41Sopenharmony_ci int32_t argNumber = MessagePattern::validateArgumentName(formatName); 7861cb0ef41Sopenharmony_ci if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) { 7871cb0ef41Sopenharmony_ci status = U_ILLEGAL_ARGUMENT_ERROR; 7881cb0ef41Sopenharmony_ci return; 7891cb0ef41Sopenharmony_ci } 7901cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; 7911cb0ef41Sopenharmony_ci (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status); 7921cb0ef41Sopenharmony_ci ) { 7931cb0ef41Sopenharmony_ci if (argNameMatches(partIndex + 1, formatName, argNumber)) { 7941cb0ef41Sopenharmony_ci Format* new_format = newFormat.clone(); 7951cb0ef41Sopenharmony_ci if (new_format == nullptr) { 7961cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 7971cb0ef41Sopenharmony_ci return; 7981cb0ef41Sopenharmony_ci } 7991cb0ef41Sopenharmony_ci setCustomArgStartFormat(partIndex, new_format, status); 8001cb0ef41Sopenharmony_ci } 8011cb0ef41Sopenharmony_ci } 8021cb0ef41Sopenharmony_ci} 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ci// ------------------------------------- 8051cb0ef41Sopenharmony_ci// Gets the format array. 8061cb0ef41Sopenharmony_ciconst Format** 8071cb0ef41Sopenharmony_ciMessageFormat::getFormats(int32_t& cnt) const 8081cb0ef41Sopenharmony_ci{ 8091cb0ef41Sopenharmony_ci // This old API returns an array (which we hold) of Format* 8101cb0ef41Sopenharmony_ci // pointers. The array is valid up to the next call to any 8111cb0ef41Sopenharmony_ci // method on this object. We construct and resize an array 8121cb0ef41Sopenharmony_ci // on demand that contains aliases to the subformats[i].format 8131cb0ef41Sopenharmony_ci // pointers. 8141cb0ef41Sopenharmony_ci 8151cb0ef41Sopenharmony_ci // Get total required capacity first (it's refreshed on each call). 8161cb0ef41Sopenharmony_ci int32_t totalCapacity = 0; 8171cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {} 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_ci MessageFormat* t = const_cast<MessageFormat*> (this); 8201cb0ef41Sopenharmony_ci cnt = 0; 8211cb0ef41Sopenharmony_ci if (formatAliases == nullptr) { 8221cb0ef41Sopenharmony_ci t->formatAliasesCapacity = totalCapacity; 8231cb0ef41Sopenharmony_ci Format** a = (Format**) 8241cb0ef41Sopenharmony_ci uprv_malloc(sizeof(Format*) * formatAliasesCapacity); 8251cb0ef41Sopenharmony_ci if (a == nullptr) { 8261cb0ef41Sopenharmony_ci t->formatAliasesCapacity = 0; 8271cb0ef41Sopenharmony_ci return nullptr; 8281cb0ef41Sopenharmony_ci } 8291cb0ef41Sopenharmony_ci t->formatAliases = a; 8301cb0ef41Sopenharmony_ci } else if (totalCapacity > formatAliasesCapacity) { 8311cb0ef41Sopenharmony_ci Format** a = (Format**) 8321cb0ef41Sopenharmony_ci uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity); 8331cb0ef41Sopenharmony_ci if (a == nullptr) { 8341cb0ef41Sopenharmony_ci t->formatAliasesCapacity = 0; 8351cb0ef41Sopenharmony_ci return nullptr; 8361cb0ef41Sopenharmony_ci } 8371cb0ef41Sopenharmony_ci t->formatAliases = a; 8381cb0ef41Sopenharmony_ci t->formatAliasesCapacity = totalCapacity; 8391cb0ef41Sopenharmony_ci } 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 8421cb0ef41Sopenharmony_ci t->formatAliases[cnt++] = getCachedFormatter(partIndex); 8431cb0ef41Sopenharmony_ci } 8441cb0ef41Sopenharmony_ci 8451cb0ef41Sopenharmony_ci return (const Format**)formatAliases; 8461cb0ef41Sopenharmony_ci} 8471cb0ef41Sopenharmony_ci 8481cb0ef41Sopenharmony_ci 8491cb0ef41Sopenharmony_ciUnicodeString MessageFormat::getArgName(int32_t partIndex) { 8501cb0ef41Sopenharmony_ci const MessagePattern::Part& part = msgPattern.getPart(partIndex); 8511cb0ef41Sopenharmony_ci return msgPattern.getSubstring(part); 8521cb0ef41Sopenharmony_ci} 8531cb0ef41Sopenharmony_ci 8541cb0ef41Sopenharmony_ciStringEnumeration* 8551cb0ef41Sopenharmony_ciMessageFormat::getFormatNames(UErrorCode& status) { 8561cb0ef41Sopenharmony_ci if (U_FAILURE(status)) return nullptr; 8571cb0ef41Sopenharmony_ci 8581cb0ef41Sopenharmony_ci LocalPointer<UVector> formatNames(new UVector(status), status); 8591cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 8601cb0ef41Sopenharmony_ci return nullptr; 8611cb0ef41Sopenharmony_ci } 8621cb0ef41Sopenharmony_ci formatNames->setDeleter(uprv_deleteUObject); 8631cb0ef41Sopenharmony_ci 8641cb0ef41Sopenharmony_ci for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 8651cb0ef41Sopenharmony_ci LocalPointer<UnicodeString> name(getArgName(partIndex + 1).clone(), status); 8661cb0ef41Sopenharmony_ci formatNames->adoptElement(name.orphan(), status); 8671cb0ef41Sopenharmony_ci if (U_FAILURE(status)) return nullptr; 8681cb0ef41Sopenharmony_ci } 8691cb0ef41Sopenharmony_ci 8701cb0ef41Sopenharmony_ci LocalPointer<StringEnumeration> nameEnumerator( 8711cb0ef41Sopenharmony_ci new FormatNameEnumeration(std::move(formatNames), status), status); 8721cb0ef41Sopenharmony_ci return U_SUCCESS(status) ? nameEnumerator.orphan() : nullptr; 8731cb0ef41Sopenharmony_ci} 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci// ------------------------------------- 8761cb0ef41Sopenharmony_ci// Formats the source Formattable array and copy into the result buffer. 8771cb0ef41Sopenharmony_ci// Ignore the FieldPosition result for error checking. 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ciUnicodeString& 8801cb0ef41Sopenharmony_ciMessageFormat::format(const Formattable* source, 8811cb0ef41Sopenharmony_ci int32_t cnt, 8821cb0ef41Sopenharmony_ci UnicodeString& appendTo, 8831cb0ef41Sopenharmony_ci FieldPosition& ignore, 8841cb0ef41Sopenharmony_ci UErrorCode& success) const 8851cb0ef41Sopenharmony_ci{ 8861cb0ef41Sopenharmony_ci return format(source, nullptr, cnt, appendTo, &ignore, success); 8871cb0ef41Sopenharmony_ci} 8881cb0ef41Sopenharmony_ci 8891cb0ef41Sopenharmony_ci// ------------------------------------- 8901cb0ef41Sopenharmony_ci// Internally creates a MessageFormat instance based on the 8911cb0ef41Sopenharmony_ci// pattern and formats the arguments Formattable array and 8921cb0ef41Sopenharmony_ci// copy into the appendTo buffer. 8931cb0ef41Sopenharmony_ci 8941cb0ef41Sopenharmony_ciUnicodeString& 8951cb0ef41Sopenharmony_ciMessageFormat::format( const UnicodeString& pattern, 8961cb0ef41Sopenharmony_ci const Formattable* arguments, 8971cb0ef41Sopenharmony_ci int32_t cnt, 8981cb0ef41Sopenharmony_ci UnicodeString& appendTo, 8991cb0ef41Sopenharmony_ci UErrorCode& success) 9001cb0ef41Sopenharmony_ci{ 9011cb0ef41Sopenharmony_ci MessageFormat temp(pattern, success); 9021cb0ef41Sopenharmony_ci return temp.format(arguments, nullptr, cnt, appendTo, nullptr, success); 9031cb0ef41Sopenharmony_ci} 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci// ------------------------------------- 9061cb0ef41Sopenharmony_ci// Formats the source Formattable object and copy into the 9071cb0ef41Sopenharmony_ci// appendTo buffer. The Formattable object must be an array 9081cb0ef41Sopenharmony_ci// of Formattable instances, returns error otherwise. 9091cb0ef41Sopenharmony_ci 9101cb0ef41Sopenharmony_ciUnicodeString& 9111cb0ef41Sopenharmony_ciMessageFormat::format(const Formattable& source, 9121cb0ef41Sopenharmony_ci UnicodeString& appendTo, 9131cb0ef41Sopenharmony_ci FieldPosition& ignore, 9141cb0ef41Sopenharmony_ci UErrorCode& success) const 9151cb0ef41Sopenharmony_ci{ 9161cb0ef41Sopenharmony_ci if (U_FAILURE(success)) 9171cb0ef41Sopenharmony_ci return appendTo; 9181cb0ef41Sopenharmony_ci if (source.getType() != Formattable::kArray) { 9191cb0ef41Sopenharmony_ci success = U_ILLEGAL_ARGUMENT_ERROR; 9201cb0ef41Sopenharmony_ci return appendTo; 9211cb0ef41Sopenharmony_ci } 9221cb0ef41Sopenharmony_ci int32_t cnt; 9231cb0ef41Sopenharmony_ci const Formattable* tmpPtr = source.getArray(cnt); 9241cb0ef41Sopenharmony_ci return format(tmpPtr, nullptr, cnt, appendTo, &ignore, success); 9251cb0ef41Sopenharmony_ci} 9261cb0ef41Sopenharmony_ci 9271cb0ef41Sopenharmony_ciUnicodeString& 9281cb0ef41Sopenharmony_ciMessageFormat::format(const UnicodeString* argumentNames, 9291cb0ef41Sopenharmony_ci const Formattable* arguments, 9301cb0ef41Sopenharmony_ci int32_t count, 9311cb0ef41Sopenharmony_ci UnicodeString& appendTo, 9321cb0ef41Sopenharmony_ci UErrorCode& success) const { 9331cb0ef41Sopenharmony_ci return format(arguments, argumentNames, count, appendTo, nullptr, success); 9341cb0ef41Sopenharmony_ci} 9351cb0ef41Sopenharmony_ci 9361cb0ef41Sopenharmony_ci// Does linear search to find the match for an ArgName. 9371cb0ef41Sopenharmony_ciconst Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments, 9381cb0ef41Sopenharmony_ci const UnicodeString *argumentNames, 9391cb0ef41Sopenharmony_ci int32_t cnt, UnicodeString& name) const { 9401cb0ef41Sopenharmony_ci for (int32_t i = 0; i < cnt; ++i) { 9411cb0ef41Sopenharmony_ci if (0 == argumentNames[i].compare(name)) { 9421cb0ef41Sopenharmony_ci return arguments + i; 9431cb0ef41Sopenharmony_ci } 9441cb0ef41Sopenharmony_ci } 9451cb0ef41Sopenharmony_ci return nullptr; 9461cb0ef41Sopenharmony_ci} 9471cb0ef41Sopenharmony_ci 9481cb0ef41Sopenharmony_ci 9491cb0ef41Sopenharmony_ciUnicodeString& 9501cb0ef41Sopenharmony_ciMessageFormat::format(const Formattable* arguments, 9511cb0ef41Sopenharmony_ci const UnicodeString *argumentNames, 9521cb0ef41Sopenharmony_ci int32_t cnt, 9531cb0ef41Sopenharmony_ci UnicodeString& appendTo, 9541cb0ef41Sopenharmony_ci FieldPosition* pos, 9551cb0ef41Sopenharmony_ci UErrorCode& status) const { 9561cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 9571cb0ef41Sopenharmony_ci return appendTo; 9581cb0ef41Sopenharmony_ci } 9591cb0ef41Sopenharmony_ci 9601cb0ef41Sopenharmony_ci UnicodeStringAppendable usapp(appendTo); 9611cb0ef41Sopenharmony_ci AppendableWrapper app(usapp); 9621cb0ef41Sopenharmony_ci format(0, nullptr, arguments, argumentNames, cnt, app, pos, status); 9631cb0ef41Sopenharmony_ci return appendTo; 9641cb0ef41Sopenharmony_ci} 9651cb0ef41Sopenharmony_ci 9661cb0ef41Sopenharmony_cinamespace { 9671cb0ef41Sopenharmony_ci 9681cb0ef41Sopenharmony_ci/** 9691cb0ef41Sopenharmony_ci * Mutable input/output values for the PluralSelectorProvider. 9701cb0ef41Sopenharmony_ci * Separate so that it is possible to make MessageFormat Freezable. 9711cb0ef41Sopenharmony_ci */ 9721cb0ef41Sopenharmony_ciclass PluralSelectorContext { 9731cb0ef41Sopenharmony_cipublic: 9741cb0ef41Sopenharmony_ci PluralSelectorContext(int32_t start, const UnicodeString &name, 9751cb0ef41Sopenharmony_ci const Formattable &num, double off, UErrorCode &errorCode) 9761cb0ef41Sopenharmony_ci : startIndex(start), argName(name), offset(off), 9771cb0ef41Sopenharmony_ci numberArgIndex(-1), formatter(nullptr), forReplaceNumber(false) { 9781cb0ef41Sopenharmony_ci // number needs to be set even when select() is not called. 9791cb0ef41Sopenharmony_ci // Keep it as a Number/Formattable: 9801cb0ef41Sopenharmony_ci // For format() methods, and to preserve information (e.g., BigDecimal). 9811cb0ef41Sopenharmony_ci if(off == 0) { 9821cb0ef41Sopenharmony_ci number = num; 9831cb0ef41Sopenharmony_ci } else { 9841cb0ef41Sopenharmony_ci number = num.getDouble(errorCode) - off; 9851cb0ef41Sopenharmony_ci } 9861cb0ef41Sopenharmony_ci } 9871cb0ef41Sopenharmony_ci 9881cb0ef41Sopenharmony_ci // Input values for plural selection with decimals. 9891cb0ef41Sopenharmony_ci int32_t startIndex; 9901cb0ef41Sopenharmony_ci const UnicodeString &argName; 9911cb0ef41Sopenharmony_ci /** argument number - plural offset */ 9921cb0ef41Sopenharmony_ci Formattable number; 9931cb0ef41Sopenharmony_ci double offset; 9941cb0ef41Sopenharmony_ci // Output values for plural selection with decimals. 9951cb0ef41Sopenharmony_ci /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */ 9961cb0ef41Sopenharmony_ci int32_t numberArgIndex; 9971cb0ef41Sopenharmony_ci const Format *formatter; 9981cb0ef41Sopenharmony_ci /** formatted argument number - plural offset */ 9991cb0ef41Sopenharmony_ci UnicodeString numberString; 10001cb0ef41Sopenharmony_ci /** true if number-offset was formatted with the stock number formatter */ 10011cb0ef41Sopenharmony_ci UBool forReplaceNumber; 10021cb0ef41Sopenharmony_ci}; 10031cb0ef41Sopenharmony_ci 10041cb0ef41Sopenharmony_ci} // namespace 10051cb0ef41Sopenharmony_ci 10061cb0ef41Sopenharmony_ci// if argumentNames is nullptr, this means arguments is a numeric array. 10071cb0ef41Sopenharmony_ci// arguments can not be nullptr. 10081cb0ef41Sopenharmony_ci// We use const void *plNumber rather than const PluralSelectorContext *pluralNumber 10091cb0ef41Sopenharmony_ci// so that we need not declare the PluralSelectorContext in the public header file. 10101cb0ef41Sopenharmony_civoid MessageFormat::format(int32_t msgStart, const void *plNumber, 10111cb0ef41Sopenharmony_ci const Formattable* arguments, 10121cb0ef41Sopenharmony_ci const UnicodeString *argumentNames, 10131cb0ef41Sopenharmony_ci int32_t cnt, 10141cb0ef41Sopenharmony_ci AppendableWrapper& appendTo, 10151cb0ef41Sopenharmony_ci FieldPosition* ignore, 10161cb0ef41Sopenharmony_ci UErrorCode& success) const { 10171cb0ef41Sopenharmony_ci if (U_FAILURE(success)) { 10181cb0ef41Sopenharmony_ci return; 10191cb0ef41Sopenharmony_ci } 10201cb0ef41Sopenharmony_ci 10211cb0ef41Sopenharmony_ci const UnicodeString& msgString = msgPattern.getPatternString(); 10221cb0ef41Sopenharmony_ci int32_t prevIndex = msgPattern.getPart(msgStart).getLimit(); 10231cb0ef41Sopenharmony_ci for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) { 10241cb0ef41Sopenharmony_ci const MessagePattern::Part* part = &msgPattern.getPart(i); 10251cb0ef41Sopenharmony_ci const UMessagePatternPartType type = part->getType(); 10261cb0ef41Sopenharmony_ci int32_t index = part->getIndex(); 10271cb0ef41Sopenharmony_ci appendTo.append(msgString, prevIndex, index - prevIndex); 10281cb0ef41Sopenharmony_ci if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { 10291cb0ef41Sopenharmony_ci return; 10301cb0ef41Sopenharmony_ci } 10311cb0ef41Sopenharmony_ci prevIndex = part->getLimit(); 10321cb0ef41Sopenharmony_ci if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) { 10331cb0ef41Sopenharmony_ci const PluralSelectorContext &pluralNumber = 10341cb0ef41Sopenharmony_ci *static_cast<const PluralSelectorContext *>(plNumber); 10351cb0ef41Sopenharmony_ci if(pluralNumber.forReplaceNumber) { 10361cb0ef41Sopenharmony_ci // number-offset was already formatted. 10371cb0ef41Sopenharmony_ci appendTo.formatAndAppend(pluralNumber.formatter, 10381cb0ef41Sopenharmony_ci pluralNumber.number, pluralNumber.numberString, success); 10391cb0ef41Sopenharmony_ci } else { 10401cb0ef41Sopenharmony_ci const NumberFormat* nf = getDefaultNumberFormat(success); 10411cb0ef41Sopenharmony_ci appendTo.formatAndAppend(nf, pluralNumber.number, success); 10421cb0ef41Sopenharmony_ci } 10431cb0ef41Sopenharmony_ci continue; 10441cb0ef41Sopenharmony_ci } 10451cb0ef41Sopenharmony_ci if (type != UMSGPAT_PART_TYPE_ARG_START) { 10461cb0ef41Sopenharmony_ci continue; 10471cb0ef41Sopenharmony_ci } 10481cb0ef41Sopenharmony_ci int32_t argLimit = msgPattern.getLimitPartIndex(i); 10491cb0ef41Sopenharmony_ci UMessagePatternArgType argType = part->getArgType(); 10501cb0ef41Sopenharmony_ci part = &msgPattern.getPart(++i); 10511cb0ef41Sopenharmony_ci const Formattable* arg; 10521cb0ef41Sopenharmony_ci UBool noArg = false; 10531cb0ef41Sopenharmony_ci UnicodeString argName = msgPattern.getSubstring(*part); 10541cb0ef41Sopenharmony_ci if (argumentNames == nullptr) { 10551cb0ef41Sopenharmony_ci int32_t argNumber = part->getValue(); // ARG_NUMBER 10561cb0ef41Sopenharmony_ci if (0 <= argNumber && argNumber < cnt) { 10571cb0ef41Sopenharmony_ci arg = arguments + argNumber; 10581cb0ef41Sopenharmony_ci } else { 10591cb0ef41Sopenharmony_ci arg = nullptr; 10601cb0ef41Sopenharmony_ci noArg = true; 10611cb0ef41Sopenharmony_ci } 10621cb0ef41Sopenharmony_ci } else { 10631cb0ef41Sopenharmony_ci arg = getArgFromListByName(arguments, argumentNames, cnt, argName); 10641cb0ef41Sopenharmony_ci if (arg == nullptr) { 10651cb0ef41Sopenharmony_ci noArg = true; 10661cb0ef41Sopenharmony_ci } 10671cb0ef41Sopenharmony_ci } 10681cb0ef41Sopenharmony_ci ++i; 10691cb0ef41Sopenharmony_ci int32_t prevDestLength = appendTo.length(); 10701cb0ef41Sopenharmony_ci const Format* formatter = nullptr; 10711cb0ef41Sopenharmony_ci if (noArg) { 10721cb0ef41Sopenharmony_ci appendTo.append( 10731cb0ef41Sopenharmony_ci UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE)); 10741cb0ef41Sopenharmony_ci } else if (arg == nullptr) { 10751cb0ef41Sopenharmony_ci appendTo.append(NULL_STRING, 4); 10761cb0ef41Sopenharmony_ci } else if(plNumber!=nullptr && 10771cb0ef41Sopenharmony_ci static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) { 10781cb0ef41Sopenharmony_ci const PluralSelectorContext &pluralNumber = 10791cb0ef41Sopenharmony_ci *static_cast<const PluralSelectorContext *>(plNumber); 10801cb0ef41Sopenharmony_ci if(pluralNumber.offset == 0) { 10811cb0ef41Sopenharmony_ci // The number was already formatted with this formatter. 10821cb0ef41Sopenharmony_ci appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number, 10831cb0ef41Sopenharmony_ci pluralNumber.numberString, success); 10841cb0ef41Sopenharmony_ci } else { 10851cb0ef41Sopenharmony_ci // Do not use the formatted (number-offset) string for a named argument 10861cb0ef41Sopenharmony_ci // that formats the number without subtracting the offset. 10871cb0ef41Sopenharmony_ci appendTo.formatAndAppend(pluralNumber.formatter, *arg, success); 10881cb0ef41Sopenharmony_ci } 10891cb0ef41Sopenharmony_ci } else if ((formatter = getCachedFormatter(i -2)) != 0) { 10901cb0ef41Sopenharmony_ci // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings. 10911cb0ef41Sopenharmony_ci if (dynamic_cast<const ChoiceFormat*>(formatter) || 10921cb0ef41Sopenharmony_ci dynamic_cast<const PluralFormat*>(formatter) || 10931cb0ef41Sopenharmony_ci dynamic_cast<const SelectFormat*>(formatter)) { 10941cb0ef41Sopenharmony_ci // We only handle nested formats here if they were provided via 10951cb0ef41Sopenharmony_ci // setFormat() or its siblings. Otherwise they are not cached and instead 10961cb0ef41Sopenharmony_ci // handled below according to argType. 10971cb0ef41Sopenharmony_ci UnicodeString subMsgString; 10981cb0ef41Sopenharmony_ci formatter->format(*arg, subMsgString, success); 10991cb0ef41Sopenharmony_ci if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 || 11001cb0ef41Sopenharmony_ci (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern)) 11011cb0ef41Sopenharmony_ci ) { 11021cb0ef41Sopenharmony_ci MessageFormat subMsgFormat(subMsgString, fLocale, success); 11031cb0ef41Sopenharmony_ci subMsgFormat.format(0, nullptr, arguments, argumentNames, cnt, appendTo, ignore, success); 11041cb0ef41Sopenharmony_ci } else { 11051cb0ef41Sopenharmony_ci appendTo.append(subMsgString); 11061cb0ef41Sopenharmony_ci } 11071cb0ef41Sopenharmony_ci } else { 11081cb0ef41Sopenharmony_ci appendTo.formatAndAppend(formatter, *arg, success); 11091cb0ef41Sopenharmony_ci } 11101cb0ef41Sopenharmony_ci } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) { 11111cb0ef41Sopenharmony_ci // We arrive here if getCachedFormatter returned nullptr, but there was actually an element in the hash table. 11121cb0ef41Sopenharmony_ci // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check 11131cb0ef41Sopenharmony_ci // for the hash table containing DummyFormat. 11141cb0ef41Sopenharmony_ci if (arg->isNumeric()) { 11151cb0ef41Sopenharmony_ci const NumberFormat* nf = getDefaultNumberFormat(success); 11161cb0ef41Sopenharmony_ci appendTo.formatAndAppend(nf, *arg, success); 11171cb0ef41Sopenharmony_ci } else if (arg->getType() == Formattable::kDate) { 11181cb0ef41Sopenharmony_ci const DateFormat* df = getDefaultDateFormat(success); 11191cb0ef41Sopenharmony_ci appendTo.formatAndAppend(df, *arg, success); 11201cb0ef41Sopenharmony_ci } else { 11211cb0ef41Sopenharmony_ci appendTo.append(arg->getString(success)); 11221cb0ef41Sopenharmony_ci } 11231cb0ef41Sopenharmony_ci } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) { 11241cb0ef41Sopenharmony_ci if (!arg->isNumeric()) { 11251cb0ef41Sopenharmony_ci success = U_ILLEGAL_ARGUMENT_ERROR; 11261cb0ef41Sopenharmony_ci return; 11271cb0ef41Sopenharmony_ci } 11281cb0ef41Sopenharmony_ci // We must use the Formattable::getDouble() variant with the UErrorCode parameter 11291cb0ef41Sopenharmony_ci // because only this one converts non-double numeric types to double. 11301cb0ef41Sopenharmony_ci const double number = arg->getDouble(success); 11311cb0ef41Sopenharmony_ci int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number); 11321cb0ef41Sopenharmony_ci formatComplexSubMessage(subMsgStart, nullptr, arguments, argumentNames, 11331cb0ef41Sopenharmony_ci cnt, appendTo, success); 11341cb0ef41Sopenharmony_ci } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) { 11351cb0ef41Sopenharmony_ci if (!arg->isNumeric()) { 11361cb0ef41Sopenharmony_ci success = U_ILLEGAL_ARGUMENT_ERROR; 11371cb0ef41Sopenharmony_ci return; 11381cb0ef41Sopenharmony_ci } 11391cb0ef41Sopenharmony_ci const PluralSelectorProvider &selector = 11401cb0ef41Sopenharmony_ci argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider; 11411cb0ef41Sopenharmony_ci // We must use the Formattable::getDouble() variant with the UErrorCode parameter 11421cb0ef41Sopenharmony_ci // because only this one converts non-double numeric types to double. 11431cb0ef41Sopenharmony_ci double offset = msgPattern.getPluralOffset(i); 11441cb0ef41Sopenharmony_ci PluralSelectorContext context(i, argName, *arg, offset, success); 11451cb0ef41Sopenharmony_ci int32_t subMsgStart = PluralFormat::findSubMessage( 11461cb0ef41Sopenharmony_ci msgPattern, i, selector, &context, arg->getDouble(success), success); 11471cb0ef41Sopenharmony_ci formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames, 11481cb0ef41Sopenharmony_ci cnt, appendTo, success); 11491cb0ef41Sopenharmony_ci } else if (argType == UMSGPAT_ARG_TYPE_SELECT) { 11501cb0ef41Sopenharmony_ci int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success); 11511cb0ef41Sopenharmony_ci formatComplexSubMessage(subMsgStart, nullptr, arguments, argumentNames, 11521cb0ef41Sopenharmony_ci cnt, appendTo, success); 11531cb0ef41Sopenharmony_ci } else { 11541cb0ef41Sopenharmony_ci // This should never happen. 11551cb0ef41Sopenharmony_ci success = U_INTERNAL_PROGRAM_ERROR; 11561cb0ef41Sopenharmony_ci return; 11571cb0ef41Sopenharmony_ci } 11581cb0ef41Sopenharmony_ci ignore = updateMetaData(appendTo, prevDestLength, ignore, arg); 11591cb0ef41Sopenharmony_ci prevIndex = msgPattern.getPart(argLimit).getLimit(); 11601cb0ef41Sopenharmony_ci i = argLimit; 11611cb0ef41Sopenharmony_ci } 11621cb0ef41Sopenharmony_ci} 11631cb0ef41Sopenharmony_ci 11641cb0ef41Sopenharmony_ci 11651cb0ef41Sopenharmony_civoid MessageFormat::formatComplexSubMessage(int32_t msgStart, 11661cb0ef41Sopenharmony_ci const void *plNumber, 11671cb0ef41Sopenharmony_ci const Formattable* arguments, 11681cb0ef41Sopenharmony_ci const UnicodeString *argumentNames, 11691cb0ef41Sopenharmony_ci int32_t cnt, 11701cb0ef41Sopenharmony_ci AppendableWrapper& appendTo, 11711cb0ef41Sopenharmony_ci UErrorCode& success) const { 11721cb0ef41Sopenharmony_ci if (U_FAILURE(success)) { 11731cb0ef41Sopenharmony_ci return; 11741cb0ef41Sopenharmony_ci } 11751cb0ef41Sopenharmony_ci 11761cb0ef41Sopenharmony_ci if (!MessageImpl::jdkAposMode(msgPattern)) { 11771cb0ef41Sopenharmony_ci format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, nullptr, success); 11781cb0ef41Sopenharmony_ci return; 11791cb0ef41Sopenharmony_ci } 11801cb0ef41Sopenharmony_ci 11811cb0ef41Sopenharmony_ci // JDK compatibility mode: (see JDK MessageFormat.format() API docs) 11821cb0ef41Sopenharmony_ci // - remove SKIP_SYNTAX; that is, remove half of the apostrophes 11831cb0ef41Sopenharmony_ci // - if the result string contains an open curly brace '{' then 11841cb0ef41Sopenharmony_ci // instantiate a temporary MessageFormat object and format again; 11851cb0ef41Sopenharmony_ci // otherwise just append the result string 11861cb0ef41Sopenharmony_ci const UnicodeString& msgString = msgPattern.getPatternString(); 11871cb0ef41Sopenharmony_ci UnicodeString sb; 11881cb0ef41Sopenharmony_ci int32_t prevIndex = msgPattern.getPart(msgStart).getLimit(); 11891cb0ef41Sopenharmony_ci for (int32_t i = msgStart;;) { 11901cb0ef41Sopenharmony_ci const MessagePattern::Part& part = msgPattern.getPart(++i); 11911cb0ef41Sopenharmony_ci const UMessagePatternPartType type = part.getType(); 11921cb0ef41Sopenharmony_ci int32_t index = part.getIndex(); 11931cb0ef41Sopenharmony_ci if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { 11941cb0ef41Sopenharmony_ci sb.append(msgString, prevIndex, index - prevIndex); 11951cb0ef41Sopenharmony_ci break; 11961cb0ef41Sopenharmony_ci } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) { 11971cb0ef41Sopenharmony_ci sb.append(msgString, prevIndex, index - prevIndex); 11981cb0ef41Sopenharmony_ci if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) { 11991cb0ef41Sopenharmony_ci const PluralSelectorContext &pluralNumber = 12001cb0ef41Sopenharmony_ci *static_cast<const PluralSelectorContext *>(plNumber); 12011cb0ef41Sopenharmony_ci if(pluralNumber.forReplaceNumber) { 12021cb0ef41Sopenharmony_ci // number-offset was already formatted. 12031cb0ef41Sopenharmony_ci sb.append(pluralNumber.numberString); 12041cb0ef41Sopenharmony_ci } else { 12051cb0ef41Sopenharmony_ci const NumberFormat* nf = getDefaultNumberFormat(success); 12061cb0ef41Sopenharmony_ci sb.append(nf->format(pluralNumber.number, sb, success)); 12071cb0ef41Sopenharmony_ci } 12081cb0ef41Sopenharmony_ci } 12091cb0ef41Sopenharmony_ci prevIndex = part.getLimit(); 12101cb0ef41Sopenharmony_ci } else if (type == UMSGPAT_PART_TYPE_ARG_START) { 12111cb0ef41Sopenharmony_ci sb.append(msgString, prevIndex, index - prevIndex); 12121cb0ef41Sopenharmony_ci prevIndex = index; 12131cb0ef41Sopenharmony_ci i = msgPattern.getLimitPartIndex(i); 12141cb0ef41Sopenharmony_ci index = msgPattern.getPart(i).getLimit(); 12151cb0ef41Sopenharmony_ci MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb); 12161cb0ef41Sopenharmony_ci prevIndex = index; 12171cb0ef41Sopenharmony_ci } 12181cb0ef41Sopenharmony_ci } 12191cb0ef41Sopenharmony_ci if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) { 12201cb0ef41Sopenharmony_ci UnicodeString emptyPattern; // gcc 3.3.3 fails with "UnicodeString()" as the first parameter. 12211cb0ef41Sopenharmony_ci MessageFormat subMsgFormat(emptyPattern, fLocale, success); 12221cb0ef41Sopenharmony_ci subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, nullptr, success); 12231cb0ef41Sopenharmony_ci subMsgFormat.format(0, nullptr, arguments, argumentNames, cnt, appendTo, nullptr, success); 12241cb0ef41Sopenharmony_ci } else { 12251cb0ef41Sopenharmony_ci appendTo.append(sb); 12261cb0ef41Sopenharmony_ci } 12271cb0ef41Sopenharmony_ci} 12281cb0ef41Sopenharmony_ci 12291cb0ef41Sopenharmony_ci 12301cb0ef41Sopenharmony_ciUnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const { 12311cb0ef41Sopenharmony_ci const UnicodeString& msgString=msgPattern.getPatternString(); 12321cb0ef41Sopenharmony_ci int32_t prevIndex=msgPattern.getPart(from).getLimit(); 12331cb0ef41Sopenharmony_ci UnicodeString b; 12341cb0ef41Sopenharmony_ci for (int32_t i = from + 1; ; ++i) { 12351cb0ef41Sopenharmony_ci const MessagePattern::Part& part = msgPattern.getPart(i); 12361cb0ef41Sopenharmony_ci const UMessagePatternPartType type=part.getType(); 12371cb0ef41Sopenharmony_ci int32_t index=part.getIndex(); 12381cb0ef41Sopenharmony_ci b.append(msgString, prevIndex, index - prevIndex); 12391cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) { 12401cb0ef41Sopenharmony_ci return b; 12411cb0ef41Sopenharmony_ci } 12421cb0ef41Sopenharmony_ci // Unexpected Part "part" in parsed message. 12431cb0ef41Sopenharmony_ci U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR); 12441cb0ef41Sopenharmony_ci prevIndex=part.getLimit(); 12451cb0ef41Sopenharmony_ci } 12461cb0ef41Sopenharmony_ci} 12471cb0ef41Sopenharmony_ci 12481cb0ef41Sopenharmony_ci 12491cb0ef41Sopenharmony_ciFieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/, 12501cb0ef41Sopenharmony_ci FieldPosition* /*fp*/, const Formattable* /*argId*/) const { 12511cb0ef41Sopenharmony_ci // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing. 12521cb0ef41Sopenharmony_ci return nullptr; 12531cb0ef41Sopenharmony_ci /* 12541cb0ef41Sopenharmony_ci if (fp != nullptr && Field.ARGUMENT.equals(fp.getFieldAttribute())) { 12551cb0ef41Sopenharmony_ci fp->setBeginIndex(prevLength); 12561cb0ef41Sopenharmony_ci fp->setEndIndex(dest.get_length()); 12571cb0ef41Sopenharmony_ci return nullptr; 12581cb0ef41Sopenharmony_ci } 12591cb0ef41Sopenharmony_ci return fp; 12601cb0ef41Sopenharmony_ci */ 12611cb0ef41Sopenharmony_ci} 12621cb0ef41Sopenharmony_ci 12631cb0ef41Sopenharmony_ciint32_t 12641cb0ef41Sopenharmony_ciMessageFormat::findOtherSubMessage(int32_t partIndex) const { 12651cb0ef41Sopenharmony_ci int32_t count=msgPattern.countParts(); 12661cb0ef41Sopenharmony_ci const MessagePattern::Part *part = &msgPattern.getPart(partIndex); 12671cb0ef41Sopenharmony_ci if(MessagePattern::Part::hasNumericValue(part->getType())) { 12681cb0ef41Sopenharmony_ci ++partIndex; 12691cb0ef41Sopenharmony_ci } 12701cb0ef41Sopenharmony_ci // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples 12711cb0ef41Sopenharmony_ci // until ARG_LIMIT or end of plural-only pattern. 12721cb0ef41Sopenharmony_ci UnicodeString other(false, OTHER_STRING, 5); 12731cb0ef41Sopenharmony_ci do { 12741cb0ef41Sopenharmony_ci part=&msgPattern.getPart(partIndex++); 12751cb0ef41Sopenharmony_ci UMessagePatternPartType type=part->getType(); 12761cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { 12771cb0ef41Sopenharmony_ci break; 12781cb0ef41Sopenharmony_ci } 12791cb0ef41Sopenharmony_ci U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR); 12801cb0ef41Sopenharmony_ci // part is an ARG_SELECTOR followed by an optional explicit value, and then a message 12811cb0ef41Sopenharmony_ci if(msgPattern.partSubstringMatches(*part, other)) { 12821cb0ef41Sopenharmony_ci return partIndex; 12831cb0ef41Sopenharmony_ci } 12841cb0ef41Sopenharmony_ci if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) { 12851cb0ef41Sopenharmony_ci ++partIndex; // skip the numeric-value part of "=1" etc. 12861cb0ef41Sopenharmony_ci } 12871cb0ef41Sopenharmony_ci partIndex=msgPattern.getLimitPartIndex(partIndex); 12881cb0ef41Sopenharmony_ci } while(++partIndex<count); 12891cb0ef41Sopenharmony_ci return 0; 12901cb0ef41Sopenharmony_ci} 12911cb0ef41Sopenharmony_ci 12921cb0ef41Sopenharmony_ciint32_t 12931cb0ef41Sopenharmony_ciMessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const { 12941cb0ef41Sopenharmony_ci for(int32_t i=msgStart+1;; ++i) { 12951cb0ef41Sopenharmony_ci const MessagePattern::Part &part=msgPattern.getPart(i); 12961cb0ef41Sopenharmony_ci UMessagePatternPartType type=part.getType(); 12971cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) { 12981cb0ef41Sopenharmony_ci return 0; 12991cb0ef41Sopenharmony_ci } 13001cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) { 13011cb0ef41Sopenharmony_ci return -1; 13021cb0ef41Sopenharmony_ci } 13031cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_ARG_START) { 13041cb0ef41Sopenharmony_ci UMessagePatternArgType argType=part.getArgType(); 13051cb0ef41Sopenharmony_ci if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) { 13061cb0ef41Sopenharmony_ci // ARG_NUMBER or ARG_NAME 13071cb0ef41Sopenharmony_ci if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) { 13081cb0ef41Sopenharmony_ci return i; 13091cb0ef41Sopenharmony_ci } 13101cb0ef41Sopenharmony_ci } 13111cb0ef41Sopenharmony_ci i=msgPattern.getLimitPartIndex(i); 13121cb0ef41Sopenharmony_ci } 13131cb0ef41Sopenharmony_ci } 13141cb0ef41Sopenharmony_ci} 13151cb0ef41Sopenharmony_ci 13161cb0ef41Sopenharmony_civoid MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) { 13171cb0ef41Sopenharmony_ci // Deep copy pointer fields. 13181cb0ef41Sopenharmony_ci // We need not copy the formatAliases because they are re-filled 13191cb0ef41Sopenharmony_ci // in each getFormats() call. 13201cb0ef41Sopenharmony_ci // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules 13211cb0ef41Sopenharmony_ci // also get created on demand. 13221cb0ef41Sopenharmony_ci argTypeCount = that.argTypeCount; 13231cb0ef41Sopenharmony_ci if (argTypeCount > 0) { 13241cb0ef41Sopenharmony_ci if (!allocateArgTypes(argTypeCount, ec)) { 13251cb0ef41Sopenharmony_ci return; 13261cb0ef41Sopenharmony_ci } 13271cb0ef41Sopenharmony_ci uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0])); 13281cb0ef41Sopenharmony_ci } 13291cb0ef41Sopenharmony_ci if (cachedFormatters != nullptr) { 13301cb0ef41Sopenharmony_ci uhash_removeAll(cachedFormatters); 13311cb0ef41Sopenharmony_ci } 13321cb0ef41Sopenharmony_ci if (customFormatArgStarts != nullptr) { 13331cb0ef41Sopenharmony_ci uhash_removeAll(customFormatArgStarts); 13341cb0ef41Sopenharmony_ci } 13351cb0ef41Sopenharmony_ci if (that.cachedFormatters) { 13361cb0ef41Sopenharmony_ci if (cachedFormatters == nullptr) { 13371cb0ef41Sopenharmony_ci cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong, 13381cb0ef41Sopenharmony_ci equalFormatsForHash, &ec); 13391cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 13401cb0ef41Sopenharmony_ci return; 13411cb0ef41Sopenharmony_ci } 13421cb0ef41Sopenharmony_ci uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject); 13431cb0ef41Sopenharmony_ci } 13441cb0ef41Sopenharmony_ci 13451cb0ef41Sopenharmony_ci const int32_t count = uhash_count(that.cachedFormatters); 13461cb0ef41Sopenharmony_ci int32_t pos, idx; 13471cb0ef41Sopenharmony_ci for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) { 13481cb0ef41Sopenharmony_ci const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos); 13491cb0ef41Sopenharmony_ci Format* newFormat = ((Format*)(cur->value.pointer))->clone(); 13501cb0ef41Sopenharmony_ci if (newFormat) { 13511cb0ef41Sopenharmony_ci uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec); 13521cb0ef41Sopenharmony_ci } else { 13531cb0ef41Sopenharmony_ci ec = U_MEMORY_ALLOCATION_ERROR; 13541cb0ef41Sopenharmony_ci return; 13551cb0ef41Sopenharmony_ci } 13561cb0ef41Sopenharmony_ci } 13571cb0ef41Sopenharmony_ci } 13581cb0ef41Sopenharmony_ci if (that.customFormatArgStarts) { 13591cb0ef41Sopenharmony_ci if (customFormatArgStarts == nullptr) { 13601cb0ef41Sopenharmony_ci customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong, 13611cb0ef41Sopenharmony_ci nullptr, &ec); 13621cb0ef41Sopenharmony_ci } 13631cb0ef41Sopenharmony_ci const int32_t count = uhash_count(that.customFormatArgStarts); 13641cb0ef41Sopenharmony_ci int32_t pos, idx; 13651cb0ef41Sopenharmony_ci for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) { 13661cb0ef41Sopenharmony_ci const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos); 13671cb0ef41Sopenharmony_ci uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec); 13681cb0ef41Sopenharmony_ci } 13691cb0ef41Sopenharmony_ci } 13701cb0ef41Sopenharmony_ci} 13711cb0ef41Sopenharmony_ci 13721cb0ef41Sopenharmony_ci 13731cb0ef41Sopenharmony_ciFormattable* 13741cb0ef41Sopenharmony_ciMessageFormat::parse(int32_t msgStart, 13751cb0ef41Sopenharmony_ci const UnicodeString& source, 13761cb0ef41Sopenharmony_ci ParsePosition& pos, 13771cb0ef41Sopenharmony_ci int32_t& count, 13781cb0ef41Sopenharmony_ci UErrorCode& ec) const { 13791cb0ef41Sopenharmony_ci count = 0; 13801cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 13811cb0ef41Sopenharmony_ci pos.setErrorIndex(pos.getIndex()); 13821cb0ef41Sopenharmony_ci return nullptr; 13831cb0ef41Sopenharmony_ci } 13841cb0ef41Sopenharmony_ci // parse() does not work with named arguments. 13851cb0ef41Sopenharmony_ci if (msgPattern.hasNamedArguments()) { 13861cb0ef41Sopenharmony_ci ec = U_ARGUMENT_TYPE_MISMATCH; 13871cb0ef41Sopenharmony_ci pos.setErrorIndex(pos.getIndex()); 13881cb0ef41Sopenharmony_ci return nullptr; 13891cb0ef41Sopenharmony_ci } 13901cb0ef41Sopenharmony_ci LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]); 13911cb0ef41Sopenharmony_ci const UnicodeString& msgString=msgPattern.getPatternString(); 13921cb0ef41Sopenharmony_ci int32_t prevIndex=msgPattern.getPart(msgStart).getLimit(); 13931cb0ef41Sopenharmony_ci int32_t sourceOffset = pos.getIndex(); 13941cb0ef41Sopenharmony_ci ParsePosition tempStatus(0); 13951cb0ef41Sopenharmony_ci 13961cb0ef41Sopenharmony_ci for(int32_t i=msgStart+1; ; ++i) { 13971cb0ef41Sopenharmony_ci UBool haveArgResult = false; 13981cb0ef41Sopenharmony_ci const MessagePattern::Part* part=&msgPattern.getPart(i); 13991cb0ef41Sopenharmony_ci const UMessagePatternPartType type=part->getType(); 14001cb0ef41Sopenharmony_ci int32_t index=part->getIndex(); 14011cb0ef41Sopenharmony_ci // Make sure the literal string matches. 14021cb0ef41Sopenharmony_ci int32_t len = index - prevIndex; 14031cb0ef41Sopenharmony_ci if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) { 14041cb0ef41Sopenharmony_ci sourceOffset += len; 14051cb0ef41Sopenharmony_ci prevIndex += len; 14061cb0ef41Sopenharmony_ci } else { 14071cb0ef41Sopenharmony_ci pos.setErrorIndex(sourceOffset); 14081cb0ef41Sopenharmony_ci return nullptr; // leave index as is to signal error 14091cb0ef41Sopenharmony_ci } 14101cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) { 14111cb0ef41Sopenharmony_ci // Things went well! Done. 14121cb0ef41Sopenharmony_ci pos.setIndex(sourceOffset); 14131cb0ef41Sopenharmony_ci return resultArray.orphan(); 14141cb0ef41Sopenharmony_ci } 14151cb0ef41Sopenharmony_ci if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) { 14161cb0ef41Sopenharmony_ci prevIndex=part->getLimit(); 14171cb0ef41Sopenharmony_ci continue; 14181cb0ef41Sopenharmony_ci } 14191cb0ef41Sopenharmony_ci // We do not support parsing Plural formats. (No REPLACE_NUMBER here.) 14201cb0ef41Sopenharmony_ci // Unexpected Part "part" in parsed message. 14211cb0ef41Sopenharmony_ci U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START); 14221cb0ef41Sopenharmony_ci int32_t argLimit=msgPattern.getLimitPartIndex(i); 14231cb0ef41Sopenharmony_ci 14241cb0ef41Sopenharmony_ci UMessagePatternArgType argType=part->getArgType(); 14251cb0ef41Sopenharmony_ci part=&msgPattern.getPart(++i); 14261cb0ef41Sopenharmony_ci int32_t argNumber = part->getValue(); // ARG_NUMBER 14271cb0ef41Sopenharmony_ci UnicodeString key; 14281cb0ef41Sopenharmony_ci ++i; 14291cb0ef41Sopenharmony_ci const Format* formatter = nullptr; 14301cb0ef41Sopenharmony_ci Formattable& argResult = resultArray[argNumber]; 14311cb0ef41Sopenharmony_ci 14321cb0ef41Sopenharmony_ci if(cachedFormatters!=nullptr && (formatter = getCachedFormatter(i - 2))!=nullptr) { 14331cb0ef41Sopenharmony_ci // Just parse using the formatter. 14341cb0ef41Sopenharmony_ci tempStatus.setIndex(sourceOffset); 14351cb0ef41Sopenharmony_ci formatter->parseObject(source, argResult, tempStatus); 14361cb0ef41Sopenharmony_ci if (tempStatus.getIndex() == sourceOffset) { 14371cb0ef41Sopenharmony_ci pos.setErrorIndex(sourceOffset); 14381cb0ef41Sopenharmony_ci return nullptr; // leave index as is to signal error 14391cb0ef41Sopenharmony_ci } 14401cb0ef41Sopenharmony_ci sourceOffset = tempStatus.getIndex(); 14411cb0ef41Sopenharmony_ci haveArgResult = true; 14421cb0ef41Sopenharmony_ci } else if( 14431cb0ef41Sopenharmony_ci argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) { 14441cb0ef41Sopenharmony_ci // We arrive here if getCachedFormatter returned nullptr, but there was actually an element in the hash table. 14451cb0ef41Sopenharmony_ci // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check 14461cb0ef41Sopenharmony_ci // for the hash table containing DummyFormat. 14471cb0ef41Sopenharmony_ci 14481cb0ef41Sopenharmony_ci // Match as a string. 14491cb0ef41Sopenharmony_ci // if at end, use longest possible match 14501cb0ef41Sopenharmony_ci // otherwise uses first match to intervening string 14511cb0ef41Sopenharmony_ci // does NOT recursively try all possibilities 14521cb0ef41Sopenharmony_ci UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit); 14531cb0ef41Sopenharmony_ci int32_t next; 14541cb0ef41Sopenharmony_ci if (!stringAfterArgument.isEmpty()) { 14551cb0ef41Sopenharmony_ci next = source.indexOf(stringAfterArgument, sourceOffset); 14561cb0ef41Sopenharmony_ci } else { 14571cb0ef41Sopenharmony_ci next = source.length(); 14581cb0ef41Sopenharmony_ci } 14591cb0ef41Sopenharmony_ci if (next < 0) { 14601cb0ef41Sopenharmony_ci pos.setErrorIndex(sourceOffset); 14611cb0ef41Sopenharmony_ci return nullptr; // leave index as is to signal error 14621cb0ef41Sopenharmony_ci } else { 14631cb0ef41Sopenharmony_ci UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset)); 14641cb0ef41Sopenharmony_ci UnicodeString compValue; 14651cb0ef41Sopenharmony_ci compValue.append(LEFT_CURLY_BRACE); 14661cb0ef41Sopenharmony_ci itos(argNumber, compValue); 14671cb0ef41Sopenharmony_ci compValue.append(RIGHT_CURLY_BRACE); 14681cb0ef41Sopenharmony_ci if (0 != strValue.compare(compValue)) { 14691cb0ef41Sopenharmony_ci argResult.setString(strValue); 14701cb0ef41Sopenharmony_ci haveArgResult = true; 14711cb0ef41Sopenharmony_ci } 14721cb0ef41Sopenharmony_ci sourceOffset = next; 14731cb0ef41Sopenharmony_ci } 14741cb0ef41Sopenharmony_ci } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) { 14751cb0ef41Sopenharmony_ci tempStatus.setIndex(sourceOffset); 14761cb0ef41Sopenharmony_ci double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus); 14771cb0ef41Sopenharmony_ci if (tempStatus.getIndex() == sourceOffset) { 14781cb0ef41Sopenharmony_ci pos.setErrorIndex(sourceOffset); 14791cb0ef41Sopenharmony_ci return nullptr; // leave index as is to signal error 14801cb0ef41Sopenharmony_ci } 14811cb0ef41Sopenharmony_ci argResult.setDouble(choiceResult); 14821cb0ef41Sopenharmony_ci haveArgResult = true; 14831cb0ef41Sopenharmony_ci sourceOffset = tempStatus.getIndex(); 14841cb0ef41Sopenharmony_ci } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) { 14851cb0ef41Sopenharmony_ci // Parsing not supported. 14861cb0ef41Sopenharmony_ci ec = U_UNSUPPORTED_ERROR; 14871cb0ef41Sopenharmony_ci return nullptr; 14881cb0ef41Sopenharmony_ci } else { 14891cb0ef41Sopenharmony_ci // This should never happen. 14901cb0ef41Sopenharmony_ci ec = U_INTERNAL_PROGRAM_ERROR; 14911cb0ef41Sopenharmony_ci return nullptr; 14921cb0ef41Sopenharmony_ci } 14931cb0ef41Sopenharmony_ci if (haveArgResult && count <= argNumber) { 14941cb0ef41Sopenharmony_ci count = argNumber + 1; 14951cb0ef41Sopenharmony_ci } 14961cb0ef41Sopenharmony_ci prevIndex=msgPattern.getPart(argLimit).getLimit(); 14971cb0ef41Sopenharmony_ci i=argLimit; 14981cb0ef41Sopenharmony_ci } 14991cb0ef41Sopenharmony_ci} 15001cb0ef41Sopenharmony_ci// ------------------------------------- 15011cb0ef41Sopenharmony_ci// Parses the source pattern and returns the Formattable objects array, 15021cb0ef41Sopenharmony_ci// the array count and the ending parse position. The caller of this method 15031cb0ef41Sopenharmony_ci// owns the array. 15041cb0ef41Sopenharmony_ci 15051cb0ef41Sopenharmony_ciFormattable* 15061cb0ef41Sopenharmony_ciMessageFormat::parse(const UnicodeString& source, 15071cb0ef41Sopenharmony_ci ParsePosition& pos, 15081cb0ef41Sopenharmony_ci int32_t& count) const { 15091cb0ef41Sopenharmony_ci UErrorCode ec = U_ZERO_ERROR; 15101cb0ef41Sopenharmony_ci return parse(0, source, pos, count, ec); 15111cb0ef41Sopenharmony_ci} 15121cb0ef41Sopenharmony_ci 15131cb0ef41Sopenharmony_ci// ------------------------------------- 15141cb0ef41Sopenharmony_ci// Parses the source string and returns the array of 15151cb0ef41Sopenharmony_ci// Formattable objects and the array count. The caller 15161cb0ef41Sopenharmony_ci// owns the returned array. 15171cb0ef41Sopenharmony_ci 15181cb0ef41Sopenharmony_ciFormattable* 15191cb0ef41Sopenharmony_ciMessageFormat::parse(const UnicodeString& source, 15201cb0ef41Sopenharmony_ci int32_t& cnt, 15211cb0ef41Sopenharmony_ci UErrorCode& success) const 15221cb0ef41Sopenharmony_ci{ 15231cb0ef41Sopenharmony_ci if (msgPattern.hasNamedArguments()) { 15241cb0ef41Sopenharmony_ci success = U_ARGUMENT_TYPE_MISMATCH; 15251cb0ef41Sopenharmony_ci return nullptr; 15261cb0ef41Sopenharmony_ci } 15271cb0ef41Sopenharmony_ci ParsePosition status(0); 15281cb0ef41Sopenharmony_ci // Calls the actual implementation method and starts 15291cb0ef41Sopenharmony_ci // from zero offset of the source text. 15301cb0ef41Sopenharmony_ci Formattable* result = parse(source, status, cnt); 15311cb0ef41Sopenharmony_ci if (status.getIndex() == 0) { 15321cb0ef41Sopenharmony_ci success = U_MESSAGE_PARSE_ERROR; 15331cb0ef41Sopenharmony_ci delete[] result; 15341cb0ef41Sopenharmony_ci return nullptr; 15351cb0ef41Sopenharmony_ci } 15361cb0ef41Sopenharmony_ci return result; 15371cb0ef41Sopenharmony_ci} 15381cb0ef41Sopenharmony_ci 15391cb0ef41Sopenharmony_ci// ------------------------------------- 15401cb0ef41Sopenharmony_ci// Parses the source text and copy into the result buffer. 15411cb0ef41Sopenharmony_ci 15421cb0ef41Sopenharmony_civoid 15431cb0ef41Sopenharmony_ciMessageFormat::parseObject( const UnicodeString& source, 15441cb0ef41Sopenharmony_ci Formattable& result, 15451cb0ef41Sopenharmony_ci ParsePosition& status) const 15461cb0ef41Sopenharmony_ci{ 15471cb0ef41Sopenharmony_ci int32_t cnt = 0; 15481cb0ef41Sopenharmony_ci Formattable* tmpResult = parse(source, status, cnt); 15491cb0ef41Sopenharmony_ci if (tmpResult != nullptr) 15501cb0ef41Sopenharmony_ci result.adoptArray(tmpResult, cnt); 15511cb0ef41Sopenharmony_ci} 15521cb0ef41Sopenharmony_ci 15531cb0ef41Sopenharmony_ciUnicodeString 15541cb0ef41Sopenharmony_ciMessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) { 15551cb0ef41Sopenharmony_ci UnicodeString result; 15561cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 15571cb0ef41Sopenharmony_ci int32_t plen = pattern.length(); 15581cb0ef41Sopenharmony_ci const char16_t* pat = pattern.getBuffer(); 15591cb0ef41Sopenharmony_ci int32_t blen = plen * 2 + 1; // space for null termination, convenience 15601cb0ef41Sopenharmony_ci char16_t* buf = result.getBuffer(blen); 15611cb0ef41Sopenharmony_ci if (buf == nullptr) { 15621cb0ef41Sopenharmony_ci status = U_MEMORY_ALLOCATION_ERROR; 15631cb0ef41Sopenharmony_ci } else { 15641cb0ef41Sopenharmony_ci int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status); 15651cb0ef41Sopenharmony_ci result.releaseBuffer(U_SUCCESS(status) ? len : 0); 15661cb0ef41Sopenharmony_ci } 15671cb0ef41Sopenharmony_ci } 15681cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 15691cb0ef41Sopenharmony_ci result.setToBogus(); 15701cb0ef41Sopenharmony_ci } 15711cb0ef41Sopenharmony_ci return result; 15721cb0ef41Sopenharmony_ci} 15731cb0ef41Sopenharmony_ci 15741cb0ef41Sopenharmony_ci// ------------------------------------- 15751cb0ef41Sopenharmony_ci 15761cb0ef41Sopenharmony_cistatic Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) { 15771cb0ef41Sopenharmony_ci RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec); 15781cb0ef41Sopenharmony_ci if (fmt == nullptr) { 15791cb0ef41Sopenharmony_ci ec = U_MEMORY_ALLOCATION_ERROR; 15801cb0ef41Sopenharmony_ci } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) { 15811cb0ef41Sopenharmony_ci UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set 15821cb0ef41Sopenharmony_ci fmt->setDefaultRuleSet(defaultRuleSet, localStatus); 15831cb0ef41Sopenharmony_ci } 15841cb0ef41Sopenharmony_ci return fmt; 15851cb0ef41Sopenharmony_ci} 15861cb0ef41Sopenharmony_ci 15871cb0ef41Sopenharmony_civoid MessageFormat::cacheExplicitFormats(UErrorCode& status) { 15881cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 15891cb0ef41Sopenharmony_ci return; 15901cb0ef41Sopenharmony_ci } 15911cb0ef41Sopenharmony_ci 15921cb0ef41Sopenharmony_ci if (cachedFormatters != nullptr) { 15931cb0ef41Sopenharmony_ci uhash_removeAll(cachedFormatters); 15941cb0ef41Sopenharmony_ci } 15951cb0ef41Sopenharmony_ci if (customFormatArgStarts != nullptr) { 15961cb0ef41Sopenharmony_ci uhash_removeAll(customFormatArgStarts); 15971cb0ef41Sopenharmony_ci } 15981cb0ef41Sopenharmony_ci 15991cb0ef41Sopenharmony_ci // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT 16001cb0ef41Sopenharmony_ci // which we need not examine. 16011cb0ef41Sopenharmony_ci int32_t limit = msgPattern.countParts() - 2; 16021cb0ef41Sopenharmony_ci argTypeCount = 0; 16031cb0ef41Sopenharmony_ci // We also need not look at the first two "parts" 16041cb0ef41Sopenharmony_ci // (at most MSG_START and ARG_START) in this loop. 16051cb0ef41Sopenharmony_ci // We determine the argTypeCount first so that we can allocateArgTypes 16061cb0ef41Sopenharmony_ci // so that the next loop can set argTypes[argNumber]. 16071cb0ef41Sopenharmony_ci // (This is for the C API which needs the argTypes to read its va_arg list.) 16081cb0ef41Sopenharmony_ci for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) { 16091cb0ef41Sopenharmony_ci const MessagePattern::Part& part = msgPattern.getPart(i); 16101cb0ef41Sopenharmony_ci if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) { 16111cb0ef41Sopenharmony_ci const int argNumber = part.getValue(); 16121cb0ef41Sopenharmony_ci if (argNumber >= argTypeCount) { 16131cb0ef41Sopenharmony_ci argTypeCount = argNumber + 1; 16141cb0ef41Sopenharmony_ci } 16151cb0ef41Sopenharmony_ci } 16161cb0ef41Sopenharmony_ci } 16171cb0ef41Sopenharmony_ci if (!allocateArgTypes(argTypeCount, status)) { 16181cb0ef41Sopenharmony_ci return; 16191cb0ef41Sopenharmony_ci } 16201cb0ef41Sopenharmony_ci // Set all argTypes to kObject, as a "none" value, for lack of any better value. 16211cb0ef41Sopenharmony_ci // We never use kObject for real arguments. 16221cb0ef41Sopenharmony_ci // We use it as "no argument yet" for the check for hasArgTypeConflicts. 16231cb0ef41Sopenharmony_ci for (int32_t i = 0; i < argTypeCount; ++i) { 16241cb0ef41Sopenharmony_ci argTypes[i] = Formattable::kObject; 16251cb0ef41Sopenharmony_ci } 16261cb0ef41Sopenharmony_ci hasArgTypeConflicts = false; 16271cb0ef41Sopenharmony_ci 16281cb0ef41Sopenharmony_ci // This loop starts at part index 1 because we do need to examine 16291cb0ef41Sopenharmony_ci // ARG_START parts. (But we can ignore the MSG_START.) 16301cb0ef41Sopenharmony_ci for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) { 16311cb0ef41Sopenharmony_ci const MessagePattern::Part* part = &msgPattern.getPart(i); 16321cb0ef41Sopenharmony_ci if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) { 16331cb0ef41Sopenharmony_ci continue; 16341cb0ef41Sopenharmony_ci } 16351cb0ef41Sopenharmony_ci UMessagePatternArgType argType = part->getArgType(); 16361cb0ef41Sopenharmony_ci 16371cb0ef41Sopenharmony_ci int32_t argNumber = -1; 16381cb0ef41Sopenharmony_ci part = &msgPattern.getPart(i + 1); 16391cb0ef41Sopenharmony_ci if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) { 16401cb0ef41Sopenharmony_ci argNumber = part->getValue(); 16411cb0ef41Sopenharmony_ci } 16421cb0ef41Sopenharmony_ci Formattable::Type formattableType; 16431cb0ef41Sopenharmony_ci 16441cb0ef41Sopenharmony_ci switch (argType) { 16451cb0ef41Sopenharmony_ci case UMSGPAT_ARG_TYPE_NONE: 16461cb0ef41Sopenharmony_ci formattableType = Formattable::kString; 16471cb0ef41Sopenharmony_ci break; 16481cb0ef41Sopenharmony_ci case UMSGPAT_ARG_TYPE_SIMPLE: { 16491cb0ef41Sopenharmony_ci int32_t index = i; 16501cb0ef41Sopenharmony_ci i += 2; 16511cb0ef41Sopenharmony_ci UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++)); 16521cb0ef41Sopenharmony_ci UnicodeString style; 16531cb0ef41Sopenharmony_ci if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) { 16541cb0ef41Sopenharmony_ci style = msgPattern.getSubstring(*part); 16551cb0ef41Sopenharmony_ci ++i; 16561cb0ef41Sopenharmony_ci } 16571cb0ef41Sopenharmony_ci UParseError parseError; 16581cb0ef41Sopenharmony_ci Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status); 16591cb0ef41Sopenharmony_ci setArgStartFormat(index, formatter, status); 16601cb0ef41Sopenharmony_ci break; 16611cb0ef41Sopenharmony_ci } 16621cb0ef41Sopenharmony_ci case UMSGPAT_ARG_TYPE_CHOICE: 16631cb0ef41Sopenharmony_ci case UMSGPAT_ARG_TYPE_PLURAL: 16641cb0ef41Sopenharmony_ci case UMSGPAT_ARG_TYPE_SELECTORDINAL: 16651cb0ef41Sopenharmony_ci formattableType = Formattable::kDouble; 16661cb0ef41Sopenharmony_ci break; 16671cb0ef41Sopenharmony_ci case UMSGPAT_ARG_TYPE_SELECT: 16681cb0ef41Sopenharmony_ci formattableType = Formattable::kString; 16691cb0ef41Sopenharmony_ci break; 16701cb0ef41Sopenharmony_ci default: 16711cb0ef41Sopenharmony_ci status = U_INTERNAL_PROGRAM_ERROR; // Should be unreachable. 16721cb0ef41Sopenharmony_ci formattableType = Formattable::kString; 16731cb0ef41Sopenharmony_ci break; 16741cb0ef41Sopenharmony_ci } 16751cb0ef41Sopenharmony_ci if (argNumber != -1) { 16761cb0ef41Sopenharmony_ci if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) { 16771cb0ef41Sopenharmony_ci hasArgTypeConflicts = true; 16781cb0ef41Sopenharmony_ci } 16791cb0ef41Sopenharmony_ci argTypes[argNumber] = formattableType; 16801cb0ef41Sopenharmony_ci } 16811cb0ef41Sopenharmony_ci } 16821cb0ef41Sopenharmony_ci} 16831cb0ef41Sopenharmony_ci 16841cb0ef41Sopenharmony_ciFormat* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style, 16851cb0ef41Sopenharmony_ci Formattable::Type& formattableType, UParseError& parseError, 16861cb0ef41Sopenharmony_ci UErrorCode& ec) { 16871cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 16881cb0ef41Sopenharmony_ci return nullptr; 16891cb0ef41Sopenharmony_ci } 16901cb0ef41Sopenharmony_ci Format* fmt = nullptr; 16911cb0ef41Sopenharmony_ci int32_t typeID, styleID; 16921cb0ef41Sopenharmony_ci DateFormat::EStyle date_style; 16931cb0ef41Sopenharmony_ci int32_t firstNonSpace; 16941cb0ef41Sopenharmony_ci 16951cb0ef41Sopenharmony_ci switch (typeID = findKeyword(type, TYPE_IDS)) { 16961cb0ef41Sopenharmony_ci case 0: // number 16971cb0ef41Sopenharmony_ci formattableType = Formattable::kDouble; 16981cb0ef41Sopenharmony_ci switch (findKeyword(style, NUMBER_STYLE_IDS)) { 16991cb0ef41Sopenharmony_ci case 0: // default 17001cb0ef41Sopenharmony_ci fmt = NumberFormat::createInstance(fLocale, ec); 17011cb0ef41Sopenharmony_ci break; 17021cb0ef41Sopenharmony_ci case 1: // currency 17031cb0ef41Sopenharmony_ci fmt = NumberFormat::createCurrencyInstance(fLocale, ec); 17041cb0ef41Sopenharmony_ci break; 17051cb0ef41Sopenharmony_ci case 2: // percent 17061cb0ef41Sopenharmony_ci fmt = NumberFormat::createPercentInstance(fLocale, ec); 17071cb0ef41Sopenharmony_ci break; 17081cb0ef41Sopenharmony_ci case 3: // integer 17091cb0ef41Sopenharmony_ci formattableType = Formattable::kLong; 17101cb0ef41Sopenharmony_ci fmt = createIntegerFormat(fLocale, ec); 17111cb0ef41Sopenharmony_ci break; 17121cb0ef41Sopenharmony_ci default: // pattern or skeleton 17131cb0ef41Sopenharmony_ci firstNonSpace = PatternProps::skipWhiteSpace(style, 0); 17141cb0ef41Sopenharmony_ci if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) { 17151cb0ef41Sopenharmony_ci // Skeleton 17161cb0ef41Sopenharmony_ci UnicodeString skeleton = style.tempSubString(firstNonSpace + 2); 17171cb0ef41Sopenharmony_ci fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec); 17181cb0ef41Sopenharmony_ci } else { 17191cb0ef41Sopenharmony_ci // Pattern 17201cb0ef41Sopenharmony_ci fmt = NumberFormat::createInstance(fLocale, ec); 17211cb0ef41Sopenharmony_ci if (fmt) { 17221cb0ef41Sopenharmony_ci auto* decfmt = dynamic_cast<DecimalFormat*>(fmt); 17231cb0ef41Sopenharmony_ci if (decfmt != nullptr) { 17241cb0ef41Sopenharmony_ci decfmt->applyPattern(style, parseError, ec); 17251cb0ef41Sopenharmony_ci } 17261cb0ef41Sopenharmony_ci } 17271cb0ef41Sopenharmony_ci } 17281cb0ef41Sopenharmony_ci break; 17291cb0ef41Sopenharmony_ci } 17301cb0ef41Sopenharmony_ci break; 17311cb0ef41Sopenharmony_ci 17321cb0ef41Sopenharmony_ci case 1: // date 17331cb0ef41Sopenharmony_ci case 2: // time 17341cb0ef41Sopenharmony_ci formattableType = Formattable::kDate; 17351cb0ef41Sopenharmony_ci firstNonSpace = PatternProps::skipWhiteSpace(style, 0); 17361cb0ef41Sopenharmony_ci if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) { 17371cb0ef41Sopenharmony_ci // Skeleton 17381cb0ef41Sopenharmony_ci UnicodeString skeleton = style.tempSubString(firstNonSpace + 2); 17391cb0ef41Sopenharmony_ci fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec); 17401cb0ef41Sopenharmony_ci } else { 17411cb0ef41Sopenharmony_ci // Pattern 17421cb0ef41Sopenharmony_ci styleID = findKeyword(style, DATE_STYLE_IDS); 17431cb0ef41Sopenharmony_ci date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault; 17441cb0ef41Sopenharmony_ci 17451cb0ef41Sopenharmony_ci if (typeID == 1) { 17461cb0ef41Sopenharmony_ci fmt = DateFormat::createDateInstance(date_style, fLocale); 17471cb0ef41Sopenharmony_ci } else { 17481cb0ef41Sopenharmony_ci fmt = DateFormat::createTimeInstance(date_style, fLocale); 17491cb0ef41Sopenharmony_ci } 17501cb0ef41Sopenharmony_ci 17511cb0ef41Sopenharmony_ci if (styleID < 0 && fmt != nullptr) { 17521cb0ef41Sopenharmony_ci SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt); 17531cb0ef41Sopenharmony_ci if (sdtfmt != nullptr) { 17541cb0ef41Sopenharmony_ci sdtfmt->applyPattern(style); 17551cb0ef41Sopenharmony_ci } 17561cb0ef41Sopenharmony_ci } 17571cb0ef41Sopenharmony_ci } 17581cb0ef41Sopenharmony_ci break; 17591cb0ef41Sopenharmony_ci 17601cb0ef41Sopenharmony_ci case 3: // spellout 17611cb0ef41Sopenharmony_ci formattableType = Formattable::kDouble; 17621cb0ef41Sopenharmony_ci fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec); 17631cb0ef41Sopenharmony_ci break; 17641cb0ef41Sopenharmony_ci case 4: // ordinal 17651cb0ef41Sopenharmony_ci formattableType = Formattable::kDouble; 17661cb0ef41Sopenharmony_ci fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec); 17671cb0ef41Sopenharmony_ci break; 17681cb0ef41Sopenharmony_ci case 5: // duration 17691cb0ef41Sopenharmony_ci formattableType = Formattable::kDouble; 17701cb0ef41Sopenharmony_ci fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec); 17711cb0ef41Sopenharmony_ci break; 17721cb0ef41Sopenharmony_ci default: 17731cb0ef41Sopenharmony_ci formattableType = Formattable::kString; 17741cb0ef41Sopenharmony_ci ec = U_ILLEGAL_ARGUMENT_ERROR; 17751cb0ef41Sopenharmony_ci break; 17761cb0ef41Sopenharmony_ci } 17771cb0ef41Sopenharmony_ci 17781cb0ef41Sopenharmony_ci return fmt; 17791cb0ef41Sopenharmony_ci} 17801cb0ef41Sopenharmony_ci 17811cb0ef41Sopenharmony_ci 17821cb0ef41Sopenharmony_ci//------------------------------------- 17831cb0ef41Sopenharmony_ci// Finds the string, s, in the string array, list. 17841cb0ef41Sopenharmony_ciint32_t MessageFormat::findKeyword(const UnicodeString& s, 17851cb0ef41Sopenharmony_ci const char16_t * const *list) 17861cb0ef41Sopenharmony_ci{ 17871cb0ef41Sopenharmony_ci if (s.isEmpty()) { 17881cb0ef41Sopenharmony_ci return 0; // default 17891cb0ef41Sopenharmony_ci } 17901cb0ef41Sopenharmony_ci 17911cb0ef41Sopenharmony_ci int32_t length = s.length(); 17921cb0ef41Sopenharmony_ci const char16_t *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length); 17931cb0ef41Sopenharmony_ci UnicodeString buffer(false, ps, length); 17941cb0ef41Sopenharmony_ci // Trims the space characters and turns all characters 17951cb0ef41Sopenharmony_ci // in s to lower case. 17961cb0ef41Sopenharmony_ci buffer.toLower(""); 17971cb0ef41Sopenharmony_ci for (int32_t i = 0; list[i]; ++i) { 17981cb0ef41Sopenharmony_ci if (!buffer.compare(list[i], u_strlen(list[i]))) { 17991cb0ef41Sopenharmony_ci return i; 18001cb0ef41Sopenharmony_ci } 18011cb0ef41Sopenharmony_ci } 18021cb0ef41Sopenharmony_ci return -1; 18031cb0ef41Sopenharmony_ci} 18041cb0ef41Sopenharmony_ci 18051cb0ef41Sopenharmony_ci/** 18061cb0ef41Sopenharmony_ci * Convenience method that ought to be in NumberFormat 18071cb0ef41Sopenharmony_ci */ 18081cb0ef41Sopenharmony_ciNumberFormat* 18091cb0ef41Sopenharmony_ciMessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const { 18101cb0ef41Sopenharmony_ci NumberFormat *temp = NumberFormat::createInstance(locale, status); 18111cb0ef41Sopenharmony_ci DecimalFormat *temp2; 18121cb0ef41Sopenharmony_ci if (temp != nullptr && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != nullptr) { 18131cb0ef41Sopenharmony_ci temp2->setMaximumFractionDigits(0); 18141cb0ef41Sopenharmony_ci temp2->setDecimalSeparatorAlwaysShown(false); 18151cb0ef41Sopenharmony_ci temp2->setParseIntegerOnly(true); 18161cb0ef41Sopenharmony_ci } 18171cb0ef41Sopenharmony_ci 18181cb0ef41Sopenharmony_ci return temp; 18191cb0ef41Sopenharmony_ci} 18201cb0ef41Sopenharmony_ci 18211cb0ef41Sopenharmony_ci/** 18221cb0ef41Sopenharmony_ci * Return the default number format. Used to format a numeric 18231cb0ef41Sopenharmony_ci * argument when subformats[i].format is nullptr. Returns nullptr 18241cb0ef41Sopenharmony_ci * on failure. 18251cb0ef41Sopenharmony_ci * 18261cb0ef41Sopenharmony_ci * Semantically const but may modify *this. 18271cb0ef41Sopenharmony_ci */ 18281cb0ef41Sopenharmony_ciconst NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const { 18291cb0ef41Sopenharmony_ci if (defaultNumberFormat == nullptr) { 18301cb0ef41Sopenharmony_ci MessageFormat* t = (MessageFormat*) this; 18311cb0ef41Sopenharmony_ci t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec); 18321cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 18331cb0ef41Sopenharmony_ci delete t->defaultNumberFormat; 18341cb0ef41Sopenharmony_ci t->defaultNumberFormat = nullptr; 18351cb0ef41Sopenharmony_ci } else if (t->defaultNumberFormat == nullptr) { 18361cb0ef41Sopenharmony_ci ec = U_MEMORY_ALLOCATION_ERROR; 18371cb0ef41Sopenharmony_ci } 18381cb0ef41Sopenharmony_ci } 18391cb0ef41Sopenharmony_ci return defaultNumberFormat; 18401cb0ef41Sopenharmony_ci} 18411cb0ef41Sopenharmony_ci 18421cb0ef41Sopenharmony_ci/** 18431cb0ef41Sopenharmony_ci * Return the default date format. Used to format a date 18441cb0ef41Sopenharmony_ci * argument when subformats[i].format is nullptr. Returns nullptr 18451cb0ef41Sopenharmony_ci * on failure. 18461cb0ef41Sopenharmony_ci * 18471cb0ef41Sopenharmony_ci * Semantically const but may modify *this. 18481cb0ef41Sopenharmony_ci */ 18491cb0ef41Sopenharmony_ciconst DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const { 18501cb0ef41Sopenharmony_ci if (defaultDateFormat == nullptr) { 18511cb0ef41Sopenharmony_ci MessageFormat* t = (MessageFormat*) this; 18521cb0ef41Sopenharmony_ci t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale); 18531cb0ef41Sopenharmony_ci if (t->defaultDateFormat == nullptr) { 18541cb0ef41Sopenharmony_ci ec = U_MEMORY_ALLOCATION_ERROR; 18551cb0ef41Sopenharmony_ci } 18561cb0ef41Sopenharmony_ci } 18571cb0ef41Sopenharmony_ci return defaultDateFormat; 18581cb0ef41Sopenharmony_ci} 18591cb0ef41Sopenharmony_ci 18601cb0ef41Sopenharmony_ciUBool 18611cb0ef41Sopenharmony_ciMessageFormat::usesNamedArguments() const { 18621cb0ef41Sopenharmony_ci return msgPattern.hasNamedArguments(); 18631cb0ef41Sopenharmony_ci} 18641cb0ef41Sopenharmony_ci 18651cb0ef41Sopenharmony_ciint32_t 18661cb0ef41Sopenharmony_ciMessageFormat::getArgTypeCount() const { 18671cb0ef41Sopenharmony_ci return argTypeCount; 18681cb0ef41Sopenharmony_ci} 18691cb0ef41Sopenharmony_ci 18701cb0ef41Sopenharmony_ciUBool MessageFormat::equalFormats(const void* left, const void* right) { 18711cb0ef41Sopenharmony_ci return *(const Format*)left==*(const Format*)right; 18721cb0ef41Sopenharmony_ci} 18731cb0ef41Sopenharmony_ci 18741cb0ef41Sopenharmony_ci 18751cb0ef41Sopenharmony_cibool MessageFormat::DummyFormat::operator==(const Format&) const { 18761cb0ef41Sopenharmony_ci return true; 18771cb0ef41Sopenharmony_ci} 18781cb0ef41Sopenharmony_ci 18791cb0ef41Sopenharmony_ciMessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const { 18801cb0ef41Sopenharmony_ci return new DummyFormat(); 18811cb0ef41Sopenharmony_ci} 18821cb0ef41Sopenharmony_ci 18831cb0ef41Sopenharmony_ciUnicodeString& MessageFormat::DummyFormat::format(const Formattable&, 18841cb0ef41Sopenharmony_ci UnicodeString& appendTo, 18851cb0ef41Sopenharmony_ci UErrorCode& status) const { 18861cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 18871cb0ef41Sopenharmony_ci status = U_UNSUPPORTED_ERROR; 18881cb0ef41Sopenharmony_ci } 18891cb0ef41Sopenharmony_ci return appendTo; 18901cb0ef41Sopenharmony_ci} 18911cb0ef41Sopenharmony_ci 18921cb0ef41Sopenharmony_ciUnicodeString& MessageFormat::DummyFormat::format(const Formattable&, 18931cb0ef41Sopenharmony_ci UnicodeString& appendTo, 18941cb0ef41Sopenharmony_ci FieldPosition&, 18951cb0ef41Sopenharmony_ci UErrorCode& status) const { 18961cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 18971cb0ef41Sopenharmony_ci status = U_UNSUPPORTED_ERROR; 18981cb0ef41Sopenharmony_ci } 18991cb0ef41Sopenharmony_ci return appendTo; 19001cb0ef41Sopenharmony_ci} 19011cb0ef41Sopenharmony_ci 19021cb0ef41Sopenharmony_ciUnicodeString& MessageFormat::DummyFormat::format(const Formattable&, 19031cb0ef41Sopenharmony_ci UnicodeString& appendTo, 19041cb0ef41Sopenharmony_ci FieldPositionIterator*, 19051cb0ef41Sopenharmony_ci UErrorCode& status) const { 19061cb0ef41Sopenharmony_ci if (U_SUCCESS(status)) { 19071cb0ef41Sopenharmony_ci status = U_UNSUPPORTED_ERROR; 19081cb0ef41Sopenharmony_ci } 19091cb0ef41Sopenharmony_ci return appendTo; 19101cb0ef41Sopenharmony_ci} 19111cb0ef41Sopenharmony_ci 19121cb0ef41Sopenharmony_civoid MessageFormat::DummyFormat::parseObject(const UnicodeString&, 19131cb0ef41Sopenharmony_ci Formattable&, 19141cb0ef41Sopenharmony_ci ParsePosition& ) const { 19151cb0ef41Sopenharmony_ci} 19161cb0ef41Sopenharmony_ci 19171cb0ef41Sopenharmony_ci 19181cb0ef41Sopenharmony_ciFormatNameEnumeration::FormatNameEnumeration(LocalPointer<UVector> nameList, UErrorCode& /*status*/) { 19191cb0ef41Sopenharmony_ci pos=0; 19201cb0ef41Sopenharmony_ci fFormatNames = std::move(nameList); 19211cb0ef41Sopenharmony_ci} 19221cb0ef41Sopenharmony_ci 19231cb0ef41Sopenharmony_ciconst UnicodeString* 19241cb0ef41Sopenharmony_ciFormatNameEnumeration::snext(UErrorCode& status) { 19251cb0ef41Sopenharmony_ci if (U_SUCCESS(status) && pos < fFormatNames->size()) { 19261cb0ef41Sopenharmony_ci return (const UnicodeString*)fFormatNames->elementAt(pos++); 19271cb0ef41Sopenharmony_ci } 19281cb0ef41Sopenharmony_ci return nullptr; 19291cb0ef41Sopenharmony_ci} 19301cb0ef41Sopenharmony_ci 19311cb0ef41Sopenharmony_civoid 19321cb0ef41Sopenharmony_ciFormatNameEnumeration::reset(UErrorCode& /*status*/) { 19331cb0ef41Sopenharmony_ci pos=0; 19341cb0ef41Sopenharmony_ci} 19351cb0ef41Sopenharmony_ci 19361cb0ef41Sopenharmony_ciint32_t 19371cb0ef41Sopenharmony_ciFormatNameEnumeration::count(UErrorCode& /*status*/) const { 19381cb0ef41Sopenharmony_ci return (fFormatNames==nullptr) ? 0 : fFormatNames->size(); 19391cb0ef41Sopenharmony_ci} 19401cb0ef41Sopenharmony_ci 19411cb0ef41Sopenharmony_ciFormatNameEnumeration::~FormatNameEnumeration() { 19421cb0ef41Sopenharmony_ci} 19431cb0ef41Sopenharmony_ci 19441cb0ef41Sopenharmony_ciMessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t) 19451cb0ef41Sopenharmony_ci : msgFormat(mf), rules(nullptr), type(t) { 19461cb0ef41Sopenharmony_ci} 19471cb0ef41Sopenharmony_ci 19481cb0ef41Sopenharmony_ciMessageFormat::PluralSelectorProvider::~PluralSelectorProvider() { 19491cb0ef41Sopenharmony_ci delete rules; 19501cb0ef41Sopenharmony_ci} 19511cb0ef41Sopenharmony_ci 19521cb0ef41Sopenharmony_ciUnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number, 19531cb0ef41Sopenharmony_ci UErrorCode& ec) const { 19541cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 19551cb0ef41Sopenharmony_ci return UnicodeString(false, OTHER_STRING, 5); 19561cb0ef41Sopenharmony_ci } 19571cb0ef41Sopenharmony_ci MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this); 19581cb0ef41Sopenharmony_ci if(rules == nullptr) { 19591cb0ef41Sopenharmony_ci t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec); 19601cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 19611cb0ef41Sopenharmony_ci return UnicodeString(false, OTHER_STRING, 5); 19621cb0ef41Sopenharmony_ci } 19631cb0ef41Sopenharmony_ci } 19641cb0ef41Sopenharmony_ci // Select a sub-message according to how the number is formatted, 19651cb0ef41Sopenharmony_ci // which is specified in the selected sub-message. 19661cb0ef41Sopenharmony_ci // We avoid this circle by looking at how 19671cb0ef41Sopenharmony_ci // the number is formatted in the "other" sub-message 19681cb0ef41Sopenharmony_ci // which must always be present and usually contains the number. 19691cb0ef41Sopenharmony_ci // Message authors should be consistent across sub-messages. 19701cb0ef41Sopenharmony_ci PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx); 19711cb0ef41Sopenharmony_ci int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex); 19721cb0ef41Sopenharmony_ci context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName); 19731cb0ef41Sopenharmony_ci if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != nullptr) { 19741cb0ef41Sopenharmony_ci context.formatter = 19751cb0ef41Sopenharmony_ci (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex); 19761cb0ef41Sopenharmony_ci } 19771cb0ef41Sopenharmony_ci if(context.formatter == nullptr) { 19781cb0ef41Sopenharmony_ci context.formatter = msgFormat.getDefaultNumberFormat(ec); 19791cb0ef41Sopenharmony_ci context.forReplaceNumber = true; 19801cb0ef41Sopenharmony_ci } 19811cb0ef41Sopenharmony_ci if (context.number.getDouble(ec) != number) { 19821cb0ef41Sopenharmony_ci ec = U_INTERNAL_PROGRAM_ERROR; 19831cb0ef41Sopenharmony_ci return UnicodeString(false, OTHER_STRING, 5); 19841cb0ef41Sopenharmony_ci } 19851cb0ef41Sopenharmony_ci context.formatter->format(context.number, context.numberString, ec); 19861cb0ef41Sopenharmony_ci auto* decFmt = dynamic_cast<const DecimalFormat *>(context.formatter); 19871cb0ef41Sopenharmony_ci if(decFmt != nullptr) { 19881cb0ef41Sopenharmony_ci number::impl::DecimalQuantity dq; 19891cb0ef41Sopenharmony_ci decFmt->formatToDecimalQuantity(context.number, dq, ec); 19901cb0ef41Sopenharmony_ci if (U_FAILURE(ec)) { 19911cb0ef41Sopenharmony_ci return UnicodeString(false, OTHER_STRING, 5); 19921cb0ef41Sopenharmony_ci } 19931cb0ef41Sopenharmony_ci return rules->select(dq); 19941cb0ef41Sopenharmony_ci } else { 19951cb0ef41Sopenharmony_ci return rules->select(number); 19961cb0ef41Sopenharmony_ci } 19971cb0ef41Sopenharmony_ci} 19981cb0ef41Sopenharmony_ci 19991cb0ef41Sopenharmony_civoid MessageFormat::PluralSelectorProvider::reset() { 20001cb0ef41Sopenharmony_ci delete rules; 20011cb0ef41Sopenharmony_ci rules = nullptr; 20021cb0ef41Sopenharmony_ci} 20031cb0ef41Sopenharmony_ci 20041cb0ef41Sopenharmony_ci 20051cb0ef41Sopenharmony_ciU_NAMESPACE_END 20061cb0ef41Sopenharmony_ci 20071cb0ef41Sopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */ 20081cb0ef41Sopenharmony_ci 20091cb0ef41Sopenharmony_ci//eof 2010