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