1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2006, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
6 *
7 * File MSGFMT.CPP
8 *
9 * Modification History:
10 *
11 * Date Name Description
12 * 02/19/97 aliu Converted from java.
13 * 03/20/97 helena Finished first cut of implementation.
14 * 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi.
15 * 06/11/97 helena Fixed addPattern to take the pattern correctly.
16 * 06/17/97 helena Fixed the getPattern to return the correct pattern.
17 * 07/09/97 helena Made ParsePosition into a class.
18 * 02/22/99 stephen Removed character literals for EBCDIC safety
19 ********************************************************************************
20 */
21
22 #include "unicode/utypes.h"
23
24 #if !UCONFIG_NO_FORMATTING
25
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/ustring.h"
32 #include "unicode/ucnv_err.h"
33 #include "unicode/uchar.h"
34 #include "unicode/umsg.h"
35 #include "unicode/rbnf.h"
36 #include "ustrfmt.h"
37 #include "cmemory.h"
38 #include "../common/util.h"
39 #include "uassert.h"
40
41 // *****************************************************************************
42 // class MessageFormat
43 // *****************************************************************************
44
45 #define COMMA ((UChar)0x002C)
46 #define SINGLE_QUOTE ((UChar)0x0027)
47 #define LEFT_CURLY_BRACE ((UChar)0x007B)
48 #define RIGHT_CURLY_BRACE ((UChar)0x007D)
49
50 //---------------------------------------
51 // static data
52
53 static const UChar ID_EMPTY[] = {
54 0 /* empty string, used for default so that null can mark end of list */
55 };
56
57 static const UChar ID_NUMBER[] = {
58 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
59 };
60 static const UChar ID_DATE[] = {
61 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
62 };
63 static const UChar ID_TIME[] = {
64 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
65 };
66 static const UChar ID_CHOICE[] = {
67 0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0 /* "choice" */
68 };
69 static const UChar ID_SPELLOUT[] = {
70 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
71 };
72 static const UChar ID_ORDINAL[] = {
73 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
74 };
75 static const UChar ID_DURATION[] = {
76 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
77 };
78
79 // MessageFormat Type List Number, Date, Time or Choice
80 static const UChar * const TYPE_IDS[] = {
81 ID_EMPTY,
82 ID_NUMBER,
83 ID_DATE,
84 ID_TIME,
85 ID_CHOICE,
86 ID_SPELLOUT,
87 ID_ORDINAL,
88 ID_DURATION,
89 NULL,
90 };
91
92 static const UChar ID_CURRENCY[] = {
93 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
94 };
95 static const UChar ID_PERCENT[] = {
96 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
97 };
98 static const UChar ID_INTEGER[] = {
99 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
100 };
101
102 // NumberFormat modifier list, default, currency, percent or integer
103 static const UChar * const NUMBER_STYLE_IDS[] = {
104 ID_EMPTY,
105 ID_CURRENCY,
106 ID_PERCENT,
107 ID_INTEGER,
108 NULL,
109 };
110
111 static const UChar ID_SHORT[] = {
112 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
113 };
114 static const UChar ID_MEDIUM[] = {
115 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
116 };
117 static const UChar ID_LONG[] = {
118 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
119 };
120 static const UChar ID_FULL[] = {
121 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
122 };
123
124 // DateFormat modifier list, default, short, medium, long or full
125 static const UChar * const DATE_STYLE_IDS[] = {
126 ID_EMPTY,
127 ID_SHORT,
128 ID_MEDIUM,
129 ID_LONG,
130 ID_FULL,
131 NULL,
132 };
133
134 static const U_NAMESPACE_QUALIFIER DateFormat::EStyle DATE_STYLES[] = {
135 U_NAMESPACE_QUALIFIER DateFormat::kDefault,
136 U_NAMESPACE_QUALIFIER DateFormat::kShort,
137 U_NAMESPACE_QUALIFIER DateFormat::kMedium,
138 U_NAMESPACE_QUALIFIER DateFormat::kLong,
139 U_NAMESPACE_QUALIFIER DateFormat::kFull,
140 };
141
142 static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
143
144 U_NAMESPACE_BEGIN
145
146 // -------------------------------------
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)147 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
148
149 //--------------------------------------------------------------------
150
151 /**
152 * Convert a string to an unsigned decimal, ignoring rule whitespace.
153 * @return a non-negative number if successful, or a negative number
154 * upon failure.
155 */
156 static int32_t stou(const UnicodeString& string) {
157 int32_t n = 0;
158 int32_t count = 0;
159 UChar32 c;
160 for (int32_t i=0; i<string.length(); i+=U16_LENGTH(c)) {
161 c = string.char32At(i);
162 if (uprv_isRuleWhiteSpace(c)) {
163 continue;
164 }
165 int32_t d = u_digit(c, 10);
166 if (d < 0 || ++count > 10) {
167 return -1;
168 }
169 n = 10*n + d;
170 }
171 return n;
172 }
173
174 /**
175 * Convert an integer value to a string and append the result to
176 * the given UnicodeString.
177 */
itos(int32_t i,UnicodeString & appendTo)178 static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
179 UChar temp[16];
180 uprv_itou(temp,16,i,10,0); // 10 == radix
181 appendTo.append(temp);
182 return appendTo;
183 }
184
185 // -------------------------------------
186 // Creates a MessageFormat instance based on the pattern.
187
MessageFormat(const UnicodeString & pattern,UErrorCode & success)188 MessageFormat::MessageFormat(const UnicodeString& pattern,
189 UErrorCode& success)
190 : fLocale(Locale::getDefault()), // Uses the default locale
191 formatAliases(NULL),
192 formatAliasesCapacity(0),
193 subformats(NULL),
194 subformatCount(0),
195 subformatCapacity(0),
196 argTypes(NULL),
197 argTypeCount(0),
198 argTypeCapacity(0),
199 defaultNumberFormat(NULL),
200 defaultDateFormat(NULL)
201 {
202 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
203 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
204 success = U_MEMORY_ALLOCATION_ERROR;
205 return;
206 }
207 applyPattern(pattern, success);
208 setLocaleIDs(fLocale.getName(), fLocale.getName());
209 }
210
MessageFormat(const UnicodeString & pattern,const Locale & newLocale,UErrorCode & success)211 MessageFormat::MessageFormat(const UnicodeString& pattern,
212 const Locale& newLocale,
213 UErrorCode& success)
214 : fLocale(newLocale),
215 formatAliases(NULL),
216 formatAliasesCapacity(0),
217 subformats(NULL),
218 subformatCount(0),
219 subformatCapacity(0),
220 argTypes(NULL),
221 argTypeCount(0),
222 argTypeCapacity(0),
223 defaultNumberFormat(NULL),
224 defaultDateFormat(NULL)
225 {
226 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
227 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
228 success = U_MEMORY_ALLOCATION_ERROR;
229 return;
230 }
231 applyPattern(pattern, success);
232 setLocaleIDs(fLocale.getName(), fLocale.getName());
233 }
234
MessageFormat(const UnicodeString & pattern,const Locale & newLocale,UParseError & parseError,UErrorCode & success)235 MessageFormat::MessageFormat(const UnicodeString& pattern,
236 const Locale& newLocale,
237 UParseError& parseError,
238 UErrorCode& success)
239 : fLocale(newLocale),
240 formatAliases(NULL),
241 formatAliasesCapacity(0),
242 subformats(NULL),
243 subformatCount(0),
244 subformatCapacity(0),
245 argTypes(NULL),
246 argTypeCount(0),
247 argTypeCapacity(0),
248 defaultNumberFormat(NULL),
249 defaultDateFormat(NULL)
250 {
251 if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
252 !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
253 success = U_MEMORY_ALLOCATION_ERROR;
254 return;
255 }
256 applyPattern(pattern, parseError, success);
257 setLocaleIDs(fLocale.getName(), fLocale.getName());
258 }
259
MessageFormat(const MessageFormat & that)260 MessageFormat::MessageFormat(const MessageFormat& that)
261 : Format(that),
262 formatAliases(NULL),
263 formatAliasesCapacity(0),
264 subformats(NULL),
265 subformatCount(0),
266 subformatCapacity(0),
267 argTypes(NULL),
268 argTypeCount(0),
269 argTypeCapacity(0),
270 defaultNumberFormat(NULL),
271 defaultDateFormat(NULL)
272 {
273 *this = that;
274 }
275
~MessageFormat()276 MessageFormat::~MessageFormat()
277 {
278 int32_t idx;
279 for (idx = 0; idx < subformatCount; idx++) {
280 delete subformats[idx].format;
281 }
282 uprv_free(subformats);
283 subformats = NULL;
284 subformatCount = subformatCapacity = 0;
285
286 uprv_free(argTypes);
287 argTypes = NULL;
288 argTypeCount = argTypeCapacity = 0;
289
290 uprv_free(formatAliases);
291
292 delete defaultNumberFormat;
293 delete defaultDateFormat;
294 }
295
296 //--------------------------------------------------------------------
297 // Variable-size array management
298
299 /**
300 * Allocate subformats[] to at least the given capacity and return
301 * TRUE if successful. If not, leave subformats[] unchanged.
302 *
303 * If subformats is NULL, allocate it. If it is not NULL, enlarge it
304 * if necessary to be at least as large as specified.
305 */
allocateSubformats(int32_t capacity)306 UBool MessageFormat::allocateSubformats(int32_t capacity) {
307 if (subformats == NULL) {
308 subformats = (Subformat*) uprv_malloc(sizeof(*subformats) * capacity);
309 subformatCapacity = capacity;
310 subformatCount = 0;
311 if (subformats == NULL) {
312 subformatCapacity = 0;
313 return FALSE;
314 }
315 } else if (subformatCapacity < capacity) {
316 if (capacity < 2*subformatCapacity) {
317 capacity = 2*subformatCapacity;
318 }
319 Subformat* a = (Subformat*)
320 uprv_realloc(subformats, sizeof(*subformats) * capacity);
321 if (a == NULL) {
322 return FALSE; // request failed
323 }
324 subformats = a;
325 subformatCapacity = capacity;
326 }
327 return TRUE;
328 }
329
330 /**
331 * Allocate argTypes[] to at least the given capacity and return
332 * TRUE if successful. If not, leave argTypes[] unchanged.
333 *
334 * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
335 * if necessary to be at least as large as specified.
336 */
allocateArgTypes(int32_t capacity)337 UBool MessageFormat::allocateArgTypes(int32_t capacity) {
338 if (argTypes == NULL) {
339 argTypes = (Formattable::Type*) uprv_malloc(sizeof(*argTypes) * capacity);
340 argTypeCount = 0;
341 argTypeCapacity = capacity;
342 if (argTypes == NULL) {
343 argTypeCapacity = 0;
344 return FALSE;
345 }
346 for (int32_t i=0; i<capacity; ++i) {
347 argTypes[i] = Formattable::kString;
348 }
349 } else if (argTypeCapacity < capacity) {
350 if (capacity < 2*argTypeCapacity) {
351 capacity = 2*argTypeCapacity;
352 }
353 Formattable::Type* a = (Formattable::Type*)
354 uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
355 if (a == NULL) {
356 return FALSE; // request failed
357 }
358 for (int32_t i=argTypeCapacity; i<capacity; ++i) {
359 a[i] = Formattable::kString;
360 }
361 argTypes = a;
362 argTypeCapacity = capacity;
363 }
364 return TRUE;
365 }
366
367 // -------------------------------------
368 // assignment operator
369
370 const MessageFormat&
operator =(const MessageFormat & that)371 MessageFormat::operator=(const MessageFormat& that)
372 {
373 // Reallocate the arrays BEFORE changing this object
374 if (this != &that &&
375 allocateSubformats(that.subformatCount) &&
376 allocateArgTypes(that.argTypeCount)) {
377
378 // Calls the super class for assignment first.
379 Format::operator=(that);
380
381 fPattern = that.fPattern;
382 setLocale(that.fLocale);
383
384 int32_t j;
385 for (j=0; j<subformatCount; ++j) {
386 delete subformats[j].format;
387 }
388 subformatCount = 0;
389
390 for (j=0; j<that.subformatCount; ++j) {
391 // Subformat::operator= does NOT delete this.format
392 subformats[j] = that.subformats[j];
393 }
394 subformatCount = that.subformatCount;
395
396 for (j=0; j<that.argTypeCount; ++j) {
397 argTypes[j] = that.argTypes[j];
398 }
399 argTypeCount = that.argTypeCount;
400 }
401 return *this;
402 }
403
404 UBool
operator ==(const Format & rhs) const405 MessageFormat::operator==(const Format& rhs) const
406 {
407 if (this == &rhs) return TRUE;
408
409 MessageFormat& that = (MessageFormat&)rhs;
410
411 // Check class ID before checking MessageFormat members
412 if (!Format::operator==(rhs) ||
413 fPattern != that.fPattern ||
414 fLocale != that.fLocale) {
415 return FALSE;
416 }
417
418 int32_t j;
419 for (j=0; j<subformatCount; ++j) {
420 if (subformats[j] != that.subformats[j]) {
421 return FALSE;
422 }
423 }
424
425 return TRUE;
426 }
427
428 // -------------------------------------
429 // Creates a copy of this MessageFormat, the caller owns the copy.
430
431 Format*
clone() const432 MessageFormat::clone() const
433 {
434 return new MessageFormat(*this);
435 }
436
437 // -------------------------------------
438 // Sets the locale of this MessageFormat object to theLocale.
439
440 void
setLocale(const Locale & theLocale)441 MessageFormat::setLocale(const Locale& theLocale)
442 {
443 if (fLocale != theLocale) {
444 delete defaultNumberFormat;
445 defaultNumberFormat = NULL;
446 delete defaultDateFormat;
447 defaultDateFormat = NULL;
448 }
449 fLocale = theLocale;
450 setLocaleIDs(fLocale.getName(), fLocale.getName());
451 }
452
453 // -------------------------------------
454 // Gets the locale of this MessageFormat object.
455
456 const Locale&
getLocale() const457 MessageFormat::getLocale() const
458 {
459 return fLocale;
460 }
461
462
463
464
465 void
applyPattern(const UnicodeString & newPattern,UErrorCode & status)466 MessageFormat::applyPattern(const UnicodeString& newPattern,
467 UErrorCode& status)
468 {
469 UParseError parseError;
470 applyPattern(newPattern,parseError,status);
471 }
472
473
474 // -------------------------------------
475 // Applies the new pattern and returns an error if the pattern
476 // is not correct.
477 void
applyPattern(const UnicodeString & pattern,UParseError & parseError,UErrorCode & ec)478 MessageFormat::applyPattern(const UnicodeString& pattern,
479 UParseError& parseError,
480 UErrorCode& ec)
481 {
482 if(U_FAILURE(ec)) {
483 return;
484 }
485 // The pattern is broken up into segments. Each time a subformat
486 // is encountered, 4 segments are recorded. For example, consider
487 // the pattern:
488 // "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}."
489 // The first set of segments is:
490 // segments[0] = "There "
491 // segments[1] = "0"
492 // segments[2] = "choice"
493 // segments[3] = "0.0#are no files|1.0#is one file|1.0<are {0, number} files"
494
495 // During parsing, the plain text is accumulated into segments[0].
496 // Segments 1..3 are used to parse each subpattern. Each time a
497 // subpattern is parsed, it creates a format object that is stored
498 // in the subformats array, together with an offset and argument
499 // number. The offset into the plain text stored in
500 // segments[0].
501
502 // Quotes in segment 0 are handled normally. They are removed.
503 // Quotes may not occur in segments 1 or 2.
504 // Quotes in segment 3 are parsed and _copied_. This makes
505 // subformat patterns work, e.g., {1,number,'#'.##} passes
506 // the pattern "'#'.##" to DecimalFormat.
507
508 UnicodeString segments[4];
509 int32_t part = 0; // segment we are in, 0..3
510 // Record the highest argument number in the pattern. (In the
511 // subpattern {3,number} the argument number is 3.)
512 int32_t formatNumber = 0;
513 UBool inQuote = FALSE;
514 int32_t braceStack = 0;
515 // Clear error struct
516 parseError.offset = -1;
517 parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
518 int32_t patLen = pattern.length();
519 int32_t i;
520
521 for (i=0; i<subformatCount; ++i) {
522 delete subformats[i].format;
523 }
524 subformatCount = 0;
525 argTypeCount = 0;
526
527 for (i=0; i<patLen; ++i) {
528 UChar ch = pattern[i];
529 if (part == 0) {
530 // In segment 0, recognize and remove quotes
531 if (ch == SINGLE_QUOTE) {
532 if (i+1 < patLen && pattern[i+1] == SINGLE_QUOTE) {
533 segments[0] += ch;
534 ++i;
535 } else {
536 inQuote = !inQuote;
537 }
538 } else if (ch == LEFT_CURLY_BRACE && !inQuote) {
539 // The only way we get from segment 0 to 1 is via an
540 // unquoted '{'.
541 part = 1;
542 } else {
543 segments[0] += ch;
544 }
545 } else if (inQuote) {
546 // In segments 1..3, recognize quoted matter, and copy it
547 // into the segment, together with the quotes. This takes
548 // care of '' as well.
549 segments[part] += ch;
550 if (ch == SINGLE_QUOTE) {
551 inQuote = FALSE;
552 }
553 } else {
554 // We have an unquoted character in segment 1..3
555 switch (ch) {
556 case COMMA:
557 // Commas bump us to the next segment, except for segment 3,
558 // which can contain commas. See example above.
559 if (part < 3)
560 part += 1;
561 else
562 segments[3] += ch;
563 break;
564 case LEFT_CURLY_BRACE:
565 // Handle '{' within segment 3. The initial '{'
566 // before segment 1 is handled above.
567 if (part != 3) {
568 ec = U_PATTERN_SYNTAX_ERROR;
569 goto SYNTAX_ERROR;
570 }
571 ++braceStack;
572 segments[part] += ch;
573 break;
574 case RIGHT_CURLY_BRACE:
575 if (braceStack == 0) {
576 makeFormat(formatNumber, segments, parseError,ec);
577 if (U_FAILURE(ec)){
578 goto SYNTAX_ERROR;
579 }
580 formatNumber++;
581 segments[1].remove();
582 segments[2].remove();
583 segments[3].remove();
584 part = 0;
585 } else {
586 --braceStack;
587 segments[part] += ch;
588 }
589 break;
590 case SINGLE_QUOTE:
591 inQuote = TRUE;
592 // fall through (copy quote chars in segments 1..3)
593 default:
594 segments[part] += ch;
595 break;
596 }
597 }
598 }
599 if (braceStack != 0 || part != 0) {
600 // Unmatched braces in the pattern
601 ec = U_UNMATCHED_BRACES;
602 goto SYNTAX_ERROR;
603 }
604 fPattern = segments[0];
605 return;
606
607 SYNTAX_ERROR:
608 syntaxError(pattern, i, parseError);
609 for (i=0; i<subformatCount; ++i) {
610 delete subformats[i].format;
611 }
612 argTypeCount = subformatCount = 0;
613 }
614 // -------------------------------------
615 // Converts this MessageFormat instance to a pattern.
616
617 UnicodeString&
toPattern(UnicodeString & appendTo) const618 MessageFormat::toPattern(UnicodeString& appendTo) const {
619 // later, make this more extensible
620 int32_t lastOffset = 0;
621 int32_t i;
622 for (i=0; i<subformatCount; ++i) {
623 copyAndFixQuotes(fPattern, lastOffset, subformats[i].offset, appendTo);
624 lastOffset = subformats[i].offset;
625 appendTo += LEFT_CURLY_BRACE;
626 itos(subformats[i].arg, appendTo);
627 Format* fmt = subformats[i].format;
628 if (fmt == NULL) {
629 // do nothing, string format
630 }
631 else if (fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
632
633 UErrorCode ec = U_ZERO_ERROR;
634 NumberFormat& formatAlias = *(NumberFormat*)fmt;
635 NumberFormat *defaultTemplate = NumberFormat::createInstance(fLocale, ec);
636 NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, ec);
637 NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, ec);
638 NumberFormat *integerTemplate = createIntegerFormat(fLocale, ec);
639
640 appendTo += COMMA;
641 appendTo += ID_NUMBER;
642 if (formatAlias != *defaultTemplate) {
643 appendTo += COMMA;
644 if (formatAlias == *currencyTemplate) {
645 appendTo += ID_CURRENCY;
646 }
647 else if (formatAlias == *percentTemplate) {
648 appendTo += ID_PERCENT;
649 }
650 else if (formatAlias == *integerTemplate) {
651 appendTo += ID_INTEGER;
652 }
653 else {
654 UnicodeString buffer;
655 appendTo += ((DecimalFormat*)fmt)->toPattern(buffer);
656 }
657 }
658
659 delete defaultTemplate;
660 delete currencyTemplate;
661 delete percentTemplate;
662 delete integerTemplate;
663 }
664 else if (fmt->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
665 DateFormat& formatAlias = *(DateFormat*)fmt;
666 DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
667 DateFormat *shortDateTemplate = DateFormat::createDateInstance(DateFormat::kShort, fLocale);
668 DateFormat *longDateTemplate = DateFormat::createDateInstance(DateFormat::kLong, fLocale);
669 DateFormat *fullDateTemplate = DateFormat::createDateInstance(DateFormat::kFull, fLocale);
670 DateFormat *defaultTimeTemplate = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
671 DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
672 DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
673 DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
674
675
676 appendTo += COMMA;
677 if (formatAlias == *defaultDateTemplate) {
678 appendTo += ID_DATE;
679 }
680 else if (formatAlias == *shortDateTemplate) {
681 appendTo += ID_DATE;
682 appendTo += COMMA;
683 appendTo += ID_SHORT;
684 }
685 else if (formatAlias == *defaultDateTemplate) {
686 appendTo += ID_DATE;
687 appendTo += COMMA;
688 appendTo += ID_MEDIUM;
689 }
690 else if (formatAlias == *longDateTemplate) {
691 appendTo += ID_DATE;
692 appendTo += COMMA;
693 appendTo += ID_LONG;
694 }
695 else if (formatAlias == *fullDateTemplate) {
696 appendTo += ID_DATE;
697 appendTo += COMMA;
698 appendTo += ID_FULL;
699 }
700 else if (formatAlias == *defaultTimeTemplate) {
701 appendTo += ID_TIME;
702 }
703 else if (formatAlias == *shortTimeTemplate) {
704 appendTo += ID_TIME;
705 appendTo += COMMA;
706 appendTo += ID_SHORT;
707 }
708 else if (formatAlias == *defaultTimeTemplate) {
709 appendTo += ID_TIME;
710 appendTo += COMMA;
711 appendTo += ID_MEDIUM;
712 }
713 else if (formatAlias == *longTimeTemplate) {
714 appendTo += ID_TIME;
715 appendTo += COMMA;
716 appendTo += ID_LONG;
717 }
718 else if (formatAlias == *fullTimeTemplate) {
719 appendTo += ID_TIME;
720 appendTo += COMMA;
721 appendTo += ID_FULL;
722 }
723 else {
724 UnicodeString buffer;
725 appendTo += ID_DATE;
726 appendTo += COMMA;
727 appendTo += ((SimpleDateFormat*)fmt)->toPattern(buffer);
728 }
729
730 delete defaultDateTemplate;
731 delete shortDateTemplate;
732 delete longDateTemplate;
733 delete fullDateTemplate;
734 delete defaultTimeTemplate;
735 delete shortTimeTemplate;
736 delete longTimeTemplate;
737 delete fullTimeTemplate;
738 // {sfb} there should be a more efficient way to do this!
739 }
740 else if (fmt->getDynamicClassID() == ChoiceFormat::getStaticClassID()) {
741 UnicodeString buffer;
742 appendTo += COMMA;
743 appendTo += ID_CHOICE;
744 appendTo += COMMA;
745 appendTo += ((ChoiceFormat*)fmt)->toPattern(buffer);
746 }
747 else {
748 //appendTo += ", unknown";
749 }
750 appendTo += RIGHT_CURLY_BRACE;
751 }
752 copyAndFixQuotes(fPattern, lastOffset, fPattern.length(), appendTo);
753 return appendTo;
754 }
755
756 // -------------------------------------
757 // Adopts the new formats array and updates the array count.
758 // This MessageFormat instance owns the new formats.
759
760 void
adoptFormats(Format ** newFormats,int32_t count)761 MessageFormat::adoptFormats(Format** newFormats,
762 int32_t count) {
763 if (newFormats == NULL || count < 0) {
764 return;
765 }
766
767 int32_t i;
768 if (allocateSubformats(count)) {
769 for (i=0; i<subformatCount; ++i) {
770 delete subformats[i].format;
771 }
772 for (i=0; i<count; ++i) {
773 subformats[i].format = newFormats[i];
774 }
775 subformatCount = count;
776 } else {
777 // An adopt method must always take ownership. Delete
778 // the incoming format objects and return unchanged.
779 for (i=0; i<count; ++i) {
780 delete newFormats[i];
781 }
782 }
783
784 // TODO: What about the .offset and .arg fields?
785 }
786
787 // -------------------------------------
788 // Sets the new formats array and updates the array count.
789 // This MessageFormat instance maks a copy of the new formats.
790
791 void
setFormats(const Format ** newFormats,int32_t count)792 MessageFormat::setFormats(const Format** newFormats,
793 int32_t count) {
794 if (newFormats == NULL || count < 0) {
795 return;
796 }
797
798 if (allocateSubformats(count)) {
799 int32_t i;
800 for (i=0; i<subformatCount; ++i) {
801 delete subformats[i].format;
802 }
803 subformatCount = 0;
804
805 for (i=0; i<count; ++i) {
806 subformats[i].format = newFormats[i] ? newFormats[i]->clone() : NULL;
807 }
808 subformatCount = count;
809 }
810
811 // TODO: What about the .offset and .arg fields?
812 }
813
814 // -------------------------------------
815 // Adopt a single format.
816 // Do nothing is the format number is not less than the array count.
817
818 void
adoptFormat(int32_t n,Format * newFormat)819 MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
820 if (n < 0 || n >= subformatCount) {
821 delete newFormat;
822 } else {
823 delete subformats[n].format;
824 subformats[n].format = newFormat;
825 }
826 }
827
828 // -------------------------------------
829 // Set a single format.
830 // Do nothing is the variable is not less than the array count.
831
832 void
setFormat(int32_t n,const Format & newFormat)833 MessageFormat::setFormat(int32_t n, const Format& newFormat) {
834 if (n >= 0 && n < subformatCount) {
835 delete subformats[n].format;
836 if (&newFormat == NULL) {
837 // This should never happen -- but we'll be nice if it does
838 subformats[n].format = NULL;
839 } else {
840 subformats[n].format = newFormat.clone();
841 }
842 }
843 }
844
845 // -------------------------------------
846 // Gets the format array.
847
848 const Format**
getFormats(int32_t & cnt) const849 MessageFormat::getFormats(int32_t& cnt) const
850 {
851 // This old API returns an array (which we hold) of Format*
852 // pointers. The array is valid up to the next call to any
853 // method on this object. We construct and resize an array
854 // on demand that contains aliases to the subformats[i].format
855 // pointers.
856 MessageFormat* t = (MessageFormat*) this;
857 cnt = 0;
858 if (formatAliases == NULL) {
859 t->formatAliasesCapacity = (subformatCount<10) ? 10 : subformatCount;
860 Format** a = (Format**)
861 uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
862 if (a == NULL) {
863 return NULL;
864 }
865 t->formatAliases = a;
866 } else if (subformatCount > formatAliasesCapacity) {
867 Format** a = (Format**)
868 uprv_realloc(formatAliases, sizeof(Format*) * subformatCount);
869 if (a == NULL) {
870 return NULL;
871 }
872 t->formatAliases = a;
873 t->formatAliasesCapacity = subformatCount;
874 }
875 for (int32_t i=0; i<subformatCount; ++i) {
876 t->formatAliases[i] = subformats[i].format;
877 }
878 cnt = subformatCount;
879 return (const Format**)formatAliases;
880 }
881
882 // -------------------------------------
883 // Formats the source Formattable array and copy into the result buffer.
884 // Ignore the FieldPosition result for error checking.
885
886 UnicodeString&
format(const Formattable * source,int32_t cnt,UnicodeString & appendTo,FieldPosition & ignore,UErrorCode & success) const887 MessageFormat::format(const Formattable* source,
888 int32_t cnt,
889 UnicodeString& appendTo,
890 FieldPosition& ignore,
891 UErrorCode& success) const
892 {
893 if (U_FAILURE(success))
894 return appendTo;
895
896 return format(source, cnt, appendTo, ignore, 0, success);
897 }
898
899 // -------------------------------------
900 // Internally creates a MessageFormat instance based on the
901 // pattern and formats the arguments Formattable array and
902 // copy into the appendTo buffer.
903
904 UnicodeString&
format(const UnicodeString & pattern,const Formattable * arguments,int32_t cnt,UnicodeString & appendTo,UErrorCode & success)905 MessageFormat::format( const UnicodeString& pattern,
906 const Formattable* arguments,
907 int32_t cnt,
908 UnicodeString& appendTo,
909 UErrorCode& success)
910 {
911 MessageFormat temp(pattern, success);
912 FieldPosition ignore(0);
913 temp.format(arguments, cnt, appendTo, ignore, success);
914 return appendTo;
915 }
916
917 // -------------------------------------
918 // Formats the source Formattable object and copy into the
919 // appendTo buffer. The Formattable object must be an array
920 // of Formattable instances, returns error otherwise.
921
922 UnicodeString&
format(const Formattable & source,UnicodeString & appendTo,FieldPosition & ignore,UErrorCode & success) const923 MessageFormat::format(const Formattable& source,
924 UnicodeString& appendTo,
925 FieldPosition& ignore,
926 UErrorCode& success) const
927 {
928 int32_t cnt;
929
930 if (U_FAILURE(success))
931 return appendTo;
932 if (source.getType() != Formattable::kArray) {
933 success = U_ILLEGAL_ARGUMENT_ERROR;
934 return appendTo;
935 }
936 const Formattable* tmpPtr = source.getArray(cnt);
937
938 return format(tmpPtr, cnt, appendTo, ignore, 0, success);
939 }
940
941 // -------------------------------------
942 // Formats the arguments Formattable array and copy into the appendTo buffer.
943 // Ignore the FieldPosition result for error checking.
944
945 UnicodeString&
format(const Formattable * arguments,int32_t cnt,UnicodeString & appendTo,FieldPosition & status,int32_t recursionProtection,UErrorCode & success) const946 MessageFormat::format(const Formattable* arguments,
947 int32_t cnt,
948 UnicodeString& appendTo,
949 FieldPosition& status,
950 int32_t recursionProtection,
951 UErrorCode& success) const
952 {
953 // Allow NULL array only if cnt == 0
954 if (cnt < 0 || (cnt && arguments == NULL)) {
955 success = U_ILLEGAL_ARGUMENT_ERROR;
956 return appendTo;
957 }
958
959 int32_t lastOffset = 0;
960 for (int32_t i=0; i<subformatCount; ++i) {
961 // Append the prefix of current format element.
962 appendTo.append(fPattern, lastOffset, subformats[i].offset - lastOffset);
963 lastOffset = subformats[i].offset;
964 int32_t argumentNumber = subformats[i].arg;
965 // Checks the scope of the argument number.
966 if (argumentNumber >= cnt) {
967 appendTo += LEFT_CURLY_BRACE;
968 itos(argumentNumber, appendTo);
969 appendTo += RIGHT_CURLY_BRACE;
970 continue;
971 }
972
973 const Formattable *obj = arguments + argumentNumber;
974 Formattable::Type type = obj->getType();
975
976 // Recursively calling the format process only if the current
977 // format argument refers to a ChoiceFormat object.
978 Format* fmt = subformats[i].format;
979 if (fmt != NULL) {
980 UnicodeString arg;
981 fmt->format(*obj, arg, success);
982
983 // Needs to reprocess the ChoiceFormat option by using the
984 // MessageFormat pattern application.
985 if (fmt->getDynamicClassID() == ChoiceFormat::getStaticClassID() &&
986 arg.indexOf(LEFT_CURLY_BRACE) >= 0) {
987 MessageFormat temp(arg, fLocale, success);
988 // TODO: Implement recursion protection
989 temp.format(arguments, cnt, appendTo, status, recursionProtection, success);
990 if (U_FAILURE(success)) {
991 return appendTo;
992 }
993 }
994 else {
995 appendTo += arg;
996 }
997 }
998 // If the obj data type is a number, use a NumberFormat instance.
999 else if ((type == Formattable::kDouble) ||
1000 (type == Formattable::kLong) ||
1001 (type == Formattable::kInt64)) {
1002
1003 const NumberFormat* nf = getDefaultNumberFormat(success);
1004 if (nf == NULL) {
1005 return appendTo;
1006 }
1007 if (type == Formattable::kDouble) {
1008 nf->format(obj->getDouble(), appendTo);
1009 } else if (type == Formattable::kLong) {
1010 nf->format(obj->getLong(), appendTo);
1011 } else {
1012 nf->format(obj->getInt64(), appendTo);
1013 }
1014 }
1015 // If the obj data type is a Date instance, use a DateFormat instance.
1016 else if (type == Formattable::kDate) {
1017 const DateFormat* df = getDefaultDateFormat(success);
1018 if (df == NULL) {
1019 return appendTo;
1020 }
1021 df->format(obj->getDate(), appendTo);
1022 }
1023 else if (type == Formattable::kString) {
1024 appendTo += obj->getString();
1025 }
1026 else {
1027 success = U_ILLEGAL_ARGUMENT_ERROR;
1028 return appendTo;
1029 }
1030 }
1031 // Appends the rest of the pattern characters after the real last offset.
1032 appendTo.append(fPattern, lastOffset, 0x7fffffff);
1033 return appendTo;
1034 }
1035
1036
1037 // -------------------------------------
1038 // Parses the source pattern and returns the Formattable objects array,
1039 // the array count and the ending parse position. The caller of this method
1040 // owns the array.
1041
1042 Formattable*
parse(const UnicodeString & source,ParsePosition & pos,int32_t & count) const1043 MessageFormat::parse(const UnicodeString& source,
1044 ParsePosition& pos,
1045 int32_t& count) const
1046 {
1047 // Allocate at least one element. Allocating an array of length
1048 // zero causes problems on some platforms (e.g. Win32).
1049 Formattable *resultArray = new Formattable[argTypeCount ? argTypeCount : 1];
1050 int32_t patternOffset = 0;
1051 int32_t sourceOffset = pos.getIndex();
1052 ParsePosition tempPos(0);
1053 count = 0; // {sfb} reset to zero
1054 int32_t len;
1055 for (int32_t i = 0; i < subformatCount; ++i) {
1056 // match up to format
1057 len = subformats[i].offset - patternOffset;
1058 if (len == 0 ||
1059 fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
1060 sourceOffset += len;
1061 patternOffset += len;
1062 }
1063 else {
1064 goto PARSE_ERROR;
1065 }
1066
1067 // now use format
1068 Format* fmt = subformats[i].format;
1069 int32_t arg = subformats[i].arg;
1070 if (fmt == NULL) { // string format
1071 // if at end, use longest possible match
1072 // otherwise uses first match to intervening string
1073 // does NOT recursively try all possibilities
1074 int32_t tempLength = (i+1<subformatCount) ?
1075 subformats[i+1].offset : fPattern.length();
1076
1077 int32_t next;
1078 if (patternOffset >= tempLength) {
1079 next = source.length();
1080 }
1081 else {
1082 UnicodeString buffer;
1083 fPattern.extract(patternOffset,tempLength - patternOffset, buffer);
1084 next = source.indexOf(buffer, sourceOffset);
1085 }
1086
1087 if (next < 0) {
1088 goto PARSE_ERROR;
1089 }
1090 else {
1091 UnicodeString buffer;
1092 source.extract(sourceOffset,next - sourceOffset, buffer);
1093 UnicodeString strValue = buffer;
1094 UnicodeString temp(LEFT_CURLY_BRACE);
1095 // {sfb} check this later
1096 itos(arg, temp);
1097 temp += RIGHT_CURLY_BRACE;
1098 if (strValue != temp) {
1099 source.extract(sourceOffset,next - sourceOffset, buffer);
1100 resultArray[arg].setString(buffer);
1101 // {sfb} not sure about this
1102 if ((arg + 1) > count) {
1103 count = arg + 1;
1104 }
1105 }
1106 sourceOffset = next;
1107 }
1108 }
1109 else {
1110 tempPos.setIndex(sourceOffset);
1111 fmt->parseObject(source, resultArray[arg], tempPos);
1112 if (tempPos.getIndex() == sourceOffset) {
1113 goto PARSE_ERROR;
1114 }
1115
1116 if ((arg + 1) > count) {
1117 count = arg + 1;
1118 }
1119 sourceOffset = tempPos.getIndex(); // update
1120 }
1121 }
1122 len = fPattern.length() - patternOffset;
1123 if (len == 0 ||
1124 fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
1125 pos.setIndex(sourceOffset + len);
1126 return resultArray;
1127 }
1128 // else fall through...
1129
1130 PARSE_ERROR:
1131 pos.setErrorIndex(sourceOffset);
1132 delete [] resultArray;
1133 count = 0;
1134 return NULL; // leave index as is to signal error
1135 }
1136
1137 // -------------------------------------
1138 // Parses the source string and returns the array of
1139 // Formattable objects and the array count. The caller
1140 // owns the returned array.
1141
1142 Formattable*
parse(const UnicodeString & source,int32_t & cnt,UErrorCode & success) const1143 MessageFormat::parse(const UnicodeString& source,
1144 int32_t& cnt,
1145 UErrorCode& success) const
1146 {
1147 ParsePosition status(0);
1148 // Calls the actual implementation method and starts
1149 // from zero offset of the source text.
1150 Formattable* result = parse(source, status, cnt);
1151 if (status.getIndex() == 0) {
1152 success = U_MESSAGE_PARSE_ERROR;
1153 delete[] result;
1154 return NULL;
1155 }
1156 return result;
1157 }
1158
1159 // -------------------------------------
1160 // Parses the source text and copy into the result buffer.
1161
1162 void
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & status) const1163 MessageFormat::parseObject( const UnicodeString& source,
1164 Formattable& result,
1165 ParsePosition& status) const
1166 {
1167 int32_t cnt = 0;
1168 Formattable* tmpResult = parse(source, status, cnt);
1169 if (tmpResult != NULL)
1170 result.adoptArray(tmpResult, cnt);
1171 }
1172
1173 UnicodeString
autoQuoteApostrophe(const UnicodeString & pattern,UErrorCode & status)1174 MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
1175 UnicodeString result;
1176 if (U_SUCCESS(status)) {
1177 int32_t plen = pattern.length();
1178 const UChar* pat = pattern.getBuffer();
1179 int32_t blen = plen * 2 + 1; // space for null termination, convenience
1180 UChar* buf = result.getBuffer(blen);
1181 if (buf == NULL) {
1182 status = U_MEMORY_ALLOCATION_ERROR;
1183 } else {
1184 int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
1185 result.releaseBuffer(U_SUCCESS(status) ? len : 0);
1186 }
1187 }
1188 if (U_FAILURE(status)) {
1189 result.setToBogus();
1190 }
1191 return result;
1192 }
1193
1194 // -------------------------------------
1195
makeRBNF(URBNFRuleSetTag tag,const Locale & locale,const UnicodeString & defaultRuleSet,UErrorCode & ec)1196 static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
1197 RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
1198 if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
1199 fmt->setDefaultRuleSet(defaultRuleSet, ec);
1200 if (U_FAILURE(ec)) { // ignore unrecognized default rule set
1201 ec = U_ZERO_ERROR;
1202 }
1203 }
1204 return fmt;
1205 }
1206
1207 /**
1208 * Reads the segments[] array (see applyPattern()) and parses the
1209 * segments[1..3] into a Format* object. Stores the format object in
1210 * the subformats[] array. Updates the argTypes[] array type
1211 * information for the corresponding argument.
1212 *
1213 * @param formatNumber index into subformats[] for this format
1214 * @param segments array of strings with the parsed pattern segments
1215 * @param parseError parse error data (output param)
1216 * @param ec error code
1217 */
1218 void
makeFormat(int32_t formatNumber,UnicodeString * segments,UParseError & parseError,UErrorCode & ec)1219 MessageFormat::makeFormat(int32_t formatNumber,
1220 UnicodeString* segments,
1221 UParseError& parseError,
1222 UErrorCode& ec) {
1223 if (U_FAILURE(ec)) {
1224 return;
1225 }
1226
1227 // Parse the argument number
1228 int32_t argumentNumber = stou(segments[1]); // always unlocalized!
1229 if (argumentNumber < 0) {
1230 ec = U_INVALID_FORMAT_ERROR;
1231 return;
1232 }
1233
1234 // Parse the format, recording the argument type and creating a
1235 // new Format object (except for string arguments).
1236 Formattable::Type argType;
1237 Format *fmt = NULL;
1238 int32_t typeID, styleID;
1239 DateFormat::EStyle style;
1240
1241 switch (typeID = findKeyword(segments[2], TYPE_IDS)) {
1242
1243 case 0: // string
1244 argType = Formattable::kString;
1245 break;
1246
1247 case 1: // number
1248 argType = Formattable::kDouble;
1249
1250 switch (findKeyword(segments[3], NUMBER_STYLE_IDS)) {
1251 case 0: // default
1252 fmt = NumberFormat::createInstance(fLocale, ec);
1253 break;
1254 case 1: // currency
1255 fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
1256 break;
1257 case 2: // percent
1258 fmt = NumberFormat::createPercentInstance(fLocale, ec);
1259 break;
1260 case 3: // integer
1261 argType = Formattable::kLong;
1262 fmt = createIntegerFormat(fLocale, ec);
1263 break;
1264 default: // pattern
1265 fmt = NumberFormat::createInstance(fLocale, ec);
1266 if (fmt &&
1267 fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
1268 ((DecimalFormat*)fmt)->applyPattern(segments[3],parseError,ec);
1269 }
1270 break;
1271 }
1272 break;
1273
1274 case 2: // date
1275 case 3: // time
1276 argType = Formattable::kDate;
1277 styleID = findKeyword(segments[3], DATE_STYLE_IDS);
1278 style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
1279
1280 if (typeID == 2) {
1281 fmt = DateFormat::createDateInstance(style, fLocale);
1282 } else {
1283 fmt = DateFormat::createTimeInstance(style, fLocale);
1284 }
1285
1286 if (styleID < 0 &&
1287 fmt != NULL &&
1288 fmt->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
1289 ((SimpleDateFormat*)fmt)->applyPattern(segments[3]);
1290 }
1291 break;
1292
1293 case 4: // choice
1294 argType = Formattable::kDouble;
1295
1296 fmt = new ChoiceFormat(segments[3], parseError, ec);
1297 break;
1298
1299 case 5: // spellout
1300 argType = Formattable::kDouble;
1301 fmt = makeRBNF(URBNF_SPELLOUT, fLocale, segments[3], ec);
1302 break;
1303 case 6: // ordinal
1304 argType = Formattable::kDouble;
1305 fmt = makeRBNF(URBNF_ORDINAL, fLocale, segments[3], ec);
1306 break;
1307 case 7: // duration
1308 argType = Formattable::kDouble;
1309 fmt = makeRBNF(URBNF_DURATION, fLocale, segments[3], ec);
1310 break;
1311 default:
1312 argType = Formattable::kString;
1313 ec = U_ILLEGAL_ARGUMENT_ERROR;
1314 break;
1315 }
1316
1317 if (fmt==NULL && argType!=Formattable::kString && U_SUCCESS(ec)) {
1318 ec = U_MEMORY_ALLOCATION_ERROR;
1319 }
1320
1321 if (!allocateSubformats(formatNumber+1) ||
1322 !allocateArgTypes(argumentNumber+1)) {
1323 ec = U_MEMORY_ALLOCATION_ERROR;
1324 }
1325
1326 if (U_FAILURE(ec)) {
1327 delete fmt;
1328 return;
1329 }
1330
1331 // Parse succeeded; record results in our arrays
1332 subformats[formatNumber].format = fmt;
1333 subformats[formatNumber].offset = segments[0].length();
1334 subformats[formatNumber].arg = argumentNumber;
1335 subformatCount = formatNumber+1;
1336
1337 // Careful here: argumentNumber may in general arrive out of
1338 // sequence, e.g., "There was {2} on {0,date} (see {1,number})."
1339 argTypes[argumentNumber] = argType;
1340 if (argumentNumber+1 > argTypeCount) {
1341 argTypeCount = argumentNumber+1;
1342 }
1343 }
1344
1345 // -------------------------------------
1346 // Finds the string, s, in the string array, list.
findKeyword(const UnicodeString & s,const UChar * const * list)1347 int32_t MessageFormat::findKeyword(const UnicodeString& s,
1348 const UChar * const *list)
1349 {
1350 if (s.length() == 0)
1351 return 0; // default
1352
1353 UnicodeString buffer = s;
1354 // Trims the space characters and turns all characters
1355 // in s to lower case.
1356 buffer.trim().toLower("");
1357 for (int32_t i = 0; list[i]; ++i) {
1358 if (!buffer.compare(list[i], u_strlen(list[i]))) {
1359 return i;
1360 }
1361 }
1362 return -1;
1363 }
1364
1365 // -------------------------------------
1366 // Checks the range of the source text to quote the special
1367 // characters, { and ' and copy to target buffer.
1368
1369 void
copyAndFixQuotes(const UnicodeString & source,int32_t start,int32_t end,UnicodeString & appendTo)1370 MessageFormat::copyAndFixQuotes(const UnicodeString& source,
1371 int32_t start,
1372 int32_t end,
1373 UnicodeString& appendTo)
1374 {
1375 UBool gotLB = FALSE;
1376
1377 for (int32_t i = start; i < end; ++i) {
1378 UChar ch = source[i];
1379 if (ch == LEFT_CURLY_BRACE) {
1380 appendTo += SINGLE_QUOTE;
1381 appendTo += LEFT_CURLY_BRACE;
1382 appendTo += SINGLE_QUOTE;
1383 gotLB = TRUE;
1384 }
1385 else if (ch == RIGHT_CURLY_BRACE) {
1386 if(gotLB) {
1387 appendTo += RIGHT_CURLY_BRACE;
1388 gotLB = FALSE;
1389 }
1390 else {
1391 // orig code.
1392 appendTo += SINGLE_QUOTE;
1393 appendTo += RIGHT_CURLY_BRACE;
1394 appendTo += SINGLE_QUOTE;
1395 }
1396 }
1397 else if (ch == SINGLE_QUOTE) {
1398 appendTo += SINGLE_QUOTE;
1399 appendTo += SINGLE_QUOTE;
1400 }
1401 else {
1402 appendTo += ch;
1403 }
1404 }
1405 }
1406
1407 /**
1408 * Convenience method that ought to be in NumberFormat
1409 */
1410 NumberFormat*
createIntegerFormat(const Locale & locale,UErrorCode & status) const1411 MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
1412 NumberFormat *temp = NumberFormat::createInstance(locale, status);
1413 if (temp != NULL && temp->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
1414 DecimalFormat *temp2 = (DecimalFormat*) temp;
1415 temp2->setMaximumFractionDigits(0);
1416 temp2->setDecimalSeparatorAlwaysShown(FALSE);
1417 temp2->setParseIntegerOnly(TRUE);
1418 }
1419
1420 return temp;
1421 }
1422
1423 /**
1424 * Return the default number format. Used to format a numeric
1425 * argument when subformats[i].format is NULL. Returns NULL
1426 * on failure.
1427 *
1428 * Semantically const but may modify *this.
1429 */
getDefaultNumberFormat(UErrorCode & ec) const1430 const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
1431 if (defaultNumberFormat == NULL) {
1432 MessageFormat* t = (MessageFormat*) this;
1433 t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
1434 if (U_FAILURE(ec)) {
1435 delete t->defaultNumberFormat;
1436 t->defaultNumberFormat = NULL;
1437 } else if (t->defaultNumberFormat == NULL) {
1438 ec = U_MEMORY_ALLOCATION_ERROR;
1439 }
1440 }
1441 return defaultNumberFormat;
1442 }
1443
1444 /**
1445 * Return the default date format. Used to format a date
1446 * argument when subformats[i].format is NULL. Returns NULL
1447 * on failure.
1448 *
1449 * Semantically const but may modify *this.
1450 */
getDefaultDateFormat(UErrorCode & ec) const1451 const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
1452 if (defaultDateFormat == NULL) {
1453 MessageFormat* t = (MessageFormat*) this;
1454 t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
1455 if (t->defaultDateFormat == NULL) {
1456 ec = U_MEMORY_ALLOCATION_ERROR;
1457 }
1458 }
1459 return defaultDateFormat;
1460 }
1461
1462 U_NAMESPACE_END
1463
1464 #endif /* #if !UCONFIG_NO_FORMATTING */
1465
1466 //eof
1467