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