1 /********************************************************************
3 * Copyright (c) 1997-2010, 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/msgfmt.h"
27 #include "unicode/decimfmt.h"
28 #include "unicode/datefmt.h"
29 #include "unicode/smpdtfmt.h"
30 #include "unicode/choicfmt.h"
31 #include "unicode/plurfmt.h"
32 #include "unicode/selfmt.h"
33 #include "unicode/ustring.h"
34 #include "unicode/ucnv_err.h"
35 #include "unicode/uchar.h"
36 #include "unicode/umsg.h"
37 #include "unicode/rbnf.h"
39 #include "msgfmt_impl.h"
45 // *****************************************************************************
46 // class MessageFormat
47 // *****************************************************************************
49 #define COMMA ((UChar)0x002C)
50 #define SINGLE_QUOTE ((UChar)0x0027)
51 #define LEFT_CURLY_BRACE ((UChar)0x007B)
52 #define RIGHT_CURLY_BRACE ((UChar)0x007D)
54 //---------------------------------------
57 static const UChar ID_EMPTY
[] = {
58 0 /* empty string, used for default so that null can mark end of list */
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_CHOICE
[] = {
71 0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0 /* "choice" */
73 static const UChar ID_SPELLOUT
[] = {
74 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
76 static const UChar ID_ORDINAL
[] = {
77 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
79 static const UChar ID_DURATION
[] = {
80 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
82 static const UChar ID_PLURAL
[] = {
83 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0 /* "plural" */
85 static const UChar ID_SELECT
[] = {
86 0x73, 0x65, 0x6C, 0x65, 0x63, 0x74, 0 /* "select" */
89 // MessageFormat Type List Number, Date, Time or Choice
90 static const UChar
* const TYPE_IDS
[] = {
104 static const UChar ID_CURRENCY
[] = {
105 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
107 static const UChar ID_PERCENT
[] = {
108 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
110 static const UChar ID_INTEGER
[] = {
111 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
114 // NumberFormat modifier list, default, currency, percent or integer
115 static const UChar
* const NUMBER_STYLE_IDS
[] = {
123 static const UChar ID_SHORT
[] = {
124 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
126 static const UChar ID_MEDIUM
[] = {
127 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
129 static const UChar ID_LONG
[] = {
130 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
132 static const UChar ID_FULL
[] = {
133 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
136 // DateFormat modifier list, default, short, medium, long or full
137 static const UChar
* const DATE_STYLE_IDS
[] = {
146 static const U_NAMESPACE_QUALIFIER
DateFormat::EStyle DATE_STYLES
[] = {
147 U_NAMESPACE_QUALIFIER
DateFormat::kDefault
,
148 U_NAMESPACE_QUALIFIER
DateFormat::kShort
,
149 U_NAMESPACE_QUALIFIER
DateFormat::kMedium
,
150 U_NAMESPACE_QUALIFIER
DateFormat::kLong
,
151 U_NAMESPACE_QUALIFIER
DateFormat::kFull
,
154 static const int32_t DEFAULT_INITIAL_CAPACITY
= 10;
158 // -------------------------------------
159 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat
)
160 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration
)
162 //--------------------------------------------------------------------
165 * Convert a string to an unsigned decimal, ignoring rule whitespace.
166 * @return a non-negative number if successful, or a negative number
169 static int32_t stou(const UnicodeString
& string
) {
173 for (int32_t i
=0; i
<string
.length(); i
+=U16_LENGTH(c
)) {
174 c
= string
.char32At(i
);
175 if (uprv_isRuleWhiteSpace(c
)) {
178 int32_t d
= u_digit(c
, 10);
179 if (d
< 0 || ++count
> 10) {
188 * Convert an integer value to a string and append the result to
189 * the given UnicodeString.
191 static UnicodeString
& itos(int32_t i
, UnicodeString
& appendTo
) {
193 uprv_itou(temp
,16,i
,10,0); // 10 == radix
194 appendTo
.append(temp
);
199 * A structure representing one subformat of this MessageFormat.
200 * Each subformat has a Format object, an offset into the plain
201 * pattern text fPattern, and an argument number. The argument
202 * number corresponds to the array of arguments to be formatted.
205 class MessageFormat::Subformat
: public UMemory
{
210 Format
* format
; // formatter
214 int32_t offset
; // offset into fPattern
218 // TODO (claireho) or save the number to argName and use itos to convert to number.=> we need this number
219 int32_t argNum
; // 0-based argument number
223 UnicodeString
* argName
; // argument name or number
226 * Clone that.format and assign it to this.format
227 * Do NOT delete this.format
230 Subformat
& operator=(const Subformat
& that
) {
232 format
= that
.format
? that
.format
->clone() : NULL
;
233 offset
= that
.offset
;
234 argNum
= that
.argNum
;
235 argName
= (that
.argNum
==-1) ? new UnicodeString(*that
.argName
): NULL
;
243 UBool
operator==(const Subformat
& that
) const {
244 // Do cheap comparisons first
245 return offset
== that
.offset
&&
246 argNum
== that
.argNum
&&
247 ((argName
== that
.argName
) ||
248 (*argName
== *that
.argName
)) &&
249 ((format
== that
.format
) || // handles NULL
250 (*format
== *that
.format
));
256 UBool
operator!=(const Subformat
& that
) const {
257 return !operator==(that
);
261 // -------------------------------------
262 // Creates a MessageFormat instance based on the pattern.
264 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
266 : fLocale(Locale::getDefault()), // Uses the default locale
268 formatAliasesCapacity(0),
269 idStart(UCHAR_ID_START
),
270 idContinue(UCHAR_ID_CONTINUE
),
273 subformatCapacity(0),
278 defaultNumberFormat(NULL
),
279 defaultDateFormat(NULL
)
281 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY
) ||
282 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY
)) {
283 success
= U_MEMORY_ALLOCATION_ERROR
;
286 applyPattern(pattern
, success
);
287 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
290 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
291 const Locale
& newLocale
,
293 : fLocale(newLocale
),
295 formatAliasesCapacity(0),
296 idStart(UCHAR_ID_START
),
297 idContinue(UCHAR_ID_CONTINUE
),
300 subformatCapacity(0),
305 defaultNumberFormat(NULL
),
306 defaultDateFormat(NULL
)
308 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY
) ||
309 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY
)) {
310 success
= U_MEMORY_ALLOCATION_ERROR
;
313 applyPattern(pattern
, success
);
314 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
317 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
318 const Locale
& newLocale
,
319 UParseError
& parseError
,
321 : fLocale(newLocale
),
323 formatAliasesCapacity(0),
324 idStart(UCHAR_ID_START
),
325 idContinue(UCHAR_ID_CONTINUE
),
328 subformatCapacity(0),
333 defaultNumberFormat(NULL
),
334 defaultDateFormat(NULL
)
336 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY
) ||
337 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY
)) {
338 success
= U_MEMORY_ALLOCATION_ERROR
;
341 applyPattern(pattern
, parseError
, success
);
342 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
345 MessageFormat::MessageFormat(const MessageFormat
& that
)
348 formatAliasesCapacity(0),
349 idStart(UCHAR_ID_START
),
350 idContinue(UCHAR_ID_CONTINUE
),
353 subformatCapacity(0),
358 defaultNumberFormat(NULL
),
359 defaultDateFormat(NULL
)
364 MessageFormat::~MessageFormat()
367 for (idx
= 0; idx
< subformatCount
; idx
++) {
368 delete subformats
[idx
].format
;
369 delete subformats
[idx
].argName
;
371 uprv_free(subformats
);
373 subformatCount
= subformatCapacity
= 0;
377 argTypeCount
= argTypeCapacity
= 0;
379 uprv_free(formatAliases
);
381 delete defaultNumberFormat
;
382 delete defaultDateFormat
;
385 //--------------------------------------------------------------------
386 // Variable-size array management
389 * Allocate subformats[] to at least the given capacity and return
390 * TRUE if successful. If not, leave subformats[] unchanged.
392 * If subformats is NULL, allocate it. If it is not NULL, enlarge it
393 * if necessary to be at least as large as specified.
395 UBool
MessageFormat::allocateSubformats(int32_t capacity
) {
396 if (subformats
== NULL
) {
397 subformats
= (Subformat
*) uprv_malloc(sizeof(*subformats
) * capacity
);
398 subformatCapacity
= capacity
;
400 if (subformats
== NULL
) {
401 subformatCapacity
= 0;
404 } else if (subformatCapacity
< capacity
) {
405 if (capacity
< 2*subformatCapacity
) {
406 capacity
= 2*subformatCapacity
;
408 Subformat
* a
= (Subformat
*)
409 uprv_realloc(subformats
, sizeof(*subformats
) * capacity
);
411 return FALSE
; // request failed
414 subformatCapacity
= capacity
;
420 * Allocate argTypes[] to at least the given capacity and return
421 * TRUE if successful. If not, leave argTypes[] unchanged.
423 * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
424 * if necessary to be at least as large as specified.
426 UBool
MessageFormat::allocateArgTypes(int32_t capacity
) {
427 if (argTypes
== NULL
) {
428 argTypes
= (Formattable::Type
*) uprv_malloc(sizeof(*argTypes
) * capacity
);
430 argTypeCapacity
= capacity
;
431 if (argTypes
== NULL
) {
435 for (int32_t i
=0; i
<capacity
; ++i
) {
436 argTypes
[i
] = Formattable::kString
;
438 } else if (argTypeCapacity
< capacity
) {
439 if (capacity
< 2*argTypeCapacity
) {
440 capacity
= 2*argTypeCapacity
;
442 Formattable::Type
* a
= (Formattable::Type
*)
443 uprv_realloc(argTypes
, sizeof(*argTypes
) * capacity
);
445 return FALSE
; // request failed
447 for (int32_t i
=argTypeCapacity
; i
<capacity
; ++i
) {
448 a
[i
] = Formattable::kString
;
451 argTypeCapacity
= capacity
;
456 // -------------------------------------
457 // assignment operator
460 MessageFormat::operator=(const MessageFormat
& that
)
462 // Reallocate the arrays BEFORE changing this object
464 allocateSubformats(that
.subformatCount
) &&
465 allocateArgTypes(that
.argTypeCount
)) {
467 // Calls the super class for assignment first.
468 Format::operator=(that
);
470 fPattern
= that
.fPattern
;
471 setLocale(that
.fLocale
);
472 isArgNumeric
= that
.isArgNumeric
;
474 for (j
=0; j
<subformatCount
; ++j
) {
475 delete subformats
[j
].format
;
479 for (j
=0; j
<that
.subformatCount
; ++j
) {
480 // Subformat::operator= does NOT delete this.format
481 subformats
[j
] = that
.subformats
[j
];
483 subformatCount
= that
.subformatCount
;
485 for (j
=0; j
<that
.argTypeCount
; ++j
) {
486 argTypes
[j
] = that
.argTypes
[j
];
488 argTypeCount
= that
.argTypeCount
;
494 MessageFormat::operator==(const Format
& rhs
) const
496 if (this == &rhs
) return TRUE
;
498 MessageFormat
& that
= (MessageFormat
&)rhs
;
500 // Check class ID before checking MessageFormat members
501 if (!Format::operator==(rhs
) ||
502 fPattern
!= that
.fPattern
||
503 fLocale
!= that
.fLocale
||
504 isArgNumeric
!= that
.isArgNumeric
) {
509 for (j
=0; j
<subformatCount
; ++j
) {
510 if (subformats
[j
] != that
.subformats
[j
]) {
518 // -------------------------------------
519 // Creates a copy of this MessageFormat, the caller owns the copy.
522 MessageFormat::clone() const
524 return new MessageFormat(*this);
527 // -------------------------------------
528 // Sets the locale of this MessageFormat object to theLocale.
531 MessageFormat::setLocale(const Locale
& theLocale
)
533 if (fLocale
!= theLocale
) {
534 delete defaultNumberFormat
;
535 defaultNumberFormat
= NULL
;
536 delete defaultDateFormat
;
537 defaultDateFormat
= NULL
;
540 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
543 // -------------------------------------
544 // Gets the locale of this MessageFormat object.
547 MessageFormat::getLocale() const
556 MessageFormat::applyPattern(const UnicodeString
& newPattern
,
559 UParseError parseError
;
560 applyPattern(newPattern
,parseError
,status
);
564 // -------------------------------------
565 // Applies the new pattern and returns an error if the pattern
568 MessageFormat::applyPattern(const UnicodeString
& pattern
,
569 UParseError
& parseError
,
575 // The pattern is broken up into segments. Each time a subformat
576 // is encountered, 4 segments are recorded. For example, consider
578 // "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}."
579 // The first set of segments is:
580 // segments[0] = "There "
582 // segments[2] = "choice"
583 // segments[3] = "0.0#are no files|1.0#is one file|1.0<are {0, number} files"
585 // During parsing, the plain text is accumulated into segments[0].
586 // Segments 1..3 are used to parse each subpattern. Each time a
587 // subpattern is parsed, it creates a format object that is stored
588 // in the subformats array, together with an offset and argument
589 // number. The offset into the plain text stored in
592 // Quotes in segment 0 are handled normally. They are removed.
593 // Quotes may not occur in segments 1 or 2.
594 // Quotes in segment 3 are parsed and _copied_. This makes
595 // subformat patterns work, e.g., {1,number,'#'.##} passes
596 // the pattern "'#'.##" to DecimalFormat.
598 UnicodeString segments
[4];
599 int32_t part
= 0; // segment we are in, 0..3
600 // Record the highest argument number in the pattern. (In the
601 // subpattern {3,number} the argument number is 3.)
602 int32_t formatNumber
= 0;
603 UBool inQuote
= FALSE
;
604 int32_t braceStack
= 0;
605 // Clear error struct
606 parseError
.offset
= -1;
607 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
608 int32_t patLen
= pattern
.length();
611 for (i
=0; i
<subformatCount
; ++i
) {
612 delete subformats
[i
].format
;
617 for (i
=0; i
<patLen
; ++i
) {
618 UChar ch
= pattern
[i
];
620 // In segment 0, recognize and remove quotes
621 if (ch
== SINGLE_QUOTE
) {
622 if (i
+1 < patLen
&& pattern
[i
+1] == SINGLE_QUOTE
) {
628 } else if (ch
== LEFT_CURLY_BRACE
&& !inQuote
) {
629 // The only way we get from segment 0 to 1 is via an
635 } else if (inQuote
) {
636 // In segments 1..3, recognize quoted matter, and copy it
637 // into the segment, together with the quotes. This takes
638 // care of '' as well.
639 segments
[part
] += ch
;
640 if (ch
== SINGLE_QUOTE
) {
644 // We have an unquoted character in segment 1..3
647 // Commas bump us to the next segment, except for segment 3,
648 // which can contain commas. See example above.
654 case LEFT_CURLY_BRACE
:
655 // Handle '{' within segment 3. The initial '{'
656 // before segment 1 is handled above.
658 ec
= U_PATTERN_SYNTAX_ERROR
;
662 segments
[part
] += ch
;
664 case RIGHT_CURLY_BRACE
:
665 if (braceStack
== 0) {
666 makeFormat(formatNumber
, segments
, parseError
,ec
);
672 segments
[1].remove();
673 segments
[2].remove();
674 segments
[3].remove();
678 segments
[part
] += ch
;
683 // fall through (copy quote chars in segments 1..3)
685 segments
[part
] += ch
;
690 if (braceStack
!= 0 || part
!= 0) {
691 // Unmatched braces in the pattern
692 ec
= U_UNMATCHED_BRACES
;
695 fPattern
= segments
[0];
699 syntaxError(pattern
, i
, parseError
);
700 for (i
=0; i
<subformatCount
; ++i
) {
701 delete subformats
[i
].format
;
703 argTypeCount
= subformatCount
= 0;
705 // -------------------------------------
706 // Converts this MessageFormat instance to a pattern.
709 MessageFormat::toPattern(UnicodeString
& appendTo
) const {
710 // later, make this more extensible
711 int32_t lastOffset
= 0;
713 for (i
=0; i
<subformatCount
; ++i
) {
714 copyAndFixQuotes(fPattern
, lastOffset
, subformats
[i
].offset
, appendTo
);
715 lastOffset
= subformats
[i
].offset
;
716 appendTo
+= LEFT_CURLY_BRACE
;
718 itos(subformats
[i
].argNum
, appendTo
);
721 appendTo
+= *subformats
[i
].argName
;
723 Format
* fmt
= subformats
[i
].format
;
724 DecimalFormat
* decfmt
;
725 SimpleDateFormat
* sdtfmt
;
726 ChoiceFormat
* chcfmt
;
728 SelectFormat
* selfmt
;
730 // do nothing, string format
732 else if ((decfmt
= dynamic_cast<DecimalFormat
*>(fmt
)) != NULL
) {
733 UErrorCode ec
= U_ZERO_ERROR
;
734 NumberFormat
& formatAlias
= *decfmt
;
735 NumberFormat
*defaultTemplate
= NumberFormat::createInstance(fLocale
, ec
);
736 NumberFormat
*currencyTemplate
= NumberFormat::createCurrencyInstance(fLocale
, ec
);
737 NumberFormat
*percentTemplate
= NumberFormat::createPercentInstance(fLocale
, ec
);
738 NumberFormat
*integerTemplate
= createIntegerFormat(fLocale
, ec
);
741 appendTo
+= ID_NUMBER
;
742 if (formatAlias
!= *defaultTemplate
) {
744 if (formatAlias
== *currencyTemplate
) {
745 appendTo
+= ID_CURRENCY
;
747 else if (formatAlias
== *percentTemplate
) {
748 appendTo
+= ID_PERCENT
;
750 else if (formatAlias
== *integerTemplate
) {
751 appendTo
+= ID_INTEGER
;
754 UnicodeString buffer
;
755 appendTo
+= decfmt
->toPattern(buffer
);
759 delete defaultTemplate
;
760 delete currencyTemplate
;
761 delete percentTemplate
;
762 delete integerTemplate
;
764 else if ((sdtfmt
= dynamic_cast<SimpleDateFormat
*>(fmt
)) != NULL
) {
765 DateFormat
& formatAlias
= *sdtfmt
;
766 DateFormat
*defaultDateTemplate
= DateFormat::createDateInstance(DateFormat::kDefault
, fLocale
);
767 DateFormat
*shortDateTemplate
= DateFormat::createDateInstance(DateFormat::kShort
, fLocale
);
768 DateFormat
*longDateTemplate
= DateFormat::createDateInstance(DateFormat::kLong
, fLocale
);
769 DateFormat
*fullDateTemplate
= DateFormat::createDateInstance(DateFormat::kFull
, fLocale
);
770 DateFormat
*defaultTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kDefault
, fLocale
);
771 DateFormat
*shortTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kShort
, fLocale
);
772 DateFormat
*longTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kLong
, fLocale
);
773 DateFormat
*fullTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kFull
, fLocale
);
777 if (formatAlias
== *defaultDateTemplate
) {
780 else if (formatAlias
== *shortDateTemplate
) {
783 appendTo
+= ID_SHORT
;
785 else if (formatAlias
== *defaultDateTemplate
) {
788 appendTo
+= ID_MEDIUM
;
790 else if (formatAlias
== *longDateTemplate
) {
795 else if (formatAlias
== *fullDateTemplate
) {
800 else if (formatAlias
== *defaultTimeTemplate
) {
803 else if (formatAlias
== *shortTimeTemplate
) {
806 appendTo
+= ID_SHORT
;
808 else if (formatAlias
== *defaultTimeTemplate
) {
811 appendTo
+= ID_MEDIUM
;
813 else if (formatAlias
== *longTimeTemplate
) {
818 else if (formatAlias
== *fullTimeTemplate
) {
824 UnicodeString buffer
;
827 appendTo
+= sdtfmt
->toPattern(buffer
);
830 delete defaultDateTemplate
;
831 delete shortDateTemplate
;
832 delete longDateTemplate
;
833 delete fullDateTemplate
;
834 delete defaultTimeTemplate
;
835 delete shortTimeTemplate
;
836 delete longTimeTemplate
;
837 delete fullTimeTemplate
;
838 // {sfb} there should be a more efficient way to do this!
840 else if ((chcfmt
= dynamic_cast<ChoiceFormat
*>(fmt
)) != NULL
) {
841 UnicodeString buffer
;
843 appendTo
+= ID_CHOICE
;
845 appendTo
+= ((ChoiceFormat
*)fmt
)->toPattern(buffer
);
847 else if ((plfmt
= dynamic_cast<PluralFormat
*>(fmt
)) != NULL
) {
848 UnicodeString buffer
;
849 appendTo
+= plfmt
->toPattern(buffer
);
851 else if ((selfmt
= dynamic_cast<SelectFormat
*>(fmt
)) != NULL
) {
852 UnicodeString buffer
;
853 appendTo
+= ((SelectFormat
*)fmt
)->toPattern(buffer
);
856 //appendTo += ", unknown";
858 appendTo
+= RIGHT_CURLY_BRACE
;
860 copyAndFixQuotes(fPattern
, lastOffset
, fPattern
.length(), appendTo
);
864 // -------------------------------------
865 // Adopts the new formats array and updates the array count.
866 // This MessageFormat instance owns the new formats.
869 MessageFormat::adoptFormats(Format
** newFormats
,
871 if (newFormats
== NULL
|| count
< 0) {
876 if (allocateSubformats(count
)) {
877 for (i
=0; i
<subformatCount
; ++i
) {
878 delete subformats
[i
].format
;
880 for (i
=0; i
<count
; ++i
) {
881 subformats
[i
].format
= newFormats
[i
];
883 subformatCount
= count
;
885 // An adopt method must always take ownership. Delete
886 // the incoming format objects and return unchanged.
887 for (i
=0; i
<count
; ++i
) {
888 delete newFormats
[i
];
892 // TODO: What about the .offset and .argNum fields?
895 // -------------------------------------
896 // Sets the new formats array and updates the array count.
897 // This MessageFormat instance maks a copy of the new formats.
900 MessageFormat::setFormats(const Format
** newFormats
,
902 if (newFormats
== NULL
|| count
< 0) {
906 if (allocateSubformats(count
)) {
908 for (i
=0; i
<subformatCount
; ++i
) {
909 delete subformats
[i
].format
;
913 for (i
=0; i
<count
; ++i
) {
914 subformats
[i
].format
= newFormats
[i
] ? newFormats
[i
]->clone() : NULL
;
916 subformatCount
= count
;
919 // TODO: What about the .offset and .arg fields?
922 // -------------------------------------
923 // Adopt a single format by format number.
924 // Do nothing if the format number is not less than the array count.
927 MessageFormat::adoptFormat(int32_t n
, Format
*newFormat
) {
928 if (n
< 0 || n
>= subformatCount
) {
931 delete subformats
[n
].format
;
932 subformats
[n
].format
= newFormat
;
936 // -------------------------------------
937 // Adopt a single format by format name.
938 // Do nothing if there is no match of formatName.
940 MessageFormat::adoptFormat(const UnicodeString
& formatName
,
941 Format
* formatToAdopt
,
942 UErrorCode
& status
) {
944 int32_t argumentNumber
= stou(formatName
);
945 if (argumentNumber
<0) {
946 status
= U_ARGUMENT_TYPE_MISMATCH
;
949 adoptFormat(argumentNumber
, formatToAdopt
);
952 for (int32_t i
=0; i
<subformatCount
; ++i
) {
953 if (formatName
==*subformats
[i
].argName
) {
954 delete subformats
[i
].format
;
955 if ( formatToAdopt
== NULL
) {
956 // This should never happen -- but we'll be nice if it does
957 subformats
[i
].format
= NULL
;
959 subformats
[i
].format
= formatToAdopt
;
965 // -------------------------------------
966 // Set a single format.
967 // Do nothing if the variable is not less than the array count.
970 MessageFormat::setFormat(int32_t n
, const Format
& newFormat
) {
971 if (n
>= 0 && n
< subformatCount
) {
972 delete subformats
[n
].format
;
973 if (&newFormat
== NULL
) {
974 // This should never happen -- but we'll be nice if it does
975 subformats
[n
].format
= NULL
;
977 subformats
[n
].format
= newFormat
.clone();
982 // -------------------------------------
983 // Get a single format by format name.
984 // Do nothing if the variable is not less than the array count.
986 MessageFormat::getFormat(const UnicodeString
& formatName
, UErrorCode
& status
) {
988 if (U_FAILURE(status
)) return NULL
;
991 int32_t argumentNumber
= stou(formatName
);
992 if (argumentNumber
<0) {
993 status
= U_ARGUMENT_TYPE_MISMATCH
;
996 if (argumentNumber
< 0 || argumentNumber
>= subformatCount
) {
997 return subformats
[argumentNumber
].format
;
1004 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1005 if (formatName
==*subformats
[i
].argName
)
1007 return subformats
[i
].format
;
1013 // -------------------------------------
1014 // Set a single format by format name
1015 // Do nothing if the variable is not less than the array count.
1017 MessageFormat::setFormat(const UnicodeString
& formatName
,
1018 const Format
& newFormat
,
1019 UErrorCode
& status
) {
1021 status
= U_ARGUMENT_TYPE_MISMATCH
;
1024 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1025 if (formatName
==*subformats
[i
].argName
)
1027 delete subformats
[i
].format
;
1028 if (&newFormat
== NULL
) {
1029 // This should never happen -- but we'll be nice if it does
1030 subformats
[i
].format
= NULL
;
1032 subformats
[i
].format
= newFormat
.clone();
1039 // -------------------------------------
1040 // Gets the format array.
1043 MessageFormat::getFormats(int32_t& cnt
) const
1045 // This old API returns an array (which we hold) of Format*
1046 // pointers. The array is valid up to the next call to any
1047 // method on this object. We construct and resize an array
1048 // on demand that contains aliases to the subformats[i].format
1050 MessageFormat
* t
= (MessageFormat
*) this;
1052 if (formatAliases
== NULL
) {
1053 t
->formatAliasesCapacity
= (subformatCount
<10) ? 10 : subformatCount
;
1054 Format
** a
= (Format
**)
1055 uprv_malloc(sizeof(Format
*) * formatAliasesCapacity
);
1059 t
->formatAliases
= a
;
1060 } else if (subformatCount
> formatAliasesCapacity
) {
1061 Format
** a
= (Format
**)
1062 uprv_realloc(formatAliases
, sizeof(Format
*) * subformatCount
);
1066 t
->formatAliases
= a
;
1067 t
->formatAliasesCapacity
= subformatCount
;
1069 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1070 t
->formatAliases
[i
] = subformats
[i
].format
;
1072 cnt
= subformatCount
;
1073 return (const Format
**)formatAliases
;
1078 MessageFormat::getFormatNames(UErrorCode
& status
) {
1079 if (U_FAILURE(status
)) return NULL
;
1082 status
= U_ARGUMENT_TYPE_MISMATCH
;
1085 UVector
*fFormatNames
= new UVector(status
);
1086 if (U_FAILURE(status
)) {
1087 status
= U_MEMORY_ALLOCATION_ERROR
;
1090 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1091 fFormatNames
->addElement(new UnicodeString(*subformats
[i
].argName
), status
);
1094 StringEnumeration
* nameEnumerator
= new FormatNameEnumeration(fFormatNames
, status
);
1095 return nameEnumerator
;
1098 // -------------------------------------
1099 // Formats the source Formattable array and copy into the result buffer.
1100 // Ignore the FieldPosition result for error checking.
1103 MessageFormat::format(const Formattable
* source
,
1105 UnicodeString
& appendTo
,
1106 FieldPosition
& ignore
,
1107 UErrorCode
& success
) const
1109 if (U_FAILURE(success
))
1112 return format(source
, cnt
, appendTo
, ignore
, 0, success
);
1115 // -------------------------------------
1116 // Internally creates a MessageFormat instance based on the
1117 // pattern and formats the arguments Formattable array and
1118 // copy into the appendTo buffer.
1121 MessageFormat::format( const UnicodeString
& pattern
,
1122 const Formattable
* arguments
,
1124 UnicodeString
& appendTo
,
1125 UErrorCode
& success
)
1127 MessageFormat
temp(pattern
, success
);
1128 FieldPosition
ignore(0);
1129 temp
.format(arguments
, cnt
, appendTo
, ignore
, success
);
1133 // -------------------------------------
1134 // Formats the source Formattable object and copy into the
1135 // appendTo buffer. The Formattable object must be an array
1136 // of Formattable instances, returns error otherwise.
1139 MessageFormat::format(const Formattable
& source
,
1140 UnicodeString
& appendTo
,
1141 FieldPosition
& ignore
,
1142 UErrorCode
& success
) const
1146 if (U_FAILURE(success
))
1148 if (source
.getType() != Formattable::kArray
) {
1149 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1152 const Formattable
* tmpPtr
= source
.getArray(cnt
);
1154 return format(tmpPtr
, cnt
, appendTo
, ignore
, 0, success
);
1159 MessageFormat::format(const UnicodeString
* argumentNames
,
1160 const Formattable
* arguments
,
1162 UnicodeString
& appendTo
,
1163 UErrorCode
& success
) const {
1164 FieldPosition
ignore(0);
1165 return format(arguments
, argumentNames
, count
, appendTo
, ignore
, 0, success
);
1169 MessageFormat::format(const Formattable
* arguments
,
1171 UnicodeString
& appendTo
,
1172 FieldPosition
& status
,
1173 int32_t recursionProtection
,
1174 UErrorCode
& success
) const
1176 return format(arguments
, NULL
, cnt
, appendTo
, status
, recursionProtection
, success
);
1179 // -------------------------------------
1180 // Formats the arguments Formattable array and copy into the appendTo buffer.
1181 // Ignore the FieldPosition result for error checking.
1184 MessageFormat::format(const Formattable
* arguments
,
1185 const UnicodeString
*argumentNames
,
1187 UnicodeString
& appendTo
,
1188 FieldPosition
& status
,
1189 int32_t recursionProtection
,
1190 UErrorCode
& success
) const
1192 int32_t lastOffset
= 0;
1193 int32_t argumentNumber
=0;
1194 if (cnt
< 0 || (cnt
&& arguments
== NULL
)) {
1195 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1199 if ( !isArgNumeric
&& argumentNames
== NULL
) {
1200 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1204 const Formattable
*obj
=NULL
;
1205 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1206 // Append the prefix of current format element.
1207 appendTo
.append(fPattern
, lastOffset
, subformats
[i
].offset
- lastOffset
);
1208 lastOffset
= subformats
[i
].offset
;
1211 argumentNumber
= subformats
[i
].argNum
;
1213 // Checks the scope of the argument number.
1214 if (argumentNumber
>= cnt
) {
1215 appendTo
+= LEFT_CURLY_BRACE
;
1216 itos(argumentNumber
, appendTo
);
1217 appendTo
+= RIGHT_CURLY_BRACE
;
1220 obj
= arguments
+argumentNumber
;
1223 for (int32_t j
=0; j
<cnt
; ++j
) {
1224 if (argumentNames
[j
]== *subformats
[i
].argName
) {
1230 appendTo
+= LEFT_CURLY_BRACE
;
1231 appendTo
+= *subformats
[i
].argName
;
1232 appendTo
+= RIGHT_CURLY_BRACE
;
1237 Formattable::Type type
= obj
->getType();
1239 // Recursively calling the format process only if the current
1240 // format argument refers to either of the following:
1241 // a ChoiceFormat object, a PluralFormat object, a SelectFormat object.
1242 Format
* fmt
= subformats
[i
].format
;
1244 UnicodeString argNum
;
1245 fmt
->format(*obj
, argNum
, success
);
1247 // Needs to reprocess the ChoiceFormat and PluralFormat and SelectFormat option by using the
1248 // MessageFormat pattern application.
1249 if ((dynamic_cast<ChoiceFormat
*>(fmt
) != NULL
||
1250 dynamic_cast<PluralFormat
*>(fmt
) != NULL
||
1251 dynamic_cast<SelectFormat
*>(fmt
) != NULL
) &&
1252 argNum
.indexOf(LEFT_CURLY_BRACE
) >= 0
1254 MessageFormat
temp(argNum
, fLocale
, success
);
1255 // TODO: Implement recursion protection
1256 if ( isArgNumeric
) {
1257 temp
.format(arguments
, NULL
, cnt
, appendTo
, status
, recursionProtection
, success
);
1260 temp
.format(arguments
, argumentNames
, cnt
, appendTo
, status
, recursionProtection
, success
);
1262 if (U_FAILURE(success
)) {
1270 // If the obj data type is a number, use a NumberFormat instance.
1271 else if ((type
== Formattable::kDouble
) ||
1272 (type
== Formattable::kLong
) ||
1273 (type
== Formattable::kInt64
)) {
1275 const NumberFormat
* nf
= getDefaultNumberFormat(success
);
1279 if (type
== Formattable::kDouble
) {
1280 nf
->format(obj
->getDouble(), appendTo
);
1281 } else if (type
== Formattable::kLong
) {
1282 nf
->format(obj
->getLong(), appendTo
);
1284 nf
->format(obj
->getInt64(), appendTo
);
1287 // If the obj data type is a Date instance, use a DateFormat instance.
1288 else if (type
== Formattable::kDate
) {
1289 const DateFormat
* df
= getDefaultDateFormat(success
);
1293 df
->format(obj
->getDate(), appendTo
);
1295 else if (type
== Formattable::kString
) {
1296 appendTo
+= obj
->getString();
1299 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1303 // Appends the rest of the pattern characters after the real last offset.
1304 appendTo
.append(fPattern
, lastOffset
, 0x7fffffff);
1309 // -------------------------------------
1310 // Parses the source pattern and returns the Formattable objects array,
1311 // the array count and the ending parse position. The caller of this method
1315 MessageFormat::parse(const UnicodeString
& source
,
1317 int32_t& count
) const
1319 // Allocate at least one element. Allocating an array of length
1320 // zero causes problems on some platforms (e.g. Win32).
1321 Formattable
*resultArray
= new Formattable
[argTypeCount
? argTypeCount
: 1];
1322 int32_t patternOffset
= 0;
1323 int32_t sourceOffset
= pos
.getIndex();
1324 ParsePosition
tempPos(0);
1325 count
= 0; // {sfb} reset to zero
1327 // If resultArray could not be created, exit out.
1328 // Avoid crossing initialization of variables above.
1329 if (resultArray
== NULL
) {
1332 for (int32_t i
= 0; i
< subformatCount
; ++i
) {
1333 // match up to format
1334 len
= subformats
[i
].offset
- patternOffset
;
1336 fPattern
.compare(patternOffset
, len
, source
, sourceOffset
, len
) == 0) {
1337 sourceOffset
+= len
;
1338 patternOffset
+= len
;
1345 Format
* fmt
= subformats
[i
].format
;
1346 int32_t argNum
= subformats
[i
].argNum
;
1347 if (fmt
== NULL
) { // string format
1348 // if at end, use longest possible match
1349 // otherwise uses first match to intervening string
1350 // does NOT recursively try all possibilities
1351 int32_t tempLength
= (i
+1<subformatCount
) ?
1352 subformats
[i
+1].offset
: fPattern
.length();
1355 if (patternOffset
>= tempLength
) {
1356 next
= source
.length();
1359 UnicodeString buffer
;
1360 fPattern
.extract(patternOffset
,tempLength
- patternOffset
, buffer
);
1361 next
= source
.indexOf(buffer
, sourceOffset
);
1368 UnicodeString buffer
;
1369 source
.extract(sourceOffset
,next
- sourceOffset
, buffer
);
1370 UnicodeString strValue
= buffer
;
1371 UnicodeString
temp(LEFT_CURLY_BRACE
);
1372 // {sfb} check this later
1377 temp
+=(*subformats
[i
].argName
);
1379 temp
+= RIGHT_CURLY_BRACE
;
1380 if (strValue
!= temp
) {
1381 source
.extract(sourceOffset
,next
- sourceOffset
, buffer
);
1382 resultArray
[argNum
].setString(buffer
);
1383 // {sfb} not sure about this
1384 if ((argNum
+ 1) > count
) {
1388 sourceOffset
= next
;
1392 tempPos
.setIndex(sourceOffset
);
1393 fmt
->parseObject(source
, resultArray
[argNum
], tempPos
);
1394 if (tempPos
.getIndex() == sourceOffset
) {
1398 if ((argNum
+ 1) > count
) {
1401 sourceOffset
= tempPos
.getIndex(); // update
1404 len
= fPattern
.length() - patternOffset
;
1406 fPattern
.compare(patternOffset
, len
, source
, sourceOffset
, len
) == 0) {
1407 pos
.setIndex(sourceOffset
+ len
);
1410 // else fall through...
1413 pos
.setErrorIndex(sourceOffset
);
1414 delete [] resultArray
;
1416 return NULL
; // leave index as is to signal error
1419 // -------------------------------------
1420 // Parses the source string and returns the array of
1421 // Formattable objects and the array count. The caller
1422 // owns the returned array.
1425 MessageFormat::parse(const UnicodeString
& source
,
1427 UErrorCode
& success
) const
1429 if (!isArgNumeric
) {
1430 success
= U_ARGUMENT_TYPE_MISMATCH
;
1433 ParsePosition
status(0);
1434 // Calls the actual implementation method and starts
1435 // from zero offset of the source text.
1436 Formattable
* result
= parse(source
, status
, cnt
);
1437 if (status
.getIndex() == 0) {
1438 success
= U_MESSAGE_PARSE_ERROR
;
1445 // -------------------------------------
1446 // Parses the source text and copy into the result buffer.
1449 MessageFormat::parseObject( const UnicodeString
& source
,
1450 Formattable
& result
,
1451 ParsePosition
& status
) const
1454 Formattable
* tmpResult
= parse(source
, status
, cnt
);
1455 if (tmpResult
!= NULL
)
1456 result
.adoptArray(tmpResult
, cnt
);
1460 MessageFormat::autoQuoteApostrophe(const UnicodeString
& pattern
, UErrorCode
& status
) {
1461 UnicodeString result
;
1462 if (U_SUCCESS(status
)) {
1463 int32_t plen
= pattern
.length();
1464 const UChar
* pat
= pattern
.getBuffer();
1465 int32_t blen
= plen
* 2 + 1; // space for null termination, convenience
1466 UChar
* buf
= result
.getBuffer(blen
);
1468 status
= U_MEMORY_ALLOCATION_ERROR
;
1470 int32_t len
= umsg_autoQuoteApostrophe(pat
, plen
, buf
, blen
, &status
);
1471 result
.releaseBuffer(U_SUCCESS(status
) ? len
: 0);
1474 if (U_FAILURE(status
)) {
1475 result
.setToBogus();
1480 // -------------------------------------
1482 static Format
* makeRBNF(URBNFRuleSetTag tag
, const Locale
& locale
, const UnicodeString
& defaultRuleSet
, UErrorCode
& ec
) {
1483 RuleBasedNumberFormat
* fmt
= new RuleBasedNumberFormat(tag
, locale
, ec
);
1485 ec
= U_MEMORY_ALLOCATION_ERROR
;
1486 } else if (U_SUCCESS(ec
) && defaultRuleSet
.length() > 0) {
1487 UErrorCode localStatus
= U_ZERO_ERROR
; // ignore unrecognized default rule set
1488 fmt
->setDefaultRuleSet(defaultRuleSet
, localStatus
);
1494 * Reads the segments[] array (see applyPattern()) and parses the
1495 * segments[1..3] into a Format* object. Stores the format object in
1496 * the subformats[] array. Updates the argTypes[] array type
1497 * information for the corresponding argument.
1499 * @param formatNumber index into subformats[] for this format
1500 * @param segments array of strings with the parsed pattern segments
1501 * @param parseError parse error data (output param)
1502 * @param ec error code
1505 MessageFormat::makeFormat(int32_t formatNumber
,
1506 UnicodeString
* segments
,
1507 UParseError
& parseError
,
1509 if (U_FAILURE(ec
)) {
1513 // Parse the argument number
1514 int32_t argumentNumber
= stou(segments
[1]); // always unlocalized!
1515 UnicodeString argumentName
;
1516 if (argumentNumber
< 0) {
1517 if ( (isArgNumeric
==TRUE
) && (formatNumber
!=0) ) {
1518 ec
= U_INVALID_FORMAT_ERROR
;
1521 isArgNumeric
= FALSE
;
1522 argumentNumber
=formatNumber
;
1524 if (!isArgNumeric
) {
1525 if ( !isLegalArgName(segments
[1]) ) {
1526 ec
= U_INVALID_FORMAT_ERROR
;
1529 argumentName
= segments
[1];
1532 // Parse the format, recording the argument type and creating a
1533 // new Format object (except for string arguments).
1534 Formattable::Type argType
;
1536 int32_t typeID
, styleID
;
1537 DateFormat::EStyle style
;
1538 UnicodeString unquotedPattern
, quotedPattern
;
1539 UBool inQuote
= FALSE
;
1541 switch (typeID
= findKeyword(segments
[2], TYPE_IDS
)) {
1544 argType
= Formattable::kString
;
1548 argType
= Formattable::kDouble
;
1550 switch (findKeyword(segments
[3], NUMBER_STYLE_IDS
)) {
1552 fmt
= NumberFormat::createInstance(fLocale
, ec
);
1555 fmt
= NumberFormat::createCurrencyInstance(fLocale
, ec
);
1558 fmt
= NumberFormat::createPercentInstance(fLocale
, ec
);
1561 argType
= Formattable::kLong
;
1562 fmt
= createIntegerFormat(fLocale
, ec
);
1565 fmt
= NumberFormat::createInstance(fLocale
, ec
);
1567 DecimalFormat
* decfmt
= dynamic_cast<DecimalFormat
*>(fmt
);
1568 if (decfmt
!= NULL
) {
1569 decfmt
->applyPattern(segments
[3],parseError
,ec
);
1578 argType
= Formattable::kDate
;
1579 styleID
= findKeyword(segments
[3], DATE_STYLE_IDS
);
1580 style
= (styleID
>= 0) ? DATE_STYLES
[styleID
] : DateFormat::kDefault
;
1583 fmt
= DateFormat::createDateInstance(style
, fLocale
);
1585 fmt
= DateFormat::createTimeInstance(style
, fLocale
);
1588 if (styleID
< 0 && fmt
!= NULL
) {
1589 SimpleDateFormat
* sdtfmt
= dynamic_cast<SimpleDateFormat
*>(fmt
);
1590 if (sdtfmt
!= NULL
) {
1591 sdtfmt
->applyPattern(segments
[3]);
1597 argType
= Formattable::kDouble
;
1599 fmt
= new ChoiceFormat(segments
[3], parseError
, ec
);
1603 argType
= Formattable::kDouble
;
1604 fmt
= makeRBNF(URBNF_SPELLOUT
, fLocale
, segments
[3], ec
);
1607 argType
= Formattable::kDouble
;
1608 fmt
= makeRBNF(URBNF_ORDINAL
, fLocale
, segments
[3], ec
);
1611 argType
= Formattable::kDouble
;
1612 fmt
= makeRBNF(URBNF_DURATION
, fLocale
, segments
[3], ec
);
1617 argType
= Formattable::kDouble
;
1619 argType
= Formattable::kString
;
1620 quotedPattern
= segments
[3];
1621 for (int32_t i
= 0; i
< quotedPattern
.length(); ++i
) {
1622 UChar ch
= quotedPattern
.charAt(i
);
1623 if (ch
== SINGLE_QUOTE
) {
1624 if (i
+1 < quotedPattern
.length() && quotedPattern
.charAt(i
+1)==SINGLE_QUOTE
) {
1625 unquotedPattern
+=ch
;
1633 unquotedPattern
+= ch
;
1637 fmt
= new PluralFormat(fLocale
, unquotedPattern
, ec
);
1639 fmt
= new SelectFormat(unquotedPattern
, ec
);
1642 argType
= Formattable::kString
;
1643 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
1647 if (fmt
==NULL
&& argType
!=Formattable::kString
&& U_SUCCESS(ec
)) {
1648 ec
= U_MEMORY_ALLOCATION_ERROR
;
1651 if (!allocateSubformats(formatNumber
+1) ||
1652 !allocateArgTypes(argumentNumber
+1)) {
1653 ec
= U_MEMORY_ALLOCATION_ERROR
;
1656 if (U_FAILURE(ec
)) {
1661 // Parse succeeded; record results in our arrays
1662 subformats
[formatNumber
].format
= fmt
;
1663 subformats
[formatNumber
].offset
= segments
[0].length();
1665 subformats
[formatNumber
].argName
= NULL
;
1666 subformats
[formatNumber
].argNum
= argumentNumber
;
1669 subformats
[formatNumber
].argName
= new UnicodeString(argumentName
);
1670 subformats
[formatNumber
].argNum
= -1;
1672 subformatCount
= formatNumber
+1;
1674 // Careful here: argumentNumber may in general arrive out of
1675 // sequence, e.g., "There was {2} on {0,date} (see {1,number})."
1676 argTypes
[argumentNumber
] = argType
;
1677 if (argumentNumber
+1 > argTypeCount
) {
1678 argTypeCount
= argumentNumber
+1;
1682 // -------------------------------------
1683 // Finds the string, s, in the string array, list.
1684 int32_t MessageFormat::findKeyword(const UnicodeString
& s
,
1685 const UChar
* const *list
)
1687 if (s
.length() == 0)
1688 return 0; // default
1690 UnicodeString buffer
= s
;
1691 // Trims the space characters and turns all characters
1692 // in s to lower case.
1693 buffer
.trim().toLower("");
1694 for (int32_t i
= 0; list
[i
]; ++i
) {
1695 if (!buffer
.compare(list
[i
], u_strlen(list
[i
]))) {
1702 // -------------------------------------
1703 // Checks the range of the source text to quote the special
1704 // characters, { and ' and copy to target buffer.
1707 MessageFormat::copyAndFixQuotes(const UnicodeString
& source
,
1710 UnicodeString
& appendTo
)
1712 UBool gotLB
= FALSE
;
1714 for (int32_t i
= start
; i
< end
; ++i
) {
1715 UChar ch
= source
[i
];
1716 if (ch
== LEFT_CURLY_BRACE
) {
1717 appendTo
+= SINGLE_QUOTE
;
1718 appendTo
+= LEFT_CURLY_BRACE
;
1719 appendTo
+= SINGLE_QUOTE
;
1722 else if (ch
== RIGHT_CURLY_BRACE
) {
1724 appendTo
+= RIGHT_CURLY_BRACE
;
1729 appendTo
+= SINGLE_QUOTE
;
1730 appendTo
+= RIGHT_CURLY_BRACE
;
1731 appendTo
+= SINGLE_QUOTE
;
1734 else if (ch
== SINGLE_QUOTE
) {
1735 appendTo
+= SINGLE_QUOTE
;
1736 appendTo
+= SINGLE_QUOTE
;
1745 * Convenience method that ought to be in NumberFormat
1748 MessageFormat::createIntegerFormat(const Locale
& locale
, UErrorCode
& status
) const {
1749 NumberFormat
*temp
= NumberFormat::createInstance(locale
, status
);
1750 DecimalFormat
*temp2
;
1751 if (temp
!= NULL
&& (temp2
= dynamic_cast<DecimalFormat
*>(temp
)) != NULL
) {
1752 temp2
->setMaximumFractionDigits(0);
1753 temp2
->setDecimalSeparatorAlwaysShown(FALSE
);
1754 temp2
->setParseIntegerOnly(TRUE
);
1761 * Return the default number format. Used to format a numeric
1762 * argument when subformats[i].format is NULL. Returns NULL
1765 * Semantically const but may modify *this.
1767 const NumberFormat
* MessageFormat::getDefaultNumberFormat(UErrorCode
& ec
) const {
1768 if (defaultNumberFormat
== NULL
) {
1769 MessageFormat
* t
= (MessageFormat
*) this;
1770 t
->defaultNumberFormat
= NumberFormat::createInstance(fLocale
, ec
);
1771 if (U_FAILURE(ec
)) {
1772 delete t
->defaultNumberFormat
;
1773 t
->defaultNumberFormat
= NULL
;
1774 } else if (t
->defaultNumberFormat
== NULL
) {
1775 ec
= U_MEMORY_ALLOCATION_ERROR
;
1778 return defaultNumberFormat
;
1782 * Return the default date format. Used to format a date
1783 * argument when subformats[i].format is NULL. Returns NULL
1786 * Semantically const but may modify *this.
1788 const DateFormat
* MessageFormat::getDefaultDateFormat(UErrorCode
& ec
) const {
1789 if (defaultDateFormat
== NULL
) {
1790 MessageFormat
* t
= (MessageFormat
*) this;
1791 t
->defaultDateFormat
= DateFormat::createDateTimeInstance(DateFormat::kShort
, DateFormat::kShort
, fLocale
);
1792 if (t
->defaultDateFormat
== NULL
) {
1793 ec
= U_MEMORY_ALLOCATION_ERROR
;
1796 return defaultDateFormat
;
1800 MessageFormat::usesNamedArguments() const {
1801 return !isArgNumeric
;
1805 MessageFormat::isLegalArgName(const UnicodeString
& argName
) const {
1806 if(!u_hasBinaryProperty(argName
.charAt(0), idStart
)) {
1809 for (int32_t i
=1; i
<argName
.length(); ++i
) {
1810 if(!u_hasBinaryProperty(argName
.charAt(i
), idContinue
)) {
1818 MessageFormat::getArgTypeCount() const {
1819 return argTypeCount
;
1822 FormatNameEnumeration::FormatNameEnumeration(UVector
*fNameList
, UErrorCode
& /*status*/) {
1824 fFormatNames
= fNameList
;
1827 const UnicodeString
*
1828 FormatNameEnumeration::snext(UErrorCode
& status
) {
1829 if (U_SUCCESS(status
) && pos
< fFormatNames
->size()) {
1830 return (const UnicodeString
*)fFormatNames
->elementAt(pos
++);
1836 FormatNameEnumeration::reset(UErrorCode
& /*status*/) {
1841 FormatNameEnumeration::count(UErrorCode
& /*status*/) const {
1842 return (fFormatNames
==NULL
) ? 0 : fFormatNames
->size();
1845 FormatNameEnumeration::~FormatNameEnumeration() {
1847 for (int32_t i
=0; i
<fFormatNames
->size(); ++i
) {
1848 if ((s
=(UnicodeString
*)fFormatNames
->elementAt(i
))!=NULL
) {
1852 delete fFormatNames
;
1856 #endif /* #if !UCONFIG_NO_FORMATTING */