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