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