Bug Summary

File:out/../deps/icu-small/source/i18n/msgfmt.cpp
Warning:line 1404, column 13
Value stored to 'prevIndex' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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