1 /********************************************************************
3 * Copyright (c) 1997-2012, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************
9 * Modification History:
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 ********************************************************************/
22 #include "unicode/utypes.h"
24 #if !UCONFIG_NO_FORMATTING
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"
39 #include "patternprops.h"
40 #include "messageimpl.h"
41 #include "msgfmt_impl.h"
49 // *****************************************************************************
50 // class MessageFormat
51 // *****************************************************************************
53 #define SINGLE_QUOTE ((UChar)0x0027)
54 #define COMMA ((UChar)0x002C)
55 #define LEFT_CURLY_BRACE ((UChar)0x007B)
56 #define RIGHT_CURLY_BRACE ((UChar)0x007D)
58 //---------------------------------------
61 static const UChar ID_NUMBER
[] = {
62 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
64 static const UChar ID_DATE
[] = {
65 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
67 static const UChar ID_TIME
[] = {
68 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
70 static const UChar ID_SPELLOUT
[] = {
71 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
73 static const UChar ID_ORDINAL
[] = {
74 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
76 static const UChar ID_DURATION
[] = {
77 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
80 // MessageFormat Type List Number, Date, Time or Choice
81 static const UChar
* const TYPE_IDS
[] = {
91 static const UChar ID_EMPTY
[] = {
92 0 /* empty string, used for default so that null can mark end of list */
94 static const UChar ID_CURRENCY
[] = {
95 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
97 static const UChar ID_PERCENT
[] = {
98 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
100 static const UChar ID_INTEGER
[] = {
101 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
104 // NumberFormat modifier list, default, currency, percent or integer
105 static const UChar
* const NUMBER_STYLE_IDS
[] = {
113 static const UChar ID_SHORT
[] = {
114 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
116 static const UChar ID_MEDIUM
[] = {
117 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
119 static const UChar ID_LONG
[] = {
120 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
122 static const UChar ID_FULL
[] = {
123 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
126 // DateFormat modifier list, default, short, medium, long or full
127 static const UChar
* const DATE_STYLE_IDS
[] = {
136 static const icu::DateFormat::EStyle DATE_STYLES
[] = {
137 icu::DateFormat::kDefault
,
138 icu::DateFormat::kShort
,
139 icu::DateFormat::kMedium
,
140 icu::DateFormat::kLong
,
141 icu::DateFormat::kFull
,
144 static const int32_t DEFAULT_INITIAL_CAPACITY
= 10;
146 static const UChar NULL_STRING
[] = {
147 0x6E, 0x75, 0x6C, 0x6C, 0 // "null"
150 static const UChar OTHER_STRING
[] = {
151 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other"
155 static UBool U_CALLCONV
equalFormatsForHash(const UHashTok key1
,
156 const UHashTok key2
) {
157 return icu::MessageFormat::equalFormats(key1
.pointer
, key2
.pointer
);
164 // -------------------------------------
165 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat
)
166 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration
)
168 //--------------------------------------------------------------------
171 * Convert an integer value to a string and append the result to
172 * the given UnicodeString.
174 static UnicodeString
& itos(int32_t i
, UnicodeString
& appendTo
) {
176 uprv_itou(temp
,16,i
,10,0); // 10 == radix
177 appendTo
.append(temp
, -1);
182 // AppendableWrapper: encapsulates the result of formatting, keeping track
183 // of the string and its length.
184 class AppendableWrapper
: public UMemory
{
186 AppendableWrapper(Appendable
& appendable
) : app(appendable
), len(0) {
188 void append(const UnicodeString
& s
) {
189 app
.appendString(s
.getBuffer(), s
.length());
192 void append(const UChar
* s
, const int32_t sLength
) {
193 app
.appendString(s
, sLength
);
196 void append(const UnicodeString
& s
, int32_t start
, int32_t length
) {
197 append(s
.tempSubString(start
, length
));
199 void formatAndAppend(const Format
* formatter
, const Formattable
& arg
, UErrorCode
& ec
) {
201 formatter
->format(arg
, s
, ec
);
215 // -------------------------------------
216 // Creates a MessageFormat instance based on the pattern.
218 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
220 : fLocale(Locale::getDefault()), // Uses the default locale
223 formatAliasesCapacity(0),
227 hasArgTypeConflicts(FALSE
),
228 defaultNumberFormat(NULL
),
229 defaultDateFormat(NULL
),
230 cachedFormatters(NULL
),
231 customFormatArgStarts(NULL
),
232 pluralProvider(&fLocale
, UPLURAL_TYPE_CARDINAL
),
233 ordinalProvider(&fLocale
, UPLURAL_TYPE_ORDINAL
)
235 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
236 applyPattern(pattern
, success
);
239 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
240 const Locale
& newLocale
,
242 : fLocale(newLocale
),
245 formatAliasesCapacity(0),
249 hasArgTypeConflicts(FALSE
),
250 defaultNumberFormat(NULL
),
251 defaultDateFormat(NULL
),
252 cachedFormatters(NULL
),
253 customFormatArgStarts(NULL
),
254 pluralProvider(&fLocale
, UPLURAL_TYPE_CARDINAL
),
255 ordinalProvider(&fLocale
, UPLURAL_TYPE_ORDINAL
)
257 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
258 applyPattern(pattern
, success
);
261 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
262 const Locale
& newLocale
,
263 UParseError
& parseError
,
265 : fLocale(newLocale
),
268 formatAliasesCapacity(0),
272 hasArgTypeConflicts(FALSE
),
273 defaultNumberFormat(NULL
),
274 defaultDateFormat(NULL
),
275 cachedFormatters(NULL
),
276 customFormatArgStarts(NULL
),
277 pluralProvider(&fLocale
, UPLURAL_TYPE_CARDINAL
),
278 ordinalProvider(&fLocale
, UPLURAL_TYPE_ORDINAL
)
280 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
281 applyPattern(pattern
, parseError
, success
);
284 MessageFormat::MessageFormat(const MessageFormat
& that
)
287 fLocale(that
.fLocale
),
288 msgPattern(that
.msgPattern
),
290 formatAliasesCapacity(0),
294 hasArgTypeConflicts(that
.hasArgTypeConflicts
),
295 defaultNumberFormat(NULL
),
296 defaultDateFormat(NULL
),
297 cachedFormatters(NULL
),
298 customFormatArgStarts(NULL
),
299 pluralProvider(&fLocale
, UPLURAL_TYPE_CARDINAL
),
300 ordinalProvider(&fLocale
, UPLURAL_TYPE_ORDINAL
)
302 // This will take care of creating the hash tables (since they are NULL).
303 UErrorCode ec
= U_ZERO_ERROR
;
304 copyObjects(that
, ec
);
310 MessageFormat::~MessageFormat()
312 uhash_close(cachedFormatters
);
313 uhash_close(customFormatArgStarts
);
316 uprv_free(formatAliases
);
317 delete defaultNumberFormat
;
318 delete defaultDateFormat
;
321 //--------------------------------------------------------------------
322 // Variable-size array management
325 * Allocate argTypes[] to at least the given capacity and return
326 * TRUE if successful. If not, leave argTypes[] unchanged.
328 * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
329 * if necessary to be at least as large as specified.
331 UBool
MessageFormat::allocateArgTypes(int32_t capacity
, UErrorCode
& status
) {
332 if (U_FAILURE(status
)) {
335 if (argTypeCapacity
>= capacity
) {
338 if (capacity
< DEFAULT_INITIAL_CAPACITY
) {
339 capacity
= DEFAULT_INITIAL_CAPACITY
;
340 } else if (capacity
< 2*argTypeCapacity
) {
341 capacity
= 2*argTypeCapacity
;
343 Formattable::Type
* a
= (Formattable::Type
*)
344 uprv_realloc(argTypes
, sizeof(*argTypes
) * capacity
);
346 status
= U_MEMORY_ALLOCATION_ERROR
;
350 argTypeCapacity
= capacity
;
354 // -------------------------------------
355 // assignment operator
358 MessageFormat::operator=(const MessageFormat
& that
)
361 // Calls the super class for assignment first.
362 Format::operator=(that
);
364 setLocale(that
.fLocale
);
365 msgPattern
= that
.msgPattern
;
366 hasArgTypeConflicts
= that
.hasArgTypeConflicts
;
368 UErrorCode ec
= U_ZERO_ERROR
;
369 copyObjects(that
, ec
);
378 MessageFormat::operator==(const Format
& rhs
) const
380 if (this == &rhs
) return TRUE
;
382 MessageFormat
& that
= (MessageFormat
&)rhs
;
384 // Check class ID before checking MessageFormat members
385 if (!Format::operator==(rhs
) ||
386 msgPattern
!= that
.msgPattern
||
387 fLocale
!= that
.fLocale
) {
391 // Compare hashtables.
392 if ((customFormatArgStarts
== NULL
) != (that
.customFormatArgStarts
== NULL
)) {
395 if (customFormatArgStarts
== NULL
) {
399 UErrorCode ec
= U_ZERO_ERROR
;
400 const int32_t count
= uhash_count(customFormatArgStarts
);
401 const int32_t rhs_count
= uhash_count(that
.customFormatArgStarts
);
402 if (count
!= rhs_count
) {
405 int32_t idx
= 0, rhs_idx
= 0, pos
= -1, rhs_pos
= -1;
406 for (; idx
< count
&& rhs_idx
< rhs_count
&& U_SUCCESS(ec
); ++idx
, ++rhs_idx
) {
407 const UHashElement
* cur
= uhash_nextElement(customFormatArgStarts
, &pos
);
408 const UHashElement
* rhs_cur
= uhash_nextElement(that
.customFormatArgStarts
, &rhs_pos
);
409 if (cur
->key
.integer
!= rhs_cur
->key
.integer
) {
412 const Format
* format
= (const Format
*)uhash_iget(cachedFormatters
, cur
->key
.integer
);
413 const Format
* rhs_format
= (const Format
*)uhash_iget(that
.cachedFormatters
, rhs_cur
->key
.integer
);
414 if (*format
!= *rhs_format
) {
421 // -------------------------------------
422 // Creates a copy of this MessageFormat, the caller owns the copy.
425 MessageFormat::clone() const
427 return new MessageFormat(*this);
430 // -------------------------------------
431 // Sets the locale of this MessageFormat object to theLocale.
434 MessageFormat::setLocale(const Locale
& theLocale
)
436 if (fLocale
!= theLocale
) {
437 delete defaultNumberFormat
;
438 defaultNumberFormat
= NULL
;
439 delete defaultDateFormat
;
440 defaultDateFormat
= NULL
;
442 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
443 pluralProvider
.reset(&fLocale
);
444 ordinalProvider
.reset(&fLocale
);
448 // -------------------------------------
449 // Gets the locale of this MessageFormat object.
452 MessageFormat::getLocale() const
458 MessageFormat::applyPattern(const UnicodeString
& newPattern
,
461 UParseError parseError
;
462 applyPattern(newPattern
,parseError
,status
);
466 // -------------------------------------
467 // Applies the new pattern and returns an error if the pattern
470 MessageFormat::applyPattern(const UnicodeString
& pattern
,
471 UParseError
& parseError
,
477 msgPattern
.parse(pattern
, &parseError
, ec
);
478 cacheExplicitFormats(ec
);
485 void MessageFormat::resetPattern() {
487 uhash_close(cachedFormatters
);
488 cachedFormatters
= NULL
;
489 uhash_close(customFormatArgStarts
);
490 customFormatArgStarts
= NULL
;
492 hasArgTypeConflicts
= FALSE
;
496 MessageFormat::applyPattern(const UnicodeString
& pattern
,
497 UMessagePatternApostropheMode aposMode
,
498 UParseError
* parseError
,
499 UErrorCode
& status
) {
500 if (aposMode
!= msgPattern
.getApostropheMode()) {
501 msgPattern
.clearPatternAndSetApostropheMode(aposMode
);
503 applyPattern(pattern
, *parseError
, status
);
506 // -------------------------------------
507 // Converts this MessageFormat instance to a pattern.
510 MessageFormat::toPattern(UnicodeString
& appendTo
) const {
511 if ((customFormatArgStarts
!= NULL
&& 0 != uhash_count(customFormatArgStarts
)) ||
512 0 == msgPattern
.countParts()
514 appendTo
.setToBogus();
517 return appendTo
.append(msgPattern
.getPatternString());
520 int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex
) const {
521 if (partIndex
!= 0) {
522 partIndex
= msgPattern
.getLimitPartIndex(partIndex
);
525 UMessagePatternPartType type
= msgPattern
.getPartType(++partIndex
);
526 if (type
== UMSGPAT_PART_TYPE_ARG_START
) {
529 if (type
== UMSGPAT_PART_TYPE_MSG_LIMIT
) {
535 void MessageFormat::setArgStartFormat(int32_t argStart
,
537 UErrorCode
& status
) {
538 if (U_FAILURE(status
)) {
541 if (cachedFormatters
== NULL
) {
542 cachedFormatters
=uhash_open(uhash_hashLong
, uhash_compareLong
,
543 equalFormatsForHash
, &status
);
544 if (U_FAILURE(status
)) {
548 uhash_setValueDeleter(cachedFormatters
, uprv_deleteUObject
);
550 if (formatter
== NULL
) {
551 formatter
= new DummyFormat();
553 uhash_iput(cachedFormatters
, argStart
, formatter
, &status
);
557 UBool
MessageFormat::argNameMatches(int32_t partIndex
, const UnicodeString
& argName
, int32_t argNumber
) {
558 const MessagePattern::Part
& part
= msgPattern
.getPart(partIndex
);
559 return part
.getType() == UMSGPAT_PART_TYPE_ARG_NAME
?
560 msgPattern
.partSubstringMatches(part
, argName
) :
561 part
.getValue() == argNumber
; // ARG_NUMBER
564 // Sets a custom formatter for a MessagePattern ARG_START part index.
565 // "Custom" formatters are provided by the user via setFormat() or similar APIs.
566 void MessageFormat::setCustomArgStartFormat(int32_t argStart
,
568 UErrorCode
& status
) {
569 setArgStartFormat(argStart
, formatter
, status
);
570 if (customFormatArgStarts
== NULL
) {
571 customFormatArgStarts
=uhash_open(uhash_hashLong
, uhash_compareLong
,
574 uhash_iputi(customFormatArgStarts
, argStart
, 1, &status
);
577 Format
* MessageFormat::getCachedFormatter(int32_t argumentNumber
) const {
578 if (cachedFormatters
== NULL
) {
581 void* ptr
= uhash_iget(cachedFormatters
, argumentNumber
);
582 if (ptr
!= NULL
&& dynamic_cast<DummyFormat
*>((Format
*)ptr
) == NULL
) {
583 return (Format
*) ptr
;
585 // Not cached, or a DummyFormat representing setFormat(NULL).
590 // -------------------------------------
591 // Adopts the new formats array and updates the array count.
592 // This MessageFormat instance owns the new formats.
594 MessageFormat::adoptFormats(Format
** newFormats
,
596 if (newFormats
== NULL
|| count
< 0) {
599 // Throw away any cached formatters.
600 if (cachedFormatters
!= NULL
) {
601 uhash_removeAll(cachedFormatters
);
603 if (customFormatArgStarts
!= NULL
) {
604 uhash_removeAll(customFormatArgStarts
);
607 int32_t formatNumber
= 0;
608 UErrorCode status
= U_ZERO_ERROR
;
609 for (int32_t partIndex
= 0;
610 formatNumber
< count
&& U_SUCCESS(status
) &&
611 (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
612 setCustomArgStartFormat(partIndex
, newFormats
[formatNumber
], status
);
615 // Delete those that didn't get used (if any).
616 for (; formatNumber
< count
; ++formatNumber
) {
617 delete newFormats
[formatNumber
];
622 // -------------------------------------
623 // Sets the new formats array and updates the array count.
624 // This MessageFormat instance maks a copy of the new formats.
627 MessageFormat::setFormats(const Format
** newFormats
,
629 if (newFormats
== NULL
|| count
< 0) {
632 // Throw away any cached formatters.
633 if (cachedFormatters
!= NULL
) {
634 uhash_removeAll(cachedFormatters
);
636 if (customFormatArgStarts
!= NULL
) {
637 uhash_removeAll(customFormatArgStarts
);
640 UErrorCode status
= U_ZERO_ERROR
;
641 int32_t formatNumber
= 0;
642 for (int32_t partIndex
= 0;
643 formatNumber
< count
&& U_SUCCESS(status
) && (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
644 Format
* newFormat
= NULL
;
645 if (newFormats
[formatNumber
] != NULL
) {
646 newFormat
= newFormats
[formatNumber
]->clone();
647 if (newFormat
== NULL
) {
648 status
= U_MEMORY_ALLOCATION_ERROR
;
651 setCustomArgStartFormat(partIndex
, newFormat
, status
);
654 if (U_FAILURE(status
)) {
659 // -------------------------------------
660 // Adopt a single format by format number.
661 // Do nothing if the format number is not less than the array count.
664 MessageFormat::adoptFormat(int32_t n
, Format
*newFormat
) {
665 LocalPointer
<Format
> p(newFormat
);
667 int32_t formatNumber
= 0;
668 for (int32_t partIndex
= 0; (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
669 if (n
== formatNumber
) {
670 UErrorCode status
= U_ZERO_ERROR
;
671 setCustomArgStartFormat(partIndex
, p
.orphan(), status
);
679 // -------------------------------------
680 // Adopt a single format by format name.
681 // Do nothing if there is no match of formatName.
683 MessageFormat::adoptFormat(const UnicodeString
& formatName
,
684 Format
* formatToAdopt
,
685 UErrorCode
& status
) {
686 LocalPointer
<Format
> p(formatToAdopt
);
687 if (U_FAILURE(status
)) {
690 int32_t argNumber
= MessagePattern::validateArgumentName(formatName
);
691 if (argNumber
< UMSGPAT_ARG_NAME_NOT_NUMBER
) {
692 status
= U_ILLEGAL_ARGUMENT_ERROR
;
695 for (int32_t partIndex
= 0;
696 (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0 && U_SUCCESS(status
);
698 if (argNameMatches(partIndex
+ 1, formatName
, argNumber
)) {
702 } else if (formatToAdopt
== NULL
) {
705 f
= formatToAdopt
->clone();
707 status
= U_MEMORY_ALLOCATION_ERROR
;
711 setCustomArgStartFormat(partIndex
, f
, status
);
716 // -------------------------------------
717 // Set a single format.
718 // Do nothing if the variable is not less than the array count.
720 MessageFormat::setFormat(int32_t n
, const Format
& newFormat
) {
723 int32_t formatNumber
= 0;
724 for (int32_t partIndex
= 0;
725 (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
726 if (n
== formatNumber
) {
727 Format
* new_format
= newFormat
.clone();
729 UErrorCode status
= U_ZERO_ERROR
;
730 setCustomArgStartFormat(partIndex
, new_format
, status
);
739 // -------------------------------------
740 // Get a single format by format name.
741 // Do nothing if the variable is not less than the array count.
743 MessageFormat::getFormat(const UnicodeString
& formatName
, UErrorCode
& status
) {
744 if (U_FAILURE(status
) || cachedFormatters
== NULL
) return NULL
;
746 int32_t argNumber
= MessagePattern::validateArgumentName(formatName
);
747 if (argNumber
< UMSGPAT_ARG_NAME_NOT_NUMBER
) {
748 status
= U_ILLEGAL_ARGUMENT_ERROR
;
751 for (int32_t partIndex
= 0; (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
752 if (argNameMatches(partIndex
+ 1, formatName
, argNumber
)) {
753 return getCachedFormatter(partIndex
);
759 // -------------------------------------
760 // Set a single format by format name
761 // Do nothing if the variable is not less than the array count.
763 MessageFormat::setFormat(const UnicodeString
& formatName
,
764 const Format
& newFormat
,
765 UErrorCode
& status
) {
766 if (U_FAILURE(status
)) return;
768 int32_t argNumber
= MessagePattern::validateArgumentName(formatName
);
769 if (argNumber
< UMSGPAT_ARG_NAME_NOT_NUMBER
) {
770 status
= U_ILLEGAL_ARGUMENT_ERROR
;
773 for (int32_t partIndex
= 0;
774 (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0 && U_SUCCESS(status
);
776 if (argNameMatches(partIndex
+ 1, formatName
, argNumber
)) {
777 if (&newFormat
== NULL
) {
778 setCustomArgStartFormat(partIndex
, NULL
, status
);
780 Format
* new_format
= newFormat
.clone();
781 if (new_format
== NULL
) {
782 status
= U_MEMORY_ALLOCATION_ERROR
;
785 setCustomArgStartFormat(partIndex
, new_format
, status
);
791 // -------------------------------------
792 // Gets the format array.
794 MessageFormat::getFormats(int32_t& cnt
) const
796 // This old API returns an array (which we hold) of Format*
797 // pointers. The array is valid up to the next call to any
798 // method on this object. We construct and resize an array
799 // on demand that contains aliases to the subformats[i].format
801 MessageFormat
* t
= const_cast<MessageFormat
*> (this);
803 if (formatAliases
== NULL
) {
804 t
->formatAliasesCapacity
= (argTypeCount
<10) ? 10 : argTypeCount
;
805 Format
** a
= (Format
**)
806 uprv_malloc(sizeof(Format
*) * formatAliasesCapacity
);
808 t
->formatAliasesCapacity
= 0;
811 t
->formatAliases
= a
;
812 } else if (argTypeCount
> formatAliasesCapacity
) {
813 Format
** a
= (Format
**)
814 uprv_realloc(formatAliases
, sizeof(Format
*) * argTypeCount
);
816 t
->formatAliasesCapacity
= 0;
819 t
->formatAliases
= a
;
820 t
->formatAliasesCapacity
= argTypeCount
;
823 for (int32_t partIndex
= 0; (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
824 t
->formatAliases
[cnt
++] = getCachedFormatter(partIndex
);
827 return (const Format
**)formatAliases
;
831 UnicodeString
MessageFormat::getArgName(int32_t partIndex
) {
832 const MessagePattern::Part
& part
= msgPattern
.getPart(partIndex
);
833 if (part
.getType() == UMSGPAT_PART_TYPE_ARG_NAME
) {
834 return msgPattern
.getSubstring(part
);
837 return itos(part
.getValue(), temp
);
842 MessageFormat::getFormatNames(UErrorCode
& status
) {
843 if (U_FAILURE(status
)) return NULL
;
845 UVector
*fFormatNames
= new UVector(status
);
846 if (U_FAILURE(status
)) {
847 status
= U_MEMORY_ALLOCATION_ERROR
;
850 fFormatNames
->setDeleter(uprv_deleteUObject
);
852 for (int32_t partIndex
= 0; (partIndex
= nextTopLevelArgStart(partIndex
)) >= 0;) {
853 fFormatNames
->addElement(new UnicodeString(getArgName(partIndex
+ 1)), status
);
856 StringEnumeration
* nameEnumerator
= new FormatNameEnumeration(fFormatNames
, status
);
857 return nameEnumerator
;
860 // -------------------------------------
861 // Formats the source Formattable array and copy into the result buffer.
862 // Ignore the FieldPosition result for error checking.
865 MessageFormat::format(const Formattable
* source
,
867 UnicodeString
& appendTo
,
868 FieldPosition
& ignore
,
869 UErrorCode
& success
) const
871 return format(source
, NULL
, cnt
, appendTo
, &ignore
, success
);
874 // -------------------------------------
875 // Internally creates a MessageFormat instance based on the
876 // pattern and formats the arguments Formattable array and
877 // copy into the appendTo buffer.
880 MessageFormat::format( const UnicodeString
& pattern
,
881 const Formattable
* arguments
,
883 UnicodeString
& appendTo
,
886 MessageFormat
temp(pattern
, success
);
887 return temp
.format(arguments
, NULL
, cnt
, appendTo
, NULL
, success
);
890 // -------------------------------------
891 // Formats the source Formattable object and copy into the
892 // appendTo buffer. The Formattable object must be an array
893 // of Formattable instances, returns error otherwise.
896 MessageFormat::format(const Formattable
& source
,
897 UnicodeString
& appendTo
,
898 FieldPosition
& ignore
,
899 UErrorCode
& success
) const
901 if (U_FAILURE(success
))
903 if (source
.getType() != Formattable::kArray
) {
904 success
= U_ILLEGAL_ARGUMENT_ERROR
;
908 const Formattable
* tmpPtr
= source
.getArray(cnt
);
909 return format(tmpPtr
, NULL
, cnt
, appendTo
, &ignore
, success
);
913 MessageFormat::format(const UnicodeString
* argumentNames
,
914 const Formattable
* arguments
,
916 UnicodeString
& appendTo
,
917 UErrorCode
& success
) const {
918 return format(arguments
, argumentNames
, count
, appendTo
, NULL
, success
);
921 // Does linear search to find the match for an ArgName.
922 const Formattable
* MessageFormat::getArgFromListByName(const Formattable
* arguments
,
923 const UnicodeString
*argumentNames
,
924 int32_t cnt
, UnicodeString
& name
) const {
925 for (int32_t i
= 0; i
< cnt
; ++i
) {
926 if (0 == argumentNames
[i
].compare(name
)) {
927 return arguments
+ i
;
935 MessageFormat::format(const Formattable
* arguments
,
936 const UnicodeString
*argumentNames
,
938 UnicodeString
& appendTo
,
940 UErrorCode
& status
) const {
941 if (U_FAILURE(status
)) {
945 UnicodeStringAppendable
usapp(appendTo
);
946 AppendableWrapper
app(usapp
);
947 format(0, 0.0, arguments
, argumentNames
, cnt
, app
, pos
, status
);
951 // if argumentNames is NULL, this means arguments is a numeric array.
952 // arguments can not be NULL.
953 void MessageFormat::format(int32_t msgStart
, double pluralNumber
,
954 const Formattable
* arguments
,
955 const UnicodeString
*argumentNames
,
957 AppendableWrapper
& appendTo
,
958 FieldPosition
* ignore
,
959 UErrorCode
& success
) const {
960 if (U_FAILURE(success
)) {
964 const UnicodeString
& msgString
= msgPattern
.getPatternString();
965 int32_t prevIndex
= msgPattern
.getPart(msgStart
).getLimit();
966 for (int32_t i
= msgStart
+ 1; U_SUCCESS(success
) ; ++i
) {
967 const MessagePattern::Part
* part
= &msgPattern
.getPart(i
);
968 const UMessagePatternPartType type
= part
->getType();
969 int32_t index
= part
->getIndex();
970 appendTo
.append(msgString
, prevIndex
, index
- prevIndex
);
971 if (type
== UMSGPAT_PART_TYPE_MSG_LIMIT
) {
974 prevIndex
= part
->getLimit();
975 if (type
== UMSGPAT_PART_TYPE_REPLACE_NUMBER
) {
976 const NumberFormat
* nf
= getDefaultNumberFormat(success
);
977 appendTo
.formatAndAppend(nf
, Formattable(pluralNumber
), success
);
980 if (type
!= UMSGPAT_PART_TYPE_ARG_START
) {
983 int32_t argLimit
= msgPattern
.getLimitPartIndex(i
);
984 UMessagePatternArgType argType
= part
->getArgType();
985 part
= &msgPattern
.getPart(++i
);
986 const Formattable
* arg
;
988 if (argumentNames
== NULL
) {
989 int32_t argNumber
= part
->getValue(); // ARG_NUMBER
990 if (0 <= argNumber
&& argNumber
< cnt
) {
991 arg
= arguments
+ argNumber
;
994 noArg
.append(LEFT_CURLY_BRACE
);
995 itos(argNumber
, noArg
);
996 noArg
.append(RIGHT_CURLY_BRACE
);
1000 if (part
->getType() == UMSGPAT_PART_TYPE_ARG_NAME
) {
1001 key
= msgPattern
.getSubstring(*part
);
1002 } else /* UMSGPAT_PART_TYPE_ARG_NUMBER */ {
1003 itos(part
->getValue(), key
);
1005 arg
= getArgFromListByName(arguments
, argumentNames
, cnt
, key
);
1007 noArg
.append(LEFT_CURLY_BRACE
);
1009 noArg
.append(RIGHT_CURLY_BRACE
);
1013 int32_t prevDestLength
= appendTo
.length();
1014 const Format
* formatter
= NULL
;
1015 if (!noArg
.isEmpty()) {
1016 appendTo
.append(noArg
);
1017 } else if (arg
== NULL
) {
1018 appendTo
.append(NULL_STRING
, 4);
1019 } else if ((formatter
= getCachedFormatter(i
-2))) {
1020 // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
1021 if (dynamic_cast<const ChoiceFormat
*>(formatter
) ||
1022 dynamic_cast<const PluralFormat
*>(formatter
) ||
1023 dynamic_cast<const SelectFormat
*>(formatter
)) {
1024 // We only handle nested formats here if they were provided via
1025 // setFormat() or its siblings. Otherwise they are not cached and instead
1026 // handled below according to argType.
1027 UnicodeString subMsgString
;
1028 formatter
->format(*arg
, subMsgString
, success
);
1029 if (subMsgString
.indexOf(LEFT_CURLY_BRACE
) >= 0 ||
1030 (subMsgString
.indexOf(SINGLE_QUOTE
) >= 0 && !MessageImpl::jdkAposMode(msgPattern
))
1032 MessageFormat
subMsgFormat(subMsgString
, fLocale
, success
);
1033 subMsgFormat
.format(0, 0, arguments
, argumentNames
, cnt
, appendTo
, ignore
, success
);
1035 appendTo
.append(subMsgString
);
1038 appendTo
.formatAndAppend(formatter
, *arg
, success
);
1040 } else if (argType
== UMSGPAT_ARG_TYPE_NONE
|| (cachedFormatters
&& uhash_iget(cachedFormatters
, i
- 2))) {
1041 // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1042 // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1043 // for the hash table containind DummyFormat.
1044 if (arg
->isNumeric()) {
1045 const NumberFormat
* nf
= getDefaultNumberFormat(success
);
1046 appendTo
.formatAndAppend(nf
, *arg
, success
);
1047 } else if (arg
->getType() == Formattable::kDate
) {
1048 const DateFormat
* df
= getDefaultDateFormat(success
);
1049 appendTo
.formatAndAppend(df
, *arg
, success
);
1051 appendTo
.append(arg
->getString(success
));
1053 } else if (argType
== UMSGPAT_ARG_TYPE_CHOICE
) {
1054 if (!arg
->isNumeric()) {
1055 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1058 // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1059 // because only this one converts non-double numeric types to double.
1060 const double number
= arg
->getDouble(success
);
1061 int32_t subMsgStart
= ChoiceFormat::findSubMessage(msgPattern
, i
, number
);
1062 formatComplexSubMessage(subMsgStart
, 0, arguments
, argumentNames
,
1063 cnt
, appendTo
, success
);
1064 } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType
)) {
1065 if (!arg
->isNumeric()) {
1066 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1069 const PluralFormat::PluralSelector
&selector
=
1070 argType
== UMSGPAT_ARG_TYPE_PLURAL
? pluralProvider
: ordinalProvider
;
1071 // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1072 // because only this one converts non-double numeric types to double.
1073 double number
= arg
->getDouble(success
);
1074 int32_t subMsgStart
= PluralFormat::findSubMessage(msgPattern
, i
, selector
, number
,
1076 double offset
= msgPattern
.getPluralOffset(i
);
1077 formatComplexSubMessage(subMsgStart
, number
-offset
, arguments
, argumentNames
,
1078 cnt
, appendTo
, success
);
1079 } else if (argType
== UMSGPAT_ARG_TYPE_SELECT
) {
1080 int32_t subMsgStart
= SelectFormat::findSubMessage(msgPattern
, i
, arg
->getString(success
), success
);
1081 formatComplexSubMessage(subMsgStart
, 0, arguments
, argumentNames
,
1082 cnt
, appendTo
, success
);
1084 // This should never happen.
1085 success
= U_INTERNAL_PROGRAM_ERROR
;
1088 ignore
= updateMetaData(appendTo
, prevDestLength
, ignore
, arg
);
1089 prevIndex
= msgPattern
.getPart(argLimit
).getLimit();
1095 void MessageFormat::formatComplexSubMessage(int32_t msgStart
,
1096 double pluralNumber
,
1097 const Formattable
* arguments
,
1098 const UnicodeString
*argumentNames
,
1100 AppendableWrapper
& appendTo
,
1101 UErrorCode
& success
) const {
1102 if (U_FAILURE(success
)) {
1106 if (!MessageImpl::jdkAposMode(msgPattern
)) {
1107 format(msgStart
, pluralNumber
, arguments
, argumentNames
, cnt
, appendTo
, NULL
, success
);
1111 // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
1112 // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
1113 // - if the result string contains an open curly brace '{' then
1114 // instantiate a temporary MessageFormat object and format again;
1115 // otherwise just append the result string
1116 const UnicodeString
& msgString
= msgPattern
.getPatternString();
1118 int32_t prevIndex
= msgPattern
.getPart(msgStart
).getLimit();
1119 for (int32_t i
= msgStart
;;) {
1120 const MessagePattern::Part
& part
= msgPattern
.getPart(++i
);
1121 const UMessagePatternPartType type
= part
.getType();
1122 int32_t index
= part
.getIndex();
1123 if (type
== UMSGPAT_PART_TYPE_MSG_LIMIT
) {
1124 sb
.append(msgString
, prevIndex
, index
- prevIndex
);
1126 } else if (type
== UMSGPAT_PART_TYPE_REPLACE_NUMBER
|| type
== UMSGPAT_PART_TYPE_SKIP_SYNTAX
) {
1127 sb
.append(msgString
, prevIndex
, index
- prevIndex
);
1128 if (type
== UMSGPAT_PART_TYPE_REPLACE_NUMBER
) {
1129 const NumberFormat
* nf
= getDefaultNumberFormat(success
);
1130 sb
.append(nf
->format(pluralNumber
, sb
, success
));
1132 prevIndex
= part
.getLimit();
1133 } else if (type
== UMSGPAT_PART_TYPE_ARG_START
) {
1134 sb
.append(msgString
, prevIndex
, index
- prevIndex
);
1136 i
= msgPattern
.getLimitPartIndex(i
);
1137 index
= msgPattern
.getPart(i
).getLimit();
1138 MessageImpl::appendReducedApostrophes(msgString
, prevIndex
, index
, sb
);
1142 if (sb
.indexOf(LEFT_CURLY_BRACE
) >= 0) {
1143 UnicodeString emptyPattern
; // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
1144 MessageFormat
subMsgFormat(emptyPattern
, fLocale
, success
);
1145 subMsgFormat
.applyPattern(sb
, UMSGPAT_APOS_DOUBLE_REQUIRED
, NULL
, success
);
1146 subMsgFormat
.format(0, 0, arguments
, argumentNames
, cnt
, appendTo
, NULL
, success
);
1148 appendTo
.append(sb
);
1153 UnicodeString
MessageFormat::getLiteralStringUntilNextArgument(int32_t from
) const {
1154 const UnicodeString
& msgString
=msgPattern
.getPatternString();
1155 int32_t prevIndex
=msgPattern
.getPart(from
).getLimit();
1157 for (int32_t i
= from
+ 1; ; ++i
) {
1158 const MessagePattern::Part
& part
= msgPattern
.getPart(i
);
1159 const UMessagePatternPartType type
=part
.getType();
1160 int32_t index
=part
.getIndex();
1161 b
.append(msgString
, prevIndex
, index
- prevIndex
);
1162 if(type
==UMSGPAT_PART_TYPE_ARG_START
|| type
==UMSGPAT_PART_TYPE_MSG_LIMIT
) {
1165 // Unexpected Part "part" in parsed message.
1166 U_ASSERT(type
==UMSGPAT_PART_TYPE_SKIP_SYNTAX
|| type
==UMSGPAT_PART_TYPE_INSERT_CHAR
);
1167 prevIndex
=part
.getLimit();
1172 FieldPosition
* MessageFormat::updateMetaData(AppendableWrapper
& /*dest*/, int32_t /*prevLength*/,
1173 FieldPosition
* /*fp*/, const Formattable
* /*argId*/) const {
1174 // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
1177 if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
1178 fp->setBeginIndex(prevLength);
1179 fp->setEndIndex(dest.get_length());
1186 void MessageFormat::copyObjects(const MessageFormat
& that
, UErrorCode
& ec
) {
1187 // Deep copy pointer fields.
1188 // We need not copy the formatAliases because they are re-filled
1189 // in each getFormats() call.
1190 // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
1191 // also get created on demand.
1192 argTypeCount
= that
.argTypeCount
;
1193 if (argTypeCount
> 0) {
1194 if (!allocateArgTypes(argTypeCount
, ec
)) {
1197 uprv_memcpy(argTypes
, that
.argTypes
, argTypeCount
* sizeof(argTypes
[0]));
1199 if (cachedFormatters
!= NULL
) {
1200 uhash_removeAll(cachedFormatters
);
1202 if (customFormatArgStarts
!= NULL
) {
1203 uhash_removeAll(customFormatArgStarts
);
1205 if (that
.cachedFormatters
) {
1206 if (cachedFormatters
== NULL
) {
1207 cachedFormatters
=uhash_open(uhash_hashLong
, uhash_compareLong
,
1208 equalFormatsForHash
, &ec
);
1209 if (U_FAILURE(ec
)) {
1212 uhash_setValueDeleter(cachedFormatters
, uprv_deleteUObject
);
1215 const int32_t count
= uhash_count(that
.cachedFormatters
);
1217 for (idx
= 0, pos
= -1; idx
< count
&& U_SUCCESS(ec
); ++idx
) {
1218 const UHashElement
* cur
= uhash_nextElement(that
.cachedFormatters
, &pos
);
1219 Format
* newFormat
= ((Format
*)(cur
->value
.pointer
))->clone();
1221 uhash_iput(cachedFormatters
, cur
->key
.integer
, newFormat
, &ec
);
1223 ec
= U_MEMORY_ALLOCATION_ERROR
;
1228 if (that
.customFormatArgStarts
) {
1229 if (customFormatArgStarts
== NULL
) {
1230 customFormatArgStarts
=uhash_open(uhash_hashLong
, uhash_compareLong
,
1233 const int32_t count
= uhash_count(that
.customFormatArgStarts
);
1235 for (idx
= 0, pos
= -1; idx
< count
&& U_SUCCESS(ec
); ++idx
) {
1236 const UHashElement
* cur
= uhash_nextElement(that
.customFormatArgStarts
, &pos
);
1237 uhash_iputi(customFormatArgStarts
, cur
->key
.integer
, cur
->value
.integer
, &ec
);
1244 MessageFormat::parse(int32_t msgStart
,
1245 const UnicodeString
& source
,
1248 UErrorCode
& ec
) const {
1250 if (U_FAILURE(ec
)) {
1251 pos
.setErrorIndex(pos
.getIndex());
1254 // parse() does not work with named arguments.
1255 if (msgPattern
.hasNamedArguments()) {
1256 ec
= U_ARGUMENT_TYPE_MISMATCH
;
1257 pos
.setErrorIndex(pos
.getIndex());
1260 LocalArray
<Formattable
> resultArray(new Formattable
[argTypeCount
? argTypeCount
: 1]);
1261 const UnicodeString
& msgString
=msgPattern
.getPatternString();
1262 int32_t prevIndex
=msgPattern
.getPart(msgStart
).getLimit();
1263 int32_t sourceOffset
= pos
.getIndex();
1264 ParsePosition
tempStatus(0);
1266 for(int32_t i
=msgStart
+1; ; ++i
) {
1267 UBool haveArgResult
= FALSE
;
1268 const MessagePattern::Part
* part
=&msgPattern
.getPart(i
);
1269 const UMessagePatternPartType type
=part
->getType();
1270 int32_t index
=part
->getIndex();
1271 // Make sure the literal string matches.
1272 int32_t len
= index
- prevIndex
;
1273 if (len
== 0 || (0 == msgString
.compare(prevIndex
, len
, source
, sourceOffset
, len
))) {
1274 sourceOffset
+= len
;
1277 pos
.setErrorIndex(sourceOffset
);
1278 return NULL
; // leave index as is to signal error
1280 if(type
==UMSGPAT_PART_TYPE_MSG_LIMIT
) {
1281 // Things went well! Done.
1282 pos
.setIndex(sourceOffset
);
1283 return resultArray
.orphan();
1285 if(type
==UMSGPAT_PART_TYPE_SKIP_SYNTAX
|| type
==UMSGPAT_PART_TYPE_INSERT_CHAR
) {
1286 prevIndex
=part
->getLimit();
1289 // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
1290 // Unexpected Part "part" in parsed message.
1291 U_ASSERT(type
==UMSGPAT_PART_TYPE_ARG_START
);
1292 int32_t argLimit
=msgPattern
.getLimitPartIndex(i
);
1294 UMessagePatternArgType argType
=part
->getArgType();
1295 part
=&msgPattern
.getPart(++i
);
1296 int32_t argNumber
= part
->getValue(); // ARG_NUMBER
1299 const Format
* formatter
= NULL
;
1300 Formattable
& argResult
= resultArray
[argNumber
];
1302 if(cachedFormatters
!=NULL
&& (formatter
= getCachedFormatter(i
- 2))!=NULL
) {
1303 // Just parse using the formatter.
1304 tempStatus
.setIndex(sourceOffset
);
1305 formatter
->parseObject(source
, argResult
, tempStatus
);
1306 if (tempStatus
.getIndex() == sourceOffset
) {
1307 pos
.setErrorIndex(sourceOffset
);
1308 return NULL
; // leave index as is to signal error
1310 sourceOffset
= tempStatus
.getIndex();
1311 haveArgResult
= TRUE
;
1313 argType
==UMSGPAT_ARG_TYPE_NONE
|| (cachedFormatters
&& uhash_iget(cachedFormatters
, i
-2))) {
1314 // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1315 // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1316 // for the hash table containind DummyFormat.
1318 // Match as a string.
1319 // if at end, use longest possible match
1320 // otherwise uses first match to intervening string
1321 // does NOT recursively try all possibilities
1322 UnicodeString stringAfterArgument
= getLiteralStringUntilNextArgument(argLimit
);
1324 if (!stringAfterArgument
.isEmpty()) {
1325 next
= source
.indexOf(stringAfterArgument
, sourceOffset
);
1327 next
= source
.length();
1330 pos
.setErrorIndex(sourceOffset
);
1331 return NULL
; // leave index as is to signal error
1333 UnicodeString
strValue(source
.tempSubString(sourceOffset
, next
- sourceOffset
));
1334 UnicodeString compValue
;
1335 compValue
.append(LEFT_CURLY_BRACE
);
1336 itos(argNumber
, compValue
);
1337 compValue
.append(RIGHT_CURLY_BRACE
);
1338 if (0 != strValue
.compare(compValue
)) {
1339 argResult
.setString(strValue
);
1340 haveArgResult
= TRUE
;
1342 sourceOffset
= next
;
1344 } else if(argType
==UMSGPAT_ARG_TYPE_CHOICE
) {
1345 tempStatus
.setIndex(sourceOffset
);
1346 double choiceResult
= ChoiceFormat::parseArgument(msgPattern
, i
, source
, tempStatus
);
1347 if (tempStatus
.getIndex() == sourceOffset
) {
1348 pos
.setErrorIndex(sourceOffset
);
1349 return NULL
; // leave index as is to signal error
1351 argResult
.setDouble(choiceResult
);
1352 haveArgResult
= TRUE
;
1353 sourceOffset
= tempStatus
.getIndex();
1354 } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType
) || argType
==UMSGPAT_ARG_TYPE_SELECT
) {
1355 // Parsing not supported.
1356 ec
= U_UNSUPPORTED_ERROR
;
1359 // This should never happen.
1360 ec
= U_INTERNAL_PROGRAM_ERROR
;
1363 if (haveArgResult
&& count
<= argNumber
) {
1364 count
= argNumber
+ 1;
1366 prevIndex
=msgPattern
.getPart(argLimit
).getLimit();
1370 // -------------------------------------
1371 // Parses the source pattern and returns the Formattable objects array,
1372 // the array count and the ending parse position. The caller of this method
1376 MessageFormat::parse(const UnicodeString
& source
,
1378 int32_t& count
) const {
1379 UErrorCode ec
= U_ZERO_ERROR
;
1380 return parse(0, source
, pos
, count
, ec
);
1383 // -------------------------------------
1384 // Parses the source string and returns the array of
1385 // Formattable objects and the array count. The caller
1386 // owns the returned array.
1389 MessageFormat::parse(const UnicodeString
& source
,
1391 UErrorCode
& success
) const
1393 if (msgPattern
.hasNamedArguments()) {
1394 success
= U_ARGUMENT_TYPE_MISMATCH
;
1397 ParsePosition
status(0);
1398 // Calls the actual implementation method and starts
1399 // from zero offset of the source text.
1400 Formattable
* result
= parse(source
, status
, cnt
);
1401 if (status
.getIndex() == 0) {
1402 success
= U_MESSAGE_PARSE_ERROR
;
1409 // -------------------------------------
1410 // Parses the source text and copy into the result buffer.
1413 MessageFormat::parseObject( const UnicodeString
& source
,
1414 Formattable
& result
,
1415 ParsePosition
& status
) const
1418 Formattable
* tmpResult
= parse(source
, status
, cnt
);
1419 if (tmpResult
!= NULL
)
1420 result
.adoptArray(tmpResult
, cnt
);
1424 MessageFormat::autoQuoteApostrophe(const UnicodeString
& pattern
, UErrorCode
& status
) {
1425 UnicodeString result
;
1426 if (U_SUCCESS(status
)) {
1427 int32_t plen
= pattern
.length();
1428 const UChar
* pat
= pattern
.getBuffer();
1429 int32_t blen
= plen
* 2 + 1; // space for null termination, convenience
1430 UChar
* buf
= result
.getBuffer(blen
);
1432 status
= U_MEMORY_ALLOCATION_ERROR
;
1434 int32_t len
= umsg_autoQuoteApostrophe(pat
, plen
, buf
, blen
, &status
);
1435 result
.releaseBuffer(U_SUCCESS(status
) ? len
: 0);
1438 if (U_FAILURE(status
)) {
1439 result
.setToBogus();
1444 // -------------------------------------
1446 static Format
* makeRBNF(URBNFRuleSetTag tag
, const Locale
& locale
, const UnicodeString
& defaultRuleSet
, UErrorCode
& ec
) {
1447 RuleBasedNumberFormat
* fmt
= new RuleBasedNumberFormat(tag
, locale
, ec
);
1449 ec
= U_MEMORY_ALLOCATION_ERROR
;
1450 } else if (U_SUCCESS(ec
) && defaultRuleSet
.length() > 0) {
1451 UErrorCode localStatus
= U_ZERO_ERROR
; // ignore unrecognized default rule set
1452 fmt
->setDefaultRuleSet(defaultRuleSet
, localStatus
);
1457 void MessageFormat::cacheExplicitFormats(UErrorCode
& status
) {
1458 if (U_FAILURE(status
)) {
1462 if (cachedFormatters
!= NULL
) {
1463 uhash_removeAll(cachedFormatters
);
1465 if (customFormatArgStarts
!= NULL
) {
1466 uhash_removeAll(customFormatArgStarts
);
1469 // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
1470 // which we need not examine.
1471 int32_t limit
= msgPattern
.countParts() - 2;
1473 // We also need not look at the first two "parts"
1474 // (at most MSG_START and ARG_START) in this loop.
1475 // We determine the argTypeCount first so that we can allocateArgTypes
1476 // so that the next loop can set argTypes[argNumber].
1477 // (This is for the C API which needs the argTypes to read its va_arg list.)
1478 for (int32_t i
= 2; i
< limit
&& U_SUCCESS(status
); ++i
) {
1479 const MessagePattern::Part
& part
= msgPattern
.getPart(i
);
1480 if (part
.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER
) {
1481 const int argNumber
= part
.getValue();
1482 if (argNumber
>= argTypeCount
) {
1483 argTypeCount
= argNumber
+ 1;
1487 if (!allocateArgTypes(argTypeCount
, status
)) {
1490 // Set all argTypes to kObject, as a "none" value, for lack of any better value.
1491 // We never use kObject for real arguments.
1492 // We use it as "no argument yet" for the check for hasArgTypeConflicts.
1493 for (int32_t i
= 0; i
< argTypeCount
; ++i
) {
1494 argTypes
[i
] = Formattable::kObject
;
1496 hasArgTypeConflicts
= FALSE
;
1498 // This loop starts at part index 1 because we do need to examine
1499 // ARG_START parts. (But we can ignore the MSG_START.)
1500 for (int32_t i
= 1; i
< limit
&& U_SUCCESS(status
); ++i
) {
1501 const MessagePattern::Part
* part
= &msgPattern
.getPart(i
);
1502 if (part
->getType() != UMSGPAT_PART_TYPE_ARG_START
) {
1505 UMessagePatternArgType argType
= part
->getArgType();
1507 int32_t argNumber
= -1;
1508 part
= &msgPattern
.getPart(i
+ 1);
1509 if (part
->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER
) {
1510 argNumber
= part
->getValue();
1512 Formattable::Type formattableType
;
1515 case UMSGPAT_ARG_TYPE_NONE
:
1516 formattableType
= Formattable::kString
;
1518 case UMSGPAT_ARG_TYPE_SIMPLE
: {
1521 UnicodeString explicitType
= msgPattern
.getSubstring(msgPattern
.getPart(i
++));
1522 UnicodeString style
;
1523 if ((part
= &msgPattern
.getPart(i
))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE
) {
1524 style
= msgPattern
.getSubstring(*part
);
1527 UParseError parseError
;
1528 Format
* formatter
= createAppropriateFormat(explicitType
, style
, formattableType
, parseError
, status
);
1529 setArgStartFormat(index
, formatter
, status
);
1532 case UMSGPAT_ARG_TYPE_CHOICE
:
1533 case UMSGPAT_ARG_TYPE_PLURAL
:
1534 case UMSGPAT_ARG_TYPE_SELECTORDINAL
:
1535 formattableType
= Formattable::kDouble
;
1537 case UMSGPAT_ARG_TYPE_SELECT
:
1538 formattableType
= Formattable::kString
;
1541 status
= U_INTERNAL_PROGRAM_ERROR
; // Should be unreachable.
1542 formattableType
= Formattable::kString
;
1545 if (argNumber
!= -1) {
1546 if (argTypes
[argNumber
] != Formattable::kObject
&& argTypes
[argNumber
] != formattableType
) {
1547 hasArgTypeConflicts
= TRUE
;
1549 argTypes
[argNumber
] = formattableType
;
1555 Format
* MessageFormat::createAppropriateFormat(UnicodeString
& type
, UnicodeString
& style
,
1556 Formattable::Type
& formattableType
, UParseError
& parseError
,
1558 if (U_FAILURE(ec
)) {
1562 int32_t typeID
, styleID
;
1563 DateFormat::EStyle date_style
;
1565 switch (typeID
= findKeyword(type
, TYPE_IDS
)) {
1567 formattableType
= Formattable::kDouble
;
1568 switch (findKeyword(style
, NUMBER_STYLE_IDS
)) {
1570 fmt
= NumberFormat::createInstance(fLocale
, ec
);
1573 fmt
= NumberFormat::createCurrencyInstance(fLocale
, ec
);
1576 fmt
= NumberFormat::createPercentInstance(fLocale
, ec
);
1579 formattableType
= Formattable::kLong
;
1580 fmt
= createIntegerFormat(fLocale
, ec
);
1583 fmt
= NumberFormat::createInstance(fLocale
, ec
);
1585 DecimalFormat
* decfmt
= dynamic_cast<DecimalFormat
*>(fmt
);
1586 if (decfmt
!= NULL
) {
1587 decfmt
->applyPattern(style
,parseError
,ec
);
1596 formattableType
= Formattable::kDate
;
1597 styleID
= findKeyword(style
, DATE_STYLE_IDS
);
1598 date_style
= (styleID
>= 0) ? DATE_STYLES
[styleID
] : DateFormat::kDefault
;
1601 fmt
= DateFormat::createDateInstance(date_style
, fLocale
);
1603 fmt
= DateFormat::createTimeInstance(date_style
, fLocale
);
1606 if (styleID
< 0 && fmt
!= NULL
) {
1607 SimpleDateFormat
* sdtfmt
= dynamic_cast<SimpleDateFormat
*>(fmt
);
1608 if (sdtfmt
!= NULL
) {
1609 sdtfmt
->applyPattern(style
);
1615 formattableType
= Formattable::kDouble
;
1616 fmt
= makeRBNF(URBNF_SPELLOUT
, fLocale
, style
, ec
);
1619 formattableType
= Formattable::kDouble
;
1620 fmt
= makeRBNF(URBNF_ORDINAL
, fLocale
, style
, ec
);
1623 formattableType
= Formattable::kDouble
;
1624 fmt
= makeRBNF(URBNF_DURATION
, fLocale
, style
, ec
);
1627 formattableType
= Formattable::kString
;
1628 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
1636 //-------------------------------------
1637 // Finds the string, s, in the string array, list.
1638 int32_t MessageFormat::findKeyword(const UnicodeString
& s
,
1639 const UChar
* const *list
)
1642 return 0; // default
1645 int32_t length
= s
.length();
1646 const UChar
*ps
= PatternProps::trimWhiteSpace(s
.getBuffer(), length
);
1647 UnicodeString
buffer(FALSE
, ps
, length
);
1648 // Trims the space characters and turns all characters
1649 // in s to lower case.
1651 for (int32_t i
= 0; list
[i
]; ++i
) {
1652 if (!buffer
.compare(list
[i
], u_strlen(list
[i
]))) {
1660 * Convenience method that ought to be in NumberFormat
1663 MessageFormat::createIntegerFormat(const Locale
& locale
, UErrorCode
& status
) const {
1664 NumberFormat
*temp
= NumberFormat::createInstance(locale
, status
);
1665 DecimalFormat
*temp2
;
1666 if (temp
!= NULL
&& (temp2
= dynamic_cast<DecimalFormat
*>(temp
)) != NULL
) {
1667 temp2
->setMaximumFractionDigits(0);
1668 temp2
->setDecimalSeparatorAlwaysShown(FALSE
);
1669 temp2
->setParseIntegerOnly(TRUE
);
1676 * Return the default number format. Used to format a numeric
1677 * argument when subformats[i].format is NULL. Returns NULL
1680 * Semantically const but may modify *this.
1682 const NumberFormat
* MessageFormat::getDefaultNumberFormat(UErrorCode
& ec
) const {
1683 if (defaultNumberFormat
== NULL
) {
1684 MessageFormat
* t
= (MessageFormat
*) this;
1685 t
->defaultNumberFormat
= NumberFormat::createInstance(fLocale
, ec
);
1686 if (U_FAILURE(ec
)) {
1687 delete t
->defaultNumberFormat
;
1688 t
->defaultNumberFormat
= NULL
;
1689 } else if (t
->defaultNumberFormat
== NULL
) {
1690 ec
= U_MEMORY_ALLOCATION_ERROR
;
1693 return defaultNumberFormat
;
1697 * Return the default date format. Used to format a date
1698 * argument when subformats[i].format is NULL. Returns NULL
1701 * Semantically const but may modify *this.
1703 const DateFormat
* MessageFormat::getDefaultDateFormat(UErrorCode
& ec
) const {
1704 if (defaultDateFormat
== NULL
) {
1705 MessageFormat
* t
= (MessageFormat
*) this;
1706 t
->defaultDateFormat
= DateFormat::createDateTimeInstance(DateFormat::kShort
, DateFormat::kShort
, fLocale
);
1707 if (t
->defaultDateFormat
== NULL
) {
1708 ec
= U_MEMORY_ALLOCATION_ERROR
;
1711 return defaultDateFormat
;
1715 MessageFormat::usesNamedArguments() const {
1716 return msgPattern
.hasNamedArguments();
1720 MessageFormat::getArgTypeCount() const {
1721 return argTypeCount
;
1724 UBool
MessageFormat::equalFormats(const void* left
, const void* right
) {
1725 return *(const Format
*)left
==*(const Format
*)right
;
1729 UBool
MessageFormat::DummyFormat::operator==(const Format
&) const {
1733 Format
* MessageFormat::DummyFormat::clone() const {
1734 return new DummyFormat();
1737 UnicodeString
& MessageFormat::DummyFormat::format(const Formattable
&,
1738 UnicodeString
& appendTo
,
1739 UErrorCode
& status
) const {
1740 if (U_SUCCESS(status
)) {
1741 status
= U_UNSUPPORTED_ERROR
;
1746 UnicodeString
& MessageFormat::DummyFormat::format(const Formattable
&,
1747 UnicodeString
& appendTo
,
1749 UErrorCode
& status
) const {
1750 if (U_SUCCESS(status
)) {
1751 status
= U_UNSUPPORTED_ERROR
;
1756 UnicodeString
& MessageFormat::DummyFormat::format(const Formattable
&,
1757 UnicodeString
& appendTo
,
1758 FieldPositionIterator
*,
1759 UErrorCode
& status
) const {
1760 if (U_SUCCESS(status
)) {
1761 status
= U_UNSUPPORTED_ERROR
;
1766 void MessageFormat::DummyFormat::parseObject(const UnicodeString
&,
1768 ParsePosition
& ) const {
1772 FormatNameEnumeration::FormatNameEnumeration(UVector
*fNameList
, UErrorCode
& /*status*/) {
1774 fFormatNames
= fNameList
;
1777 const UnicodeString
*
1778 FormatNameEnumeration::snext(UErrorCode
& status
) {
1779 if (U_SUCCESS(status
) && pos
< fFormatNames
->size()) {
1780 return (const UnicodeString
*)fFormatNames
->elementAt(pos
++);
1786 FormatNameEnumeration::reset(UErrorCode
& /*status*/) {
1791 FormatNameEnumeration::count(UErrorCode
& /*status*/) const {
1792 return (fFormatNames
==NULL
) ? 0 : fFormatNames
->size();
1795 FormatNameEnumeration::~FormatNameEnumeration() {
1796 delete fFormatNames
;
1800 MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const Locale
* loc
, UPluralType t
)
1801 : locale(loc
), rules(NULL
), type(t
) {
1804 MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
1805 // We own the rules but not the locale.
1809 UnicodeString
MessageFormat::PluralSelectorProvider::select(double number
, UErrorCode
& ec
) const {
1810 if (U_FAILURE(ec
)) {
1811 return UnicodeString(FALSE
, OTHER_STRING
, 5);
1813 MessageFormat::PluralSelectorProvider
* t
= const_cast<MessageFormat::PluralSelectorProvider
*>(this);
1815 t
->rules
= PluralRules::forLocale(*locale
, type
, ec
);
1816 if (U_FAILURE(ec
)) {
1817 return UnicodeString(FALSE
, OTHER_STRING
, 5);
1820 return rules
->select(number
);
1823 void MessageFormat::PluralSelectorProvider::reset(const Locale
* loc
) {
1832 #endif /* #if !UCONFIG_NO_FORMATTING */