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