2 *******************************************************************************
3 * Copyright (C) 2007-2008, 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 ********************************************************************************
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/ustring.h"
33 #include "unicode/ucnv_err.h"
34 #include "unicode/uchar.h"
35 #include "unicode/umsg.h"
36 #include "unicode/rbnf.h"
38 #include "msgfmt_impl.h"
44 // *****************************************************************************
45 // class MessageFormat
46 // *****************************************************************************
48 #define COMMA ((UChar)0x002C)
49 #define SINGLE_QUOTE ((UChar)0x0027)
50 #define LEFT_CURLY_BRACE ((UChar)0x007B)
51 #define RIGHT_CURLY_BRACE ((UChar)0x007D)
53 //---------------------------------------
56 static const UChar ID_EMPTY
[] = {
57 0 /* empty string, used for default so that null can mark end of list */
60 static const UChar ID_NUMBER
[] = {
61 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
63 static const UChar ID_DATE
[] = {
64 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
66 static const UChar ID_TIME
[] = {
67 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
69 static const UChar ID_CHOICE
[] = {
70 0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0 /* "choice" */
72 static const UChar ID_SPELLOUT
[] = {
73 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
75 static const UChar ID_ORDINAL
[] = {
76 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
78 static const UChar ID_DURATION
[] = {
79 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
81 static const UChar ID_PLURAL
[] = {
82 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0 /* "plural" */
85 // MessageFormat Type List Number, Date, Time or Choice
86 static const UChar
* const TYPE_IDS
[] = {
99 static const UChar ID_CURRENCY
[] = {
100 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
102 static const UChar ID_PERCENT
[] = {
103 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
105 static const UChar ID_INTEGER
[] = {
106 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
109 // NumberFormat modifier list, default, currency, percent or integer
110 static const UChar
* const NUMBER_STYLE_IDS
[] = {
118 static const UChar ID_SHORT
[] = {
119 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
121 static const UChar ID_MEDIUM
[] = {
122 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
124 static const UChar ID_LONG
[] = {
125 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
127 static const UChar ID_FULL
[] = {
128 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
131 // DateFormat modifier list, default, short, medium, long or full
132 static const UChar
* const DATE_STYLE_IDS
[] = {
141 static const U_NAMESPACE_QUALIFIER
DateFormat::EStyle DATE_STYLES
[] = {
142 U_NAMESPACE_QUALIFIER
DateFormat::kDefault
,
143 U_NAMESPACE_QUALIFIER
DateFormat::kShort
,
144 U_NAMESPACE_QUALIFIER
DateFormat::kMedium
,
145 U_NAMESPACE_QUALIFIER
DateFormat::kLong
,
146 U_NAMESPACE_QUALIFIER
DateFormat::kFull
,
149 static const int32_t DEFAULT_INITIAL_CAPACITY
= 10;
153 // -------------------------------------
154 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat
)
155 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration
)
157 //--------------------------------------------------------------------
160 * Convert a string to an unsigned decimal, ignoring rule whitespace.
161 * @return a non-negative number if successful, or a negative number
164 static int32_t stou(const UnicodeString
& string
) {
168 for (int32_t i
=0; i
<string
.length(); i
+=U16_LENGTH(c
)) {
169 c
= string
.char32At(i
);
170 if (uprv_isRuleWhiteSpace(c
)) {
173 int32_t d
= u_digit(c
, 10);
174 if (d
< 0 || ++count
> 10) {
183 * Convert an integer value to a string and append the result to
184 * the given UnicodeString.
186 static UnicodeString
& itos(int32_t i
, UnicodeString
& appendTo
) {
188 uprv_itou(temp
,16,i
,10,0); // 10 == radix
189 appendTo
.append(temp
);
194 * A structure representing one subformat of this MessageFormat.
195 * Each subformat has a Format object, an offset into the plain
196 * pattern text fPattern, and an argument number. The argument
197 * number corresponds to the array of arguments to be formatted.
200 class MessageFormat::Subformat
: public UMemory
{
205 Format
* format
; // formatter
209 int32_t offset
; // offset into fPattern
213 // TODO (claireho) or save the number to argName and use itos to convert to number.=> we need this number
214 int32_t argNum
; // 0-based argument number
218 UnicodeString
* argName
; // argument name or number
221 * Clone that.format and assign it to this.format
222 * Do NOT delete this.format
225 Subformat
& operator=(const Subformat
& that
) {
227 format
= that
.format
? that
.format
->clone() : NULL
;
228 offset
= that
.offset
;
229 argNum
= that
.argNum
;
230 argName
= (that
.argNum
==-1) ? new UnicodeString(*that
.argName
): NULL
;
238 UBool
operator==(const Subformat
& that
) const {
239 // Do cheap comparisons first
240 return offset
== that
.offset
&&
241 argNum
== that
.argNum
&&
242 ((argName
== that
.argName
) ||
243 (*argName
== *that
.argName
)) &&
244 ((format
== that
.format
) || // handles NULL
245 (*format
== *that
.format
));
251 UBool
operator!=(const Subformat
& that
) const {
252 return !operator==(that
);
256 // -------------------------------------
257 // Creates a MessageFormat instance based on the pattern.
259 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
261 : fLocale(Locale::getDefault()), // Uses the default locale
263 formatAliasesCapacity(0),
264 idStart(UCHAR_ID_START
),
265 idContinue(UCHAR_ID_CONTINUE
),
268 subformatCapacity(0),
273 defaultNumberFormat(NULL
),
274 defaultDateFormat(NULL
)
276 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY
) ||
277 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY
)) {
278 success
= U_MEMORY_ALLOCATION_ERROR
;
281 applyPattern(pattern
, success
);
282 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
285 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
286 const Locale
& newLocale
,
288 : fLocale(newLocale
),
290 formatAliasesCapacity(0),
291 idStart(UCHAR_ID_START
),
292 idContinue(UCHAR_ID_CONTINUE
),
295 subformatCapacity(0),
300 defaultNumberFormat(NULL
),
301 defaultDateFormat(NULL
)
303 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY
) ||
304 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY
)) {
305 success
= U_MEMORY_ALLOCATION_ERROR
;
308 applyPattern(pattern
, success
);
309 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
312 MessageFormat::MessageFormat(const UnicodeString
& pattern
,
313 const Locale
& newLocale
,
314 UParseError
& parseError
,
316 : fLocale(newLocale
),
318 formatAliasesCapacity(0),
319 idStart(UCHAR_ID_START
),
320 idContinue(UCHAR_ID_CONTINUE
),
323 subformatCapacity(0),
328 defaultNumberFormat(NULL
),
329 defaultDateFormat(NULL
)
331 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY
) ||
332 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY
)) {
333 success
= U_MEMORY_ALLOCATION_ERROR
;
336 applyPattern(pattern
, parseError
, success
);
337 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
340 MessageFormat::MessageFormat(const MessageFormat
& that
)
343 formatAliasesCapacity(0),
344 idStart(UCHAR_ID_START
),
345 idContinue(UCHAR_ID_CONTINUE
),
348 subformatCapacity(0),
353 defaultNumberFormat(NULL
),
354 defaultDateFormat(NULL
)
359 MessageFormat::~MessageFormat()
362 for (idx
= 0; idx
< subformatCount
; idx
++) {
363 delete subformats
[idx
].format
;
364 delete subformats
[idx
].argName
;
366 uprv_free(subformats
);
368 subformatCount
= subformatCapacity
= 0;
372 argTypeCount
= argTypeCapacity
= 0;
374 uprv_free(formatAliases
);
376 delete defaultNumberFormat
;
377 delete defaultDateFormat
;
380 //--------------------------------------------------------------------
381 // Variable-size array management
384 * Allocate subformats[] to at least the given capacity and return
385 * TRUE if successful. If not, leave subformats[] unchanged.
387 * If subformats is NULL, allocate it. If it is not NULL, enlarge it
388 * if necessary to be at least as large as specified.
390 UBool
MessageFormat::allocateSubformats(int32_t capacity
) {
391 if (subformats
== NULL
) {
392 subformats
= (Subformat
*) uprv_malloc(sizeof(*subformats
) * capacity
);
393 subformatCapacity
= capacity
;
395 if (subformats
== NULL
) {
396 subformatCapacity
= 0;
399 } else if (subformatCapacity
< capacity
) {
400 if (capacity
< 2*subformatCapacity
) {
401 capacity
= 2*subformatCapacity
;
403 Subformat
* a
= (Subformat
*)
404 uprv_realloc(subformats
, sizeof(*subformats
) * capacity
);
406 return FALSE
; // request failed
409 subformatCapacity
= capacity
;
415 * Allocate argTypes[] to at least the given capacity and return
416 * TRUE if successful. If not, leave argTypes[] unchanged.
418 * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
419 * if necessary to be at least as large as specified.
421 UBool
MessageFormat::allocateArgTypes(int32_t capacity
) {
422 if (argTypes
== NULL
) {
423 argTypes
= (Formattable::Type
*) uprv_malloc(sizeof(*argTypes
) * capacity
);
425 argTypeCapacity
= capacity
;
426 if (argTypes
== NULL
) {
430 for (int32_t i
=0; i
<capacity
; ++i
) {
431 argTypes
[i
] = Formattable::kString
;
433 } else if (argTypeCapacity
< capacity
) {
434 if (capacity
< 2*argTypeCapacity
) {
435 capacity
= 2*argTypeCapacity
;
437 Formattable::Type
* a
= (Formattable::Type
*)
438 uprv_realloc(argTypes
, sizeof(*argTypes
) * capacity
);
440 return FALSE
; // request failed
442 for (int32_t i
=argTypeCapacity
; i
<capacity
; ++i
) {
443 a
[i
] = Formattable::kString
;
446 argTypeCapacity
= capacity
;
451 // -------------------------------------
452 // assignment operator
455 MessageFormat::operator=(const MessageFormat
& that
)
457 // Reallocate the arrays BEFORE changing this object
459 allocateSubformats(that
.subformatCount
) &&
460 allocateArgTypes(that
.argTypeCount
)) {
462 // Calls the super class for assignment first.
463 Format::operator=(that
);
465 fPattern
= that
.fPattern
;
466 setLocale(that
.fLocale
);
467 isArgNumeric
= that
.isArgNumeric
;
469 for (j
=0; j
<subformatCount
; ++j
) {
470 delete subformats
[j
].format
;
474 for (j
=0; j
<that
.subformatCount
; ++j
) {
475 // Subformat::operator= does NOT delete this.format
476 subformats
[j
] = that
.subformats
[j
];
478 subformatCount
= that
.subformatCount
;
480 for (j
=0; j
<that
.argTypeCount
; ++j
) {
481 argTypes
[j
] = that
.argTypes
[j
];
483 argTypeCount
= that
.argTypeCount
;
489 MessageFormat::operator==(const Format
& rhs
) const
491 if (this == &rhs
) return TRUE
;
493 MessageFormat
& that
= (MessageFormat
&)rhs
;
495 // Check class ID before checking MessageFormat members
496 if (!Format::operator==(rhs
) ||
497 fPattern
!= that
.fPattern
||
498 fLocale
!= that
.fLocale
||
499 isArgNumeric
!= that
.isArgNumeric
) {
504 for (j
=0; j
<subformatCount
; ++j
) {
505 if (subformats
[j
] != that
.subformats
[j
]) {
513 // -------------------------------------
514 // Creates a copy of this MessageFormat, the caller owns the copy.
517 MessageFormat::clone() const
519 return new MessageFormat(*this);
522 // -------------------------------------
523 // Sets the locale of this MessageFormat object to theLocale.
526 MessageFormat::setLocale(const Locale
& theLocale
)
528 if (fLocale
!= theLocale
) {
529 delete defaultNumberFormat
;
530 defaultNumberFormat
= NULL
;
531 delete defaultDateFormat
;
532 defaultDateFormat
= NULL
;
535 setLocaleIDs(fLocale
.getName(), fLocale
.getName());
538 // -------------------------------------
539 // Gets the locale of this MessageFormat object.
542 MessageFormat::getLocale() const
551 MessageFormat::applyPattern(const UnicodeString
& newPattern
,
554 UParseError parseError
;
555 applyPattern(newPattern
,parseError
,status
);
559 // -------------------------------------
560 // Applies the new pattern and returns an error if the pattern
563 MessageFormat::applyPattern(const UnicodeString
& pattern
,
564 UParseError
& parseError
,
570 // The pattern is broken up into segments. Each time a subformat
571 // is encountered, 4 segments are recorded. For example, consider
573 // "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}."
574 // The first set of segments is:
575 // segments[0] = "There "
577 // segments[2] = "choice"
578 // segments[3] = "0.0#are no files|1.0#is one file|1.0<are {0, number} files"
580 // During parsing, the plain text is accumulated into segments[0].
581 // Segments 1..3 are used to parse each subpattern. Each time a
582 // subpattern is parsed, it creates a format object that is stored
583 // in the subformats array, together with an offset and argument
584 // number. The offset into the plain text stored in
587 // Quotes in segment 0 are handled normally. They are removed.
588 // Quotes may not occur in segments 1 or 2.
589 // Quotes in segment 3 are parsed and _copied_. This makes
590 // subformat patterns work, e.g., {1,number,'#'.##} passes
591 // the pattern "'#'.##" to DecimalFormat.
593 UnicodeString segments
[4];
594 int32_t part
= 0; // segment we are in, 0..3
595 // Record the highest argument number in the pattern. (In the
596 // subpattern {3,number} the argument number is 3.)
597 int32_t formatNumber
= 0;
598 UBool inQuote
= FALSE
;
599 int32_t braceStack
= 0;
600 // Clear error struct
601 parseError
.offset
= -1;
602 parseError
.preContext
[0] = parseError
.postContext
[0] = (UChar
)0;
603 int32_t patLen
= pattern
.length();
606 for (i
=0; i
<subformatCount
; ++i
) {
607 delete subformats
[i
].format
;
612 for (i
=0; i
<patLen
; ++i
) {
613 UChar ch
= pattern
[i
];
615 // In segment 0, recognize and remove quotes
616 if (ch
== SINGLE_QUOTE
) {
617 if (i
+1 < patLen
&& pattern
[i
+1] == SINGLE_QUOTE
) {
623 } else if (ch
== LEFT_CURLY_BRACE
&& !inQuote
) {
624 // The only way we get from segment 0 to 1 is via an
630 } else if (inQuote
) {
631 // In segments 1..3, recognize quoted matter, and copy it
632 // into the segment, together with the quotes. This takes
633 // care of '' as well.
634 segments
[part
] += ch
;
635 if (ch
== SINGLE_QUOTE
) {
639 // We have an unquoted character in segment 1..3
642 // Commas bump us to the next segment, except for segment 3,
643 // which can contain commas. See example above.
649 case LEFT_CURLY_BRACE
:
650 // Handle '{' within segment 3. The initial '{'
651 // before segment 1 is handled above.
653 ec
= U_PATTERN_SYNTAX_ERROR
;
657 segments
[part
] += ch
;
659 case RIGHT_CURLY_BRACE
:
660 if (braceStack
== 0) {
661 makeFormat(formatNumber
, segments
, parseError
,ec
);
666 segments
[1].remove();
667 segments
[2].remove();
668 segments
[3].remove();
672 segments
[part
] += ch
;
677 // fall through (copy quote chars in segments 1..3)
679 segments
[part
] += ch
;
684 if (braceStack
!= 0 || part
!= 0) {
685 // Unmatched braces in the pattern
686 ec
= U_UNMATCHED_BRACES
;
689 fPattern
= segments
[0];
693 syntaxError(pattern
, i
, parseError
);
694 for (i
=0; i
<subformatCount
; ++i
) {
695 delete subformats
[i
].format
;
697 argTypeCount
= subformatCount
= 0;
699 // -------------------------------------
700 // Converts this MessageFormat instance to a pattern.
703 MessageFormat::toPattern(UnicodeString
& appendTo
) const {
704 // later, make this more extensible
705 int32_t lastOffset
= 0;
707 for (i
=0; i
<subformatCount
; ++i
) {
708 copyAndFixQuotes(fPattern
, lastOffset
, subformats
[i
].offset
, appendTo
);
709 lastOffset
= subformats
[i
].offset
;
710 appendTo
+= LEFT_CURLY_BRACE
;
712 itos(subformats
[i
].argNum
, appendTo
);
715 appendTo
+= *subformats
[i
].argName
;
717 Format
* fmt
= subformats
[i
].format
;
719 // do nothing, string format
721 else if (fmt
->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
723 UErrorCode ec
= U_ZERO_ERROR
;
724 NumberFormat
& formatAlias
= *(NumberFormat
*)fmt
;
725 NumberFormat
*defaultTemplate
= NumberFormat::createInstance(fLocale
, ec
);
726 NumberFormat
*currencyTemplate
= NumberFormat::createCurrencyInstance(fLocale
, ec
);
727 NumberFormat
*percentTemplate
= NumberFormat::createPercentInstance(fLocale
, ec
);
728 NumberFormat
*integerTemplate
= createIntegerFormat(fLocale
, ec
);
731 appendTo
+= ID_NUMBER
;
732 if (formatAlias
!= *defaultTemplate
) {
734 if (formatAlias
== *currencyTemplate
) {
735 appendTo
+= ID_CURRENCY
;
737 else if (formatAlias
== *percentTemplate
) {
738 appendTo
+= ID_PERCENT
;
740 else if (formatAlias
== *integerTemplate
) {
741 appendTo
+= ID_INTEGER
;
744 UnicodeString buffer
;
745 appendTo
+= ((DecimalFormat
*)fmt
)->toPattern(buffer
);
749 delete defaultTemplate
;
750 delete currencyTemplate
;
751 delete percentTemplate
;
752 delete integerTemplate
;
754 else if (fmt
->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
755 DateFormat
& formatAlias
= *(DateFormat
*)fmt
;
756 DateFormat
*defaultDateTemplate
= DateFormat::createDateInstance(DateFormat::kDefault
, fLocale
);
757 DateFormat
*shortDateTemplate
= DateFormat::createDateInstance(DateFormat::kShort
, fLocale
);
758 DateFormat
*longDateTemplate
= DateFormat::createDateInstance(DateFormat::kLong
, fLocale
);
759 DateFormat
*fullDateTemplate
= DateFormat::createDateInstance(DateFormat::kFull
, fLocale
);
760 DateFormat
*defaultTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kDefault
, fLocale
);
761 DateFormat
*shortTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kShort
, fLocale
);
762 DateFormat
*longTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kLong
, fLocale
);
763 DateFormat
*fullTimeTemplate
= DateFormat::createTimeInstance(DateFormat::kFull
, fLocale
);
767 if (formatAlias
== *defaultDateTemplate
) {
770 else if (formatAlias
== *shortDateTemplate
) {
773 appendTo
+= ID_SHORT
;
775 else if (formatAlias
== *defaultDateTemplate
) {
778 appendTo
+= ID_MEDIUM
;
780 else if (formatAlias
== *longDateTemplate
) {
785 else if (formatAlias
== *fullDateTemplate
) {
790 else if (formatAlias
== *defaultTimeTemplate
) {
793 else if (formatAlias
== *shortTimeTemplate
) {
796 appendTo
+= ID_SHORT
;
798 else if (formatAlias
== *defaultTimeTemplate
) {
801 appendTo
+= ID_MEDIUM
;
803 else if (formatAlias
== *longTimeTemplate
) {
808 else if (formatAlias
== *fullTimeTemplate
) {
814 UnicodeString buffer
;
817 appendTo
+= ((SimpleDateFormat
*)fmt
)->toPattern(buffer
);
820 delete defaultDateTemplate
;
821 delete shortDateTemplate
;
822 delete longDateTemplate
;
823 delete fullDateTemplate
;
824 delete defaultTimeTemplate
;
825 delete shortTimeTemplate
;
826 delete longTimeTemplate
;
827 delete fullTimeTemplate
;
828 // {sfb} there should be a more efficient way to do this!
830 else if (fmt
->getDynamicClassID() == ChoiceFormat::getStaticClassID()) {
831 UnicodeString buffer
;
833 appendTo
+= ID_CHOICE
;
835 appendTo
+= ((ChoiceFormat
*)fmt
)->toPattern(buffer
);
837 else if (fmt
->getDynamicClassID() == PluralFormat::getStaticClassID()) {
838 UnicodeString buffer
;
839 appendTo
+= ((PluralFormat
*)fmt
)->toPattern(buffer
);
842 //appendTo += ", unknown";
844 appendTo
+= RIGHT_CURLY_BRACE
;
846 copyAndFixQuotes(fPattern
, lastOffset
, fPattern
.length(), appendTo
);
850 // -------------------------------------
851 // Adopts the new formats array and updates the array count.
852 // This MessageFormat instance owns the new formats.
855 MessageFormat::adoptFormats(Format
** newFormats
,
857 if (newFormats
== NULL
|| count
< 0) {
862 if (allocateSubformats(count
)) {
863 for (i
=0; i
<subformatCount
; ++i
) {
864 delete subformats
[i
].format
;
866 for (i
=0; i
<count
; ++i
) {
867 subformats
[i
].format
= newFormats
[i
];
869 subformatCount
= count
;
871 // An adopt method must always take ownership. Delete
872 // the incoming format objects and return unchanged.
873 for (i
=0; i
<count
; ++i
) {
874 delete newFormats
[i
];
878 // TODO: What about the .offset and .argNum fields?
881 // -------------------------------------
882 // Sets the new formats array and updates the array count.
883 // This MessageFormat instance maks a copy of the new formats.
886 MessageFormat::setFormats(const Format
** newFormats
,
888 if (newFormats
== NULL
|| count
< 0) {
892 if (allocateSubformats(count
)) {
894 for (i
=0; i
<subformatCount
; ++i
) {
895 delete subformats
[i
].format
;
899 for (i
=0; i
<count
; ++i
) {
900 subformats
[i
].format
= newFormats
[i
] ? newFormats
[i
]->clone() : NULL
;
902 subformatCount
= count
;
905 // TODO: What about the .offset and .arg fields?
908 // -------------------------------------
909 // Adopt a single format by format number.
910 // Do nothing if the format number is not less than the array count.
913 MessageFormat::adoptFormat(int32_t n
, Format
*newFormat
) {
914 if (n
< 0 || n
>= subformatCount
) {
917 delete subformats
[n
].format
;
918 subformats
[n
].format
= newFormat
;
922 // -------------------------------------
923 // Adopt a single format by format name.
924 // Do nothing if there is no match of formatName.
926 MessageFormat::adoptFormat(const UnicodeString
& formatName
,
927 Format
* formatToAdopt
,
928 UErrorCode
& status
) {
930 int32_t argumentNumber
= stou(formatName
);
931 if (argumentNumber
<0) {
932 status
= U_ARGUMENT_TYPE_MISMATCH
;
935 adoptFormat(argumentNumber
, formatToAdopt
);
938 for (int32_t i
=0; i
<subformatCount
; ++i
) {
939 if (formatName
==*subformats
[i
].argName
) {
940 delete subformats
[i
].format
;
941 if ( formatToAdopt
== NULL
) {
942 // This should never happen -- but we'll be nice if it does
943 subformats
[i
].format
= NULL
;
945 subformats
[i
].format
= formatToAdopt
;
951 // -------------------------------------
952 // Set a single format.
953 // Do nothing if the variable is not less than the array count.
956 MessageFormat::setFormat(int32_t n
, const Format
& newFormat
) {
957 if (n
>= 0 && n
< subformatCount
) {
958 delete subformats
[n
].format
;
959 if (&newFormat
== NULL
) {
960 // This should never happen -- but we'll be nice if it does
961 subformats
[n
].format
= NULL
;
963 subformats
[n
].format
= newFormat
.clone();
968 // -------------------------------------
969 // Get a single format by format name.
970 // Do nothing if the variable is not less than the array count.
972 MessageFormat::getFormat(const UnicodeString
& formatName
, UErrorCode
& status
) {
974 if (U_FAILURE(status
)) return NULL
;
977 int32_t argumentNumber
= stou(formatName
);
978 if (argumentNumber
<0) {
979 status
= U_ARGUMENT_TYPE_MISMATCH
;
982 if (argumentNumber
< 0 || argumentNumber
>= subformatCount
) {
983 return subformats
[argumentNumber
].format
;
990 for (int32_t i
=0; i
<subformatCount
; ++i
) {
991 if (formatName
==*subformats
[i
].argName
)
993 return subformats
[i
].format
;
999 // -------------------------------------
1000 // Set a single format by format name
1001 // Do nothing if the variable is not less than the array count.
1003 MessageFormat::setFormat(const UnicodeString
& formatName
,
1004 const Format
& newFormat
,
1005 UErrorCode
& status
) {
1007 status
= U_ARGUMENT_TYPE_MISMATCH
;
1010 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1011 if (formatName
==*subformats
[i
].argName
)
1013 delete subformats
[i
].format
;
1014 if (&newFormat
== NULL
) {
1015 // This should never happen -- but we'll be nice if it does
1016 subformats
[i
].format
= NULL
;
1018 subformats
[i
].format
= newFormat
.clone();
1025 // -------------------------------------
1026 // Gets the format array.
1029 MessageFormat::getFormats(int32_t& cnt
) const
1031 // This old API returns an array (which we hold) of Format*
1032 // pointers. The array is valid up to the next call to any
1033 // method on this object. We construct and resize an array
1034 // on demand that contains aliases to the subformats[i].format
1036 MessageFormat
* t
= (MessageFormat
*) this;
1038 if (formatAliases
== NULL
) {
1039 t
->formatAliasesCapacity
= (subformatCount
<10) ? 10 : subformatCount
;
1040 Format
** a
= (Format
**)
1041 uprv_malloc(sizeof(Format
*) * formatAliasesCapacity
);
1045 t
->formatAliases
= a
;
1046 } else if (subformatCount
> formatAliasesCapacity
) {
1047 Format
** a
= (Format
**)
1048 uprv_realloc(formatAliases
, sizeof(Format
*) * subformatCount
);
1052 t
->formatAliases
= a
;
1053 t
->formatAliasesCapacity
= subformatCount
;
1055 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1056 t
->formatAliases
[i
] = subformats
[i
].format
;
1058 cnt
= subformatCount
;
1059 return (const Format
**)formatAliases
;
1064 MessageFormat::getFormatNames(UErrorCode
& status
) {
1065 if (U_FAILURE(status
)) return NULL
;
1068 status
= U_ARGUMENT_TYPE_MISMATCH
;
1071 UVector
*fFormatNames
= new UVector(status
);
1072 if (U_FAILURE(status
)) {
1073 status
= U_MEMORY_ALLOCATION_ERROR
;
1076 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1077 fFormatNames
->addElement(new UnicodeString(*subformats
[i
].argName
), status
);
1080 StringEnumeration
* nameEnumerator
= new FormatNameEnumeration(fFormatNames
, status
);
1081 return nameEnumerator
;
1084 // -------------------------------------
1085 // Formats the source Formattable array and copy into the result buffer.
1086 // Ignore the FieldPosition result for error checking.
1089 MessageFormat::format(const Formattable
* source
,
1091 UnicodeString
& appendTo
,
1092 FieldPosition
& ignore
,
1093 UErrorCode
& success
) const
1095 if (U_FAILURE(success
))
1098 return format(source
, cnt
, appendTo
, ignore
, 0, success
);
1101 // -------------------------------------
1102 // Internally creates a MessageFormat instance based on the
1103 // pattern and formats the arguments Formattable array and
1104 // copy into the appendTo buffer.
1107 MessageFormat::format( const UnicodeString
& pattern
,
1108 const Formattable
* arguments
,
1110 UnicodeString
& appendTo
,
1111 UErrorCode
& success
)
1113 MessageFormat
temp(pattern
, success
);
1114 FieldPosition
ignore(0);
1115 temp
.format(arguments
, cnt
, appendTo
, ignore
, success
);
1119 // -------------------------------------
1120 // Formats the source Formattable object and copy into the
1121 // appendTo buffer. The Formattable object must be an array
1122 // of Formattable instances, returns error otherwise.
1125 MessageFormat::format(const Formattable
& source
,
1126 UnicodeString
& appendTo
,
1127 FieldPosition
& ignore
,
1128 UErrorCode
& success
) const
1132 if (U_FAILURE(success
))
1134 if (source
.getType() != Formattable::kArray
) {
1135 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1138 const Formattable
* tmpPtr
= source
.getArray(cnt
);
1140 return format(tmpPtr
, cnt
, appendTo
, ignore
, 0, success
);
1145 MessageFormat::format(const UnicodeString
* argumentNames
,
1146 const Formattable
* arguments
,
1148 UnicodeString
& appendTo
,
1149 UErrorCode
& success
) const {
1150 FieldPosition
ignore(0);
1151 return format(arguments
, argumentNames
, count
, appendTo
, ignore
, 0, success
);
1155 MessageFormat::format(const Formattable
* arguments
,
1157 UnicodeString
& appendTo
,
1158 FieldPosition
& status
,
1159 int32_t recursionProtection
,
1160 UErrorCode
& success
) const
1162 return format(arguments
, NULL
, cnt
, appendTo
, status
, recursionProtection
, success
);
1165 // -------------------------------------
1166 // Formats the arguments Formattable array and copy into the appendTo buffer.
1167 // Ignore the FieldPosition result for error checking.
1170 MessageFormat::format(const Formattable
* arguments
,
1171 const UnicodeString
*argumentNames
,
1173 UnicodeString
& appendTo
,
1174 FieldPosition
& status
,
1175 int32_t recursionProtection
,
1176 UErrorCode
& success
) const
1178 int32_t lastOffset
= 0;
1179 int32_t argumentNumber
=0;
1180 if (cnt
< 0 || (cnt
&& arguments
== NULL
)) {
1181 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1185 if ( !isArgNumeric
&& argumentNames
== NULL
) {
1186 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1190 const Formattable
*obj
=NULL
;
1191 for (int32_t i
=0; i
<subformatCount
; ++i
) {
1192 // Append the prefix of current format element.
1193 appendTo
.append(fPattern
, lastOffset
, subformats
[i
].offset
- lastOffset
);
1194 lastOffset
= subformats
[i
].offset
;
1197 argumentNumber
= subformats
[i
].argNum
;
1199 // Checks the scope of the argument number.
1200 if (argumentNumber
>= cnt
) {
1201 appendTo
+= LEFT_CURLY_BRACE
;
1202 itos(argumentNumber
, appendTo
);
1203 appendTo
+= RIGHT_CURLY_BRACE
;
1206 obj
= arguments
+argumentNumber
;
1209 for (int32_t j
=0; j
<cnt
; ++j
) {
1210 if (argumentNames
[j
]== *subformats
[i
].argName
) {
1216 appendTo
+= LEFT_CURLY_BRACE
;
1217 appendTo
+= *subformats
[i
].argName
;
1218 appendTo
+= RIGHT_CURLY_BRACE
;
1223 Formattable::Type type
= obj
->getType();
1225 // Recursively calling the format process only if the current
1226 // format argument refers to a ChoiceFormat object.
1227 Format
* fmt
= subformats
[i
].format
;
1229 UnicodeString argNum
;
1230 fmt
->format(*obj
, argNum
, success
);
1232 // Needs to reprocess the ChoiceFormat option by using the
1233 // MessageFormat pattern application.
1234 if ((fmt
->getDynamicClassID() == ChoiceFormat::getStaticClassID() ||
1235 fmt
->getDynamicClassID() == PluralFormat::getStaticClassID()) &&
1236 argNum
.indexOf(LEFT_CURLY_BRACE
) >= 0) {
1237 MessageFormat
temp(argNum
, fLocale
, success
);
1238 // TODO: Implement recursion protection
1239 if ( isArgNumeric
) {
1240 temp
.format(arguments
, NULL
, cnt
, appendTo
, status
, recursionProtection
, success
);
1243 temp
.format(arguments
, argumentNames
, cnt
, appendTo
, status
, recursionProtection
, success
);
1245 if (U_FAILURE(success
)) {
1253 // If the obj data type is a number, use a NumberFormat instance.
1254 else if ((type
== Formattable::kDouble
) ||
1255 (type
== Formattable::kLong
) ||
1256 (type
== Formattable::kInt64
)) {
1258 const NumberFormat
* nf
= getDefaultNumberFormat(success
);
1262 if (type
== Formattable::kDouble
) {
1263 nf
->format(obj
->getDouble(), appendTo
);
1264 } else if (type
== Formattable::kLong
) {
1265 nf
->format(obj
->getLong(), appendTo
);
1267 nf
->format(obj
->getInt64(), appendTo
);
1270 // If the obj data type is a Date instance, use a DateFormat instance.
1271 else if (type
== Formattable::kDate
) {
1272 const DateFormat
* df
= getDefaultDateFormat(success
);
1276 df
->format(obj
->getDate(), appendTo
);
1278 else if (type
== Formattable::kString
) {
1279 appendTo
+= obj
->getString();
1282 success
= U_ILLEGAL_ARGUMENT_ERROR
;
1286 // Appends the rest of the pattern characters after the real last offset.
1287 appendTo
.append(fPattern
, lastOffset
, 0x7fffffff);
1292 // -------------------------------------
1293 // Parses the source pattern and returns the Formattable objects array,
1294 // the array count and the ending parse position. The caller of this method
1298 MessageFormat::parse(const UnicodeString
& source
,
1300 int32_t& count
) const
1302 // Allocate at least one element. Allocating an array of length
1303 // zero causes problems on some platforms (e.g. Win32).
1304 Formattable
*resultArray
= new Formattable
[argTypeCount
? argTypeCount
: 1];
1305 int32_t patternOffset
= 0;
1306 int32_t sourceOffset
= pos
.getIndex();
1307 ParsePosition
tempPos(0);
1308 count
= 0; // {sfb} reset to zero
1310 // If resultArray could not be created, exit out.
1311 // Avoid crossing initialization of variables above.
1312 if (resultArray
== NULL
) {
1315 for (int32_t i
= 0; i
< subformatCount
; ++i
) {
1316 // match up to format
1317 len
= subformats
[i
].offset
- patternOffset
;
1319 fPattern
.compare(patternOffset
, len
, source
, sourceOffset
, len
) == 0) {
1320 sourceOffset
+= len
;
1321 patternOffset
+= len
;
1328 Format
* fmt
= subformats
[i
].format
;
1329 int32_t argNum
= subformats
[i
].argNum
;
1330 if (fmt
== NULL
) { // string format
1331 // if at end, use longest possible match
1332 // otherwise uses first match to intervening string
1333 // does NOT recursively try all possibilities
1334 int32_t tempLength
= (i
+1<subformatCount
) ?
1335 subformats
[i
+1].offset
: fPattern
.length();
1338 if (patternOffset
>= tempLength
) {
1339 next
= source
.length();
1342 UnicodeString buffer
;
1343 fPattern
.extract(patternOffset
,tempLength
- patternOffset
, buffer
);
1344 next
= source
.indexOf(buffer
, sourceOffset
);
1351 UnicodeString buffer
;
1352 source
.extract(sourceOffset
,next
- sourceOffset
, buffer
);
1353 UnicodeString strValue
= buffer
;
1354 UnicodeString
temp(LEFT_CURLY_BRACE
);
1355 // {sfb} check this later
1360 temp
+=(*subformats
[i
].argName
);
1362 temp
+= RIGHT_CURLY_BRACE
;
1363 if (strValue
!= temp
) {
1364 source
.extract(sourceOffset
,next
- sourceOffset
, buffer
);
1365 resultArray
[argNum
].setString(buffer
);
1366 // {sfb} not sure about this
1367 if ((argNum
+ 1) > count
) {
1371 sourceOffset
= next
;
1375 tempPos
.setIndex(sourceOffset
);
1376 fmt
->parseObject(source
, resultArray
[argNum
], tempPos
);
1377 if (tempPos
.getIndex() == sourceOffset
) {
1381 if ((argNum
+ 1) > count
) {
1384 sourceOffset
= tempPos
.getIndex(); // update
1387 len
= fPattern
.length() - patternOffset
;
1389 fPattern
.compare(patternOffset
, len
, source
, sourceOffset
, len
) == 0) {
1390 pos
.setIndex(sourceOffset
+ len
);
1393 // else fall through...
1396 pos
.setErrorIndex(sourceOffset
);
1397 delete [] resultArray
;
1399 return NULL
; // leave index as is to signal error
1402 // -------------------------------------
1403 // Parses the source string and returns the array of
1404 // Formattable objects and the array count. The caller
1405 // owns the returned array.
1408 MessageFormat::parse(const UnicodeString
& source
,
1410 UErrorCode
& success
) const
1412 if (!isArgNumeric
) {
1413 success
= U_ARGUMENT_TYPE_MISMATCH
;
1416 ParsePosition
status(0);
1417 // Calls the actual implementation method and starts
1418 // from zero offset of the source text.
1419 Formattable
* result
= parse(source
, status
, cnt
);
1420 if (status
.getIndex() == 0) {
1421 success
= U_MESSAGE_PARSE_ERROR
;
1428 // -------------------------------------
1429 // Parses the source text and copy into the result buffer.
1432 MessageFormat::parseObject( const UnicodeString
& source
,
1433 Formattable
& result
,
1434 ParsePosition
& status
) const
1437 Formattable
* tmpResult
= parse(source
, status
, cnt
);
1438 if (tmpResult
!= NULL
)
1439 result
.adoptArray(tmpResult
, cnt
);
1443 MessageFormat::autoQuoteApostrophe(const UnicodeString
& pattern
, UErrorCode
& status
) {
1444 UnicodeString result
;
1445 if (U_SUCCESS(status
)) {
1446 int32_t plen
= pattern
.length();
1447 const UChar
* pat
= pattern
.getBuffer();
1448 int32_t blen
= plen
* 2 + 1; // space for null termination, convenience
1449 UChar
* buf
= result
.getBuffer(blen
);
1451 status
= U_MEMORY_ALLOCATION_ERROR
;
1453 int32_t len
= umsg_autoQuoteApostrophe(pat
, plen
, buf
, blen
, &status
);
1454 result
.releaseBuffer(U_SUCCESS(status
) ? len
: 0);
1457 if (U_FAILURE(status
)) {
1458 result
.setToBogus();
1463 // -------------------------------------
1465 static Format
* makeRBNF(URBNFRuleSetTag tag
, const Locale
& locale
, const UnicodeString
& defaultRuleSet
, UErrorCode
& ec
) {
1466 RuleBasedNumberFormat
* fmt
= new RuleBasedNumberFormat(tag
, locale
, ec
);
1468 ec
= U_MEMORY_ALLOCATION_ERROR
;
1469 } else if (U_SUCCESS(ec
) && defaultRuleSet
.length() > 0) {
1470 UErrorCode localStatus
= U_ZERO_ERROR
; // ignore unrecognized default rule set
1471 fmt
->setDefaultRuleSet(defaultRuleSet
, localStatus
);
1477 * Reads the segments[] array (see applyPattern()) and parses the
1478 * segments[1..3] into a Format* object. Stores the format object in
1479 * the subformats[] array. Updates the argTypes[] array type
1480 * information for the corresponding argument.
1482 * @param formatNumber index into subformats[] for this format
1483 * @param segments array of strings with the parsed pattern segments
1484 * @param parseError parse error data (output param)
1485 * @param ec error code
1488 MessageFormat::makeFormat(int32_t formatNumber
,
1489 UnicodeString
* segments
,
1490 UParseError
& parseError
,
1492 if (U_FAILURE(ec
)) {
1496 // Parse the argument number
1497 int32_t argumentNumber
= stou(segments
[1]); // always unlocalized!
1498 UnicodeString argumentName
;
1499 if (argumentNumber
< 0) {
1500 if ( (isArgNumeric
==TRUE
) && (formatNumber
!=0) ) {
1501 ec
= U_INVALID_FORMAT_ERROR
;
1504 isArgNumeric
= FALSE
;
1505 argumentNumber
=formatNumber
;
1507 if (!isArgNumeric
) {
1508 if ( !isLegalArgName(segments
[1]) ) {
1509 ec
= U_INVALID_FORMAT_ERROR
;
1512 argumentName
= segments
[1];
1515 // Parse the format, recording the argument type and creating a
1516 // new Format object (except for string arguments).
1517 Formattable::Type argType
;
1519 int32_t typeID
, styleID
;
1520 DateFormat::EStyle style
;
1521 UnicodeString unquotedPattern
, quotedPattern
;
1522 UBool inQuote
= FALSE
;
1524 switch (typeID
= findKeyword(segments
[2], TYPE_IDS
)) {
1527 argType
= Formattable::kString
;
1531 argType
= Formattable::kDouble
;
1533 switch (findKeyword(segments
[3], NUMBER_STYLE_IDS
)) {
1535 fmt
= NumberFormat::createInstance(fLocale
, ec
);
1538 fmt
= NumberFormat::createCurrencyInstance(fLocale
, ec
);
1541 fmt
= NumberFormat::createPercentInstance(fLocale
, ec
);
1544 argType
= Formattable::kLong
;
1545 fmt
= createIntegerFormat(fLocale
, ec
);
1548 fmt
= NumberFormat::createInstance(fLocale
, ec
);
1550 fmt
->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
1551 ((DecimalFormat
*)fmt
)->applyPattern(segments
[3],parseError
,ec
);
1559 argType
= Formattable::kDate
;
1560 styleID
= findKeyword(segments
[3], DATE_STYLE_IDS
);
1561 style
= (styleID
>= 0) ? DATE_STYLES
[styleID
] : DateFormat::kDefault
;
1564 fmt
= DateFormat::createDateInstance(style
, fLocale
);
1566 fmt
= DateFormat::createTimeInstance(style
, fLocale
);
1571 fmt
->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
1572 ((SimpleDateFormat
*)fmt
)->applyPattern(segments
[3]);
1577 argType
= Formattable::kDouble
;
1579 fmt
= new ChoiceFormat(segments
[3], parseError
, ec
);
1583 argType
= Formattable::kDouble
;
1584 fmt
= makeRBNF(URBNF_SPELLOUT
, fLocale
, segments
[3], ec
);
1587 argType
= Formattable::kDouble
;
1588 fmt
= makeRBNF(URBNF_ORDINAL
, fLocale
, segments
[3], ec
);
1591 argType
= Formattable::kDouble
;
1592 fmt
= makeRBNF(URBNF_DURATION
, fLocale
, segments
[3], ec
);
1595 argType
= Formattable::kDouble
;
1596 quotedPattern
= segments
[3];
1597 for (int32_t i
= 0; i
< quotedPattern
.length(); ++i
) {
1598 UChar ch
= quotedPattern
.charAt(i
);
1599 if (ch
== SINGLE_QUOTE
) {
1600 if (i
+1 < quotedPattern
.length() && quotedPattern
.charAt(i
+1)==SINGLE_QUOTE
) {
1601 unquotedPattern
+=ch
;
1609 unquotedPattern
+= ch
;
1612 fmt
= new PluralFormat(fLocale
, unquotedPattern
, ec
);
1615 argType
= Formattable::kString
;
1616 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
1620 if (fmt
==NULL
&& argType
!=Formattable::kString
&& U_SUCCESS(ec
)) {
1621 ec
= U_MEMORY_ALLOCATION_ERROR
;
1624 if (!allocateSubformats(formatNumber
+1) ||
1625 !allocateArgTypes(argumentNumber
+1)) {
1626 ec
= U_MEMORY_ALLOCATION_ERROR
;
1629 if (U_FAILURE(ec
)) {
1634 // Parse succeeded; record results in our arrays
1635 subformats
[formatNumber
].format
= fmt
;
1636 subformats
[formatNumber
].offset
= segments
[0].length();
1638 subformats
[formatNumber
].argName
= NULL
;
1639 subformats
[formatNumber
].argNum
= argumentNumber
;
1642 subformats
[formatNumber
].argName
= new UnicodeString(argumentName
);
1643 subformats
[formatNumber
].argNum
= -1;
1645 subformatCount
= formatNumber
+1;
1647 // Careful here: argumentNumber may in general arrive out of
1648 // sequence, e.g., "There was {2} on {0,date} (see {1,number})."
1649 argTypes
[argumentNumber
] = argType
;
1650 if (argumentNumber
+1 > argTypeCount
) {
1651 argTypeCount
= argumentNumber
+1;
1655 // -------------------------------------
1656 // Finds the string, s, in the string array, list.
1657 int32_t MessageFormat::findKeyword(const UnicodeString
& s
,
1658 const UChar
* const *list
)
1660 if (s
.length() == 0)
1661 return 0; // default
1663 UnicodeString buffer
= s
;
1664 // Trims the space characters and turns all characters
1665 // in s to lower case.
1666 buffer
.trim().toLower("");
1667 for (int32_t i
= 0; list
[i
]; ++i
) {
1668 if (!buffer
.compare(list
[i
], u_strlen(list
[i
]))) {
1675 // -------------------------------------
1676 // Checks the range of the source text to quote the special
1677 // characters, { and ' and copy to target buffer.
1680 MessageFormat::copyAndFixQuotes(const UnicodeString
& source
,
1683 UnicodeString
& appendTo
)
1685 UBool gotLB
= FALSE
;
1687 for (int32_t i
= start
; i
< end
; ++i
) {
1688 UChar ch
= source
[i
];
1689 if (ch
== LEFT_CURLY_BRACE
) {
1690 appendTo
+= SINGLE_QUOTE
;
1691 appendTo
+= LEFT_CURLY_BRACE
;
1692 appendTo
+= SINGLE_QUOTE
;
1695 else if (ch
== RIGHT_CURLY_BRACE
) {
1697 appendTo
+= RIGHT_CURLY_BRACE
;
1702 appendTo
+= SINGLE_QUOTE
;
1703 appendTo
+= RIGHT_CURLY_BRACE
;
1704 appendTo
+= SINGLE_QUOTE
;
1707 else if (ch
== SINGLE_QUOTE
) {
1708 appendTo
+= SINGLE_QUOTE
;
1709 appendTo
+= SINGLE_QUOTE
;
1718 * Convenience method that ought to be in NumberFormat
1721 MessageFormat::createIntegerFormat(const Locale
& locale
, UErrorCode
& status
) const {
1722 NumberFormat
*temp
= NumberFormat::createInstance(locale
, status
);
1723 if (temp
!= NULL
&& temp
->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
1724 DecimalFormat
*temp2
= (DecimalFormat
*) temp
;
1725 temp2
->setMaximumFractionDigits(0);
1726 temp2
->setDecimalSeparatorAlwaysShown(FALSE
);
1727 temp2
->setParseIntegerOnly(TRUE
);
1734 * Return the default number format. Used to format a numeric
1735 * argument when subformats[i].format is NULL. Returns NULL
1738 * Semantically const but may modify *this.
1740 const NumberFormat
* MessageFormat::getDefaultNumberFormat(UErrorCode
& ec
) const {
1741 if (defaultNumberFormat
== NULL
) {
1742 MessageFormat
* t
= (MessageFormat
*) this;
1743 t
->defaultNumberFormat
= NumberFormat::createInstance(fLocale
, ec
);
1744 if (U_FAILURE(ec
)) {
1745 delete t
->defaultNumberFormat
;
1746 t
->defaultNumberFormat
= NULL
;
1747 } else if (t
->defaultNumberFormat
== NULL
) {
1748 ec
= U_MEMORY_ALLOCATION_ERROR
;
1751 return defaultNumberFormat
;
1755 * Return the default date format. Used to format a date
1756 * argument when subformats[i].format is NULL. Returns NULL
1759 * Semantically const but may modify *this.
1761 const DateFormat
* MessageFormat::getDefaultDateFormat(UErrorCode
& ec
) const {
1762 if (defaultDateFormat
== NULL
) {
1763 MessageFormat
* t
= (MessageFormat
*) this;
1764 t
->defaultDateFormat
= DateFormat::createDateTimeInstance(DateFormat::kShort
, DateFormat::kShort
, fLocale
);
1765 if (t
->defaultDateFormat
== NULL
) {
1766 ec
= U_MEMORY_ALLOCATION_ERROR
;
1769 return defaultDateFormat
;
1773 MessageFormat::usesNamedArguments() const {
1774 return !isArgNumeric
;
1778 MessageFormat::isLegalArgName(const UnicodeString
& argName
) const {
1779 if(!u_hasBinaryProperty(argName
.charAt(0), idStart
)) {
1782 for (int32_t i
=1; i
<argName
.length(); ++i
) {
1783 if(!u_hasBinaryProperty(argName
.charAt(i
), idContinue
)) {
1790 FormatNameEnumeration::FormatNameEnumeration(UVector
*fNameList
, UErrorCode
& /*status*/) {
1792 fFormatNames
= fNameList
;
1795 const UnicodeString
*
1796 FormatNameEnumeration::snext(UErrorCode
& status
) {
1797 if (U_SUCCESS(status
) && pos
< fFormatNames
->size()) {
1798 return (const UnicodeString
*)fFormatNames
->elementAt(pos
++);
1804 FormatNameEnumeration::reset(UErrorCode
& /*status*/) {
1809 FormatNameEnumeration::count(UErrorCode
& /*status*/) const {
1810 return (fFormatNames
==NULL
) ? 0 : fFormatNames
->size();
1813 FormatNameEnumeration::~FormatNameEnumeration() {
1815 for (int32_t i
=0; i
<fFormatNames
->size(); ++i
) {
1816 if ((s
=(UnicodeString
*)fFormatNames
->elementAt(i
))!=NULL
) {
1820 delete fFormatNames
;
1824 #endif /* #if !UCONFIG_NO_FORMATTING */