• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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