• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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