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