]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/msgfmt.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / msgfmt.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
729e4ab9
A
3/********************************************************************
4 * COPYRIGHT:
2ca993e8 5 * Copyright (c) 1997-2015, International Business Machines Corporation and
729e4ab9
A
6 * others. All Rights Reserved.
7 ********************************************************************
8 *
9 * File MSGFMT.CPP
10 *
11 * Modification History:
12 *
13 * Date Name Description
14 * 02/19/97 aliu Converted from java.
15 * 03/20/97 helena Finished first cut of implementation.
16 * 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi.
17 * 06/11/97 helena Fixed addPattern to take the pattern correctly.
18 * 06/17/97 helena Fixed the getPattern to return the correct pattern.
19 * 07/09/97 helena Made ParsePosition into a class.
20 * 02/22/99 stephen Removed character literals for EBCDIC safety
21 * 11/01/09 kirtig Added SelectFormat
22 ********************************************************************/
b75a7d8f
A
23
24#include "unicode/utypes.h"
25
26#if !UCONFIG_NO_FORMATTING
27
4388f060 28#include "unicode/appendable.h"
b75a7d8f 29#include "unicode/choicfmt.h"
4388f060
A
30#include "unicode/datefmt.h"
31#include "unicode/decimfmt.h"
32#include "unicode/localpointer.h"
33#include "unicode/msgfmt.h"
46f4442e 34#include "unicode/plurfmt.h"
4388f060 35#include "unicode/rbnf.h"
729e4ab9 36#include "unicode/selfmt.h"
4388f060 37#include "unicode/smpdtfmt.h"
73c04bcf 38#include "unicode/umsg.h"
4388f060 39#include "unicode/ustring.h"
b75a7d8f 40#include "cmemory.h"
4388f060
A
41#include "patternprops.h"
42#include "messageimpl.h"
46f4442e 43#include "msgfmt_impl.h"
57a6839d 44#include "plurrule_impl.h"
b75a7d8f 45#include "uassert.h"
4388f060
A
46#include "uelement.h"
47#include "uhash.h"
46f4442e 48#include "ustrfmt.h"
4388f060 49#include "util.h"
46f4442e 50#include "uvector.h"
2ca993e8 51#include "visibledigits.h"
b75a7d8f
A
52
53// *****************************************************************************
54// class MessageFormat
55// *****************************************************************************
56
b75a7d8f 57#define SINGLE_QUOTE ((UChar)0x0027)
4388f060 58#define COMMA ((UChar)0x002C)
b75a7d8f
A
59#define LEFT_CURLY_BRACE ((UChar)0x007B)
60#define RIGHT_CURLY_BRACE ((UChar)0x007D)
61
62//---------------------------------------
63// static data
64
65static const UChar ID_NUMBER[] = {
66 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
67};
68static const UChar ID_DATE[] = {
69 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
70};
71static const UChar ID_TIME[] = {
72 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
73};
374ca955
A
74static const UChar ID_SPELLOUT[] = {
75 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
76};
77static const UChar ID_ORDINAL[] = {
78 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
79};
80static const UChar ID_DURATION[] = {
81 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
82};
b75a7d8f
A
83
84// MessageFormat Type List Number, Date, Time or Choice
85static const UChar * const TYPE_IDS[] = {
b75a7d8f 86 ID_NUMBER,
729e4ab9 87 ID_DATE,
b75a7d8f 88 ID_TIME,
374ca955
A
89 ID_SPELLOUT,
90 ID_ORDINAL,
91 ID_DURATION,
92 NULL,
b75a7d8f 93};
729e4ab9 94
4388f060
A
95static const UChar ID_EMPTY[] = {
96 0 /* empty string, used for default so that null can mark end of list */
97};
b75a7d8f
A
98static const UChar ID_CURRENCY[] = {
99 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
100};
101static const UChar ID_PERCENT[] = {
102 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
103};
104static const UChar ID_INTEGER[] = {
105 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
106};
107
108// NumberFormat modifier list, default, currency, percent or integer
109static const UChar * const NUMBER_STYLE_IDS[] = {
374ca955 110 ID_EMPTY,
b75a7d8f
A
111 ID_CURRENCY,
112 ID_PERCENT,
113 ID_INTEGER,
114 NULL,
115};
374ca955 116
b75a7d8f
A
117static const UChar ID_SHORT[] = {
118 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
119};
120static const UChar ID_MEDIUM[] = {
121 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
122};
123static const UChar ID_LONG[] = {
124 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
125};
126static const UChar ID_FULL[] = {
127 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
128};
129
130// DateFormat modifier list, default, short, medium, long or full
131static const UChar * const DATE_STYLE_IDS[] = {
374ca955 132 ID_EMPTY,
b75a7d8f
A
133 ID_SHORT,
134 ID_MEDIUM,
135 ID_LONG,
374ca955
A
136 ID_FULL,
137 NULL,
b75a7d8f 138};
729e4ab9 139
4388f060
A
140static const icu::DateFormat::EStyle DATE_STYLES[] = {
141 icu::DateFormat::kDefault,
142 icu::DateFormat::kShort,
143 icu::DateFormat::kMedium,
144 icu::DateFormat::kLong,
145 icu::DateFormat::kFull,
b75a7d8f
A
146};
147
b75a7d8f
A
148static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
149
4388f060
A
150static const UChar NULL_STRING[] = {
151 0x6E, 0x75, 0x6C, 0x6C, 0 // "null"
152};
153
154static const UChar OTHER_STRING[] = {
155 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other"
156};
157
158U_CDECL_BEGIN
159static UBool U_CALLCONV equalFormatsForHash(const UHashTok key1,
160 const UHashTok key2) {
161 return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer);
162}
163
164U_CDECL_END
165
b75a7d8f
A
166U_NAMESPACE_BEGIN
167
168// -------------------------------------
374ca955 169UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
46f4442e 170UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration)
b75a7d8f
A
171
172//--------------------------------------------------------------------
173
b75a7d8f
A
174/**
175 * Convert an integer value to a string and append the result to
176 * the given UnicodeString.
177 */
178static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
179 UChar temp[16];
180 uprv_itou(temp,16,i,10,0); // 10 == radix
4388f060 181 appendTo.append(temp, -1);
b75a7d8f
A
182 return appendTo;
183}
184
4388f060
A
185
186// AppendableWrapper: encapsulates the result of formatting, keeping track
187// of the string and its length.
188class AppendableWrapper : public UMemory {
46f4442e 189public:
4388f060 190 AppendableWrapper(Appendable& appendable) : app(appendable), len(0) {
46f4442e 191 }
4388f060
A
192 void append(const UnicodeString& s) {
193 app.appendString(s.getBuffer(), s.length());
194 len += s.length();
46f4442e 195 }
4388f060
A
196 void append(const UChar* s, const int32_t sLength) {
197 app.appendString(s, sLength);
198 len += sLength;
199 }
200 void append(const UnicodeString& s, int32_t start, int32_t length) {
201 append(s.tempSubString(start, length));
202 }
203 void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) {
204 UnicodeString s;
205 formatter->format(arg, s, ec);
206 if (U_SUCCESS(ec)) {
207 append(s);
208 }
209 }
57a6839d
A
210 void formatAndAppend(const Format* formatter, const Formattable& arg,
211 const UnicodeString &argString, UErrorCode& ec) {
212 if (!argString.isEmpty()) {
213 if (U_SUCCESS(ec)) {
214 append(argString);
215 }
216 } else {
217 formatAndAppend(formatter, arg, ec);
218 }
219 }
4388f060
A
220 int32_t length() {
221 return len;
46f4442e 222 }
4388f060
A
223private:
224 Appendable& app;
225 int32_t len;
46f4442e
A
226};
227
4388f060 228
b75a7d8f
A
229// -------------------------------------
230// Creates a MessageFormat instance based on the pattern.
231
232MessageFormat::MessageFormat(const UnicodeString& pattern,
233 UErrorCode& success)
234: fLocale(Locale::getDefault()), // Uses the default locale
4388f060 235 msgPattern(success),
b75a7d8f
A
236 formatAliases(NULL),
237 formatAliasesCapacity(0),
b75a7d8f
A
238 argTypes(NULL),
239 argTypeCount(0),
240 argTypeCapacity(0),
4388f060 241 hasArgTypeConflicts(FALSE),
b75a7d8f 242 defaultNumberFormat(NULL),
4388f060
A
243 defaultDateFormat(NULL),
244 cachedFormatters(NULL),
245 customFormatArgStarts(NULL),
57a6839d
A
246 pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
247 ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
b75a7d8f 248{
374ca955 249 setLocaleIDs(fLocale.getName(), fLocale.getName());
4388f060 250 applyPattern(pattern, success);
b75a7d8f 251}
729e4ab9 252
b75a7d8f
A
253MessageFormat::MessageFormat(const UnicodeString& pattern,
254 const Locale& newLocale,
255 UErrorCode& success)
256: fLocale(newLocale),
4388f060 257 msgPattern(success),
b75a7d8f
A
258 formatAliases(NULL),
259 formatAliasesCapacity(0),
b75a7d8f
A
260 argTypes(NULL),
261 argTypeCount(0),
262 argTypeCapacity(0),
4388f060 263 hasArgTypeConflicts(FALSE),
b75a7d8f 264 defaultNumberFormat(NULL),
4388f060
A
265 defaultDateFormat(NULL),
266 cachedFormatters(NULL),
267 customFormatArgStarts(NULL),
57a6839d
A
268 pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
269 ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
b75a7d8f 270{
374ca955 271 setLocaleIDs(fLocale.getName(), fLocale.getName());
4388f060 272 applyPattern(pattern, success);
b75a7d8f
A
273}
274
275MessageFormat::MessageFormat(const UnicodeString& pattern,
276 const Locale& newLocale,
277 UParseError& parseError,
278 UErrorCode& success)
279: fLocale(newLocale),
4388f060 280 msgPattern(success),
b75a7d8f
A
281 formatAliases(NULL),
282 formatAliasesCapacity(0),
b75a7d8f
A
283 argTypes(NULL),
284 argTypeCount(0),
285 argTypeCapacity(0),
4388f060 286 hasArgTypeConflicts(FALSE),
b75a7d8f 287 defaultNumberFormat(NULL),
4388f060
A
288 defaultDateFormat(NULL),
289 cachedFormatters(NULL),
290 customFormatArgStarts(NULL),
57a6839d
A
291 pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
292 ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
b75a7d8f 293{
374ca955 294 setLocaleIDs(fLocale.getName(), fLocale.getName());
4388f060 295 applyPattern(pattern, parseError, success);
b75a7d8f
A
296}
297
298MessageFormat::MessageFormat(const MessageFormat& that)
4388f060
A
299:
300 Format(that),
301 fLocale(that.fLocale),
302 msgPattern(that.msgPattern),
b75a7d8f
A
303 formatAliases(NULL),
304 formatAliasesCapacity(0),
b75a7d8f
A
305 argTypes(NULL),
306 argTypeCount(0),
307 argTypeCapacity(0),
4388f060 308 hasArgTypeConflicts(that.hasArgTypeConflicts),
b75a7d8f 309 defaultNumberFormat(NULL),
4388f060
A
310 defaultDateFormat(NULL),
311 cachedFormatters(NULL),
312 customFormatArgStarts(NULL),
57a6839d
A
313 pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
314 ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
b75a7d8f 315{
4388f060
A
316 // This will take care of creating the hash tables (since they are NULL).
317 UErrorCode ec = U_ZERO_ERROR;
318 copyObjects(that, ec);
319 if (U_FAILURE(ec)) {
320 resetPattern();
321 }
b75a7d8f
A
322}
323
324MessageFormat::~MessageFormat()
325{
4388f060
A
326 uhash_close(cachedFormatters);
327 uhash_close(customFormatArgStarts);
b75a7d8f
A
328
329 uprv_free(argTypes);
b75a7d8f 330 uprv_free(formatAliases);
b75a7d8f
A
331 delete defaultNumberFormat;
332 delete defaultDateFormat;
333}
334
335//--------------------------------------------------------------------
336// Variable-size array management
337
b75a7d8f
A
338/**
339 * Allocate argTypes[] to at least the given capacity and return
340 * TRUE if successful. If not, leave argTypes[] unchanged.
341 *
342 * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
343 * if necessary to be at least as large as specified.
344 */
4388f060
A
345UBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) {
346 if (U_FAILURE(status)) {
347 return FALSE;
348 }
349 if (argTypeCapacity >= capacity) {
350 return TRUE;
351 }
352 if (capacity < DEFAULT_INITIAL_CAPACITY) {
353 capacity = DEFAULT_INITIAL_CAPACITY;
354 } else if (capacity < 2*argTypeCapacity) {
355 capacity = 2*argTypeCapacity;
356 }
357 Formattable::Type* a = (Formattable::Type*)
b75a7d8f 358 uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
4388f060
A
359 if (a == NULL) {
360 status = U_MEMORY_ALLOCATION_ERROR;
361 return FALSE;
b75a7d8f 362 }
4388f060
A
363 argTypes = a;
364 argTypeCapacity = capacity;
b75a7d8f
A
365 return TRUE;
366}
367
368// -------------------------------------
369// assignment operator
370
371const MessageFormat&
372MessageFormat::operator=(const MessageFormat& that)
373{
4388f060 374 if (this != &that) {
b75a7d8f
A
375 // Calls the super class for assignment first.
376 Format::operator=(that);
377
b75a7d8f 378 setLocale(that.fLocale);
4388f060
A
379 msgPattern = that.msgPattern;
380 hasArgTypeConflicts = that.hasArgTypeConflicts;
729e4ab9 381
4388f060
A
382 UErrorCode ec = U_ZERO_ERROR;
383 copyObjects(that, ec);
384 if (U_FAILURE(ec)) {
385 resetPattern();
b75a7d8f 386 }
b75a7d8f
A
387 }
388 return *this;
389}
390
391UBool
729e4ab9 392MessageFormat::operator==(const Format& rhs) const
b75a7d8f
A
393{
394 if (this == &rhs) return TRUE;
729e4ab9 395
b75a7d8f
A
396 MessageFormat& that = (MessageFormat&)rhs;
397
398 // Check class ID before checking MessageFormat members
399 if (!Format::operator==(rhs) ||
4388f060
A
400 msgPattern != that.msgPattern ||
401 fLocale != that.fLocale) {
b75a7d8f
A
402 return FALSE;
403 }
404
4388f060
A
405 // Compare hashtables.
406 if ((customFormatArgStarts == NULL) != (that.customFormatArgStarts == NULL)) {
407 return FALSE;
408 }
409 if (customFormatArgStarts == NULL) {
410 return TRUE;
411 }
412
413 UErrorCode ec = U_ZERO_ERROR;
414 const int32_t count = uhash_count(customFormatArgStarts);
415 const int32_t rhs_count = uhash_count(that.customFormatArgStarts);
416 if (count != rhs_count) {
417 return FALSE;
418 }
b331163b 419 int32_t idx = 0, rhs_idx = 0, pos = UHASH_FIRST, rhs_pos = UHASH_FIRST;
4388f060
A
420 for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) {
421 const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos);
422 const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos);
423 if (cur->key.integer != rhs_cur->key.integer) {
424 return FALSE;
425 }
426 const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer);
427 const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer);
428 if (*format != *rhs_format) {
b75a7d8f
A
429 return FALSE;
430 }
431 }
b75a7d8f
A
432 return TRUE;
433}
434
435// -------------------------------------
436// Creates a copy of this MessageFormat, the caller owns the copy.
729e4ab9 437
b75a7d8f
A
438Format*
439MessageFormat::clone() const
440{
441 return new MessageFormat(*this);
442}
729e4ab9 443
b75a7d8f
A
444// -------------------------------------
445// Sets the locale of this MessageFormat object to theLocale.
729e4ab9 446
b75a7d8f
A
447void
448MessageFormat::setLocale(const Locale& theLocale)
449{
450 if (fLocale != theLocale) {
451 delete defaultNumberFormat;
452 defaultNumberFormat = NULL;
453 delete defaultDateFormat;
454 defaultDateFormat = NULL;
4388f060
A
455 fLocale = theLocale;
456 setLocaleIDs(fLocale.getName(), fLocale.getName());
57a6839d
A
457 pluralProvider.reset();
458 ordinalProvider.reset();
b75a7d8f 459 }
b75a7d8f 460}
729e4ab9 461
b75a7d8f
A
462// -------------------------------------
463// Gets the locale of this MessageFormat object.
729e4ab9 464
b75a7d8f
A
465const Locale&
466MessageFormat::getLocale() const
467{
468 return fLocale;
469}
470
b75a7d8f 471void
729e4ab9 472MessageFormat::applyPattern(const UnicodeString& newPattern,
b75a7d8f
A
473 UErrorCode& status)
474{
475 UParseError parseError;
476 applyPattern(newPattern,parseError,status);
477}
478
479
480// -------------------------------------
481// Applies the new pattern and returns an error if the pattern
482// is not correct.
483void
729e4ab9 484MessageFormat::applyPattern(const UnicodeString& pattern,
b75a7d8f
A
485 UParseError& parseError,
486 UErrorCode& ec)
729e4ab9 487{
b75a7d8f
A
488 if(U_FAILURE(ec)) {
489 return;
490 }
4388f060
A
491 msgPattern.parse(pattern, &parseError, ec);
492 cacheExplicitFormats(ec);
b75a7d8f 493
4388f060
A
494 if (U_FAILURE(ec)) {
495 resetPattern();
b75a7d8f 496 }
4388f060
A
497}
498
499void MessageFormat::resetPattern() {
500 msgPattern.clear();
501 uhash_close(cachedFormatters);
502 cachedFormatters = NULL;
503 uhash_close(customFormatArgStarts);
504 customFormatArgStarts = NULL;
505 argTypeCount = 0;
506 hasArgTypeConflicts = FALSE;
507}
b75a7d8f 508
4388f060
A
509void
510MessageFormat::applyPattern(const UnicodeString& pattern,
511 UMessagePatternApostropheMode aposMode,
512 UParseError* parseError,
513 UErrorCode& status) {
514 if (aposMode != msgPattern.getApostropheMode()) {
515 msgPattern.clearPatternAndSetApostropheMode(aposMode);
b75a7d8f 516 }
4388f060 517 applyPattern(pattern, *parseError, status);
b75a7d8f 518}
4388f060 519
b75a7d8f 520// -------------------------------------
729e4ab9 521// Converts this MessageFormat instance to a pattern.
b75a7d8f
A
522
523UnicodeString&
524MessageFormat::toPattern(UnicodeString& appendTo) const {
4388f060
A
525 if ((customFormatArgStarts != NULL && 0 != uhash_count(customFormatArgStarts)) ||
526 0 == msgPattern.countParts()
527 ) {
528 appendTo.setToBogus();
529 return appendTo;
530 }
531 return appendTo.append(msgPattern.getPatternString());
532}
533
534int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
535 if (partIndex != 0) {
536 partIndex = msgPattern.getLimitPartIndex(partIndex);
537 }
538 for (;;) {
539 UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
540 if (type == UMSGPAT_PART_TYPE_ARG_START) {
541 return partIndex;
46f4442e 542 }
4388f060
A
543 if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
544 return -1;
729e4ab9 545 }
4388f060
A
546 }
547}
729e4ab9 548
4388f060
A
549void MessageFormat::setArgStartFormat(int32_t argStart,
550 Format* formatter,
551 UErrorCode& status) {
552 if (U_FAILURE(status)) {
553 delete formatter;
57a6839d 554 return;
4388f060
A
555 }
556 if (cachedFormatters == NULL) {
557 cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
558 equalFormatsForHash, &status);
559 if (U_FAILURE(status)) {
560 delete formatter;
561 return;
729e4ab9 562 }
4388f060
A
563 uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
564 }
565 if (formatter == NULL) {
566 formatter = new DummyFormat();
567 }
568 uhash_iput(cachedFormatters, argStart, formatter, &status);
569}
729e4ab9 570
4388f060
A
571
572UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
573 const MessagePattern::Part& part = msgPattern.getPart(partIndex);
574 return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
575 msgPattern.partSubstringMatches(part, argName) :
576 part.getValue() == argNumber; // ARG_NUMBER
577}
578
579// Sets a custom formatter for a MessagePattern ARG_START part index.
580// "Custom" formatters are provided by the user via setFormat() or similar APIs.
581void MessageFormat::setCustomArgStartFormat(int32_t argStart,
582 Format* formatter,
583 UErrorCode& status) {
584 setArgStartFormat(argStart, formatter, status);
585 if (customFormatArgStarts == NULL) {
586 customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
587 NULL, &status);
588 }
589 uhash_iputi(customFormatArgStarts, argStart, 1, &status);
590}
591
592Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
593 if (cachedFormatters == NULL) {
594 return NULL;
595 }
596 void* ptr = uhash_iget(cachedFormatters, argumentNumber);
597 if (ptr != NULL && dynamic_cast<DummyFormat*>((Format*)ptr) == NULL) {
598 return (Format*) ptr;
599 } else {
600 // Not cached, or a DummyFormat representing setFormat(NULL).
601 return NULL;
b75a7d8f 602 }
b75a7d8f 603}
729e4ab9 604
b75a7d8f
A
605// -------------------------------------
606// Adopts the new formats array and updates the array count.
607// This MessageFormat instance owns the new formats.
b75a7d8f
A
608void
609MessageFormat::adoptFormats(Format** newFormats,
610 int32_t count) {
611 if (newFormats == NULL || count < 0) {
612 return;
613 }
4388f060
A
614 // Throw away any cached formatters.
615 if (cachedFormatters != NULL) {
616 uhash_removeAll(cachedFormatters);
617 }
618 if (customFormatArgStarts != NULL) {
619 uhash_removeAll(customFormatArgStarts);
620 }
729e4ab9 621
4388f060
A
622 int32_t formatNumber = 0;
623 UErrorCode status = U_ZERO_ERROR;
624 for (int32_t partIndex = 0;
625 formatNumber < count && U_SUCCESS(status) &&
626 (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
627 setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
628 ++formatNumber;
629 }
630 // Delete those that didn't get used (if any).
631 for (; formatNumber < count; ++formatNumber) {
632 delete newFormats[formatNumber];
b75a7d8f
A
633 }
634
729e4ab9 635}
b75a7d8f
A
636
637// -------------------------------------
638// Sets the new formats array and updates the array count.
639// This MessageFormat instance maks a copy of the new formats.
729e4ab9 640
b75a7d8f
A
641void
642MessageFormat::setFormats(const Format** newFormats,
643 int32_t count) {
644 if (newFormats == NULL || count < 0) {
645 return;
646 }
4388f060
A
647 // Throw away any cached formatters.
648 if (cachedFormatters != NULL) {
649 uhash_removeAll(cachedFormatters);
650 }
651 if (customFormatArgStarts != NULL) {
652 uhash_removeAll(customFormatArgStarts);
b75a7d8f
A
653 }
654
4388f060
A
655 UErrorCode status = U_ZERO_ERROR;
656 int32_t formatNumber = 0;
657 for (int32_t partIndex = 0;
658 formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
659 Format* newFormat = NULL;
660 if (newFormats[formatNumber] != NULL) {
661 newFormat = newFormats[formatNumber]->clone();
662 if (newFormat == NULL) {
663 status = U_MEMORY_ALLOCATION_ERROR;
664 }
665 }
666 setCustomArgStartFormat(partIndex, newFormat, status);
667 ++formatNumber;
668 }
669 if (U_FAILURE(status)) {
670 resetPattern();
671 }
729e4ab9
A
672}
673
b75a7d8f 674// -------------------------------------
46f4442e
A
675// Adopt a single format by format number.
676// Do nothing if the format number is not less than the array count.
729e4ab9 677
b75a7d8f
A
678void
679MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
4388f060
A
680 LocalPointer<Format> p(newFormat);
681 if (n >= 0) {
682 int32_t formatNumber = 0;
683 for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
684 if (n == formatNumber) {
685 UErrorCode status = U_ZERO_ERROR;
686 setCustomArgStartFormat(partIndex, p.orphan(), status);
687 return;
688 }
689 ++formatNumber;
690 }
b75a7d8f
A
691 }
692}
693
46f4442e
A
694// -------------------------------------
695// Adopt a single format by format name.
696// Do nothing if there is no match of formatName.
697void
729e4ab9 698MessageFormat::adoptFormat(const UnicodeString& formatName,
46f4442e
A
699 Format* formatToAdopt,
700 UErrorCode& status) {
4388f060
A
701 LocalPointer<Format> p(formatToAdopt);
702 if (U_FAILURE(status)) {
703 return;
704 }
705 int32_t argNumber = MessagePattern::validateArgumentName(formatName);
706 if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
707 status = U_ILLEGAL_ARGUMENT_ERROR;
46f4442e
A
708 return;
709 }
4388f060
A
710 for (int32_t partIndex = 0;
711 (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
712 ) {
713 if (argNameMatches(partIndex + 1, formatName, argNumber)) {
714 Format* f;
715 if (p.isValid()) {
716 f = p.orphan();
717 } else if (formatToAdopt == NULL) {
718 f = NULL;
46f4442e 719 } else {
4388f060
A
720 f = formatToAdopt->clone();
721 if (f == NULL) {
722 status = U_MEMORY_ALLOCATION_ERROR;
723 return;
724 }
46f4442e 725 }
4388f060 726 setCustomArgStartFormat(partIndex, f, status);
46f4442e
A
727 }
728 }
729}
730
b75a7d8f
A
731// -------------------------------------
732// Set a single format.
46f4442e 733// Do nothing if the variable is not less than the array count.
b75a7d8f
A
734void
735MessageFormat::setFormat(int32_t n, const Format& newFormat) {
4388f060
A
736
737 if (n >= 0) {
738 int32_t formatNumber = 0;
739 for (int32_t partIndex = 0;
740 (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
741 if (n == formatNumber) {
742 Format* new_format = newFormat.clone();
743 if (new_format) {
744 UErrorCode status = U_ZERO_ERROR;
745 setCustomArgStartFormat(partIndex, new_format, status);
746 }
747 return;
748 }
749 ++formatNumber;
b75a7d8f
A
750 }
751 }
752}
46f4442e
A
753
754// -------------------------------------
755// Get a single format by format name.
756// Do nothing if the variable is not less than the array count.
757Format *
758MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
4388f060 759 if (U_FAILURE(status) || cachedFormatters == NULL) return NULL;
46f4442e 760
4388f060
A
761 int32_t argNumber = MessagePattern::validateArgumentName(formatName);
762 if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
763 status = U_ILLEGAL_ARGUMENT_ERROR;
764 return NULL;
46f4442e 765 }
4388f060
A
766 for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
767 if (argNameMatches(partIndex + 1, formatName, argNumber)) {
768 return getCachedFormatter(partIndex);
46f4442e
A
769 }
770 }
771 return NULL;
772}
773
774// -------------------------------------
775// Set a single format by format name
776// Do nothing if the variable is not less than the array count.
777void
778MessageFormat::setFormat(const UnicodeString& formatName,
779 const Format& newFormat,
780 UErrorCode& status) {
4388f060
A
781 if (U_FAILURE(status)) return;
782
783 int32_t argNumber = MessagePattern::validateArgumentName(formatName);
784 if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
785 status = U_ILLEGAL_ARGUMENT_ERROR;
46f4442e
A
786 return;
787 }
4388f060
A
788 for (int32_t partIndex = 0;
789 (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
790 ) {
791 if (argNameMatches(partIndex + 1, formatName, argNumber)) {
b331163b
A
792 Format* new_format = newFormat.clone();
793 if (new_format == NULL) {
794 status = U_MEMORY_ALLOCATION_ERROR;
795 return;
46f4442e 796 }
b331163b 797 setCustomArgStartFormat(partIndex, new_format, status);
46f4442e
A
798 }
799 }
800}
801
b75a7d8f
A
802// -------------------------------------
803// Gets the format array.
b75a7d8f
A
804const Format**
805MessageFormat::getFormats(int32_t& cnt) const
806{
807 // This old API returns an array (which we hold) of Format*
808 // pointers. The array is valid up to the next call to any
809 // method on this object. We construct and resize an array
810 // on demand that contains aliases to the subformats[i].format
811 // pointers.
4388f060 812 MessageFormat* t = const_cast<MessageFormat*> (this);
b75a7d8f
A
813 cnt = 0;
814 if (formatAliases == NULL) {
4388f060 815 t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount;
b75a7d8f
A
816 Format** a = (Format**)
817 uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
818 if (a == NULL) {
4388f060 819 t->formatAliasesCapacity = 0;
b75a7d8f
A
820 return NULL;
821 }
729e4ab9 822 t->formatAliases = a;
4388f060 823 } else if (argTypeCount > formatAliasesCapacity) {
b75a7d8f 824 Format** a = (Format**)
4388f060 825 uprv_realloc(formatAliases, sizeof(Format*) * argTypeCount);
b75a7d8f 826 if (a == NULL) {
4388f060 827 t->formatAliasesCapacity = 0;
b75a7d8f
A
828 return NULL;
829 }
830 t->formatAliases = a;
4388f060 831 t->formatAliasesCapacity = argTypeCount;
b75a7d8f 832 }
4388f060
A
833
834 for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
835 t->formatAliases[cnt++] = getCachedFormatter(partIndex);
b75a7d8f 836 }
4388f060 837
b75a7d8f
A
838 return (const Format**)formatAliases;
839}
729e4ab9 840
46f4442e 841
4388f060
A
842UnicodeString MessageFormat::getArgName(int32_t partIndex) {
843 const MessagePattern::Part& part = msgPattern.getPart(partIndex);
57a6839d 844 return msgPattern.getSubstring(part);
4388f060
A
845}
846
46f4442e
A
847StringEnumeration*
848MessageFormat::getFormatNames(UErrorCode& status) {
849 if (U_FAILURE(status)) return NULL;
729e4ab9 850
46f4442e
A
851 UVector *fFormatNames = new UVector(status);
852 if (U_FAILURE(status)) {
853 status = U_MEMORY_ALLOCATION_ERROR;
854 return NULL;
855 }
4388f060
A
856 fFormatNames->setDeleter(uprv_deleteUObject);
857
858 for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
51004dcb 859 fFormatNames->addElement(new UnicodeString(getArgName(partIndex + 1)), status);
46f4442e
A
860 }
861
862 StringEnumeration* nameEnumerator = new FormatNameEnumeration(fFormatNames, status);
863 return nameEnumerator;
864}
865
b75a7d8f
A
866// -------------------------------------
867// Formats the source Formattable array and copy into the result buffer.
868// Ignore the FieldPosition result for error checking.
729e4ab9 869
b75a7d8f
A
870UnicodeString&
871MessageFormat::format(const Formattable* source,
729e4ab9
A
872 int32_t cnt,
873 UnicodeString& appendTo,
874 FieldPosition& ignore,
b75a7d8f
A
875 UErrorCode& success) const
876{
4388f060 877 return format(source, NULL, cnt, appendTo, &ignore, success);
b75a7d8f 878}
729e4ab9 879
b75a7d8f
A
880// -------------------------------------
881// Internally creates a MessageFormat instance based on the
729e4ab9 882// pattern and formats the arguments Formattable array and
b75a7d8f 883// copy into the appendTo buffer.
729e4ab9 884
b75a7d8f
A
885UnicodeString&
886MessageFormat::format( const UnicodeString& pattern,
887 const Formattable* arguments,
888 int32_t cnt,
729e4ab9 889 UnicodeString& appendTo,
b75a7d8f
A
890 UErrorCode& success)
891{
892 MessageFormat temp(pattern, success);
4388f060 893 return temp.format(arguments, NULL, cnt, appendTo, NULL, success);
b75a7d8f 894}
729e4ab9 895
b75a7d8f 896// -------------------------------------
729e4ab9 897// Formats the source Formattable object and copy into the
b75a7d8f
A
898// appendTo buffer. The Formattable object must be an array
899// of Formattable instances, returns error otherwise.
729e4ab9 900
b75a7d8f 901UnicodeString&
729e4ab9
A
902MessageFormat::format(const Formattable& source,
903 UnicodeString& appendTo,
904 FieldPosition& ignore,
b75a7d8f
A
905 UErrorCode& success) const
906{
729e4ab9 907 if (U_FAILURE(success))
b75a7d8f
A
908 return appendTo;
909 if (source.getType() != Formattable::kArray) {
910 success = U_ILLEGAL_ARGUMENT_ERROR;
911 return appendTo;
912 }
4388f060 913 int32_t cnt;
b75a7d8f 914 const Formattable* tmpPtr = source.getArray(cnt);
4388f060 915 return format(tmpPtr, NULL, cnt, appendTo, &ignore, success);
b75a7d8f 916}
46f4442e 917
46f4442e
A
918UnicodeString&
919MessageFormat::format(const UnicodeString* argumentNames,
920 const Formattable* arguments,
921 int32_t count,
922 UnicodeString& appendTo,
923 UErrorCode& success) const {
4388f060 924 return format(arguments, argumentNames, count, appendTo, NULL, success);
46f4442e
A
925}
926
4388f060
A
927// Does linear search to find the match for an ArgName.
928const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
929 const UnicodeString *argumentNames,
930 int32_t cnt, UnicodeString& name) const {
931 for (int32_t i = 0; i < cnt; ++i) {
932 if (0 == argumentNames[i].compare(name)) {
933 return arguments + i;
934 }
935 }
936 return NULL;
46f4442e
A
937}
938
b75a7d8f
A
939
940UnicodeString&
46f4442e
A
941MessageFormat::format(const Formattable* arguments,
942 const UnicodeString *argumentNames,
729e4ab9
A
943 int32_t cnt,
944 UnicodeString& appendTo,
4388f060
A
945 FieldPosition* pos,
946 UErrorCode& status) const {
947 if (U_FAILURE(status)) {
b75a7d8f
A
948 return appendTo;
949 }
729e4ab9 950
4388f060
A
951 UnicodeStringAppendable usapp(appendTo);
952 AppendableWrapper app(usapp);
57a6839d 953 format(0, NULL, arguments, argumentNames, cnt, app, pos, status);
4388f060
A
954 return appendTo;
955}
956
57a6839d
A
957namespace {
958
959/**
960 * Mutable input/output values for the PluralSelectorProvider.
961 * Separate so that it is possible to make MessageFormat Freezable.
962 */
963class PluralSelectorContext {
964public:
965 PluralSelectorContext(int32_t start, const UnicodeString &name,
966 const Formattable &num, double off, UErrorCode &errorCode)
967 : startIndex(start), argName(name), offset(off),
968 numberArgIndex(-1), formatter(NULL), forReplaceNumber(FALSE) {
969 // number needs to be set even when select() is not called.
970 // Keep it as a Number/Formattable:
971 // For format() methods, and to preserve information (e.g., BigDecimal).
972 if(off == 0) {
973 number = num;
974 } else {
975 number = num.getDouble(errorCode) - off;
976 }
977 }
978
979 // Input values for plural selection with decimals.
980 int32_t startIndex;
981 const UnicodeString &argName;
982 /** argument number - plural offset */
983 Formattable number;
984 double offset;
985 // Output values for plural selection with decimals.
986 /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */
987 int32_t numberArgIndex;
988 const Format *formatter;
989 /** formatted argument number - plural offset */
990 UnicodeString numberString;
991 /** TRUE if number-offset was formatted with the stock number formatter */
992 UBool forReplaceNumber;
993};
994
995} // namespace
996
4388f060
A
997// if argumentNames is NULL, this means arguments is a numeric array.
998// arguments can not be NULL.
57a6839d
A
999// We use const void *plNumber rather than const PluralSelectorContext *pluralNumber
1000// so that we need not declare the PluralSelectorContext in the public header file.
1001void MessageFormat::format(int32_t msgStart, const void *plNumber,
4388f060
A
1002 const Formattable* arguments,
1003 const UnicodeString *argumentNames,
1004 int32_t cnt,
1005 AppendableWrapper& appendTo,
1006 FieldPosition* ignore,
1007 UErrorCode& success) const {
1008 if (U_FAILURE(success)) {
1009 return;
46f4442e 1010 }
729e4ab9 1011
4388f060
A
1012 const UnicodeString& msgString = msgPattern.getPatternString();
1013 int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1014 for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
1015 const MessagePattern::Part* part = &msgPattern.getPart(i);
1016 const UMessagePatternPartType type = part->getType();
1017 int32_t index = part->getIndex();
1018 appendTo.append(msgString, prevIndex, index - prevIndex);
1019 if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1020 return;
46f4442e 1021 }
4388f060
A
1022 prevIndex = part->getLimit();
1023 if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
57a6839d
A
1024 const PluralSelectorContext &pluralNumber =
1025 *static_cast<const PluralSelectorContext *>(plNumber);
1026 if(pluralNumber.forReplaceNumber) {
1027 // number-offset was already formatted.
1028 appendTo.formatAndAppend(pluralNumber.formatter,
1029 pluralNumber.number, pluralNumber.numberString, success);
1030 } else {
1031 const NumberFormat* nf = getDefaultNumberFormat(success);
1032 appendTo.formatAndAppend(nf, pluralNumber.number, success);
1033 }
4388f060
A
1034 continue;
1035 }
1036 if (type != UMSGPAT_PART_TYPE_ARG_START) {
1037 continue;
1038 }
1039 int32_t argLimit = msgPattern.getLimitPartIndex(i);
1040 UMessagePatternArgType argType = part->getArgType();
1041 part = &msgPattern.getPart(++i);
1042 const Formattable* arg;
57a6839d
A
1043 UBool noArg = FALSE;
1044 UnicodeString argName = msgPattern.getSubstring(*part);
4388f060
A
1045 if (argumentNames == NULL) {
1046 int32_t argNumber = part->getValue(); // ARG_NUMBER
1047 if (0 <= argNumber && argNumber < cnt) {
1048 arg = arguments + argNumber;
1049 } else {
1050 arg = NULL;
57a6839d 1051 noArg = TRUE;
46f4442e 1052 }
4388f060 1053 } else {
57a6839d 1054 arg = getArgFromListByName(arguments, argumentNames, cnt, argName);
4388f060 1055 if (arg == NULL) {
57a6839d 1056 noArg = TRUE;
46f4442e 1057 }
b75a7d8f 1058 }
4388f060
A
1059 ++i;
1060 int32_t prevDestLength = appendTo.length();
1061 const Format* formatter = NULL;
57a6839d
A
1062 if (noArg) {
1063 appendTo.append(
1064 UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE));
4388f060
A
1065 } else if (arg == NULL) {
1066 appendTo.append(NULL_STRING, 4);
57a6839d
A
1067 } else if(plNumber!=NULL &&
1068 static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) {
1069 const PluralSelectorContext &pluralNumber =
1070 *static_cast<const PluralSelectorContext *>(plNumber);
1071 if(pluralNumber.offset == 0) {
1072 // The number was already formatted with this formatter.
1073 appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number,
1074 pluralNumber.numberString, success);
1075 } else {
1076 // Do not use the formatted (number-offset) string for a named argument
1077 // that formats the number without subtracting the offset.
1078 appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
1079 }
4388f060
A
1080 } else if ((formatter = getCachedFormatter(i -2))) {
1081 // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
1082 if (dynamic_cast<const ChoiceFormat*>(formatter) ||
1083 dynamic_cast<const PluralFormat*>(formatter) ||
1084 dynamic_cast<const SelectFormat*>(formatter)) {
1085 // We only handle nested formats here if they were provided via
1086 // setFormat() or its siblings. Otherwise they are not cached and instead
1087 // handled below according to argType.
1088 UnicodeString subMsgString;
1089 formatter->format(*arg, subMsgString, success);
1090 if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
1091 (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
1092 ) {
1093 MessageFormat subMsgFormat(subMsgString, fLocale, success);
57a6839d 1094 subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, ignore, success);
4388f060
A
1095 } else {
1096 appendTo.append(subMsgString);
b75a7d8f 1097 }
4388f060
A
1098 } else {
1099 appendTo.formatAndAppend(formatter, *arg, success);
b75a7d8f 1100 }
4388f060
A
1101 } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) {
1102 // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1103 // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1104 // for the hash table containind DummyFormat.
1105 if (arg->isNumeric()) {
1106 const NumberFormat* nf = getDefaultNumberFormat(success);
1107 appendTo.formatAndAppend(nf, *arg, success);
1108 } else if (arg->getType() == Formattable::kDate) {
1109 const DateFormat* df = getDefaultDateFormat(success);
1110 appendTo.formatAndAppend(df, *arg, success);
1111 } else {
1112 appendTo.append(arg->getString(success));
1113 }
1114 } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
1115 if (!arg->isNumeric()) {
1116 success = U_ILLEGAL_ARGUMENT_ERROR;
1117 return;
b75a7d8f 1118 }
4388f060
A
1119 // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1120 // because only this one converts non-double numeric types to double.
1121 const double number = arg->getDouble(success);
1122 int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
57a6839d 1123 formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
4388f060 1124 cnt, appendTo, success);
51004dcb 1125 } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
4388f060
A
1126 if (!arg->isNumeric()) {
1127 success = U_ILLEGAL_ARGUMENT_ERROR;
1128 return;
1129 }
57a6839d 1130 const PluralSelectorProvider &selector =
51004dcb 1131 argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider;
4388f060
A
1132 // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1133 // because only this one converts non-double numeric types to double.
4388f060 1134 double offset = msgPattern.getPluralOffset(i);
57a6839d
A
1135 PluralSelectorContext context(i, argName, *arg, offset, success);
1136 int32_t subMsgStart = PluralFormat::findSubMessage(
1137 msgPattern, i, selector, &context, arg->getDouble(success), success);
1138 formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames,
4388f060
A
1139 cnt, appendTo, success);
1140 } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
1141 int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
57a6839d 1142 formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
4388f060
A
1143 cnt, appendTo, success);
1144 } else {
1145 // This should never happen.
1146 success = U_INTERNAL_PROGRAM_ERROR;
1147 return;
b75a7d8f 1148 }
4388f060
A
1149 ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
1150 prevIndex = msgPattern.getPart(argLimit).getLimit();
1151 i = argLimit;
1152 }
1153}
374ca955 1154
4388f060
A
1155
1156void MessageFormat::formatComplexSubMessage(int32_t msgStart,
57a6839d 1157 const void *plNumber,
4388f060
A
1158 const Formattable* arguments,
1159 const UnicodeString *argumentNames,
1160 int32_t cnt,
1161 AppendableWrapper& appendTo,
1162 UErrorCode& success) const {
1163 if (U_FAILURE(success)) {
1164 return;
1165 }
1166
1167 if (!MessageImpl::jdkAposMode(msgPattern)) {
57a6839d 1168 format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, NULL, success);
4388f060
A
1169 return;
1170 }
1171
1172 // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
1173 // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
1174 // - if the result string contains an open curly brace '{' then
1175 // instantiate a temporary MessageFormat object and format again;
1176 // otherwise just append the result string
1177 const UnicodeString& msgString = msgPattern.getPatternString();
1178 UnicodeString sb;
1179 int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1180 for (int32_t i = msgStart;;) {
1181 const MessagePattern::Part& part = msgPattern.getPart(++i);
1182 const UMessagePatternPartType type = part.getType();
1183 int32_t index = part.getIndex();
1184 if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1185 sb.append(msgString, prevIndex, index - prevIndex);
1186 break;
1187 } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1188 sb.append(msgString, prevIndex, index - prevIndex);
1189 if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
57a6839d
A
1190 const PluralSelectorContext &pluralNumber =
1191 *static_cast<const PluralSelectorContext *>(plNumber);
1192 if(pluralNumber.forReplaceNumber) {
1193 // number-offset was already formatted.
1194 sb.append(pluralNumber.numberString);
1195 } else {
1196 const NumberFormat* nf = getDefaultNumberFormat(success);
1197 sb.append(nf->format(pluralNumber.number, sb, success));
1198 }
b75a7d8f 1199 }
4388f060
A
1200 prevIndex = part.getLimit();
1201 } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
1202 sb.append(msgString, prevIndex, index - prevIndex);
1203 prevIndex = index;
1204 i = msgPattern.getLimitPartIndex(i);
1205 index = msgPattern.getPart(i).getLimit();
1206 MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
1207 prevIndex = index;
1208 }
1209 }
1210 if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
1211 UnicodeString emptyPattern; // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
1212 MessageFormat subMsgFormat(emptyPattern, fLocale, success);
1213 subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, success);
57a6839d 1214 subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, NULL, success);
4388f060
A
1215 } else {
1216 appendTo.append(sb);
1217 }
1218}
1219
1220
1221UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
1222 const UnicodeString& msgString=msgPattern.getPatternString();
1223 int32_t prevIndex=msgPattern.getPart(from).getLimit();
1224 UnicodeString b;
1225 for (int32_t i = from + 1; ; ++i) {
1226 const MessagePattern::Part& part = msgPattern.getPart(i);
1227 const UMessagePatternPartType type=part.getType();
1228 int32_t index=part.getIndex();
1229 b.append(msgString, prevIndex, index - prevIndex);
1230 if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1231 return b;
1232 }
1233 // Unexpected Part "part" in parsed message.
1234 U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
1235 prevIndex=part.getLimit();
1236 }
1237}
1238
1239
1240FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
1241 FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
1242 // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
1243 return NULL;
1244 /*
1245 if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
1246 fp->setBeginIndex(prevLength);
1247 fp->setEndIndex(dest.get_length());
1248 return NULL;
1249 }
1250 return fp;
1251 */
1252}
1253
57a6839d
A
1254int32_t
1255MessageFormat::findOtherSubMessage(int32_t partIndex) const {
1256 int32_t count=msgPattern.countParts();
1257 const MessagePattern::Part *part = &msgPattern.getPart(partIndex);
1258 if(MessagePattern::Part::hasNumericValue(part->getType())) {
1259 ++partIndex;
1260 }
1261 // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
1262 // until ARG_LIMIT or end of plural-only pattern.
1263 UnicodeString other(FALSE, OTHER_STRING, 5);
1264 do {
1265 part=&msgPattern.getPart(partIndex++);
1266 UMessagePatternPartType type=part->getType();
1267 if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
1268 break;
1269 }
1270 U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR);
1271 // part is an ARG_SELECTOR followed by an optional explicit value, and then a message
1272 if(msgPattern.partSubstringMatches(*part, other)) {
1273 return partIndex;
1274 }
1275 if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) {
1276 ++partIndex; // skip the numeric-value part of "=1" etc.
1277 }
1278 partIndex=msgPattern.getLimitPartIndex(partIndex);
1279 } while(++partIndex<count);
1280 return 0;
1281}
1282
1283int32_t
1284MessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const {
1285 for(int32_t i=msgStart+1;; ++i) {
1286 const MessagePattern::Part &part=msgPattern.getPart(i);
1287 UMessagePatternPartType type=part.getType();
1288 if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1289 return 0;
1290 }
1291 if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1292 return -1;
1293 }
1294 if(type==UMSGPAT_PART_TYPE_ARG_START) {
1295 UMessagePatternArgType argType=part.getArgType();
1296 if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) {
1297 // ARG_NUMBER or ARG_NAME
1298 if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) {
1299 return i;
1300 }
1301 }
1302 i=msgPattern.getLimitPartIndex(i);
1303 }
1304 }
1305}
1306
4388f060
A
1307void MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) {
1308 // Deep copy pointer fields.
1309 // We need not copy the formatAliases because they are re-filled
1310 // in each getFormats() call.
1311 // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
1312 // also get created on demand.
1313 argTypeCount = that.argTypeCount;
1314 if (argTypeCount > 0) {
1315 if (!allocateArgTypes(argTypeCount, ec)) {
1316 return;
1317 }
1318 uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
1319 }
1320 if (cachedFormatters != NULL) {
1321 uhash_removeAll(cachedFormatters);
1322 }
1323 if (customFormatArgStarts != NULL) {
1324 uhash_removeAll(customFormatArgStarts);
1325 }
1326 if (that.cachedFormatters) {
1327 if (cachedFormatters == NULL) {
1328 cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
1329 equalFormatsForHash, &ec);
1330 if (U_FAILURE(ec)) {
1331 return;
b75a7d8f 1332 }
4388f060 1333 uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
b75a7d8f 1334 }
4388f060
A
1335
1336 const int32_t count = uhash_count(that.cachedFormatters);
1337 int32_t pos, idx;
b331163b 1338 for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
4388f060
A
1339 const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
1340 Format* newFormat = ((Format*)(cur->value.pointer))->clone();
1341 if (newFormat) {
1342 uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
1343 } else {
1344 ec = U_MEMORY_ALLOCATION_ERROR;
1345 return;
b75a7d8f 1346 }
b75a7d8f 1347 }
4388f060
A
1348 }
1349 if (that.customFormatArgStarts) {
1350 if (customFormatArgStarts == NULL) {
1351 customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
1352 NULL, &ec);
b75a7d8f 1353 }
4388f060
A
1354 const int32_t count = uhash_count(that.customFormatArgStarts);
1355 int32_t pos, idx;
b331163b 1356 for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
4388f060
A
1357 const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
1358 uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
b75a7d8f
A
1359 }
1360 }
b75a7d8f
A
1361}
1362
1363
b75a7d8f 1364Formattable*
4388f060
A
1365MessageFormat::parse(int32_t msgStart,
1366 const UnicodeString& source,
b75a7d8f 1367 ParsePosition& pos,
4388f060
A
1368 int32_t& count,
1369 UErrorCode& ec) const {
1370 count = 0;
1371 if (U_FAILURE(ec)) {
1372 pos.setErrorIndex(pos.getIndex());
1373 return NULL;
1374 }
1375 // parse() does not work with named arguments.
1376 if (msgPattern.hasNamedArguments()) {
1377 ec = U_ARGUMENT_TYPE_MISMATCH;
1378 pos.setErrorIndex(pos.getIndex());
1379 return NULL;
1380 }
1381 LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
1382 const UnicodeString& msgString=msgPattern.getPatternString();
1383 int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
b75a7d8f 1384 int32_t sourceOffset = pos.getIndex();
4388f060
A
1385 ParsePosition tempStatus(0);
1386
1387 for(int32_t i=msgStart+1; ; ++i) {
1388 UBool haveArgResult = FALSE;
1389 const MessagePattern::Part* part=&msgPattern.getPart(i);
1390 const UMessagePatternPartType type=part->getType();
1391 int32_t index=part->getIndex();
1392 // Make sure the literal string matches.
1393 int32_t len = index - prevIndex;
1394 if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
b75a7d8f 1395 sourceOffset += len;
4388f060
A
1396 prevIndex += len;
1397 } else {
1398 pos.setErrorIndex(sourceOffset);
1399 return NULL; // leave index as is to signal error
729e4ab9 1400 }
4388f060
A
1401 if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1402 // Things went well! Done.
1403 pos.setIndex(sourceOffset);
1404 return resultArray.orphan();
b75a7d8f 1405 }
4388f060
A
1406 if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
1407 prevIndex=part->getLimit();
1408 continue;
1409 }
1410 // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
1411 // Unexpected Part "part" in parsed message.
1412 U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
1413 int32_t argLimit=msgPattern.getLimitPartIndex(i);
1414
1415 UMessagePatternArgType argType=part->getArgType();
1416 part=&msgPattern.getPart(++i);
1417 int32_t argNumber = part->getValue(); // ARG_NUMBER
1418 UnicodeString key;
1419 ++i;
1420 const Format* formatter = NULL;
1421 Formattable& argResult = resultArray[argNumber];
1422
1423 if(cachedFormatters!=NULL && (formatter = getCachedFormatter(i - 2))!=NULL) {
1424 // Just parse using the formatter.
1425 tempStatus.setIndex(sourceOffset);
1426 formatter->parseObject(source, argResult, tempStatus);
1427 if (tempStatus.getIndex() == sourceOffset) {
1428 pos.setErrorIndex(sourceOffset);
1429 return NULL; // leave index as is to signal error
1430 }
1431 sourceOffset = tempStatus.getIndex();
1432 haveArgResult = TRUE;
1433 } else if(
1434 argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) {
1435 // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1436 // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1437 // for the hash table containind DummyFormat.
1438
1439 // Match as a string.
b75a7d8f
A
1440 // if at end, use longest possible match
1441 // otherwise uses first match to intervening string
1442 // does NOT recursively try all possibilities
4388f060 1443 UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
b75a7d8f 1444 int32_t next;
4388f060
A
1445 if (!stringAfterArgument.isEmpty()) {
1446 next = source.indexOf(stringAfterArgument, sourceOffset);
1447 } else {
b75a7d8f
A
1448 next = source.length();
1449 }
b75a7d8f 1450 if (next < 0) {
4388f060
A
1451 pos.setErrorIndex(sourceOffset);
1452 return NULL; // leave index as is to signal error
1453 } else {
1454 UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
1455 UnicodeString compValue;
1456 compValue.append(LEFT_CURLY_BRACE);
1457 itos(argNumber, compValue);
1458 compValue.append(RIGHT_CURLY_BRACE);
1459 if (0 != strValue.compare(compValue)) {
1460 argResult.setString(strValue);
1461 haveArgResult = TRUE;
b75a7d8f
A
1462 }
1463 sourceOffset = next;
1464 }
4388f060
A
1465 } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
1466 tempStatus.setIndex(sourceOffset);
1467 double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
1468 if (tempStatus.getIndex() == sourceOffset) {
1469 pos.setErrorIndex(sourceOffset);
1470 return NULL; // leave index as is to signal error
b75a7d8f 1471 }
4388f060
A
1472 argResult.setDouble(choiceResult);
1473 haveArgResult = TRUE;
1474 sourceOffset = tempStatus.getIndex();
51004dcb 1475 } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
4388f060
A
1476 // Parsing not supported.
1477 ec = U_UNSUPPORTED_ERROR;
1478 return NULL;
1479 } else {
1480 // This should never happen.
1481 ec = U_INTERNAL_PROGRAM_ERROR;
1482 return NULL;
b75a7d8f 1483 }
4388f060
A
1484 if (haveArgResult && count <= argNumber) {
1485 count = argNumber + 1;
1486 }
1487 prevIndex=msgPattern.getPart(argLimit).getLimit();
1488 i=argLimit;
b75a7d8f 1489 }
4388f060
A
1490}
1491// -------------------------------------
1492// Parses the source pattern and returns the Formattable objects array,
1493// the array count and the ending parse position. The caller of this method
1494// owns the array.
b75a7d8f 1495
4388f060
A
1496Formattable*
1497MessageFormat::parse(const UnicodeString& source,
1498 ParsePosition& pos,
1499 int32_t& count) const {
1500 UErrorCode ec = U_ZERO_ERROR;
1501 return parse(0, source, pos, count, ec);
b75a7d8f 1502}
729e4ab9 1503
b75a7d8f 1504// -------------------------------------
729e4ab9
A
1505// Parses the source string and returns the array of
1506// Formattable objects and the array count. The caller
b75a7d8f 1507// owns the returned array.
729e4ab9 1508
b75a7d8f 1509Formattable*
729e4ab9 1510MessageFormat::parse(const UnicodeString& source,
b75a7d8f
A
1511 int32_t& cnt,
1512 UErrorCode& success) const
1513{
4388f060 1514 if (msgPattern.hasNamedArguments()) {
46f4442e 1515 success = U_ARGUMENT_TYPE_MISMATCH;
729e4ab9 1516 return NULL;
46f4442e 1517 }
b75a7d8f
A
1518 ParsePosition status(0);
1519 // Calls the actual implementation method and starts
1520 // from zero offset of the source text.
1521 Formattable* result = parse(source, status, cnt);
1522 if (status.getIndex() == 0) {
1523 success = U_MESSAGE_PARSE_ERROR;
1524 delete[] result;
1525 return NULL;
1526 }
1527 return result;
1528}
729e4ab9 1529
b75a7d8f
A
1530// -------------------------------------
1531// Parses the source text and copy into the result buffer.
729e4ab9 1532
b75a7d8f
A
1533void
1534MessageFormat::parseObject( const UnicodeString& source,
1535 Formattable& result,
1536 ParsePosition& status) const
1537{
1538 int32_t cnt = 0;
1539 Formattable* tmpResult = parse(source, status, cnt);
729e4ab9 1540 if (tmpResult != NULL)
b75a7d8f
A
1541 result.adoptArray(tmpResult, cnt);
1542}
729e4ab9
A
1543
1544UnicodeString
73c04bcf 1545MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
4388f060
A
1546 UnicodeString result;
1547 if (U_SUCCESS(status)) {
1548 int32_t plen = pattern.length();
1549 const UChar* pat = pattern.getBuffer();
1550 int32_t blen = plen * 2 + 1; // space for null termination, convenience
1551 UChar* buf = result.getBuffer(blen);
1552 if (buf == NULL) {
1553 status = U_MEMORY_ALLOCATION_ERROR;
1554 } else {
1555 int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
1556 result.releaseBuffer(U_SUCCESS(status) ? len : 0);
1557 }
1558 }
1559 if (U_FAILURE(status)) {
1560 result.setToBogus();
73c04bcf 1561 }
4388f060 1562 return result;
73c04bcf
A
1563}
1564
b75a7d8f 1565// -------------------------------------
374ca955
A
1566
1567static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
1568 RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
46f4442e
A
1569 if (fmt == NULL) {
1570 ec = U_MEMORY_ALLOCATION_ERROR;
1571 } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
1572 UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
1573 fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
374ca955
A
1574 }
1575 return fmt;
1576}
729e4ab9 1577
4388f060
A
1578void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
1579 if (U_FAILURE(status)) {
b75a7d8f
A
1580 return;
1581 }
1582
4388f060
A
1583 if (cachedFormatters != NULL) {
1584 uhash_removeAll(cachedFormatters);
46f4442e 1585 }
4388f060
A
1586 if (customFormatArgStarts != NULL) {
1587 uhash_removeAll(customFormatArgStarts);
1588 }
1589
1590 // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
1591 // which we need not examine.
1592 int32_t limit = msgPattern.countParts() - 2;
1593 argTypeCount = 0;
1594 // We also need not look at the first two "parts"
1595 // (at most MSG_START and ARG_START) in this loop.
1596 // We determine the argTypeCount first so that we can allocateArgTypes
1597 // so that the next loop can set argTypes[argNumber].
1598 // (This is for the C API which needs the argTypes to read its va_arg list.)
1599 for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
1600 const MessagePattern::Part& part = msgPattern.getPart(i);
1601 if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1602 const int argNumber = part.getValue();
1603 if (argNumber >= argTypeCount) {
1604 argTypeCount = argNumber + 1;
1605 }
46f4442e 1606 }
b75a7d8f 1607 }
4388f060
A
1608 if (!allocateArgTypes(argTypeCount, status)) {
1609 return;
1610 }
1611 // Set all argTypes to kObject, as a "none" value, for lack of any better value.
1612 // We never use kObject for real arguments.
51004dcb 1613 // We use it as "no argument yet" for the check for hasArgTypeConflicts.
4388f060
A
1614 for (int32_t i = 0; i < argTypeCount; ++i) {
1615 argTypes[i] = Formattable::kObject;
1616 }
1617 hasArgTypeConflicts = FALSE;
b75a7d8f 1618
4388f060
A
1619 // This loop starts at part index 1 because we do need to examine
1620 // ARG_START parts. (But we can ignore the MSG_START.)
1621 for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
1622 const MessagePattern::Part* part = &msgPattern.getPart(i);
1623 if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
1624 continue;
1625 }
1626 UMessagePatternArgType argType = part->getArgType();
b75a7d8f 1627
4388f060
A
1628 int32_t argNumber = -1;
1629 part = &msgPattern.getPart(i + 1);
1630 if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1631 argNumber = part->getValue();
1632 }
1633 Formattable::Type formattableType;
b75a7d8f 1634
4388f060
A
1635 switch (argType) {
1636 case UMSGPAT_ARG_TYPE_NONE:
1637 formattableType = Formattable::kString;
1638 break;
1639 case UMSGPAT_ARG_TYPE_SIMPLE: {
1640 int32_t index = i;
1641 i += 2;
1642 UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
1643 UnicodeString style;
1644 if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
1645 style = msgPattern.getSubstring(*part);
1646 ++i;
1647 }
1648 UParseError parseError;
1649 Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
1650 setArgStartFormat(index, formatter, status);
1651 break;
1652 }
1653 case UMSGPAT_ARG_TYPE_CHOICE:
1654 case UMSGPAT_ARG_TYPE_PLURAL:
51004dcb 1655 case UMSGPAT_ARG_TYPE_SELECTORDINAL:
4388f060
A
1656 formattableType = Formattable::kDouble;
1657 break;
1658 case UMSGPAT_ARG_TYPE_SELECT:
1659 formattableType = Formattable::kString;
1660 break;
1661 default:
1662 status = U_INTERNAL_PROGRAM_ERROR; // Should be unreachable.
1663 formattableType = Formattable::kString;
1664 break;
1665 }
1666 if (argNumber != -1) {
1667 if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
1668 hasArgTypeConflicts = TRUE;
1669 }
1670 argTypes[argNumber] = formattableType;
1671 }
1672 }
1673}
b75a7d8f 1674
b75a7d8f 1675
4388f060
A
1676Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
1677 Formattable::Type& formattableType, UParseError& parseError,
1678 UErrorCode& ec) {
1679 if (U_FAILURE(ec)) {
1680 return NULL;
1681 }
1682 Format* fmt = NULL;
1683 int32_t typeID, styleID;
1684 DateFormat::EStyle date_style;
1685
1686 switch (typeID = findKeyword(type, TYPE_IDS)) {
1687 case 0: // number
1688 formattableType = Formattable::kDouble;
1689 switch (findKeyword(style, NUMBER_STYLE_IDS)) {
b75a7d8f
A
1690 case 0: // default
1691 fmt = NumberFormat::createInstance(fLocale, ec);
1692 break;
1693 case 1: // currency
1694 fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
1695 break;
1696 case 2: // percent
1697 fmt = NumberFormat::createPercentInstance(fLocale, ec);
1698 break;
1699 case 3: // integer
4388f060 1700 formattableType = Formattable::kLong;
b75a7d8f
A
1701 fmt = createIntegerFormat(fLocale, ec);
1702 break;
1703 default: // pattern
1704 fmt = NumberFormat::createInstance(fLocale, ec);
729e4ab9
A
1705 if (fmt) {
1706 DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt);
1707 if (decfmt != NULL) {
4388f060 1708 decfmt->applyPattern(style,parseError,ec);
729e4ab9 1709 }
b75a7d8f
A
1710 }
1711 break;
1712 }
1713 break;
1714
4388f060
A
1715 case 1: // date
1716 case 2: // time
1717 formattableType = Formattable::kDate;
1718 styleID = findKeyword(style, DATE_STYLE_IDS);
1719 date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
b75a7d8f 1720
4388f060
A
1721 if (typeID == 1) {
1722 fmt = DateFormat::createDateInstance(date_style, fLocale);
b75a7d8f 1723 } else {
4388f060 1724 fmt = DateFormat::createTimeInstance(date_style, fLocale);
b75a7d8f
A
1725 }
1726
729e4ab9
A
1727 if (styleID < 0 && fmt != NULL) {
1728 SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
1729 if (sdtfmt != NULL) {
4388f060 1730 sdtfmt->applyPattern(style);
729e4ab9 1731 }
b75a7d8f
A
1732 }
1733 break;
1734
4388f060
A
1735 case 3: // spellout
1736 formattableType = Formattable::kDouble;
1737 fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
374ca955 1738 break;
4388f060
A
1739 case 4: // ordinal
1740 formattableType = Formattable::kDouble;
1741 fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
374ca955 1742 break;
4388f060
A
1743 case 5: // duration
1744 formattableType = Formattable::kDouble;
1745 fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
46f4442e 1746 break;
b75a7d8f 1747 default:
4388f060 1748 formattableType = Formattable::kString;
b75a7d8f
A
1749 ec = U_ILLEGAL_ARGUMENT_ERROR;
1750 break;
1751 }
1752
4388f060 1753 return fmt;
b75a7d8f 1754}
729e4ab9 1755
4388f060
A
1756
1757//-------------------------------------
729e4ab9
A
1758// Finds the string, s, in the string array, list.
1759int32_t MessageFormat::findKeyword(const UnicodeString& s,
b75a7d8f
A
1760 const UChar * const *list)
1761{
4388f060 1762 if (s.isEmpty()) {
374ca955 1763 return 0; // default
4388f060 1764 }
b75a7d8f 1765
4388f060
A
1766 int32_t length = s.length();
1767 const UChar *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
1768 UnicodeString buffer(FALSE, ps, length);
b75a7d8f
A
1769 // Trims the space characters and turns all characters
1770 // in s to lower case.
4388f060 1771 buffer.toLower("");
374ca955
A
1772 for (int32_t i = 0; list[i]; ++i) {
1773 if (!buffer.compare(list[i], u_strlen(list[i]))) {
b75a7d8f 1774 return i;
374ca955 1775 }
b75a7d8f
A
1776 }
1777 return -1;
1778}
729e4ab9 1779
b75a7d8f
A
1780/**
1781 * Convenience method that ought to be in NumberFormat
1782 */
729e4ab9 1783NumberFormat*
b75a7d8f
A
1784MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
1785 NumberFormat *temp = NumberFormat::createInstance(locale, status);
729e4ab9
A
1786 DecimalFormat *temp2;
1787 if (temp != NULL && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != NULL) {
b75a7d8f
A
1788 temp2->setMaximumFractionDigits(0);
1789 temp2->setDecimalSeparatorAlwaysShown(FALSE);
1790 temp2->setParseIntegerOnly(TRUE);
1791 }
1792
1793 return temp;
1794}
1795
1796/**
1797 * Return the default number format. Used to format a numeric
1798 * argument when subformats[i].format is NULL. Returns NULL
1799 * on failure.
1800 *
1801 * Semantically const but may modify *this.
1802 */
1803const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
1804 if (defaultNumberFormat == NULL) {
1805 MessageFormat* t = (MessageFormat*) this;
1806 t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
729e4ab9 1807 if (U_FAILURE(ec)) {
b75a7d8f
A
1808 delete t->defaultNumberFormat;
1809 t->defaultNumberFormat = NULL;
1810 } else if (t->defaultNumberFormat == NULL) {
1811 ec = U_MEMORY_ALLOCATION_ERROR;
1812 }
1813 }
1814 return defaultNumberFormat;
1815}
1816
1817/**
1818 * Return the default date format. Used to format a date
1819 * argument when subformats[i].format is NULL. Returns NULL
1820 * on failure.
1821 *
1822 * Semantically const but may modify *this.
1823 */
1824const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
1825 if (defaultDateFormat == NULL) {
1826 MessageFormat* t = (MessageFormat*) this;
1827 t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
1828 if (t->defaultDateFormat == NULL) {
1829 ec = U_MEMORY_ALLOCATION_ERROR;
1830 }
1831 }
1832 return defaultDateFormat;
1833}
1834
46f4442e
A
1835UBool
1836MessageFormat::usesNamedArguments() const {
4388f060 1837 return msgPattern.hasNamedArguments();
46f4442e
A
1838}
1839
4388f060
A
1840int32_t
1841MessageFormat::getArgTypeCount() const {
1842 return argTypeCount;
1843}
1844
1845UBool MessageFormat::equalFormats(const void* left, const void* right) {
1846 return *(const Format*)left==*(const Format*)right;
1847}
1848
1849
1850UBool MessageFormat::DummyFormat::operator==(const Format&) const {
46f4442e
A
1851 return TRUE;
1852}
1853
4388f060
A
1854Format* MessageFormat::DummyFormat::clone() const {
1855 return new DummyFormat();
729e4ab9
A
1856}
1857
51004dcb
A
1858UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1859 UnicodeString& appendTo,
1860 UErrorCode& status) const {
1861 if (U_SUCCESS(status)) {
1862 status = U_UNSUPPORTED_ERROR;
1863 }
1864 return appendTo;
1865}
1866
4388f060
A
1867UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1868 UnicodeString& appendTo,
1869 FieldPosition&,
1870 UErrorCode& status) const {
1871 if (U_SUCCESS(status)) {
1872 status = U_UNSUPPORTED_ERROR;
1873 }
1874 return appendTo;
1875}
1876
51004dcb
A
1877UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1878 UnicodeString& appendTo,
1879 FieldPositionIterator*,
1880 UErrorCode& status) const {
1881 if (U_SUCCESS(status)) {
1882 status = U_UNSUPPORTED_ERROR;
1883 }
1884 return appendTo;
1885}
1886
4388f060
A
1887void MessageFormat::DummyFormat::parseObject(const UnicodeString&,
1888 Formattable&,
1889 ParsePosition& ) const {
1890}
1891
1892
46f4442e
A
1893FormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
1894 pos=0;
1895 fFormatNames = fNameList;
1896}
1897
1898const UnicodeString*
1899FormatNameEnumeration::snext(UErrorCode& status) {
1900 if (U_SUCCESS(status) && pos < fFormatNames->size()) {
1901 return (const UnicodeString*)fFormatNames->elementAt(pos++);
1902 }
1903 return NULL;
1904}
1905
1906void
1907FormatNameEnumeration::reset(UErrorCode& /*status*/) {
1908 pos=0;
1909}
1910
1911int32_t
1912FormatNameEnumeration::count(UErrorCode& /*status*/) const {
4388f060 1913 return (fFormatNames==NULL) ? 0 : fFormatNames->size();
46f4442e
A
1914}
1915
1916FormatNameEnumeration::~FormatNameEnumeration() {
4388f060
A
1917 delete fFormatNames;
1918}
1919
57a6839d
A
1920MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t)
1921 : msgFormat(mf), rules(NULL), type(t) {
4388f060
A
1922}
1923
1924MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
4388f060
A
1925 delete rules;
1926}
1927
57a6839d
A
1928UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number,
1929 UErrorCode& ec) const {
4388f060
A
1930 if (U_FAILURE(ec)) {
1931 return UnicodeString(FALSE, OTHER_STRING, 5);
1932 }
1933 MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
1934 if(rules == NULL) {
57a6839d 1935 t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec);
4388f060
A
1936 if (U_FAILURE(ec)) {
1937 return UnicodeString(FALSE, OTHER_STRING, 5);
46f4442e
A
1938 }
1939 }
57a6839d
A
1940 // Select a sub-message according to how the number is formatted,
1941 // which is specified in the selected sub-message.
1942 // We avoid this circle by looking at how
1943 // the number is formatted in the "other" sub-message
1944 // which must always be present and usually contains the number.
1945 // Message authors should be consistent across sub-messages.
1946 PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx);
1947 int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex);
1948 context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName);
1949 if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != NULL) {
1950 context.formatter =
1951 (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex);
1952 }
1953 if(context.formatter == NULL) {
1954 context.formatter = msgFormat.getDefaultNumberFormat(ec);
1955 context.forReplaceNumber = TRUE;
1956 }
1957 U_ASSERT(context.number.getDouble(ec) == number); // argument number minus the offset
1958 context.formatter->format(context.number, context.numberString, ec);
1959 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
1960 if(decFmt != NULL) {
2ca993e8
A
1961 VisibleDigitsWithExponent digits;
1962 decFmt->initVisibleDigitsWithExponent(context.number, digits, ec);
1963 if (U_FAILURE(ec)) {
1964 return UnicodeString(FALSE, OTHER_STRING, 5);
1965 }
1966 return rules->select(digits);
57a6839d
A
1967 } else {
1968 return rules->select(number);
1969 }
46f4442e 1970}
4388f060 1971
57a6839d 1972void MessageFormat::PluralSelectorProvider::reset() {
4388f060
A
1973 delete rules;
1974 rules = NULL;
1975}
1976
1977
b75a7d8f
A
1978U_NAMESPACE_END
1979
1980#endif /* #if !UCONFIG_NO_FORMATTING */
1981
1982//eof