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