16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/********************************************************************
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * COPYRIGHT:
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Copyright (c) 1997-2013, International Business Machines Corporation and
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * others. All Rights Reserved.
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org ********************************************************************
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * File MSGFMT.CPP
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Modification History:
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   Date        Name        Description
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   02/19/97    aliu        Converted from java.
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   03/20/97    helena      Finished first cut of implementation.
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   04/10/97    aliu        Made to work on AIX.  Added stoi to replace wtoi.
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   06/11/97    helena      Fixed addPattern to take the pattern correctly.
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   06/17/97    helena      Fixed the getPattern to return the correct pattern.
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   07/09/97    helena      Made ParsePosition into a class.
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   02/22/99    stephen     Removed character literals for EBCDIC safety
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   11/01/09    kirtig      Added SelectFormat
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org ********************************************************************/
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/utypes.h"
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_FORMATTING
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/appendable.h"
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/choicfmt.h"
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/datefmt.h"
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/decimfmt.h"
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/localpointer.h"
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/msgfmt.h"
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/plurfmt.h"
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/rbnf.h"
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/selfmt.h"
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/smpdtfmt.h"
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/umsg.h"
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/ustring.h"
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cmemory.h"
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "patternprops.h"
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "messageimpl.h"
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "msgfmt_impl.h"
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "plurrule_impl.h"
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uelement.h"
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uhash.h"
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "ustrfmt.h"
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "util.h"
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uvector.h"
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// *****************************************************************************
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// class MessageFormat
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// *****************************************************************************
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define SINGLE_QUOTE      ((UChar)0x0027)
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define COMMA             ((UChar)0x002C)
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define LEFT_CURLY_BRACE  ((UChar)0x007B)
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define RIGHT_CURLY_BRACE ((UChar)0x007D)
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//---------------------------------------
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// static data
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_NUMBER[]    = {
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0  /* "number" */
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_DATE[]      = {
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x64, 0x61, 0x74, 0x65, 0              /* "date" */
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_TIME[]      = {
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x74, 0x69, 0x6D, 0x65, 0              /* "time" */
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_SPELLOUT[]  = {
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_ORDINAL[]   = {
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_DURATION[]  = {
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// MessageFormat Type List  Number, Date, Time or Choice
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar * const TYPE_IDS[] = {
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_NUMBER,
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_DATE,
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_TIME,
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_SPELLOUT,
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_ORDINAL,
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_DURATION,
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NULL,
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_EMPTY[]     = {
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0 /* empty string, used for default so that null can mark end of list */
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_CURRENCY[]  = {
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0  /* "currency" */
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_PERCENT[]   = {
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0        /* "percent" */
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_INTEGER[]   = {
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0        /* "integer" */
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// NumberFormat modifier list, default, currency, percent or integer
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar * const NUMBER_STYLE_IDS[] = {
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_EMPTY,
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_CURRENCY,
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_PERCENT,
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_INTEGER,
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NULL,
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_SHORT[]     = {
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x73, 0x68, 0x6F, 0x72, 0x74, 0        /* "short" */
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_MEDIUM[]    = {
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0  /* "medium" */
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_LONG[]      = {
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x6C, 0x6F, 0x6E, 0x67, 0              /* "long" */
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar ID_FULL[]      = {
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x66, 0x75, 0x6C, 0x6C, 0              /* "full" */
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// DateFormat modifier list, default, short, medium, long or full
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar * const DATE_STYLE_IDS[] = {
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_EMPTY,
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_SHORT,
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_MEDIUM,
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_LONG,
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ID_FULL,
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NULL,
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const icu::DateFormat::EStyle DATE_STYLES[] = {
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    icu::DateFormat::kDefault,
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    icu::DateFormat::kShort,
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    icu::DateFormat::kMedium,
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    icu::DateFormat::kLong,
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    icu::DateFormat::kFull,
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const int32_t DEFAULT_INITIAL_CAPACITY = 10;
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar NULL_STRING[] = {
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x6E, 0x75, 0x6C, 0x6C, 0  // "null"
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar OTHER_STRING[] = {
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    0x6F, 0x74, 0x68, 0x65, 0x72, 0  // "other"
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CDECL_BEGIN
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UBool U_CALLCONV equalFormatsForHash(const UHashTok key1,
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            const UHashTok key2) {
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer);
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CDECL_END
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_BEGIN
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration)
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//--------------------------------------------------------------------
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Convert an integer value to a string and append the result to
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * the given UnicodeString.
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UChar temp[16];
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_itou(temp,16,i,10,0); // 10 == radix
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    appendTo.append(temp, -1);
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// AppendableWrapper: encapsulates the result of formatting, keeping track
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// of the string and its length.
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgclass AppendableWrapper : public UMemory {
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgpublic:
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    AppendableWrapper(Appendable& appendable) : app(appendable), len(0) {
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void append(const UnicodeString& s) {
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        app.appendString(s.getBuffer(), s.length());
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        len += s.length();
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void append(const UChar* s, const int32_t sLength) {
1946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        app.appendString(s, sLength);
1956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        len += sLength;
1966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void append(const UnicodeString& s, int32_t start, int32_t length) {
1986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        append(s.tempSubString(start, length));
1996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) {
2016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString s;
2026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formatter->format(arg, s, ec);
2036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_SUCCESS(ec)) {
2046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            append(s);
2056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void formatAndAppend(const Format* formatter, const Formattable& arg,
2086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         const UnicodeString &argString, UErrorCode& ec) {
2096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (!argString.isEmpty()) {
2106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (U_SUCCESS(ec)) {
2116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                append(argString);
2126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
2136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
2146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formatAndAppend(formatter, arg, ec);
2156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t length() {
2186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return len;
2196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgprivate:
2216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Appendable& app;
2226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t len;
2236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
2246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
2276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Creates a MessageFormat instance based on the pattern.
2286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::MessageFormat(const UnicodeString& pattern,
2306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             UErrorCode& success)
2316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: fLocale(Locale::getDefault()),  // Uses the default locale
2326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(success),
2336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliases(NULL),
2346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliasesCapacity(0),
2356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypes(NULL),
2366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCount(0),
2376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCapacity(0),
2386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  hasArgTypeConflicts(FALSE),
2396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultNumberFormat(NULL),
2406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultDateFormat(NULL),
2416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  cachedFormatters(NULL),
2426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  customFormatArgStarts(NULL),
2436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
2446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
2456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setLocaleIDs(fLocale.getName(), fLocale.getName());
2476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(pattern, success);
2486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::MessageFormat(const UnicodeString& pattern,
2516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             const Locale& newLocale,
2526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             UErrorCode& success)
2536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: fLocale(newLocale),
2546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(success),
2556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliases(NULL),
2566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliasesCapacity(0),
2576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypes(NULL),
2586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCount(0),
2596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCapacity(0),
2606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  hasArgTypeConflicts(FALSE),
2616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultNumberFormat(NULL),
2626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultDateFormat(NULL),
2636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  cachedFormatters(NULL),
2646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  customFormatArgStarts(NULL),
2656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
2666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
2676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setLocaleIDs(fLocale.getName(), fLocale.getName());
2696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(pattern, success);
2706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::MessageFormat(const UnicodeString& pattern,
2736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             const Locale& newLocale,
2746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             UParseError& parseError,
2756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             UErrorCode& success)
2766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: fLocale(newLocale),
2776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(success),
2786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliases(NULL),
2796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliasesCapacity(0),
2806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypes(NULL),
2816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCount(0),
2826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCapacity(0),
2836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  hasArgTypeConflicts(FALSE),
2846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultNumberFormat(NULL),
2856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultDateFormat(NULL),
2866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  cachedFormatters(NULL),
2876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  customFormatArgStarts(NULL),
2886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
2896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
2906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setLocaleIDs(fLocale.getName(), fLocale.getName());
2926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(pattern, parseError, success);
2936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::MessageFormat(const MessageFormat& that)
2966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org:
2976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  Format(that),
2986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  fLocale(that.fLocale),
2996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(that.msgPattern),
3006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliases(NULL),
3016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  formatAliasesCapacity(0),
3026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypes(NULL),
3036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCount(0),
3046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  argTypeCapacity(0),
3056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  hasArgTypeConflicts(that.hasArgTypeConflicts),
3066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultNumberFormat(NULL),
3076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  defaultDateFormat(NULL),
3086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  cachedFormatters(NULL),
3096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  customFormatArgStarts(NULL),
3106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
3116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
3126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // This will take care of creating the hash tables (since they are NULL).
3146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
3156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    copyObjects(that, ec);
3166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
3176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        resetPattern();
3186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::~MessageFormat()
3226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uhash_close(cachedFormatters);
3246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uhash_close(customFormatArgStarts);
3256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(argTypes);
3276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uprv_free(formatAliases);
3286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    delete defaultNumberFormat;
3296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    delete defaultDateFormat;
3306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//--------------------------------------------------------------------
3336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Variable-size array management
3346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
3366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Allocate argTypes[] to at least the given capacity and return
3376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * TRUE if successful.  If not, leave argTypes[] unchanged.
3386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
3396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * If argTypes is NULL, allocate it.  If it is not NULL, enlarge it
3406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * if necessary to be at least as large as specified.
3416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
3426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) {
3436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
3446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE;
3456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (argTypeCapacity >= capacity) {
3476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return TRUE;
3486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (capacity < DEFAULT_INITIAL_CAPACITY) {
3506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        capacity = DEFAULT_INITIAL_CAPACITY;
3516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else if (capacity < 2*argTypeCapacity) {
3526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        capacity = 2*argTypeCapacity;
3536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Formattable::Type* a = (Formattable::Type*)
3556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
3566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (a == NULL) {
3576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_MEMORY_ALLOCATION_ERROR;
3586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE;
3596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    argTypes = a;
3616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    argTypeCapacity = capacity;
3626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
3636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// assignment operator
3676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst MessageFormat&
3696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::operator=(const MessageFormat& that)
3706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (this != &that) {
3726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Calls the super class for assignment first.
3736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        Format::operator=(that);
3746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        setLocale(that.fLocale);
3766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern = that.msgPattern;
3776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        hasArgTypeConflicts = that.hasArgTypeConflicts;
3786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UErrorCode ec = U_ZERO_ERROR;
3806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        copyObjects(that, ec);
3816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_FAILURE(ec)) {
3826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            resetPattern();
3836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
3846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return *this;
3866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool
3896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::operator==(const Format& rhs) const
3906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (this == &rhs) return TRUE;
3926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    MessageFormat& that = (MessageFormat&)rhs;
3946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Check class ID before checking MessageFormat members
3966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!Format::operator==(rhs) ||
3976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern != that.msgPattern ||
3986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fLocale != that.fLocale) {
3996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE;
4006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Compare hashtables.
4036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if ((customFormatArgStarts == NULL) != (that.customFormatArgStarts == NULL)) {
4046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE;
4056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (customFormatArgStarts == NULL) {
4076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return TRUE;
4086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
4116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const int32_t count = uhash_count(customFormatArgStarts);
4126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const int32_t rhs_count = uhash_count(that.customFormatArgStarts);
4136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (count != rhs_count) {
4146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return FALSE;
4156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t idx = 0, rhs_idx = 0, pos = -1, rhs_pos = -1;
4176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) {
4186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos);
4196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos);
4206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (cur->key.integer != rhs_cur->key.integer) {
4216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return FALSE;
4226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer);
4246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer);
4256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (*format != *rhs_format) {
4266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return FALSE;
4276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
4306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
4336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Creates a copy of this MessageFormat, the caller owns the copy.
4346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat*
4366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::clone() const
4376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return new MessageFormat(*this);
4396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
4426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Sets the locale of this MessageFormat object to theLocale.
4436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
4456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::setLocale(const Locale& theLocale)
4466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (fLocale != theLocale) {
4486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete defaultNumberFormat;
4496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        defaultNumberFormat = NULL;
4506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete defaultDateFormat;
4516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        defaultDateFormat = NULL;
4526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fLocale = theLocale;
4536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        setLocaleIDs(fLocale.getName(), fLocale.getName());
4546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        pluralProvider.reset();
4556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ordinalProvider.reset();
4566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
4606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Gets the locale of this MessageFormat object.
4616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst Locale&
4636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::getLocale() const
4646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return fLocale;
4666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
4696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::applyPattern(const UnicodeString& newPattern,
4706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UErrorCode& status)
4716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UParseError parseError;
4736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(newPattern,parseError,status);
4746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
4786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Applies the new pattern and returns an error if the pattern
4796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// is not correct.
4806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
4816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::applyPattern(const UnicodeString& pattern,
4826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UParseError& parseError,
4836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UErrorCode& ec)
4846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(U_FAILURE(ec)) {
4866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
4876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    msgPattern.parse(pattern, &parseError, ec);
4896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cacheExplicitFormats(ec);
4906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
4926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        resetPattern();
4936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::resetPattern() {
4976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    msgPattern.clear();
4986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uhash_close(cachedFormatters);
4996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cachedFormatters = NULL;
5006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uhash_close(customFormatArgStarts);
5016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    customFormatArgStarts = NULL;
5026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    argTypeCount = 0;
5036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    hasArgTypeConflicts = FALSE;
5046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
5076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::applyPattern(const UnicodeString& pattern,
5086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UMessagePatternApostropheMode aposMode,
5096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UParseError* parseError,
5106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            UErrorCode& status) {
5116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (aposMode != msgPattern.getApostropheMode()) {
5126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern.clearPatternAndSetApostropheMode(aposMode);
5136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(pattern, *parseError, status);
5156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
5186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Converts this MessageFormat instance to a pattern.
5196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
5216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::toPattern(UnicodeString& appendTo) const {
5226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if ((customFormatArgStarts != NULL && 0 != uhash_count(customFormatArgStarts)) ||
5236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        0 == msgPattern.countParts()
5246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ) {
5256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.setToBogus();
5266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
5276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo.append(msgPattern.getPatternString());
5296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
5326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (partIndex != 0) {
5336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        partIndex = msgPattern.getLimitPartIndex(partIndex);
5346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (;;) {
5366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
5376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type == UMSGPAT_PART_TYPE_ARG_START) {
5386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return partIndex;
5396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
5406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
5416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return -1;
5426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
5436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::setArgStartFormat(int32_t argStart,
5476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                      Format* formatter,
5486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                      UErrorCode& status) {
5496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
5506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete formatter;
5516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
5526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cachedFormatters == NULL) {
5546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
5556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    equalFormatsForHash, &status);
5566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_FAILURE(status)) {
5576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete formatter;
5586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return;
5596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
5606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
5616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (formatter == NULL) {
5636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formatter = new DummyFormat();
5646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uhash_iput(cachedFormatters, argStart, formatter, &status);
5666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
5706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const MessagePattern::Part& part = msgPattern.getPart(partIndex);
5716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
5726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern.partSubstringMatches(part, argName) :
5736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        part.getValue() == argNumber;  // ARG_NUMBER
5746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Sets a custom formatter for a MessagePattern ARG_START part index.
5776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// "Custom" formatters are provided by the user via setFormat() or similar APIs.
5786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::setCustomArgStartFormat(int32_t argStart,
5796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            Format* formatter,
5806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            UErrorCode& status) {
5816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setArgStartFormat(argStart, formatter, status);
5826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (customFormatArgStarts == NULL) {
5836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
5846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                         NULL, &status);
5856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    uhash_iputi(customFormatArgStarts, argStart, 1, &status);
5876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
5906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cachedFormatters == NULL) {
5916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
5926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void* ptr = uhash_iget(cachedFormatters, argumentNumber);
5946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (ptr != NULL && dynamic_cast<DummyFormat*>((Format*)ptr) == NULL) {
5956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return (Format*) ptr;
5966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
5976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Not cached, or a DummyFormat representing setFormat(NULL).
5986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
5996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
6036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Adopts the new formats array and updates the array count.
6046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// This MessageFormat instance owns the new formats.
6056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
6066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::adoptFormats(Format** newFormats,
6076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            int32_t count) {
6086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (newFormats == NULL || count < 0) {
6096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
6106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Throw away any cached formatters.
6126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cachedFormatters != NULL) {
6136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(cachedFormatters);
6146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (customFormatArgStarts != NULL) {
6166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(customFormatArgStarts);
6176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t formatNumber = 0;
6206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode status = U_ZERO_ERROR;
6216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0;
6226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formatNumber < count && U_SUCCESS(status) &&
6236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
6246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
6256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ++formatNumber;
6266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Delete those that didn't get used (if any).
6286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (; formatNumber < count; ++formatNumber) {
6296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete newFormats[formatNumber];
6306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
6356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Sets the new formats array and updates the array count.
6366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// This MessageFormat instance maks a copy of the new formats.
6376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
6396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::setFormats(const Format** newFormats,
6406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          int32_t count) {
6416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (newFormats == NULL || count < 0) {
6426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
6436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Throw away any cached formatters.
6456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cachedFormatters != NULL) {
6466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(cachedFormatters);
6476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (customFormatArgStarts != NULL) {
6496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(customFormatArgStarts);
6506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode status = U_ZERO_ERROR;
6536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t formatNumber = 0;
6546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0;
6556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
6566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      Format* newFormat = NULL;
6576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (newFormats[formatNumber] != NULL) {
6586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          newFormat = newFormats[formatNumber]->clone();
6596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          if (newFormat == NULL) {
6606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org              status = U_MEMORY_ALLOCATION_ERROR;
6616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          }
6626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
6636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      setCustomArgStartFormat(partIndex, newFormat, status);
6646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      ++formatNumber;
6656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
6676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        resetPattern();
6686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
6726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Adopt a single format by format number.
6736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Do nothing if the format number is not less than the array count.
6746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
6766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::adoptFormat(int32_t n, Format *newFormat) {
6776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    LocalPointer<Format> p(newFormat);
6786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (n >= 0) {
6796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t formatNumber = 0;
6806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
6816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (n == formatNumber) {
6826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UErrorCode status = U_ZERO_ERROR;
6836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                setCustomArgStartFormat(partIndex, p.orphan(), status);
6846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return;
6856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
6866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ++formatNumber;
6876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
6886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
6896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
6906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
6916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
6926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Adopt a single format by format name.
6936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Do nothing if there is no match of formatName.
6946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
6956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::adoptFormat(const UnicodeString& formatName,
6966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           Format* formatToAdopt,
6976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& status) {
6986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    LocalPointer<Format> p(formatToAdopt);
6996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
7006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
7016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t argNumber = MessagePattern::validateArgumentName(formatName);
7036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
7046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;
7056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
7066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0;
7086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
7096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ) {
7106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (argNameMatches(partIndex + 1, formatName, argNumber)) {
7116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            Format* f;
7126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (p.isValid()) {
7136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                f = p.orphan();
7146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else if (formatToAdopt == NULL) {
7156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                f = NULL;
7166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
7176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                f = formatToAdopt->clone();
7186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (f == NULL) {
7196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    status = U_MEMORY_ALLOCATION_ERROR;
7206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    return;
7216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
7226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
7236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            setCustomArgStartFormat(partIndex, f, status);
7246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
7256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
7296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Set a single format.
7306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Do nothing if the variable is not less than the array count.
7316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
7326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::setFormat(int32_t n, const Format& newFormat) {
7336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (n >= 0) {
7356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t formatNumber = 0;
7366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (int32_t partIndex = 0;
7376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org             (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
7386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (n == formatNumber) {
7396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                Format* new_format = newFormat.clone();
7406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (new_format) {
7416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    UErrorCode status = U_ZERO_ERROR;
7426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    setCustomArgStartFormat(partIndex, new_format, status);
7436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
7446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return;
7456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
7466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ++formatNumber;
7476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
7486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
7526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Get a single format by format name.
7536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Do nothing if the variable is not less than the array count.
7546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat *
7556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
7566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status) || cachedFormatters == NULL) return NULL;
7576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t argNumber = MessagePattern::validateArgumentName(formatName);
7596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
7606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;
7616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
7626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
7646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (argNameMatches(partIndex + 1, formatName, argNumber)) {
7656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return getCachedFormatter(partIndex);
7666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
7676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
7696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
7706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
7726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Set a single format by format name
7736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Do nothing if the variable is not less than the array count.
7746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
7756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::setFormat(const UnicodeString& formatName,
7766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         const Format& newFormat,
7776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         UErrorCode& status) {
7786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) return;
7796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
7806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t argNumber = MessagePattern::validateArgumentName(formatName);
7816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
7826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;
7836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
7846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
7856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0;
7866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
7876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ) {
7886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (argNameMatches(partIndex + 1, formatName, argNumber)) {
7896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (&newFormat == NULL) {
7906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                setCustomArgStartFormat(partIndex, NULL, status);
7916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
7926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                Format* new_format = newFormat.clone();
7936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (new_format == NULL) {
7946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    status = U_MEMORY_ALLOCATION_ERROR;
7956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    return;
7966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
7976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                setCustomArgStartFormat(partIndex, new_format, status);
7986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
7996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
8006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
8046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Gets the format array.
8056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst Format**
8066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::getFormats(int32_t& cnt) const
8076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
8086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // This old API returns an array (which we hold) of Format*
8096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // pointers.  The array is valid up to the next call to any
8106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // method on this object.  We construct and resize an array
8116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // on demand that contains aliases to the subformats[i].format
8126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // pointers.
8136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    MessageFormat* t = const_cast<MessageFormat*> (this);
8146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cnt = 0;
8156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (formatAliases == NULL) {
8166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount;
8176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        Format** a = (Format**)
8186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
8196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (a == NULL) {
8206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->formatAliasesCapacity = 0;
8216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return NULL;
8226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
8236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->formatAliases = a;
8246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else if (argTypeCount > formatAliasesCapacity) {
8256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        Format** a = (Format**)
8266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uprv_realloc(formatAliases, sizeof(Format*) * argTypeCount);
8276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (a == NULL) {
8286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->formatAliasesCapacity = 0;
8296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return NULL;
8306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
8316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->formatAliases = a;
8326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->formatAliasesCapacity = argTypeCount;
8336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
8366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->formatAliases[cnt++] = getCachedFormatter(partIndex);
8376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return (const Format**)formatAliases;
8406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString MessageFormat::getArgName(int32_t partIndex) {
8446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const MessagePattern::Part& part = msgPattern.getPart(partIndex);
8456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return msgPattern.getSubstring(part);
8466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgStringEnumeration*
8496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::getFormatNames(UErrorCode& status) {
8506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status))  return NULL;
8516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UVector *fFormatNames = new UVector(status);
8536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
8546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_MEMORY_ALLOCATION_ERROR;
8556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
8566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    fFormatNames->setDeleter(uprv_deleteUObject);
8586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
8606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fFormatNames->addElement(new UnicodeString(getArgName(partIndex + 1)), status);
8616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
8626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    StringEnumeration* nameEnumerator = new FormatNameEnumeration(fFormatNames, status);
8646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return nameEnumerator;
8656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
8686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formats the source Formattable array and copy into the result buffer.
8696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Ignore the FieldPosition result for error checking.
8706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
8726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::format(const Formattable* source,
8736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      int32_t cnt,
8746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UnicodeString& appendTo,
8756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      FieldPosition& ignore,
8766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UErrorCode& success) const
8776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
8786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return format(source, NULL, cnt, appendTo, &ignore, success);
8796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
8826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Internally creates a MessageFormat instance based on the
8836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// pattern and formats the arguments Formattable array and
8846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// copy into the appendTo buffer.
8856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
8876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::format(  const UnicodeString& pattern,
8886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        const Formattable* arguments,
8896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        int32_t cnt,
8906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        UnicodeString& appendTo,
8916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        UErrorCode& success)
8926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
8936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    MessageFormat temp(pattern, success);
8946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return temp.format(arguments, NULL, cnt, appendTo, NULL, success);
8956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
8966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
8976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
8986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formats the source Formattable object and copy into the
8996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// appendTo buffer.  The Formattable object must be an array
9006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// of Formattable instances, returns error otherwise.
9016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
9036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::format(const Formattable& source,
9046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UnicodeString& appendTo,
9056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      FieldPosition& ignore,
9066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UErrorCode& success) const
9076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
9086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(success))
9096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
9106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (source.getType() != Formattable::kArray) {
9116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        success = U_ILLEGAL_ARGUMENT_ERROR;
9126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
9136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t cnt;
9156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const Formattable* tmpPtr = source.getArray(cnt);
9166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return format(tmpPtr, NULL, cnt, appendTo, &ignore, success);
9176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
9186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
9206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::format(const UnicodeString* argumentNames,
9216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      const Formattable* arguments,
9226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      int32_t count,
9236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UnicodeString& appendTo,
9246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UErrorCode& success) const {
9256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return format(arguments, argumentNames, count, appendTo, NULL, success);
9266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
9276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Does linear search to find the match for an ArgName.
9296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
9306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                       const UnicodeString *argumentNames,
9316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                       int32_t cnt, UnicodeString& name) const {
9326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 0; i < cnt; ++i) {
9336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (0 == argumentNames[i].compare(name)) {
9346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return arguments + i;
9356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
9366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
9386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
9396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
9426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::format(const Formattable* arguments,
9436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      const UnicodeString *argumentNames,
9446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      int32_t cnt,
9456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UnicodeString& appendTo,
9466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      FieldPosition* pos,
9476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                      UErrorCode& status) const {
9486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
9496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
9506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeStringAppendable usapp(appendTo);
9536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    AppendableWrapper app(usapp);
9546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    format(0, NULL, arguments, argumentNames, cnt, app, pos, status);
9556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
9566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
9576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgnamespace {
9596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
9616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Mutable input/output values for the PluralSelectorProvider.
9626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Separate so that it is possible to make MessageFormat Freezable.
9636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
9646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgclass PluralSelectorContext {
9656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgpublic:
9666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    PluralSelectorContext(int32_t start, const UnicodeString &name,
9676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          const Formattable &num, double off, UErrorCode &errorCode)
9686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            : startIndex(start), argName(name), offset(off),
9696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org              numberArgIndex(-1), formatter(NULL), forReplaceNumber(FALSE) {
9706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // number needs to be set even when select() is not called.
9716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Keep it as a Number/Formattable:
9726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // For format() methods, and to preserve information (e.g., BigDecimal).
9736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(off == 0) {
9746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            number = num;
9756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
9766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            number = num.getDouble(errorCode) - off;
9776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
9786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
9796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Input values for plural selection with decimals.
9816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t startIndex;
9826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString &argName;
9836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /** argument number - plural offset */
9846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Formattable number;
9856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    double offset;
9866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Output values for plural selection with decimals.
9876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */
9886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t numberArgIndex;
9896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const Format *formatter;
9906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /** formatted argument number - plural offset */
9916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString numberString;
9926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /** TRUE if number-offset was formatted with the stock number formatter */
9936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UBool forReplaceNumber;
9946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org};
9956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}  // namespace
9976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
9986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// if argumentNames is NULL, this means arguments is a numeric array.
9996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// arguments can not be NULL.
10006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// We use const void *plNumber rather than const PluralSelectorContext *pluralNumber
10016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// so that we need not declare the PluralSelectorContext in the public header file.
10026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::format(int32_t msgStart, const void *plNumber,
10036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const Formattable* arguments,
10046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UnicodeString *argumentNames,
10056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           int32_t cnt,
10066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           AppendableWrapper& appendTo,
10076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           FieldPosition* ignore,
10086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& success) const {
10096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(success)) {
10106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
10116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
10126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
10136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString& msgString = msgPattern.getPatternString();
10146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
10156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
10166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part* part = &msgPattern.getPart(i);
10176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UMessagePatternPartType type = part->getType();
10186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t index = part->getIndex();
10196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.append(msgString, prevIndex, index - prevIndex);
10206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
10216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return;
10226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        prevIndex = part->getLimit();
10246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
10256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const PluralSelectorContext &pluralNumber =
10266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                *static_cast<const PluralSelectorContext *>(plNumber);
10276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if(pluralNumber.forReplaceNumber) {
10286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // number-offset was already formatted.
10296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(pluralNumber.formatter,
10306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        pluralNumber.number, pluralNumber.numberString, success);
10316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
10326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                const NumberFormat* nf = getDefaultNumberFormat(success);
10336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(nf, pluralNumber.number, success);
10346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
10356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            continue;
10366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type != UMSGPAT_PART_TYPE_ARG_START) {
10386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            continue;
10396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t argLimit = msgPattern.getLimitPartIndex(i);
10416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternArgType argType = part->getArgType();
10426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        part = &msgPattern.getPart(++i);
10436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const Formattable* arg;
10446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UBool noArg = FALSE;
10456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString argName = msgPattern.getSubstring(*part);
10466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (argumentNames == NULL) {
10476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t argNumber = part->getValue();  // ARG_NUMBER
10486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (0 <= argNumber && argNumber < cnt) {
10496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                arg = arguments + argNumber;
10506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
10516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                arg = NULL;
10526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                noArg = TRUE;
10536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
10546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
10556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            arg = getArgFromListByName(arguments, argumentNames, cnt, argName);
10566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (arg == NULL) {
10576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                noArg = TRUE;
10586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
10596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
10606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ++i;
10616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t prevDestLength = appendTo.length();
10626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const Format* formatter = NULL;
10636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (noArg) {
10646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            appendTo.append(
10656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE));
10666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (arg == NULL) {
10676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            appendTo.append(NULL_STRING, 4);
10686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if(plNumber!=NULL &&
10696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) {
10706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const PluralSelectorContext &pluralNumber =
10716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                *static_cast<const PluralSelectorContext *>(plNumber);
10726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if(pluralNumber.offset == 0) {
10736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // The number was already formatted with this formatter.
10746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number,
10756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                         pluralNumber.numberString, success);
10766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
10776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Do not use the formatted (number-offset) string for a named argument
10786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // that formats the number without subtracting the offset.
10796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
10806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
10816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if ((formatter = getCachedFormatter(i -2))) {
10826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
10836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (dynamic_cast<const ChoiceFormat*>(formatter) ||
10846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                dynamic_cast<const PluralFormat*>(formatter) ||
10856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                dynamic_cast<const SelectFormat*>(formatter)) {
10866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // We only handle nested formats here if they were provided via
10876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // setFormat() or its siblings. Otherwise they are not cached and instead
10886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // handled below according to argType.
10896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UnicodeString subMsgString;
10906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                formatter->format(*arg, subMsgString, success);
10916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
10926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
10936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                ) {
10946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    MessageFormat subMsgFormat(subMsgString, fLocale, success);
10956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, ignore, success);
10966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                } else {
10976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    appendTo.append(subMsgString);
10986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
10996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
11006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(formatter, *arg, success);
11016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) {
11036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
11046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
11056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // for the hash table containind DummyFormat.
11066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (arg->isNumeric()) {
11076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                const NumberFormat* nf = getDefaultNumberFormat(success);
11086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(nf, *arg, success);
11096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else if (arg->getType() == Formattable::kDate) {
11106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                const DateFormat* df = getDefaultDateFormat(success);
11116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.formatAndAppend(df, *arg, success);
11126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
11136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                appendTo.append(arg->getString(success));
11146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
11166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (!arg->isNumeric()) {
11176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                success = U_ILLEGAL_ARGUMENT_ERROR;
11186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return;
11196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // We must use the Formattable::getDouble() variant with the UErrorCode parameter
11216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // because only this one converts non-double numeric types to double.
11226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const double number = arg->getDouble(success);
11236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
11246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
11256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    cnt, appendTo, success);
11266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
11276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (!arg->isNumeric()) {
11286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                success = U_ILLEGAL_ARGUMENT_ERROR;
11296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return;
11306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
11316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const PluralSelectorProvider &selector =
11326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider;
11336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // We must use the Formattable::getDouble() variant with the UErrorCode parameter
11346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // because only this one converts non-double numeric types to double.
11356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            double offset = msgPattern.getPluralOffset(i);
11366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            PluralSelectorContext context(i, argName, *arg, offset, success);
11376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t subMsgStart = PluralFormat::findSubMessage(
11386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    msgPattern, i, selector, &context, arg->getDouble(success), success);
11396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames,
11406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    cnt, appendTo, success);
11416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
11426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
11436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
11446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                    cnt, appendTo, success);
11456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
11466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // This should never happen.
11476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            success = U_INTERNAL_PROGRAM_ERROR;
11486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return;
11496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
11506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
11516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        prevIndex = msgPattern.getPart(argLimit).getLimit();
11526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        i = argLimit;
11536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
11556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::formatComplexSubMessage(int32_t msgStart,
11586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            const void *plNumber,
11596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            const Formattable* arguments,
11606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            const UnicodeString *argumentNames,
11616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            int32_t cnt,
11626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            AppendableWrapper& appendTo,
11636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                            UErrorCode& success) const {
11646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(success)) {
11656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
11666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!MessageImpl::jdkAposMode(msgPattern)) {
11696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, NULL, success);
11706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
11716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
11726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
11736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
11746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
11756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // - if the result string contains an open curly brace '{' then
11766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //   instantiate a temporary MessageFormat object and format again;
11776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    //   otherwise just append the result string
11786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString& msgString = msgPattern.getPatternString();
11796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString sb;
11806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
11816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = msgStart;;) {
11826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part& part = msgPattern.getPart(++i);
11836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UMessagePatternPartType type = part.getType();
11846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t index = part.getIndex();
11856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
11866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sb.append(msgString, prevIndex, index - prevIndex);
11876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
11886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
11896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sb.append(msgString, prevIndex, index - prevIndex);
11906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
11916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                const PluralSelectorContext &pluralNumber =
11926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    *static_cast<const PluralSelectorContext *>(plNumber);
11936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if(pluralNumber.forReplaceNumber) {
11946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    // number-offset was already formatted.
11956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    sb.append(pluralNumber.numberString);
11966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                } else {
11976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    const NumberFormat* nf = getDefaultNumberFormat(success);
11986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    sb.append(nf->format(pluralNumber.number, sb, success));
11996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
12006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
12016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            prevIndex = part.getLimit();
12026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
12036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sb.append(msgString, prevIndex, index - prevIndex);
12046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            prevIndex = index;
12056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            i = msgPattern.getLimitPartIndex(i);
12066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            index = msgPattern.getPart(i).getLimit();
12076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
12086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            prevIndex = index;
12096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
12126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString emptyPattern;  // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
12136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        MessageFormat subMsgFormat(emptyPattern, fLocale, success);
12146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, success);
12156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, NULL, success);
12166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
12176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.append(sb);
12186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
12236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString& msgString=msgPattern.getPatternString();
12246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t prevIndex=msgPattern.getPart(from).getLimit();
12256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString b;
12266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = from + 1; ; ++i) {
12276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part& part = msgPattern.getPart(i);
12286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UMessagePatternPartType type=part.getType();
12296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t index=part.getIndex();
12306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        b.append(msgString, prevIndex, index - prevIndex);
12316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
12326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return b;
12336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Unexpected Part "part" in parsed message.
12356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
12366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        prevIndex=part.getLimit();
12376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
12426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                             FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
12436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
12446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
12456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /*
12466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
12476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          fp->setBeginIndex(prevLength);
12486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          fp->setEndIndex(dest.get_length());
12496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          return NULL;
12506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
12516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      return fp;
12526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    */
12536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t
12566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::findOtherSubMessage(int32_t partIndex) const {
12576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t count=msgPattern.countParts();
12586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const MessagePattern::Part *part = &msgPattern.getPart(partIndex);
12596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(MessagePattern::Part::hasNumericValue(part->getType())) {
12606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ++partIndex;
12616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
12626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
12636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // until ARG_LIMIT or end of plural-only pattern.
12646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString other(FALSE, OTHER_STRING, 5);
12656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    do {
12666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        part=&msgPattern.getPart(partIndex++);
12676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternPartType type=part->getType();
12686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
12696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
12706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR);
12726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // part is an ARG_SELECTOR followed by an optional explicit value, and then a message
12736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(msgPattern.partSubstringMatches(*part, other)) {
12746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return partIndex;
12756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) {
12776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ++partIndex;  // skip the numeric-value part of "=1" etc.
12786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        partIndex=msgPattern.getLimitPartIndex(partIndex);
12806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } while(++partIndex<count);
12816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return 0;
12826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
12836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
12846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t
12856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const {
12866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for(int32_t i=msgStart+1;; ++i) {
12876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part &part=msgPattern.getPart(i);
12886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternPartType type=part.getType();
12896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
12906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return 0;
12916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
12936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return -1;
12946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
12956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_ARG_START) {
12966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UMessagePatternArgType argType=part.getArgType();
12976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) {
12986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // ARG_NUMBER or ARG_NAME
12996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) {
13006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    return i;
13016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
13026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
13036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            i=msgPattern.getLimitPartIndex(i);
13046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
13056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) {
13096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Deep copy pointer fields.
13106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We need not copy the formatAliases because they are re-filled
13116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // in each getFormats() call.
13126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
13136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // also get created on demand.
13146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    argTypeCount = that.argTypeCount;
13156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (argTypeCount > 0) {
13166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (!allocateArgTypes(argTypeCount, ec)) {
13176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return;
13186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
13196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
13206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cachedFormatters != NULL) {
13226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(cachedFormatters);
13236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (customFormatArgStarts != NULL) {
13256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(customFormatArgStarts);
13266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (that.cachedFormatters) {
13286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (cachedFormatters == NULL) {
13296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
13306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                        equalFormatsForHash, &ec);
13316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (U_FAILURE(ec)) {
13326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return;
13336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
13346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
13356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
13366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const int32_t count = uhash_count(that.cachedFormatters);
13386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t pos, idx;
13396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (idx = 0, pos = -1; idx < count && U_SUCCESS(ec); ++idx) {
13406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
13416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            Format* newFormat = ((Format*)(cur->value.pointer))->clone();
13426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (newFormat) {
13436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
13446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
13456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                ec = U_MEMORY_ALLOCATION_ERROR;
13466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return;
13476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
13486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
13496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (that.customFormatArgStarts) {
13516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (customFormatArgStarts == NULL) {
13526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
13536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                              NULL, &ec);
13546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
13556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const int32_t count = uhash_count(that.customFormatArgStarts);
13566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t pos, idx;
13576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (idx = 0, pos = -1; idx < count && U_SUCCESS(ec); ++idx) {
13586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
13596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
13606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
13616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
13636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormattable*
13666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::parse(int32_t msgStart,
13676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     const UnicodeString& source,
13686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     ParsePosition& pos,
13696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     int32_t& count,
13706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UErrorCode& ec) const {
13716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    count = 0;
13726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
13736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        pos.setErrorIndex(pos.getIndex());
13746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
13756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // parse() does not work with named arguments.
13776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (msgPattern.hasNamedArguments()) {
13786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ec = U_ARGUMENT_TYPE_MISMATCH;
13796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        pos.setErrorIndex(pos.getIndex());
13806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
13816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
13826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
13836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString& msgString=msgPattern.getPatternString();
13846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
13856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t sourceOffset = pos.getIndex();
13866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ParsePosition tempStatus(0);
13876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
13886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for(int32_t i=msgStart+1; ; ++i) {
13896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UBool haveArgResult = FALSE;
13906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part* part=&msgPattern.getPart(i);
13916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UMessagePatternPartType type=part->getType();
13926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t index=part->getIndex();
13936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Make sure the literal string matches.
13946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t len = index - prevIndex;
13956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
13966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sourceOffset += len;
13976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            prevIndex += len;
13986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
13996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            pos.setErrorIndex(sourceOffset);
14006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return NULL; // leave index as is to signal error
14016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
14026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
14036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Things went well! Done.
14046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            pos.setIndex(sourceOffset);
14056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return resultArray.orphan();
14066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
14076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
14086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            prevIndex=part->getLimit();
14096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            continue;
14106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
14116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
14126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Unexpected Part "part" in parsed message.
14136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
14146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t argLimit=msgPattern.getLimitPartIndex(i);
14156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternArgType argType=part->getArgType();
14176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        part=&msgPattern.getPart(++i);
14186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t argNumber = part->getValue();  // ARG_NUMBER
14196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString key;
14206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ++i;
14216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const Format* formatter = NULL;
14226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        Formattable& argResult = resultArray[argNumber];
14236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(cachedFormatters!=NULL && (formatter = getCachedFormatter(i - 2))!=NULL) {
14256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Just parse using the formatter.
14266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            tempStatus.setIndex(sourceOffset);
14276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formatter->parseObject(source, argResult, tempStatus);
14286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (tempStatus.getIndex() == sourceOffset) {
14296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                pos.setErrorIndex(sourceOffset);
14306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return NULL; // leave index as is to signal error
14316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
14326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sourceOffset = tempStatus.getIndex();
14336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            haveArgResult = TRUE;
14346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if(
14356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) {
14366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
14376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
14386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // for the hash table containind DummyFormat.
14396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Match as a string.
14416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // if at end, use longest possible match
14426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // otherwise uses first match to intervening string
14436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // does NOT recursively try all possibilities
14446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
14456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t next;
14466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (!stringAfterArgument.isEmpty()) {
14476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                next = source.indexOf(stringAfterArgument, sourceOffset);
14486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
14496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                next = source.length();
14506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
14516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (next < 0) {
14526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                pos.setErrorIndex(sourceOffset);
14536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return NULL; // leave index as is to signal error
14546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
14556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
14566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                UnicodeString compValue;
14576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                compValue.append(LEFT_CURLY_BRACE);
14586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                itos(argNumber, compValue);
14596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                compValue.append(RIGHT_CURLY_BRACE);
14606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (0 != strValue.compare(compValue)) {
14616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    argResult.setString(strValue);
14626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    haveArgResult = TRUE;
14636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
14646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                sourceOffset = next;
14656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
14666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
14676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            tempStatus.setIndex(sourceOffset);
14686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
14696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (tempStatus.getIndex() == sourceOffset) {
14706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                pos.setErrorIndex(sourceOffset);
14716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return NULL; // leave index as is to signal error
14726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
14736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            argResult.setDouble(choiceResult);
14746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            haveArgResult = TRUE;
14756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sourceOffset = tempStatus.getIndex();
14766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
14776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Parsing not supported.
14786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ec = U_UNSUPPORTED_ERROR;
14796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return NULL;
14806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
14816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // This should never happen.
14826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ec = U_INTERNAL_PROGRAM_ERROR;
14836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return NULL;
14846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
14856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (haveArgResult && count <= argNumber) {
14866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            count = argNumber + 1;
14876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
14886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        prevIndex=msgPattern.getPart(argLimit).getLimit();
14896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        i=argLimit;
14906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
14916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
14926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
14936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Parses the source pattern and returns the Formattable objects array,
14946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// the array count and the ending parse position.  The caller of this method
14956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// owns the array.
14966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
14976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormattable*
14986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::parse(const UnicodeString& source,
14996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     ParsePosition& pos,
15006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     int32_t& count) const {
15016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode ec = U_ZERO_ERROR;
15026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return parse(0, source, pos, count, ec);
15036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
15046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
15066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Parses the source string and returns the array of
15076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formattable objects and the array count.  The caller
15086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// owns the returned array.
15096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormattable*
15116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::parse(const UnicodeString& source,
15126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     int32_t& cnt,
15136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UErrorCode& success) const
15146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
15156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (msgPattern.hasNamedArguments()) {
15166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        success = U_ARGUMENT_TYPE_MISMATCH;
15176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
15186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ParsePosition status(0);
15206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Calls the actual implementation method and starts
15216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // from zero offset of the source text.
15226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Formattable* result = parse(source, status, cnt);
15236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (status.getIndex() == 0) {
15246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        success = U_MESSAGE_PARSE_ERROR;
15256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete[] result;
15266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
15276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
15296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
15306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
15326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Parses the source text and copy into the result buffer.
15336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
15356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::parseObject( const UnicodeString& source,
15366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            Formattable& result,
15376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                            ParsePosition& status) const
15386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
15396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t cnt = 0;
15406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Formattable* tmpResult = parse(source, status, cnt);
15416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (tmpResult != NULL)
15426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.adoptArray(tmpResult, cnt);
15436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
15446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString
15466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
15476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString result;
15486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status)) {
15496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t plen = pattern.length();
15506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UChar* pat = pattern.getBuffer();
15516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t blen = plen * 2 + 1; // space for null termination, convenience
15526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UChar* buf = result.getBuffer(blen);
15536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (buf == NULL) {
15546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            status = U_MEMORY_ALLOCATION_ERROR;
15556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
15566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
15576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result.releaseBuffer(U_SUCCESS(status) ? len : 0);
15586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
15596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
15616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.setToBogus();
15626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
15646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
15656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
15676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
15696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
15706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (fmt == NULL) {
15716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ec = U_MEMORY_ALLOCATION_ERROR;
15726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
15736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
15746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
15756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return fmt;
15776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
15786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::cacheExplicitFormats(UErrorCode& status) {
15806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(status)) {
15816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
15826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cachedFormatters != NULL) {
15856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(cachedFormatters);
15866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (customFormatArgStarts != NULL) {
15886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uhash_removeAll(customFormatArgStarts);
15896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
15906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
15916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
15926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // which we need not examine.
15936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t limit = msgPattern.countParts() - 2;
15946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    argTypeCount = 0;
15956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We also need not look at the first two "parts"
15966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // (at most MSG_START and ARG_START) in this loop.
15976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We determine the argTypeCount first so that we can allocateArgTypes
15986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // so that the next loop can set argTypes[argNumber].
15996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // (This is for the C API which needs the argTypes to read its va_arg list.)
16006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
16016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part& part = msgPattern.getPart(i);
16026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
16036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const int argNumber = part.getValue();
16046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (argNumber >= argTypeCount) {
16056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                argTypeCount = argNumber + 1;
16066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
16076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
16086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
16096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!allocateArgTypes(argTypeCount, status)) {
16106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
16116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
16126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Set all argTypes to kObject, as a "none" value, for lack of any better value.
16136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We never use kObject for real arguments.
16146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We use it as "no argument yet" for the check for hasArgTypeConflicts.
16156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 0; i < argTypeCount; ++i) {
16166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        argTypes[i] = Formattable::kObject;
16176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
16186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    hasArgTypeConflicts = FALSE;
16196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // This loop starts at part index 1 because we do need to examine
16216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // ARG_START parts. (But we can ignore the MSG_START.)
16226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
16236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part* part = &msgPattern.getPart(i);
16246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
16256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            continue;
16266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
16276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternArgType argType = part->getArgType();
16286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t argNumber = -1;
16306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        part = &msgPattern.getPart(i + 1);
16316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
16326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            argNumber = part->getValue();
16336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
16346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        Formattable::Type formattableType;
16356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        switch (argType) {
16376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case UMSGPAT_ARG_TYPE_NONE:
16386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formattableType = Formattable::kString;
16396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case UMSGPAT_ARG_TYPE_SIMPLE: {
16416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t index = i;
16426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            i += 2;
16436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
16446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UnicodeString style;
16456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
16466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                style = msgPattern.getSubstring(*part);
16476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                ++i;
16486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
16496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UParseError parseError;
16506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
16516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            setArgStartFormat(index, formatter, status);
16526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
16546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case UMSGPAT_ARG_TYPE_CHOICE:
16556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case UMSGPAT_ARG_TYPE_PLURAL:
16566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case UMSGPAT_ARG_TYPE_SELECTORDINAL:
16576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formattableType = Formattable::kDouble;
16586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case UMSGPAT_ARG_TYPE_SELECT:
16606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formattableType = Formattable::kString;
16616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        default:
16636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            status = U_INTERNAL_PROGRAM_ERROR;  // Should be unreachable.
16646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formattableType = Formattable::kString;
16656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
16676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (argNumber != -1) {
16686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
16696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                hasArgTypeConflicts = TRUE;
16706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
16716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            argTypes[argNumber] = formattableType;
16726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
16736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
16746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
16756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
16786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                               Formattable::Type& formattableType, UParseError& parseError,
16796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                               UErrorCode& ec) {
16806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
16816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return NULL;
16826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
16836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Format* fmt = NULL;
16846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t typeID, styleID;
16856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    DateFormat::EStyle date_style;
16866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
16876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    switch (typeID = findKeyword(type, TYPE_IDS)) {
16886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    case 0: // number
16896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formattableType = Formattable::kDouble;
16906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        switch (findKeyword(style, NUMBER_STYLE_IDS)) {
16916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case 0: // default
16926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = NumberFormat::createInstance(fLocale, ec);
16936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case 1: // currency
16956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
16966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
16976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case 2: // percent
16986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = NumberFormat::createPercentInstance(fLocale, ec);
16996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
17006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        case 3: // integer
17016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            formattableType = Formattable::kLong;
17026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = createIntegerFormat(fLocale, ec);
17036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
17046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        default: // pattern
17056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = NumberFormat::createInstance(fLocale, ec);
17066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (fmt) {
17076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt);
17086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (decfmt != NULL) {
17096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    decfmt->applyPattern(style,parseError,ec);
17106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
17116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
17126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
17136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
17146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
17156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    case 1: // date
17176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    case 2: // time
17186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formattableType = Formattable::kDate;
17196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        styleID = findKeyword(style, DATE_STYLE_IDS);
17206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
17216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (typeID == 1) {
17236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = DateFormat::createDateInstance(date_style, fLocale);
17246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
17256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            fmt = DateFormat::createTimeInstance(date_style, fLocale);
17266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
17276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (styleID < 0 && fmt != NULL) {
17296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
17306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (sdtfmt != NULL) {
17316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                sdtfmt->applyPattern(style);
17326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
17336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
17346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
17356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    case 3: // spellout
17376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formattableType = Formattable::kDouble;
17386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
17396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
17406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    case 4: // ordinal
17416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formattableType = Formattable::kDouble;
17426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
17436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
17446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    case 5: // duration
17456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formattableType = Formattable::kDouble;
17466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
17476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
17486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    default:
17496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        formattableType = Formattable::kString;
17506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ec = U_ILLEGAL_ARGUMENT_ERROR;
17516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        break;
17526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
17536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return fmt;
17556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
17566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//-------------------------------------
17596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Finds the string, s, in the string array, list.
17606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t MessageFormat::findKeyword(const UnicodeString& s,
17616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   const UChar * const *list)
17626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
17636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (s.isEmpty()) {
17646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return 0; // default
17656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
17666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t length = s.length();
17686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UChar *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
17696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString buffer(FALSE, ps, length);
17706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Trims the space characters and turns all characters
17716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // in s to lower case.
17726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    buffer.toLower("");
17736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 0; list[i]; ++i) {
17746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (!buffer.compare(list[i], u_strlen(list[i]))) {
17756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return i;
17766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
17776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
17786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return -1;
17796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
17806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
17826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Convenience method that ought to be in NumberFormat
17836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
17846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgNumberFormat*
17856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
17866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    NumberFormat *temp = NumberFormat::createInstance(locale, status);
17876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    DecimalFormat *temp2;
17886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (temp != NULL && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != NULL) {
17896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        temp2->setMaximumFractionDigits(0);
17906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        temp2->setDecimalSeparatorAlwaysShown(FALSE);
17916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        temp2->setParseIntegerOnly(TRUE);
17926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
17936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return temp;
17956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
17966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
17976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
17986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Return the default number format.  Used to format a numeric
17996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * argument when subformats[i].format is NULL.  Returns NULL
18006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * on failure.
18016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
18026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Semantically const but may modify *this.
18036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
18046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
18056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (defaultNumberFormat == NULL) {
18066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        MessageFormat* t = (MessageFormat*) this;
18076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
18086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_FAILURE(ec)) {
18096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            delete t->defaultNumberFormat;
18106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            t->defaultNumberFormat = NULL;
18116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (t->defaultNumberFormat == NULL) {
18126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ec = U_MEMORY_ALLOCATION_ERROR;
18136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
18146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
18156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return defaultNumberFormat;
18166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
18196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Return the default date format.  Used to format a date
18206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * argument when subformats[i].format is NULL.  Returns NULL
18216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * on failure.
18226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
18236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Semantically const but may modify *this.
18246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
18256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
18266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (defaultDateFormat == NULL) {
18276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        MessageFormat* t = (MessageFormat*) this;
18286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
18296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (t->defaultDateFormat == NULL) {
18306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ec = U_MEMORY_ALLOCATION_ERROR;
18316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
18326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
18336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return defaultDateFormat;
18346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool
18376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::usesNamedArguments() const {
18386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return msgPattern.hasNamedArguments();
18396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t
18426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::getArgTypeCount() const {
18436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return argTypeCount;
18446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool MessageFormat::equalFormats(const void* left, const void* right) {
18476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return *(const Format*)left==*(const Format*)right;
18486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool MessageFormat::DummyFormat::operator==(const Format&) const {
18526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
18536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat* MessageFormat::DummyFormat::clone() const {
18566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return new DummyFormat();
18576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
18606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          UnicodeString& appendTo,
18616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          UErrorCode& status) const {
18626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status)) {
18636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_UNSUPPORTED_ERROR;
18646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
18656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
18666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
18696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          UnicodeString& appendTo,
18706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          FieldPosition&,
18716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          UErrorCode& status) const {
18726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status)) {
18736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_UNSUPPORTED_ERROR;
18746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
18756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
18766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
18796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          UnicodeString& appendTo,
18806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          FieldPositionIterator*,
18816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                          UErrorCode& status) const {
18826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status)) {
18836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_UNSUPPORTED_ERROR;
18846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
18856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
18866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::DummyFormat::parseObject(const UnicodeString&,
18896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                     Formattable&,
18906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                     ParsePosition& ) const {
18916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
18956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pos=0;
18966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    fFormatNames = fNameList;
18976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
18986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
18996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst UnicodeString*
19006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormatNameEnumeration::snext(UErrorCode& status) {
19016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_SUCCESS(status) && pos < fFormatNames->size()) {
19026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return (const UnicodeString*)fFormatNames->elementAt(pos++);
19036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
19046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
19056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
19086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormatNameEnumeration::reset(UErrorCode& /*status*/) {
19096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pos=0;
19106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t
19136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormatNameEnumeration::count(UErrorCode& /*status*/) const {
19146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return (fFormatNames==NULL) ? 0 : fFormatNames->size();
19156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormatNameEnumeration::~FormatNameEnumeration() {
19186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    delete fFormatNames;
19196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t)
19226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        : msgFormat(mf), rules(NULL), type(t) {
19236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgMessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
19266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    delete rules;
19276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number,
19306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                            UErrorCode& ec) const {
19316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(ec)) {
19326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return UnicodeString(FALSE, OTHER_STRING, 5);
19336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
19346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
19356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(rules == NULL) {
19366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec);
19376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_FAILURE(ec)) {
19386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return UnicodeString(FALSE, OTHER_STRING, 5);
19396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
19406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
19416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Select a sub-message according to how the number is formatted,
19426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // which is specified in the selected sub-message.
19436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // We avoid this circle by looking at how
19446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // the number is formatted in the "other" sub-message
19456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // which must always be present and usually contains the number.
19466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Message authors should be consistent across sub-messages.
19476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx);
19486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex);
19496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName);
19506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != NULL) {
19516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        context.formatter =
19526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex);
19536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
19546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(context.formatter == NULL) {
19556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        context.formatter = msgFormat.getDefaultNumberFormat(ec);
19566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        context.forReplaceNumber = TRUE;
19576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
19586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_ASSERT(context.number.getDouble(ec) == number);  // argument number minus the offset
19596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    context.formatter->format(context.number, context.numberString, ec);
19606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
19616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(decFmt != NULL) {
19626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        FixedDecimal dec = decFmt->getFixedDecimal(context.number, ec);
19636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return rules->select(dec);
19646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
19656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return rules->select(number);
19666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
19676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid MessageFormat::PluralSelectorProvider::reset() {
19706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    delete rules;
19716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    rules = NULL;
19726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
19736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_END
19766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif /* #if !UCONFIG_NO_FORMATTING */
19786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
19796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//eof
1980