Line data Source code
1 : // © 2016 and later: Unicode, Inc. and others.
2 : // License & terms of use: http://www.unicode.org/copyright.html
3 : /********************************************************************
4 : * COPYRIGHT:
5 : * Copyright (c) 1997-2015, International Business Machines Corporation and
6 : * others. All Rights Reserved.
7 : ********************************************************************
8 : *
9 : * File MSGFMT.CPP
10 : *
11 : * Modification History:
12 : *
13 : * Date Name Description
14 : * 02/19/97 aliu Converted from java.
15 : * 03/20/97 helena Finished first cut of implementation.
16 : * 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi.
17 : * 06/11/97 helena Fixed addPattern to take the pattern correctly.
18 : * 06/17/97 helena Fixed the getPattern to return the correct pattern.
19 : * 07/09/97 helena Made ParsePosition into a class.
20 : * 02/22/99 stephen Removed character literals for EBCDIC safety
21 : * 11/01/09 kirtig Added SelectFormat
22 : ********************************************************************/
23 :
24 : #include "unicode/utypes.h"
25 :
26 : #if !UCONFIG_NO_FORMATTING
27 :
28 : #include "unicode/appendable.h"
29 : #include "unicode/choicfmt.h"
30 : #include "unicode/datefmt.h"
31 : #include "unicode/decimfmt.h"
32 : #include "unicode/localpointer.h"
33 : #include "unicode/msgfmt.h"
34 : #include "unicode/plurfmt.h"
35 : #include "unicode/rbnf.h"
36 : #include "unicode/selfmt.h"
37 : #include "unicode/smpdtfmt.h"
38 : #include "unicode/umsg.h"
39 : #include "unicode/ustring.h"
40 : #include "cmemory.h"
41 : #include "patternprops.h"
42 : #include "messageimpl.h"
43 : #include "msgfmt_impl.h"
44 : #include "plurrule_impl.h"
45 : #include "uassert.h"
46 : #include "uelement.h"
47 : #include "uhash.h"
48 : #include "ustrfmt.h"
49 : #include "util.h"
50 : #include "uvector.h"
51 : #include "visibledigits.h"
52 :
53 : // *****************************************************************************
54 : // class MessageFormat
55 : // *****************************************************************************
56 :
57 : #define SINGLE_QUOTE ((UChar)0x0027)
58 : #define COMMA ((UChar)0x002C)
59 : #define LEFT_CURLY_BRACE ((UChar)0x007B)
60 : #define RIGHT_CURLY_BRACE ((UChar)0x007D)
61 :
62 : //---------------------------------------
63 : // static data
64 :
65 : static const UChar ID_NUMBER[] = {
66 : 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
67 : };
68 : static const UChar ID_DATE[] = {
69 : 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
70 : };
71 : static const UChar ID_TIME[] = {
72 : 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
73 : };
74 : static const UChar ID_SPELLOUT[] = {
75 : 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
76 : };
77 : static const UChar ID_ORDINAL[] = {
78 : 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
79 : };
80 : static const UChar ID_DURATION[] = {
81 : 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
82 : };
83 :
84 : // MessageFormat Type List Number, Date, Time or Choice
85 : static const UChar * const TYPE_IDS[] = {
86 : ID_NUMBER,
87 : ID_DATE,
88 : ID_TIME,
89 : ID_SPELLOUT,
90 : ID_ORDINAL,
91 : ID_DURATION,
92 : NULL,
93 : };
94 :
95 : static const UChar ID_EMPTY[] = {
96 : 0 /* empty string, used for default so that null can mark end of list */
97 : };
98 : static const UChar ID_CURRENCY[] = {
99 : 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
100 : };
101 : static const UChar ID_PERCENT[] = {
102 : 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
103 : };
104 : static const UChar ID_INTEGER[] = {
105 : 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
106 : };
107 :
108 : // NumberFormat modifier list, default, currency, percent or integer
109 : static const UChar * const NUMBER_STYLE_IDS[] = {
110 : ID_EMPTY,
111 : ID_CURRENCY,
112 : ID_PERCENT,
113 : ID_INTEGER,
114 : NULL,
115 : };
116 :
117 : static const UChar ID_SHORT[] = {
118 : 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
119 : };
120 : static const UChar ID_MEDIUM[] = {
121 : 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
122 : };
123 : static const UChar ID_LONG[] = {
124 : 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
125 : };
126 : static const UChar ID_FULL[] = {
127 : 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
128 : };
129 :
130 : // DateFormat modifier list, default, short, medium, long or full
131 : static const UChar * const DATE_STYLE_IDS[] = {
132 : ID_EMPTY,
133 : ID_SHORT,
134 : ID_MEDIUM,
135 : ID_LONG,
136 : ID_FULL,
137 : NULL,
138 : };
139 :
140 : static const icu::DateFormat::EStyle DATE_STYLES[] = {
141 : icu::DateFormat::kDefault,
142 : icu::DateFormat::kShort,
143 : icu::DateFormat::kMedium,
144 : icu::DateFormat::kLong,
145 : icu::DateFormat::kFull,
146 : };
147 :
148 : static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
149 :
150 : static const UChar NULL_STRING[] = {
151 : 0x6E, 0x75, 0x6C, 0x6C, 0 // "null"
152 : };
153 :
154 : static const UChar OTHER_STRING[] = {
155 : 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other"
156 : };
157 :
158 : U_CDECL_BEGIN
159 0 : static UBool U_CALLCONV equalFormatsForHash(const UHashTok key1,
160 : const UHashTok key2) {
161 0 : return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer);
162 : }
163 :
164 : U_CDECL_END
165 :
166 : U_NAMESPACE_BEGIN
167 :
168 : // -------------------------------------
169 0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
170 0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration)
171 :
172 : //--------------------------------------------------------------------
173 :
174 : /**
175 : * Convert an integer value to a string and append the result to
176 : * the given UnicodeString.
177 : */
178 0 : static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
179 : UChar temp[16];
180 0 : uprv_itou(temp,16,i,10,0); // 10 == radix
181 0 : appendTo.append(temp, -1);
182 0 : return appendTo;
183 : }
184 :
185 :
186 : // AppendableWrapper: encapsulates the result of formatting, keeping track
187 : // of the string and its length.
188 : class AppendableWrapper : public UMemory {
189 : public:
190 0 : AppendableWrapper(Appendable& appendable) : app(appendable), len(0) {
191 0 : }
192 0 : void append(const UnicodeString& s) {
193 0 : app.appendString(s.getBuffer(), s.length());
194 0 : len += s.length();
195 0 : }
196 0 : void append(const UChar* s, const int32_t sLength) {
197 0 : app.appendString(s, sLength);
198 0 : len += sLength;
199 0 : }
200 0 : void append(const UnicodeString& s, int32_t start, int32_t length) {
201 0 : append(s.tempSubString(start, length));
202 0 : }
203 0 : void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) {
204 0 : UnicodeString s;
205 0 : formatter->format(arg, s, ec);
206 0 : if (U_SUCCESS(ec)) {
207 0 : append(s);
208 : }
209 0 : }
210 0 : void formatAndAppend(const Format* formatter, const Formattable& arg,
211 : const UnicodeString &argString, UErrorCode& ec) {
212 0 : if (!argString.isEmpty()) {
213 0 : if (U_SUCCESS(ec)) {
214 0 : append(argString);
215 : }
216 : } else {
217 0 : formatAndAppend(formatter, arg, ec);
218 : }
219 0 : }
220 0 : int32_t length() {
221 0 : return len;
222 : }
223 : private:
224 : Appendable& app;
225 : int32_t len;
226 : };
227 :
228 :
229 : // -------------------------------------
230 : // Creates a MessageFormat instance based on the pattern.
231 :
232 0 : MessageFormat::MessageFormat(const UnicodeString& pattern,
233 0 : UErrorCode& success)
234 : : fLocale(Locale::getDefault()), // Uses the default locale
235 : msgPattern(success),
236 : formatAliases(NULL),
237 : formatAliasesCapacity(0),
238 : argTypes(NULL),
239 : argTypeCount(0),
240 : argTypeCapacity(0),
241 : hasArgTypeConflicts(FALSE),
242 : defaultNumberFormat(NULL),
243 : defaultDateFormat(NULL),
244 : cachedFormatters(NULL),
245 : customFormatArgStarts(NULL),
246 : pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
247 0 : ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
248 : {
249 0 : setLocaleIDs(fLocale.getName(), fLocale.getName());
250 0 : applyPattern(pattern, success);
251 0 : }
252 :
253 0 : MessageFormat::MessageFormat(const UnicodeString& pattern,
254 : const Locale& newLocale,
255 0 : UErrorCode& success)
256 : : fLocale(newLocale),
257 : msgPattern(success),
258 : formatAliases(NULL),
259 : formatAliasesCapacity(0),
260 : argTypes(NULL),
261 : argTypeCount(0),
262 : argTypeCapacity(0),
263 : hasArgTypeConflicts(FALSE),
264 : defaultNumberFormat(NULL),
265 : defaultDateFormat(NULL),
266 : cachedFormatters(NULL),
267 : customFormatArgStarts(NULL),
268 : pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
269 0 : ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
270 : {
271 0 : setLocaleIDs(fLocale.getName(), fLocale.getName());
272 0 : applyPattern(pattern, success);
273 0 : }
274 :
275 0 : MessageFormat::MessageFormat(const UnicodeString& pattern,
276 : const Locale& newLocale,
277 : UParseError& parseError,
278 0 : UErrorCode& success)
279 : : fLocale(newLocale),
280 : msgPattern(success),
281 : formatAliases(NULL),
282 : formatAliasesCapacity(0),
283 : argTypes(NULL),
284 : argTypeCount(0),
285 : argTypeCapacity(0),
286 : hasArgTypeConflicts(FALSE),
287 : defaultNumberFormat(NULL),
288 : defaultDateFormat(NULL),
289 : cachedFormatters(NULL),
290 : customFormatArgStarts(NULL),
291 : pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
292 0 : ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
293 : {
294 0 : setLocaleIDs(fLocale.getName(), fLocale.getName());
295 0 : applyPattern(pattern, parseError, success);
296 0 : }
297 :
298 0 : MessageFormat::MessageFormat(const MessageFormat& that)
299 : :
300 : Format(that),
301 : fLocale(that.fLocale),
302 : msgPattern(that.msgPattern),
303 : formatAliases(NULL),
304 : formatAliasesCapacity(0),
305 : argTypes(NULL),
306 : argTypeCount(0),
307 : argTypeCapacity(0),
308 0 : hasArgTypeConflicts(that.hasArgTypeConflicts),
309 : defaultNumberFormat(NULL),
310 : defaultDateFormat(NULL),
311 : cachedFormatters(NULL),
312 : customFormatArgStarts(NULL),
313 : pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
314 0 : ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
315 : {
316 : // This will take care of creating the hash tables (since they are NULL).
317 0 : UErrorCode ec = U_ZERO_ERROR;
318 0 : copyObjects(that, ec);
319 0 : if (U_FAILURE(ec)) {
320 0 : resetPattern();
321 : }
322 0 : }
323 :
324 0 : MessageFormat::~MessageFormat()
325 : {
326 0 : uhash_close(cachedFormatters);
327 0 : uhash_close(customFormatArgStarts);
328 :
329 0 : uprv_free(argTypes);
330 0 : uprv_free(formatAliases);
331 0 : delete defaultNumberFormat;
332 0 : delete defaultDateFormat;
333 0 : }
334 :
335 : //--------------------------------------------------------------------
336 : // Variable-size array management
337 :
338 : /**
339 : * Allocate argTypes[] to at least the given capacity and return
340 : * TRUE if successful. If not, leave argTypes[] unchanged.
341 : *
342 : * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
343 : * if necessary to be at least as large as specified.
344 : */
345 0 : UBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) {
346 0 : if (U_FAILURE(status)) {
347 0 : return FALSE;
348 : }
349 0 : if (argTypeCapacity >= capacity) {
350 0 : return TRUE;
351 : }
352 0 : if (capacity < DEFAULT_INITIAL_CAPACITY) {
353 0 : capacity = DEFAULT_INITIAL_CAPACITY;
354 0 : } else if (capacity < 2*argTypeCapacity) {
355 0 : capacity = 2*argTypeCapacity;
356 : }
357 : Formattable::Type* a = (Formattable::Type*)
358 0 : uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
359 0 : if (a == NULL) {
360 0 : status = U_MEMORY_ALLOCATION_ERROR;
361 0 : return FALSE;
362 : }
363 0 : argTypes = a;
364 0 : argTypeCapacity = capacity;
365 0 : return TRUE;
366 : }
367 :
368 : // -------------------------------------
369 : // assignment operator
370 :
371 : const MessageFormat&
372 0 : MessageFormat::operator=(const MessageFormat& that)
373 : {
374 0 : if (this != &that) {
375 : // Calls the super class for assignment first.
376 0 : Format::operator=(that);
377 :
378 0 : setLocale(that.fLocale);
379 0 : msgPattern = that.msgPattern;
380 0 : hasArgTypeConflicts = that.hasArgTypeConflicts;
381 :
382 0 : UErrorCode ec = U_ZERO_ERROR;
383 0 : copyObjects(that, ec);
384 0 : if (U_FAILURE(ec)) {
385 0 : resetPattern();
386 : }
387 : }
388 0 : return *this;
389 : }
390 :
391 : UBool
392 0 : MessageFormat::operator==(const Format& rhs) const
393 : {
394 0 : if (this == &rhs) return TRUE;
395 :
396 0 : MessageFormat& that = (MessageFormat&)rhs;
397 :
398 : // Check class ID before checking MessageFormat members
399 0 : if (!Format::operator==(rhs) ||
400 0 : msgPattern != that.msgPattern ||
401 0 : fLocale != that.fLocale) {
402 0 : return FALSE;
403 : }
404 :
405 : // Compare hashtables.
406 0 : if ((customFormatArgStarts == NULL) != (that.customFormatArgStarts == NULL)) {
407 0 : return FALSE;
408 : }
409 0 : if (customFormatArgStarts == NULL) {
410 0 : return TRUE;
411 : }
412 :
413 0 : UErrorCode ec = U_ZERO_ERROR;
414 0 : const int32_t count = uhash_count(customFormatArgStarts);
415 0 : const int32_t rhs_count = uhash_count(that.customFormatArgStarts);
416 0 : if (count != rhs_count) {
417 0 : return FALSE;
418 : }
419 0 : int32_t idx = 0, rhs_idx = 0, pos = UHASH_FIRST, rhs_pos = UHASH_FIRST;
420 0 : for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) {
421 0 : const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos);
422 0 : const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos);
423 0 : if (cur->key.integer != rhs_cur->key.integer) {
424 0 : return FALSE;
425 : }
426 0 : const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer);
427 0 : const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer);
428 0 : if (*format != *rhs_format) {
429 0 : return FALSE;
430 : }
431 : }
432 0 : return TRUE;
433 : }
434 :
435 : // -------------------------------------
436 : // Creates a copy of this MessageFormat, the caller owns the copy.
437 :
438 : Format*
439 0 : MessageFormat::clone() const
440 : {
441 0 : return new MessageFormat(*this);
442 : }
443 :
444 : // -------------------------------------
445 : // Sets the locale of this MessageFormat object to theLocale.
446 :
447 : void
448 0 : MessageFormat::setLocale(const Locale& theLocale)
449 : {
450 0 : if (fLocale != theLocale) {
451 0 : delete defaultNumberFormat;
452 0 : defaultNumberFormat = NULL;
453 0 : delete defaultDateFormat;
454 0 : defaultDateFormat = NULL;
455 0 : fLocale = theLocale;
456 0 : setLocaleIDs(fLocale.getName(), fLocale.getName());
457 0 : pluralProvider.reset();
458 0 : ordinalProvider.reset();
459 : }
460 0 : }
461 :
462 : // -------------------------------------
463 : // Gets the locale of this MessageFormat object.
464 :
465 : const Locale&
466 0 : MessageFormat::getLocale() const
467 : {
468 0 : return fLocale;
469 : }
470 :
471 : void
472 0 : MessageFormat::applyPattern(const UnicodeString& newPattern,
473 : UErrorCode& status)
474 : {
475 : UParseError parseError;
476 0 : applyPattern(newPattern,parseError,status);
477 0 : }
478 :
479 :
480 : // -------------------------------------
481 : // Applies the new pattern and returns an error if the pattern
482 : // is not correct.
483 : void
484 0 : MessageFormat::applyPattern(const UnicodeString& pattern,
485 : UParseError& parseError,
486 : UErrorCode& ec)
487 : {
488 0 : if(U_FAILURE(ec)) {
489 0 : return;
490 : }
491 0 : msgPattern.parse(pattern, &parseError, ec);
492 0 : cacheExplicitFormats(ec);
493 :
494 0 : if (U_FAILURE(ec)) {
495 0 : resetPattern();
496 : }
497 : }
498 :
499 0 : void MessageFormat::resetPattern() {
500 0 : msgPattern.clear();
501 0 : uhash_close(cachedFormatters);
502 0 : cachedFormatters = NULL;
503 0 : uhash_close(customFormatArgStarts);
504 0 : customFormatArgStarts = NULL;
505 0 : argTypeCount = 0;
506 0 : hasArgTypeConflicts = FALSE;
507 0 : }
508 :
509 : void
510 0 : MessageFormat::applyPattern(const UnicodeString& pattern,
511 : UMessagePatternApostropheMode aposMode,
512 : UParseError* parseError,
513 : UErrorCode& status) {
514 0 : if (aposMode != msgPattern.getApostropheMode()) {
515 0 : msgPattern.clearPatternAndSetApostropheMode(aposMode);
516 : }
517 0 : applyPattern(pattern, *parseError, status);
518 0 : }
519 :
520 : // -------------------------------------
521 : // Converts this MessageFormat instance to a pattern.
522 :
523 : UnicodeString&
524 0 : MessageFormat::toPattern(UnicodeString& appendTo) const {
525 0 : if ((customFormatArgStarts != NULL && 0 != uhash_count(customFormatArgStarts)) ||
526 0 : 0 == msgPattern.countParts()
527 : ) {
528 0 : appendTo.setToBogus();
529 0 : return appendTo;
530 : }
531 0 : return appendTo.append(msgPattern.getPatternString());
532 : }
533 :
534 0 : int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
535 0 : if (partIndex != 0) {
536 0 : partIndex = msgPattern.getLimitPartIndex(partIndex);
537 : }
538 : for (;;) {
539 0 : UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
540 0 : if (type == UMSGPAT_PART_TYPE_ARG_START) {
541 0 : return partIndex;
542 : }
543 0 : if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
544 0 : return -1;
545 : }
546 0 : }
547 : }
548 :
549 0 : void MessageFormat::setArgStartFormat(int32_t argStart,
550 : Format* formatter,
551 : UErrorCode& status) {
552 0 : if (U_FAILURE(status)) {
553 0 : delete formatter;
554 0 : return;
555 : }
556 0 : if (cachedFormatters == NULL) {
557 0 : cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
558 : equalFormatsForHash, &status);
559 0 : if (U_FAILURE(status)) {
560 0 : delete formatter;
561 0 : return;
562 : }
563 0 : uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
564 : }
565 0 : if (formatter == NULL) {
566 0 : formatter = new DummyFormat();
567 : }
568 0 : uhash_iput(cachedFormatters, argStart, formatter, &status);
569 : }
570 :
571 :
572 0 : UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
573 0 : const MessagePattern::Part& part = msgPattern.getPart(partIndex);
574 0 : return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
575 0 : msgPattern.partSubstringMatches(part, argName) :
576 0 : part.getValue() == argNumber; // ARG_NUMBER
577 : }
578 :
579 : // Sets a custom formatter for a MessagePattern ARG_START part index.
580 : // "Custom" formatters are provided by the user via setFormat() or similar APIs.
581 0 : void MessageFormat::setCustomArgStartFormat(int32_t argStart,
582 : Format* formatter,
583 : UErrorCode& status) {
584 0 : setArgStartFormat(argStart, formatter, status);
585 0 : if (customFormatArgStarts == NULL) {
586 0 : customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
587 : NULL, &status);
588 : }
589 0 : uhash_iputi(customFormatArgStarts, argStart, 1, &status);
590 0 : }
591 :
592 0 : Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
593 0 : if (cachedFormatters == NULL) {
594 0 : return NULL;
595 : }
596 0 : void* ptr = uhash_iget(cachedFormatters, argumentNumber);
597 0 : if (ptr != NULL && dynamic_cast<DummyFormat*>((Format*)ptr) == NULL) {
598 0 : return (Format*) ptr;
599 : } else {
600 : // Not cached, or a DummyFormat representing setFormat(NULL).
601 0 : return NULL;
602 : }
603 : }
604 :
605 : // -------------------------------------
606 : // Adopts the new formats array and updates the array count.
607 : // This MessageFormat instance owns the new formats.
608 : void
609 0 : MessageFormat::adoptFormats(Format** newFormats,
610 : int32_t count) {
611 0 : if (newFormats == NULL || count < 0) {
612 0 : return;
613 : }
614 : // Throw away any cached formatters.
615 0 : if (cachedFormatters != NULL) {
616 0 : uhash_removeAll(cachedFormatters);
617 : }
618 0 : if (customFormatArgStarts != NULL) {
619 0 : uhash_removeAll(customFormatArgStarts);
620 : }
621 :
622 0 : int32_t formatNumber = 0;
623 0 : UErrorCode status = U_ZERO_ERROR;
624 0 : for (int32_t partIndex = 0;
625 0 : formatNumber < count && U_SUCCESS(status) &&
626 : (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
627 0 : setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
628 0 : ++formatNumber;
629 : }
630 : // Delete those that didn't get used (if any).
631 0 : for (; formatNumber < count; ++formatNumber) {
632 0 : delete newFormats[formatNumber];
633 : }
634 :
635 : }
636 :
637 : // -------------------------------------
638 : // Sets the new formats array and updates the array count.
639 : // This MessageFormat instance maks a copy of the new formats.
640 :
641 : void
642 0 : MessageFormat::setFormats(const Format** newFormats,
643 : int32_t count) {
644 0 : if (newFormats == NULL || count < 0) {
645 0 : return;
646 : }
647 : // Throw away any cached formatters.
648 0 : if (cachedFormatters != NULL) {
649 0 : uhash_removeAll(cachedFormatters);
650 : }
651 0 : if (customFormatArgStarts != NULL) {
652 0 : uhash_removeAll(customFormatArgStarts);
653 : }
654 :
655 0 : UErrorCode status = U_ZERO_ERROR;
656 0 : int32_t formatNumber = 0;
657 0 : for (int32_t partIndex = 0;
658 0 : formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
659 0 : Format* newFormat = NULL;
660 0 : if (newFormats[formatNumber] != NULL) {
661 0 : newFormat = newFormats[formatNumber]->clone();
662 0 : if (newFormat == NULL) {
663 0 : status = U_MEMORY_ALLOCATION_ERROR;
664 : }
665 : }
666 0 : setCustomArgStartFormat(partIndex, newFormat, status);
667 0 : ++formatNumber;
668 : }
669 0 : if (U_FAILURE(status)) {
670 0 : resetPattern();
671 : }
672 : }
673 :
674 : // -------------------------------------
675 : // Adopt a single format by format number.
676 : // Do nothing if the format number is not less than the array count.
677 :
678 : void
679 0 : MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
680 0 : LocalPointer<Format> p(newFormat);
681 0 : if (n >= 0) {
682 0 : int32_t formatNumber = 0;
683 0 : for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
684 0 : if (n == formatNumber) {
685 0 : UErrorCode status = U_ZERO_ERROR;
686 0 : setCustomArgStartFormat(partIndex, p.orphan(), status);
687 0 : return;
688 : }
689 0 : ++formatNumber;
690 : }
691 : }
692 : }
693 :
694 : // -------------------------------------
695 : // Adopt a single format by format name.
696 : // Do nothing if there is no match of formatName.
697 : void
698 0 : MessageFormat::adoptFormat(const UnicodeString& formatName,
699 : Format* formatToAdopt,
700 : UErrorCode& status) {
701 0 : LocalPointer<Format> p(formatToAdopt);
702 0 : if (U_FAILURE(status)) {
703 0 : return;
704 : }
705 0 : int32_t argNumber = MessagePattern::validateArgumentName(formatName);
706 0 : if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
707 0 : status = U_ILLEGAL_ARGUMENT_ERROR;
708 0 : return;
709 : }
710 0 : for (int32_t partIndex = 0;
711 0 : (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
712 : ) {
713 0 : if (argNameMatches(partIndex + 1, formatName, argNumber)) {
714 : Format* f;
715 0 : if (p.isValid()) {
716 0 : f = p.orphan();
717 0 : } else if (formatToAdopt == NULL) {
718 0 : f = NULL;
719 : } else {
720 0 : f = formatToAdopt->clone();
721 0 : if (f == NULL) {
722 0 : status = U_MEMORY_ALLOCATION_ERROR;
723 0 : return;
724 : }
725 : }
726 0 : setCustomArgStartFormat(partIndex, f, status);
727 : }
728 : }
729 : }
730 :
731 : // -------------------------------------
732 : // Set a single format.
733 : // Do nothing if the variable is not less than the array count.
734 : void
735 0 : MessageFormat::setFormat(int32_t n, const Format& newFormat) {
736 :
737 0 : if (n >= 0) {
738 0 : int32_t formatNumber = 0;
739 0 : for (int32_t partIndex = 0;
740 : (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
741 0 : if (n == formatNumber) {
742 0 : Format* new_format = newFormat.clone();
743 0 : if (new_format) {
744 0 : UErrorCode status = U_ZERO_ERROR;
745 0 : setCustomArgStartFormat(partIndex, new_format, status);
746 : }
747 0 : return;
748 : }
749 0 : ++formatNumber;
750 : }
751 : }
752 : }
753 :
754 : // -------------------------------------
755 : // Get a single format by format name.
756 : // Do nothing if the variable is not less than the array count.
757 : Format *
758 0 : MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
759 0 : if (U_FAILURE(status) || cachedFormatters == NULL) return NULL;
760 :
761 0 : int32_t argNumber = MessagePattern::validateArgumentName(formatName);
762 0 : if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
763 0 : status = U_ILLEGAL_ARGUMENT_ERROR;
764 0 : return NULL;
765 : }
766 0 : for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
767 0 : if (argNameMatches(partIndex + 1, formatName, argNumber)) {
768 0 : return getCachedFormatter(partIndex);
769 : }
770 : }
771 0 : return NULL;
772 : }
773 :
774 : // -------------------------------------
775 : // Set a single format by format name
776 : // Do nothing if the variable is not less than the array count.
777 : void
778 0 : MessageFormat::setFormat(const UnicodeString& formatName,
779 : const Format& newFormat,
780 : UErrorCode& status) {
781 0 : if (U_FAILURE(status)) return;
782 :
783 0 : int32_t argNumber = MessagePattern::validateArgumentName(formatName);
784 0 : if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
785 0 : status = U_ILLEGAL_ARGUMENT_ERROR;
786 0 : return;
787 : }
788 0 : for (int32_t partIndex = 0;
789 0 : (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
790 : ) {
791 0 : if (argNameMatches(partIndex + 1, formatName, argNumber)) {
792 0 : Format* new_format = newFormat.clone();
793 0 : if (new_format == NULL) {
794 0 : status = U_MEMORY_ALLOCATION_ERROR;
795 0 : return;
796 : }
797 0 : setCustomArgStartFormat(partIndex, new_format, status);
798 : }
799 : }
800 : }
801 :
802 : // -------------------------------------
803 : // Gets the format array.
804 : const Format**
805 0 : MessageFormat::getFormats(int32_t& cnt) const
806 : {
807 : // This old API returns an array (which we hold) of Format*
808 : // pointers. The array is valid up to the next call to any
809 : // method on this object. We construct and resize an array
810 : // on demand that contains aliases to the subformats[i].format
811 : // pointers.
812 0 : MessageFormat* t = const_cast<MessageFormat*> (this);
813 0 : cnt = 0;
814 0 : if (formatAliases == NULL) {
815 0 : t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount;
816 : Format** a = (Format**)
817 0 : uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
818 0 : if (a == NULL) {
819 0 : t->formatAliasesCapacity = 0;
820 0 : return NULL;
821 : }
822 0 : t->formatAliases = a;
823 0 : } else if (argTypeCount > formatAliasesCapacity) {
824 : Format** a = (Format**)
825 0 : uprv_realloc(formatAliases, sizeof(Format*) * argTypeCount);
826 0 : if (a == NULL) {
827 0 : t->formatAliasesCapacity = 0;
828 0 : return NULL;
829 : }
830 0 : t->formatAliases = a;
831 0 : t->formatAliasesCapacity = argTypeCount;
832 : }
833 :
834 0 : for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
835 0 : t->formatAliases[cnt++] = getCachedFormatter(partIndex);
836 : }
837 :
838 0 : return (const Format**)formatAliases;
839 : }
840 :
841 :
842 0 : UnicodeString MessageFormat::getArgName(int32_t partIndex) {
843 0 : const MessagePattern::Part& part = msgPattern.getPart(partIndex);
844 0 : return msgPattern.getSubstring(part);
845 : }
846 :
847 : StringEnumeration*
848 0 : MessageFormat::getFormatNames(UErrorCode& status) {
849 0 : if (U_FAILURE(status)) return NULL;
850 :
851 0 : UVector *fFormatNames = new UVector(status);
852 0 : if (U_FAILURE(status)) {
853 0 : status = U_MEMORY_ALLOCATION_ERROR;
854 0 : return NULL;
855 : }
856 0 : fFormatNames->setDeleter(uprv_deleteUObject);
857 :
858 0 : for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
859 0 : fFormatNames->addElement(new UnicodeString(getArgName(partIndex + 1)), status);
860 : }
861 :
862 0 : StringEnumeration* nameEnumerator = new FormatNameEnumeration(fFormatNames, status);
863 0 : return nameEnumerator;
864 : }
865 :
866 : // -------------------------------------
867 : // Formats the source Formattable array and copy into the result buffer.
868 : // Ignore the FieldPosition result for error checking.
869 :
870 : UnicodeString&
871 0 : MessageFormat::format(const Formattable* source,
872 : int32_t cnt,
873 : UnicodeString& appendTo,
874 : FieldPosition& ignore,
875 : UErrorCode& success) const
876 : {
877 0 : return format(source, NULL, cnt, appendTo, &ignore, success);
878 : }
879 :
880 : // -------------------------------------
881 : // Internally creates a MessageFormat instance based on the
882 : // pattern and formats the arguments Formattable array and
883 : // copy into the appendTo buffer.
884 :
885 : UnicodeString&
886 0 : MessageFormat::format( const UnicodeString& pattern,
887 : const Formattable* arguments,
888 : int32_t cnt,
889 : UnicodeString& appendTo,
890 : UErrorCode& success)
891 : {
892 0 : MessageFormat temp(pattern, success);
893 0 : return temp.format(arguments, NULL, cnt, appendTo, NULL, success);
894 : }
895 :
896 : // -------------------------------------
897 : // Formats the source Formattable object and copy into the
898 : // appendTo buffer. The Formattable object must be an array
899 : // of Formattable instances, returns error otherwise.
900 :
901 : UnicodeString&
902 0 : MessageFormat::format(const Formattable& source,
903 : UnicodeString& appendTo,
904 : FieldPosition& ignore,
905 : UErrorCode& success) const
906 : {
907 0 : if (U_FAILURE(success))
908 0 : return appendTo;
909 0 : if (source.getType() != Formattable::kArray) {
910 0 : success = U_ILLEGAL_ARGUMENT_ERROR;
911 0 : return appendTo;
912 : }
913 : int32_t cnt;
914 0 : const Formattable* tmpPtr = source.getArray(cnt);
915 0 : return format(tmpPtr, NULL, cnt, appendTo, &ignore, success);
916 : }
917 :
918 : UnicodeString&
919 0 : MessageFormat::format(const UnicodeString* argumentNames,
920 : const Formattable* arguments,
921 : int32_t count,
922 : UnicodeString& appendTo,
923 : UErrorCode& success) const {
924 0 : return format(arguments, argumentNames, count, appendTo, NULL, success);
925 : }
926 :
927 : // Does linear search to find the match for an ArgName.
928 0 : const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
929 : const UnicodeString *argumentNames,
930 : int32_t cnt, UnicodeString& name) const {
931 0 : for (int32_t i = 0; i < cnt; ++i) {
932 0 : if (0 == argumentNames[i].compare(name)) {
933 0 : return arguments + i;
934 : }
935 : }
936 0 : return NULL;
937 : }
938 :
939 :
940 : UnicodeString&
941 0 : MessageFormat::format(const Formattable* arguments,
942 : const UnicodeString *argumentNames,
943 : int32_t cnt,
944 : UnicodeString& appendTo,
945 : FieldPosition* pos,
946 : UErrorCode& status) const {
947 0 : if (U_FAILURE(status)) {
948 0 : return appendTo;
949 : }
950 :
951 0 : UnicodeStringAppendable usapp(appendTo);
952 0 : AppendableWrapper app(usapp);
953 0 : format(0, NULL, arguments, argumentNames, cnt, app, pos, status);
954 0 : return appendTo;
955 : }
956 :
957 : namespace {
958 :
959 : /**
960 : * Mutable input/output values for the PluralSelectorProvider.
961 : * Separate so that it is possible to make MessageFormat Freezable.
962 : */
963 0 : class PluralSelectorContext {
964 : public:
965 0 : PluralSelectorContext(int32_t start, const UnicodeString &name,
966 : const Formattable &num, double off, UErrorCode &errorCode)
967 0 : : startIndex(start), argName(name), offset(off),
968 0 : numberArgIndex(-1), formatter(NULL), forReplaceNumber(FALSE) {
969 : // number needs to be set even when select() is not called.
970 : // Keep it as a Number/Formattable:
971 : // For format() methods, and to preserve information (e.g., BigDecimal).
972 0 : if(off == 0) {
973 0 : number = num;
974 : } else {
975 0 : number = num.getDouble(errorCode) - off;
976 : }
977 0 : }
978 :
979 : // Input values for plural selection with decimals.
980 : int32_t startIndex;
981 : const UnicodeString &argName;
982 : /** argument number - plural offset */
983 : Formattable number;
984 : double offset;
985 : // Output values for plural selection with decimals.
986 : /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */
987 : int32_t numberArgIndex;
988 : const Format *formatter;
989 : /** formatted argument number - plural offset */
990 : UnicodeString numberString;
991 : /** TRUE if number-offset was formatted with the stock number formatter */
992 : UBool forReplaceNumber;
993 : };
994 :
995 : } // namespace
996 :
997 : // if argumentNames is NULL, this means arguments is a numeric array.
998 : // arguments can not be NULL.
999 : // We use const void *plNumber rather than const PluralSelectorContext *pluralNumber
1000 : // so that we need not declare the PluralSelectorContext in the public header file.
1001 0 : void MessageFormat::format(int32_t msgStart, const void *plNumber,
1002 : const Formattable* arguments,
1003 : const UnicodeString *argumentNames,
1004 : int32_t cnt,
1005 : AppendableWrapper& appendTo,
1006 : FieldPosition* ignore,
1007 : UErrorCode& success) const {
1008 0 : if (U_FAILURE(success)) {
1009 0 : return;
1010 : }
1011 :
1012 0 : const UnicodeString& msgString = msgPattern.getPatternString();
1013 0 : int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1014 0 : for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
1015 0 : const MessagePattern::Part* part = &msgPattern.getPart(i);
1016 0 : const UMessagePatternPartType type = part->getType();
1017 0 : int32_t index = part->getIndex();
1018 0 : appendTo.append(msgString, prevIndex, index - prevIndex);
1019 0 : if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1020 0 : return;
1021 : }
1022 0 : prevIndex = part->getLimit();
1023 0 : if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1024 : const PluralSelectorContext &pluralNumber =
1025 0 : *static_cast<const PluralSelectorContext *>(plNumber);
1026 0 : if(pluralNumber.forReplaceNumber) {
1027 : // number-offset was already formatted.
1028 0 : appendTo.formatAndAppend(pluralNumber.formatter,
1029 0 : pluralNumber.number, pluralNumber.numberString, success);
1030 : } else {
1031 0 : const NumberFormat* nf = getDefaultNumberFormat(success);
1032 0 : appendTo.formatAndAppend(nf, pluralNumber.number, success);
1033 : }
1034 0 : continue;
1035 : }
1036 0 : if (type != UMSGPAT_PART_TYPE_ARG_START) {
1037 0 : continue;
1038 : }
1039 0 : int32_t argLimit = msgPattern.getLimitPartIndex(i);
1040 0 : UMessagePatternArgType argType = part->getArgType();
1041 0 : part = &msgPattern.getPart(++i);
1042 : const Formattable* arg;
1043 0 : UBool noArg = FALSE;
1044 0 : UnicodeString argName = msgPattern.getSubstring(*part);
1045 0 : if (argumentNames == NULL) {
1046 0 : int32_t argNumber = part->getValue(); // ARG_NUMBER
1047 0 : if (0 <= argNumber && argNumber < cnt) {
1048 0 : arg = arguments + argNumber;
1049 : } else {
1050 0 : arg = NULL;
1051 0 : noArg = TRUE;
1052 : }
1053 : } else {
1054 0 : arg = getArgFromListByName(arguments, argumentNames, cnt, argName);
1055 0 : if (arg == NULL) {
1056 0 : noArg = TRUE;
1057 : }
1058 : }
1059 0 : ++i;
1060 0 : int32_t prevDestLength = appendTo.length();
1061 0 : const Format* formatter = NULL;
1062 0 : if (noArg) {
1063 : appendTo.append(
1064 0 : UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE));
1065 0 : } else if (arg == NULL) {
1066 0 : appendTo.append(NULL_STRING, 4);
1067 0 : } else if(plNumber!=NULL &&
1068 0 : static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) {
1069 : const PluralSelectorContext &pluralNumber =
1070 0 : *static_cast<const PluralSelectorContext *>(plNumber);
1071 0 : if(pluralNumber.offset == 0) {
1072 : // The number was already formatted with this formatter.
1073 0 : appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number,
1074 0 : pluralNumber.numberString, success);
1075 : } else {
1076 : // Do not use the formatted (number-offset) string for a named argument
1077 : // that formats the number without subtracting the offset.
1078 0 : appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
1079 0 : }
1080 0 : } else if ((formatter = getCachedFormatter(i -2))) {
1081 : // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
1082 0 : if (dynamic_cast<const ChoiceFormat*>(formatter) ||
1083 0 : dynamic_cast<const PluralFormat*>(formatter) ||
1084 0 : dynamic_cast<const SelectFormat*>(formatter)) {
1085 : // We only handle nested formats here if they were provided via
1086 : // setFormat() or its siblings. Otherwise they are not cached and instead
1087 : // handled below according to argType.
1088 0 : UnicodeString subMsgString;
1089 0 : formatter->format(*arg, subMsgString, success);
1090 0 : if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
1091 0 : (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
1092 : ) {
1093 0 : MessageFormat subMsgFormat(subMsgString, fLocale, success);
1094 0 : subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, ignore, success);
1095 : } else {
1096 0 : appendTo.append(subMsgString);
1097 : }
1098 : } else {
1099 0 : appendTo.formatAndAppend(formatter, *arg, success);
1100 : }
1101 0 : } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) {
1102 : // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1103 : // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1104 : // for the hash table containind DummyFormat.
1105 0 : if (arg->isNumeric()) {
1106 0 : const NumberFormat* nf = getDefaultNumberFormat(success);
1107 0 : appendTo.formatAndAppend(nf, *arg, success);
1108 0 : } else if (arg->getType() == Formattable::kDate) {
1109 0 : const DateFormat* df = getDefaultDateFormat(success);
1110 0 : appendTo.formatAndAppend(df, *arg, success);
1111 : } else {
1112 0 : appendTo.append(arg->getString(success));
1113 : }
1114 0 : } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
1115 0 : if (!arg->isNumeric()) {
1116 0 : success = U_ILLEGAL_ARGUMENT_ERROR;
1117 0 : return;
1118 : }
1119 : // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1120 : // because only this one converts non-double numeric types to double.
1121 0 : const double number = arg->getDouble(success);
1122 0 : int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
1123 : formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
1124 0 : cnt, appendTo, success);
1125 0 : } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
1126 0 : if (!arg->isNumeric()) {
1127 0 : success = U_ILLEGAL_ARGUMENT_ERROR;
1128 0 : return;
1129 : }
1130 : const PluralSelectorProvider &selector =
1131 0 : argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider;
1132 : // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1133 : // because only this one converts non-double numeric types to double.
1134 0 : double offset = msgPattern.getPluralOffset(i);
1135 0 : PluralSelectorContext context(i, argName, *arg, offset, success);
1136 0 : int32_t subMsgStart = PluralFormat::findSubMessage(
1137 0 : msgPattern, i, selector, &context, arg->getDouble(success), success);
1138 : formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames,
1139 0 : cnt, appendTo, success);
1140 0 : } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
1141 0 : int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
1142 : formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
1143 0 : cnt, appendTo, success);
1144 : } else {
1145 : // This should never happen.
1146 0 : success = U_INTERNAL_PROGRAM_ERROR;
1147 0 : return;
1148 : }
1149 0 : ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
1150 0 : prevIndex = msgPattern.getPart(argLimit).getLimit();
1151 0 : i = argLimit;
1152 : }
1153 : }
1154 :
1155 :
1156 0 : void MessageFormat::formatComplexSubMessage(int32_t msgStart,
1157 : const void *plNumber,
1158 : const Formattable* arguments,
1159 : const UnicodeString *argumentNames,
1160 : int32_t cnt,
1161 : AppendableWrapper& appendTo,
1162 : UErrorCode& success) const {
1163 0 : if (U_FAILURE(success)) {
1164 0 : return;
1165 : }
1166 :
1167 0 : if (!MessageImpl::jdkAposMode(msgPattern)) {
1168 0 : format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, NULL, success);
1169 0 : return;
1170 : }
1171 :
1172 : // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
1173 : // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
1174 : // - if the result string contains an open curly brace '{' then
1175 : // instantiate a temporary MessageFormat object and format again;
1176 : // otherwise just append the result string
1177 0 : const UnicodeString& msgString = msgPattern.getPatternString();
1178 0 : UnicodeString sb;
1179 0 : int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1180 0 : for (int32_t i = msgStart;;) {
1181 0 : const MessagePattern::Part& part = msgPattern.getPart(++i);
1182 0 : const UMessagePatternPartType type = part.getType();
1183 0 : int32_t index = part.getIndex();
1184 0 : if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1185 0 : sb.append(msgString, prevIndex, index - prevIndex);
1186 0 : break;
1187 0 : } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1188 0 : sb.append(msgString, prevIndex, index - prevIndex);
1189 0 : if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1190 : const PluralSelectorContext &pluralNumber =
1191 0 : *static_cast<const PluralSelectorContext *>(plNumber);
1192 0 : if(pluralNumber.forReplaceNumber) {
1193 : // number-offset was already formatted.
1194 0 : sb.append(pluralNumber.numberString);
1195 : } else {
1196 0 : const NumberFormat* nf = getDefaultNumberFormat(success);
1197 0 : sb.append(nf->format(pluralNumber.number, sb, success));
1198 : }
1199 : }
1200 0 : prevIndex = part.getLimit();
1201 0 : } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
1202 0 : sb.append(msgString, prevIndex, index - prevIndex);
1203 0 : prevIndex = index;
1204 0 : i = msgPattern.getLimitPartIndex(i);
1205 0 : index = msgPattern.getPart(i).getLimit();
1206 0 : MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
1207 0 : prevIndex = index;
1208 : }
1209 0 : }
1210 0 : if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
1211 0 : UnicodeString emptyPattern; // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
1212 0 : MessageFormat subMsgFormat(emptyPattern, fLocale, success);
1213 0 : subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, success);
1214 0 : subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, NULL, success);
1215 : } else {
1216 0 : appendTo.append(sb);
1217 : }
1218 : }
1219 :
1220 :
1221 0 : UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
1222 0 : const UnicodeString& msgString=msgPattern.getPatternString();
1223 0 : int32_t prevIndex=msgPattern.getPart(from).getLimit();
1224 0 : UnicodeString b;
1225 0 : for (int32_t i = from + 1; ; ++i) {
1226 0 : const MessagePattern::Part& part = msgPattern.getPart(i);
1227 0 : const UMessagePatternPartType type=part.getType();
1228 0 : int32_t index=part.getIndex();
1229 0 : b.append(msgString, prevIndex, index - prevIndex);
1230 0 : if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1231 0 : return b;
1232 : }
1233 : // Unexpected Part "part" in parsed message.
1234 0 : U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
1235 0 : prevIndex=part.getLimit();
1236 0 : }
1237 : }
1238 :
1239 :
1240 0 : FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
1241 : FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
1242 : // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
1243 0 : return NULL;
1244 : /*
1245 : if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
1246 : fp->setBeginIndex(prevLength);
1247 : fp->setEndIndex(dest.get_length());
1248 : return NULL;
1249 : }
1250 : return fp;
1251 : */
1252 : }
1253 :
1254 : int32_t
1255 0 : MessageFormat::findOtherSubMessage(int32_t partIndex) const {
1256 0 : int32_t count=msgPattern.countParts();
1257 0 : const MessagePattern::Part *part = &msgPattern.getPart(partIndex);
1258 0 : if(MessagePattern::Part::hasNumericValue(part->getType())) {
1259 0 : ++partIndex;
1260 : }
1261 : // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
1262 : // until ARG_LIMIT or end of plural-only pattern.
1263 0 : UnicodeString other(FALSE, OTHER_STRING, 5);
1264 0 : do {
1265 0 : part=&msgPattern.getPart(partIndex++);
1266 0 : UMessagePatternPartType type=part->getType();
1267 0 : if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
1268 0 : break;
1269 : }
1270 0 : U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR);
1271 : // part is an ARG_SELECTOR followed by an optional explicit value, and then a message
1272 0 : if(msgPattern.partSubstringMatches(*part, other)) {
1273 0 : return partIndex;
1274 : }
1275 0 : if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) {
1276 0 : ++partIndex; // skip the numeric-value part of "=1" etc.
1277 : }
1278 0 : partIndex=msgPattern.getLimitPartIndex(partIndex);
1279 : } while(++partIndex<count);
1280 0 : return 0;
1281 : }
1282 :
1283 : int32_t
1284 0 : MessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const {
1285 0 : for(int32_t i=msgStart+1;; ++i) {
1286 0 : const MessagePattern::Part &part=msgPattern.getPart(i);
1287 0 : UMessagePatternPartType type=part.getType();
1288 0 : if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1289 0 : return 0;
1290 : }
1291 0 : if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1292 0 : return -1;
1293 : }
1294 0 : if(type==UMSGPAT_PART_TYPE_ARG_START) {
1295 0 : UMessagePatternArgType argType=part.getArgType();
1296 0 : if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) {
1297 : // ARG_NUMBER or ARG_NAME
1298 0 : if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) {
1299 0 : return i;
1300 : }
1301 : }
1302 0 : i=msgPattern.getLimitPartIndex(i);
1303 : }
1304 0 : }
1305 : }
1306 :
1307 0 : void MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) {
1308 : // Deep copy pointer fields.
1309 : // We need not copy the formatAliases because they are re-filled
1310 : // in each getFormats() call.
1311 : // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
1312 : // also get created on demand.
1313 0 : argTypeCount = that.argTypeCount;
1314 0 : if (argTypeCount > 0) {
1315 0 : if (!allocateArgTypes(argTypeCount, ec)) {
1316 0 : return;
1317 : }
1318 0 : uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
1319 : }
1320 0 : if (cachedFormatters != NULL) {
1321 0 : uhash_removeAll(cachedFormatters);
1322 : }
1323 0 : if (customFormatArgStarts != NULL) {
1324 0 : uhash_removeAll(customFormatArgStarts);
1325 : }
1326 0 : if (that.cachedFormatters) {
1327 0 : if (cachedFormatters == NULL) {
1328 0 : cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
1329 : equalFormatsForHash, &ec);
1330 0 : if (U_FAILURE(ec)) {
1331 0 : return;
1332 : }
1333 0 : uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
1334 : }
1335 :
1336 0 : const int32_t count = uhash_count(that.cachedFormatters);
1337 : int32_t pos, idx;
1338 0 : for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1339 0 : const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
1340 0 : Format* newFormat = ((Format*)(cur->value.pointer))->clone();
1341 0 : if (newFormat) {
1342 0 : uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
1343 : } else {
1344 0 : ec = U_MEMORY_ALLOCATION_ERROR;
1345 0 : return;
1346 : }
1347 : }
1348 : }
1349 0 : if (that.customFormatArgStarts) {
1350 0 : if (customFormatArgStarts == NULL) {
1351 0 : customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
1352 : NULL, &ec);
1353 : }
1354 0 : const int32_t count = uhash_count(that.customFormatArgStarts);
1355 : int32_t pos, idx;
1356 0 : for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1357 0 : const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
1358 0 : uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
1359 : }
1360 : }
1361 : }
1362 :
1363 :
1364 : Formattable*
1365 0 : MessageFormat::parse(int32_t msgStart,
1366 : const UnicodeString& source,
1367 : ParsePosition& pos,
1368 : int32_t& count,
1369 : UErrorCode& ec) const {
1370 0 : count = 0;
1371 0 : if (U_FAILURE(ec)) {
1372 0 : pos.setErrorIndex(pos.getIndex());
1373 0 : return NULL;
1374 : }
1375 : // parse() does not work with named arguments.
1376 0 : if (msgPattern.hasNamedArguments()) {
1377 0 : ec = U_ARGUMENT_TYPE_MISMATCH;
1378 0 : pos.setErrorIndex(pos.getIndex());
1379 0 : return NULL;
1380 : }
1381 0 : LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
1382 0 : const UnicodeString& msgString=msgPattern.getPatternString();
1383 0 : int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
1384 0 : int32_t sourceOffset = pos.getIndex();
1385 0 : ParsePosition tempStatus(0);
1386 :
1387 0 : for(int32_t i=msgStart+1; ; ++i) {
1388 0 : UBool haveArgResult = FALSE;
1389 0 : const MessagePattern::Part* part=&msgPattern.getPart(i);
1390 0 : const UMessagePatternPartType type=part->getType();
1391 0 : int32_t index=part->getIndex();
1392 : // Make sure the literal string matches.
1393 0 : int32_t len = index - prevIndex;
1394 0 : if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
1395 0 : sourceOffset += len;
1396 0 : prevIndex += len;
1397 : } else {
1398 0 : pos.setErrorIndex(sourceOffset);
1399 0 : return NULL; // leave index as is to signal error
1400 : }
1401 0 : if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1402 : // Things went well! Done.
1403 0 : pos.setIndex(sourceOffset);
1404 0 : return resultArray.orphan();
1405 : }
1406 0 : if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
1407 0 : prevIndex=part->getLimit();
1408 0 : continue;
1409 : }
1410 : // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
1411 : // Unexpected Part "part" in parsed message.
1412 0 : U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
1413 0 : int32_t argLimit=msgPattern.getLimitPartIndex(i);
1414 :
1415 0 : UMessagePatternArgType argType=part->getArgType();
1416 0 : part=&msgPattern.getPart(++i);
1417 0 : int32_t argNumber = part->getValue(); // ARG_NUMBER
1418 0 : UnicodeString key;
1419 0 : ++i;
1420 0 : const Format* formatter = NULL;
1421 0 : Formattable& argResult = resultArray[argNumber];
1422 :
1423 0 : if(cachedFormatters!=NULL && (formatter = getCachedFormatter(i - 2))!=NULL) {
1424 : // Just parse using the formatter.
1425 0 : tempStatus.setIndex(sourceOffset);
1426 0 : formatter->parseObject(source, argResult, tempStatus);
1427 0 : if (tempStatus.getIndex() == sourceOffset) {
1428 0 : pos.setErrorIndex(sourceOffset);
1429 0 : return NULL; // leave index as is to signal error
1430 : }
1431 0 : sourceOffset = tempStatus.getIndex();
1432 0 : haveArgResult = TRUE;
1433 0 : } else if(
1434 0 : argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) {
1435 : // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1436 : // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1437 : // for the hash table containind DummyFormat.
1438 :
1439 : // Match as a string.
1440 : // if at end, use longest possible match
1441 : // otherwise uses first match to intervening string
1442 : // does NOT recursively try all possibilities
1443 0 : UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
1444 : int32_t next;
1445 0 : if (!stringAfterArgument.isEmpty()) {
1446 0 : next = source.indexOf(stringAfterArgument, sourceOffset);
1447 : } else {
1448 0 : next = source.length();
1449 : }
1450 0 : if (next < 0) {
1451 0 : pos.setErrorIndex(sourceOffset);
1452 0 : return NULL; // leave index as is to signal error
1453 : } else {
1454 0 : UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
1455 0 : UnicodeString compValue;
1456 0 : compValue.append(LEFT_CURLY_BRACE);
1457 0 : itos(argNumber, compValue);
1458 0 : compValue.append(RIGHT_CURLY_BRACE);
1459 0 : if (0 != strValue.compare(compValue)) {
1460 0 : argResult.setString(strValue);
1461 0 : haveArgResult = TRUE;
1462 : }
1463 0 : sourceOffset = next;
1464 : }
1465 0 : } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
1466 0 : tempStatus.setIndex(sourceOffset);
1467 0 : double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
1468 0 : if (tempStatus.getIndex() == sourceOffset) {
1469 0 : pos.setErrorIndex(sourceOffset);
1470 0 : return NULL; // leave index as is to signal error
1471 : }
1472 0 : argResult.setDouble(choiceResult);
1473 0 : haveArgResult = TRUE;
1474 0 : sourceOffset = tempStatus.getIndex();
1475 0 : } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
1476 : // Parsing not supported.
1477 0 : ec = U_UNSUPPORTED_ERROR;
1478 0 : return NULL;
1479 : } else {
1480 : // This should never happen.
1481 0 : ec = U_INTERNAL_PROGRAM_ERROR;
1482 0 : return NULL;
1483 : }
1484 0 : if (haveArgResult && count <= argNumber) {
1485 0 : count = argNumber + 1;
1486 : }
1487 0 : prevIndex=msgPattern.getPart(argLimit).getLimit();
1488 0 : i=argLimit;
1489 0 : }
1490 : }
1491 : // -------------------------------------
1492 : // Parses the source pattern and returns the Formattable objects array,
1493 : // the array count and the ending parse position. The caller of this method
1494 : // owns the array.
1495 :
1496 : Formattable*
1497 0 : MessageFormat::parse(const UnicodeString& source,
1498 : ParsePosition& pos,
1499 : int32_t& count) const {
1500 0 : UErrorCode ec = U_ZERO_ERROR;
1501 0 : return parse(0, source, pos, count, ec);
1502 : }
1503 :
1504 : // -------------------------------------
1505 : // Parses the source string and returns the array of
1506 : // Formattable objects and the array count. The caller
1507 : // owns the returned array.
1508 :
1509 : Formattable*
1510 0 : MessageFormat::parse(const UnicodeString& source,
1511 : int32_t& cnt,
1512 : UErrorCode& success) const
1513 : {
1514 0 : if (msgPattern.hasNamedArguments()) {
1515 0 : success = U_ARGUMENT_TYPE_MISMATCH;
1516 0 : return NULL;
1517 : }
1518 0 : ParsePosition status(0);
1519 : // Calls the actual implementation method and starts
1520 : // from zero offset of the source text.
1521 0 : Formattable* result = parse(source, status, cnt);
1522 0 : if (status.getIndex() == 0) {
1523 0 : success = U_MESSAGE_PARSE_ERROR;
1524 0 : delete[] result;
1525 0 : return NULL;
1526 : }
1527 0 : return result;
1528 : }
1529 :
1530 : // -------------------------------------
1531 : // Parses the source text and copy into the result buffer.
1532 :
1533 : void
1534 0 : MessageFormat::parseObject( const UnicodeString& source,
1535 : Formattable& result,
1536 : ParsePosition& status) const
1537 : {
1538 0 : int32_t cnt = 0;
1539 0 : Formattable* tmpResult = parse(source, status, cnt);
1540 0 : if (tmpResult != NULL)
1541 0 : result.adoptArray(tmpResult, cnt);
1542 0 : }
1543 :
1544 : UnicodeString
1545 0 : MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
1546 0 : UnicodeString result;
1547 0 : if (U_SUCCESS(status)) {
1548 0 : int32_t plen = pattern.length();
1549 0 : const UChar* pat = pattern.getBuffer();
1550 0 : int32_t blen = plen * 2 + 1; // space for null termination, convenience
1551 0 : UChar* buf = result.getBuffer(blen);
1552 0 : if (buf == NULL) {
1553 0 : status = U_MEMORY_ALLOCATION_ERROR;
1554 : } else {
1555 0 : int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
1556 0 : result.releaseBuffer(U_SUCCESS(status) ? len : 0);
1557 : }
1558 : }
1559 0 : if (U_FAILURE(status)) {
1560 0 : result.setToBogus();
1561 : }
1562 0 : return result;
1563 : }
1564 :
1565 : // -------------------------------------
1566 :
1567 0 : static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
1568 0 : RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
1569 0 : if (fmt == NULL) {
1570 0 : ec = U_MEMORY_ALLOCATION_ERROR;
1571 0 : } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
1572 0 : UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
1573 0 : fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
1574 : }
1575 0 : return fmt;
1576 : }
1577 :
1578 0 : void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
1579 0 : if (U_FAILURE(status)) {
1580 0 : return;
1581 : }
1582 :
1583 0 : if (cachedFormatters != NULL) {
1584 0 : uhash_removeAll(cachedFormatters);
1585 : }
1586 0 : if (customFormatArgStarts != NULL) {
1587 0 : uhash_removeAll(customFormatArgStarts);
1588 : }
1589 :
1590 : // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
1591 : // which we need not examine.
1592 0 : int32_t limit = msgPattern.countParts() - 2;
1593 0 : argTypeCount = 0;
1594 : // We also need not look at the first two "parts"
1595 : // (at most MSG_START and ARG_START) in this loop.
1596 : // We determine the argTypeCount first so that we can allocateArgTypes
1597 : // so that the next loop can set argTypes[argNumber].
1598 : // (This is for the C API which needs the argTypes to read its va_arg list.)
1599 0 : for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
1600 0 : const MessagePattern::Part& part = msgPattern.getPart(i);
1601 0 : if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1602 0 : const int argNumber = part.getValue();
1603 0 : if (argNumber >= argTypeCount) {
1604 0 : argTypeCount = argNumber + 1;
1605 : }
1606 : }
1607 : }
1608 0 : if (!allocateArgTypes(argTypeCount, status)) {
1609 0 : return;
1610 : }
1611 : // Set all argTypes to kObject, as a "none" value, for lack of any better value.
1612 : // We never use kObject for real arguments.
1613 : // We use it as "no argument yet" for the check for hasArgTypeConflicts.
1614 0 : for (int32_t i = 0; i < argTypeCount; ++i) {
1615 0 : argTypes[i] = Formattable::kObject;
1616 : }
1617 0 : hasArgTypeConflicts = FALSE;
1618 :
1619 : // This loop starts at part index 1 because we do need to examine
1620 : // ARG_START parts. (But we can ignore the MSG_START.)
1621 0 : for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
1622 0 : const MessagePattern::Part* part = &msgPattern.getPart(i);
1623 0 : if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
1624 0 : continue;
1625 : }
1626 0 : UMessagePatternArgType argType = part->getArgType();
1627 :
1628 0 : int32_t argNumber = -1;
1629 0 : part = &msgPattern.getPart(i + 1);
1630 0 : if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1631 0 : argNumber = part->getValue();
1632 : }
1633 : Formattable::Type formattableType;
1634 :
1635 0 : switch (argType) {
1636 : case UMSGPAT_ARG_TYPE_NONE:
1637 0 : formattableType = Formattable::kString;
1638 0 : break;
1639 : case UMSGPAT_ARG_TYPE_SIMPLE: {
1640 0 : int32_t index = i;
1641 0 : i += 2;
1642 0 : UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
1643 0 : UnicodeString style;
1644 0 : if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
1645 0 : style = msgPattern.getSubstring(*part);
1646 0 : ++i;
1647 : }
1648 : UParseError parseError;
1649 0 : Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
1650 0 : setArgStartFormat(index, formatter, status);
1651 0 : break;
1652 : }
1653 : case UMSGPAT_ARG_TYPE_CHOICE:
1654 : case UMSGPAT_ARG_TYPE_PLURAL:
1655 : case UMSGPAT_ARG_TYPE_SELECTORDINAL:
1656 0 : formattableType = Formattable::kDouble;
1657 0 : break;
1658 : case UMSGPAT_ARG_TYPE_SELECT:
1659 0 : formattableType = Formattable::kString;
1660 0 : break;
1661 : default:
1662 0 : status = U_INTERNAL_PROGRAM_ERROR; // Should be unreachable.
1663 0 : formattableType = Formattable::kString;
1664 0 : break;
1665 : }
1666 0 : if (argNumber != -1) {
1667 0 : if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
1668 0 : hasArgTypeConflicts = TRUE;
1669 : }
1670 0 : argTypes[argNumber] = formattableType;
1671 : }
1672 : }
1673 : }
1674 :
1675 :
1676 0 : Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
1677 : Formattable::Type& formattableType, UParseError& parseError,
1678 : UErrorCode& ec) {
1679 0 : if (U_FAILURE(ec)) {
1680 0 : return NULL;
1681 : }
1682 0 : Format* fmt = NULL;
1683 : int32_t typeID, styleID;
1684 : DateFormat::EStyle date_style;
1685 :
1686 0 : switch (typeID = findKeyword(type, TYPE_IDS)) {
1687 : case 0: // number
1688 0 : formattableType = Formattable::kDouble;
1689 0 : switch (findKeyword(style, NUMBER_STYLE_IDS)) {
1690 : case 0: // default
1691 0 : fmt = NumberFormat::createInstance(fLocale, ec);
1692 0 : break;
1693 : case 1: // currency
1694 0 : fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
1695 0 : break;
1696 : case 2: // percent
1697 0 : fmt = NumberFormat::createPercentInstance(fLocale, ec);
1698 0 : break;
1699 : case 3: // integer
1700 0 : formattableType = Formattable::kLong;
1701 0 : fmt = createIntegerFormat(fLocale, ec);
1702 0 : break;
1703 : default: // pattern
1704 0 : fmt = NumberFormat::createInstance(fLocale, ec);
1705 0 : if (fmt) {
1706 0 : DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt);
1707 0 : if (decfmt != NULL) {
1708 0 : decfmt->applyPattern(style,parseError,ec);
1709 : }
1710 : }
1711 0 : break;
1712 : }
1713 0 : break;
1714 :
1715 : case 1: // date
1716 : case 2: // time
1717 0 : formattableType = Formattable::kDate;
1718 0 : styleID = findKeyword(style, DATE_STYLE_IDS);
1719 0 : date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
1720 :
1721 0 : if (typeID == 1) {
1722 0 : fmt = DateFormat::createDateInstance(date_style, fLocale);
1723 : } else {
1724 0 : fmt = DateFormat::createTimeInstance(date_style, fLocale);
1725 : }
1726 :
1727 0 : if (styleID < 0 && fmt != NULL) {
1728 0 : SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
1729 0 : if (sdtfmt != NULL) {
1730 0 : sdtfmt->applyPattern(style);
1731 : }
1732 : }
1733 0 : break;
1734 :
1735 : case 3: // spellout
1736 0 : formattableType = Formattable::kDouble;
1737 0 : fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
1738 0 : break;
1739 : case 4: // ordinal
1740 0 : formattableType = Formattable::kDouble;
1741 0 : fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
1742 0 : break;
1743 : case 5: // duration
1744 0 : formattableType = Formattable::kDouble;
1745 0 : fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
1746 0 : break;
1747 : default:
1748 0 : formattableType = Formattable::kString;
1749 0 : ec = U_ILLEGAL_ARGUMENT_ERROR;
1750 0 : break;
1751 : }
1752 :
1753 0 : return fmt;
1754 : }
1755 :
1756 :
1757 : //-------------------------------------
1758 : // Finds the string, s, in the string array, list.
1759 0 : int32_t MessageFormat::findKeyword(const UnicodeString& s,
1760 : const UChar * const *list)
1761 : {
1762 0 : if (s.isEmpty()) {
1763 0 : return 0; // default
1764 : }
1765 :
1766 0 : int32_t length = s.length();
1767 0 : const UChar *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
1768 0 : UnicodeString buffer(FALSE, ps, length);
1769 : // Trims the space characters and turns all characters
1770 : // in s to lower case.
1771 0 : buffer.toLower("");
1772 0 : for (int32_t i = 0; list[i]; ++i) {
1773 0 : if (!buffer.compare(list[i], u_strlen(list[i]))) {
1774 0 : return i;
1775 : }
1776 : }
1777 0 : return -1;
1778 : }
1779 :
1780 : /**
1781 : * Convenience method that ought to be in NumberFormat
1782 : */
1783 : NumberFormat*
1784 0 : MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
1785 0 : NumberFormat *temp = NumberFormat::createInstance(locale, status);
1786 : DecimalFormat *temp2;
1787 0 : if (temp != NULL && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != NULL) {
1788 0 : temp2->setMaximumFractionDigits(0);
1789 0 : temp2->setDecimalSeparatorAlwaysShown(FALSE);
1790 0 : temp2->setParseIntegerOnly(TRUE);
1791 : }
1792 :
1793 0 : return temp;
1794 : }
1795 :
1796 : /**
1797 : * Return the default number format. Used to format a numeric
1798 : * argument when subformats[i].format is NULL. Returns NULL
1799 : * on failure.
1800 : *
1801 : * Semantically const but may modify *this.
1802 : */
1803 0 : const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
1804 0 : if (defaultNumberFormat == NULL) {
1805 0 : MessageFormat* t = (MessageFormat*) this;
1806 0 : t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
1807 0 : if (U_FAILURE(ec)) {
1808 0 : delete t->defaultNumberFormat;
1809 0 : t->defaultNumberFormat = NULL;
1810 0 : } else if (t->defaultNumberFormat == NULL) {
1811 0 : ec = U_MEMORY_ALLOCATION_ERROR;
1812 : }
1813 : }
1814 0 : return defaultNumberFormat;
1815 : }
1816 :
1817 : /**
1818 : * Return the default date format. Used to format a date
1819 : * argument when subformats[i].format is NULL. Returns NULL
1820 : * on failure.
1821 : *
1822 : * Semantically const but may modify *this.
1823 : */
1824 0 : const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
1825 0 : if (defaultDateFormat == NULL) {
1826 0 : MessageFormat* t = (MessageFormat*) this;
1827 0 : t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
1828 0 : if (t->defaultDateFormat == NULL) {
1829 0 : ec = U_MEMORY_ALLOCATION_ERROR;
1830 : }
1831 : }
1832 0 : return defaultDateFormat;
1833 : }
1834 :
1835 : UBool
1836 0 : MessageFormat::usesNamedArguments() const {
1837 0 : return msgPattern.hasNamedArguments();
1838 : }
1839 :
1840 : int32_t
1841 0 : MessageFormat::getArgTypeCount() const {
1842 0 : return argTypeCount;
1843 : }
1844 :
1845 0 : UBool MessageFormat::equalFormats(const void* left, const void* right) {
1846 0 : return *(const Format*)left==*(const Format*)right;
1847 : }
1848 :
1849 :
1850 0 : UBool MessageFormat::DummyFormat::operator==(const Format&) const {
1851 0 : return TRUE;
1852 : }
1853 :
1854 0 : Format* MessageFormat::DummyFormat::clone() const {
1855 0 : return new DummyFormat();
1856 : }
1857 :
1858 0 : UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1859 : UnicodeString& appendTo,
1860 : UErrorCode& status) const {
1861 0 : if (U_SUCCESS(status)) {
1862 0 : status = U_UNSUPPORTED_ERROR;
1863 : }
1864 0 : return appendTo;
1865 : }
1866 :
1867 0 : UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1868 : UnicodeString& appendTo,
1869 : FieldPosition&,
1870 : UErrorCode& status) const {
1871 0 : if (U_SUCCESS(status)) {
1872 0 : status = U_UNSUPPORTED_ERROR;
1873 : }
1874 0 : return appendTo;
1875 : }
1876 :
1877 0 : UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1878 : UnicodeString& appendTo,
1879 : FieldPositionIterator*,
1880 : UErrorCode& status) const {
1881 0 : if (U_SUCCESS(status)) {
1882 0 : status = U_UNSUPPORTED_ERROR;
1883 : }
1884 0 : return appendTo;
1885 : }
1886 :
1887 0 : void MessageFormat::DummyFormat::parseObject(const UnicodeString&,
1888 : Formattable&,
1889 : ParsePosition& ) const {
1890 0 : }
1891 :
1892 :
1893 0 : FormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
1894 0 : pos=0;
1895 0 : fFormatNames = fNameList;
1896 0 : }
1897 :
1898 : const UnicodeString*
1899 0 : FormatNameEnumeration::snext(UErrorCode& status) {
1900 0 : if (U_SUCCESS(status) && pos < fFormatNames->size()) {
1901 0 : return (const UnicodeString*)fFormatNames->elementAt(pos++);
1902 : }
1903 0 : return NULL;
1904 : }
1905 :
1906 : void
1907 0 : FormatNameEnumeration::reset(UErrorCode& /*status*/) {
1908 0 : pos=0;
1909 0 : }
1910 :
1911 : int32_t
1912 0 : FormatNameEnumeration::count(UErrorCode& /*status*/) const {
1913 0 : return (fFormatNames==NULL) ? 0 : fFormatNames->size();
1914 : }
1915 :
1916 0 : FormatNameEnumeration::~FormatNameEnumeration() {
1917 0 : delete fFormatNames;
1918 0 : }
1919 :
1920 0 : MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t)
1921 0 : : msgFormat(mf), rules(NULL), type(t) {
1922 0 : }
1923 :
1924 0 : MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
1925 0 : delete rules;
1926 0 : }
1927 :
1928 0 : UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number,
1929 : UErrorCode& ec) const {
1930 0 : if (U_FAILURE(ec)) {
1931 0 : return UnicodeString(FALSE, OTHER_STRING, 5);
1932 : }
1933 0 : MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
1934 0 : if(rules == NULL) {
1935 0 : t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec);
1936 0 : if (U_FAILURE(ec)) {
1937 0 : return UnicodeString(FALSE, OTHER_STRING, 5);
1938 : }
1939 : }
1940 : // Select a sub-message according to how the number is formatted,
1941 : // which is specified in the selected sub-message.
1942 : // We avoid this circle by looking at how
1943 : // the number is formatted in the "other" sub-message
1944 : // which must always be present and usually contains the number.
1945 : // Message authors should be consistent across sub-messages.
1946 0 : PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx);
1947 0 : int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex);
1948 0 : context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName);
1949 0 : if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != NULL) {
1950 0 : context.formatter =
1951 0 : (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex);
1952 : }
1953 0 : if(context.formatter == NULL) {
1954 0 : context.formatter = msgFormat.getDefaultNumberFormat(ec);
1955 0 : context.forReplaceNumber = TRUE;
1956 : }
1957 0 : U_ASSERT(context.number.getDouble(ec) == number); // argument number minus the offset
1958 0 : context.formatter->format(context.number, context.numberString, ec);
1959 0 : const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
1960 0 : if(decFmt != NULL) {
1961 0 : VisibleDigitsWithExponent digits;
1962 0 : decFmt->initVisibleDigitsWithExponent(context.number, digits, ec);
1963 0 : if (U_FAILURE(ec)) {
1964 0 : return UnicodeString(FALSE, OTHER_STRING, 5);
1965 : }
1966 0 : return rules->select(digits);
1967 : } else {
1968 0 : return rules->select(number);
1969 : }
1970 : }
1971 :
1972 0 : void MessageFormat::PluralSelectorProvider::reset() {
1973 0 : delete rules;
1974 0 : rules = NULL;
1975 0 : }
1976 :
1977 :
1978 : U_NAMESPACE_END
1979 :
1980 : #endif /* #if !UCONFIG_NO_FORMATTING */
1981 :
1982 : //eof
|