1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/msgfmt.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1979 @@ 1.4 +/******************************************************************** 1.5 + * COPYRIGHT: 1.6 + * Copyright (c) 1997-2013, International Business Machines Corporation and 1.7 + * others. All Rights Reserved. 1.8 + ******************************************************************** 1.9 + * 1.10 + * File MSGFMT.CPP 1.11 + * 1.12 + * Modification History: 1.13 + * 1.14 + * Date Name Description 1.15 + * 02/19/97 aliu Converted from java. 1.16 + * 03/20/97 helena Finished first cut of implementation. 1.17 + * 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi. 1.18 + * 06/11/97 helena Fixed addPattern to take the pattern correctly. 1.19 + * 06/17/97 helena Fixed the getPattern to return the correct pattern. 1.20 + * 07/09/97 helena Made ParsePosition into a class. 1.21 + * 02/22/99 stephen Removed character literals for EBCDIC safety 1.22 + * 11/01/09 kirtig Added SelectFormat 1.23 + ********************************************************************/ 1.24 + 1.25 +#include "unicode/utypes.h" 1.26 + 1.27 +#if !UCONFIG_NO_FORMATTING 1.28 + 1.29 +#include "unicode/appendable.h" 1.30 +#include "unicode/choicfmt.h" 1.31 +#include "unicode/datefmt.h" 1.32 +#include "unicode/decimfmt.h" 1.33 +#include "unicode/localpointer.h" 1.34 +#include "unicode/msgfmt.h" 1.35 +#include "unicode/plurfmt.h" 1.36 +#include "unicode/rbnf.h" 1.37 +#include "unicode/selfmt.h" 1.38 +#include "unicode/smpdtfmt.h" 1.39 +#include "unicode/umsg.h" 1.40 +#include "unicode/ustring.h" 1.41 +#include "cmemory.h" 1.42 +#include "patternprops.h" 1.43 +#include "messageimpl.h" 1.44 +#include "msgfmt_impl.h" 1.45 +#include "plurrule_impl.h" 1.46 +#include "uassert.h" 1.47 +#include "uelement.h" 1.48 +#include "uhash.h" 1.49 +#include "ustrfmt.h" 1.50 +#include "util.h" 1.51 +#include "uvector.h" 1.52 + 1.53 +// ***************************************************************************** 1.54 +// class MessageFormat 1.55 +// ***************************************************************************** 1.56 + 1.57 +#define SINGLE_QUOTE ((UChar)0x0027) 1.58 +#define COMMA ((UChar)0x002C) 1.59 +#define LEFT_CURLY_BRACE ((UChar)0x007B) 1.60 +#define RIGHT_CURLY_BRACE ((UChar)0x007D) 1.61 + 1.62 +//--------------------------------------- 1.63 +// static data 1.64 + 1.65 +static const UChar ID_NUMBER[] = { 1.66 + 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */ 1.67 +}; 1.68 +static const UChar ID_DATE[] = { 1.69 + 0x64, 0x61, 0x74, 0x65, 0 /* "date" */ 1.70 +}; 1.71 +static const UChar ID_TIME[] = { 1.72 + 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */ 1.73 +}; 1.74 +static const UChar ID_SPELLOUT[] = { 1.75 + 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */ 1.76 +}; 1.77 +static const UChar ID_ORDINAL[] = { 1.78 + 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */ 1.79 +}; 1.80 +static const UChar ID_DURATION[] = { 1.81 + 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */ 1.82 +}; 1.83 + 1.84 +// MessageFormat Type List Number, Date, Time or Choice 1.85 +static const UChar * const TYPE_IDS[] = { 1.86 + ID_NUMBER, 1.87 + ID_DATE, 1.88 + ID_TIME, 1.89 + ID_SPELLOUT, 1.90 + ID_ORDINAL, 1.91 + ID_DURATION, 1.92 + NULL, 1.93 +}; 1.94 + 1.95 +static const UChar ID_EMPTY[] = { 1.96 + 0 /* empty string, used for default so that null can mark end of list */ 1.97 +}; 1.98 +static const UChar ID_CURRENCY[] = { 1.99 + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */ 1.100 +}; 1.101 +static const UChar ID_PERCENT[] = { 1.102 + 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */ 1.103 +}; 1.104 +static const UChar ID_INTEGER[] = { 1.105 + 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */ 1.106 +}; 1.107 + 1.108 +// NumberFormat modifier list, default, currency, percent or integer 1.109 +static const UChar * const NUMBER_STYLE_IDS[] = { 1.110 + ID_EMPTY, 1.111 + ID_CURRENCY, 1.112 + ID_PERCENT, 1.113 + ID_INTEGER, 1.114 + NULL, 1.115 +}; 1.116 + 1.117 +static const UChar ID_SHORT[] = { 1.118 + 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */ 1.119 +}; 1.120 +static const UChar ID_MEDIUM[] = { 1.121 + 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */ 1.122 +}; 1.123 +static const UChar ID_LONG[] = { 1.124 + 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */ 1.125 +}; 1.126 +static const UChar ID_FULL[] = { 1.127 + 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */ 1.128 +}; 1.129 + 1.130 +// DateFormat modifier list, default, short, medium, long or full 1.131 +static const UChar * const DATE_STYLE_IDS[] = { 1.132 + ID_EMPTY, 1.133 + ID_SHORT, 1.134 + ID_MEDIUM, 1.135 + ID_LONG, 1.136 + ID_FULL, 1.137 + NULL, 1.138 +}; 1.139 + 1.140 +static const icu::DateFormat::EStyle DATE_STYLES[] = { 1.141 + icu::DateFormat::kDefault, 1.142 + icu::DateFormat::kShort, 1.143 + icu::DateFormat::kMedium, 1.144 + icu::DateFormat::kLong, 1.145 + icu::DateFormat::kFull, 1.146 +}; 1.147 + 1.148 +static const int32_t DEFAULT_INITIAL_CAPACITY = 10; 1.149 + 1.150 +static const UChar NULL_STRING[] = { 1.151 + 0x6E, 0x75, 0x6C, 0x6C, 0 // "null" 1.152 +}; 1.153 + 1.154 +static const UChar OTHER_STRING[] = { 1.155 + 0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other" 1.156 +}; 1.157 + 1.158 +U_CDECL_BEGIN 1.159 +static UBool U_CALLCONV equalFormatsForHash(const UHashTok key1, 1.160 + const UHashTok key2) { 1.161 + return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer); 1.162 +} 1.163 + 1.164 +U_CDECL_END 1.165 + 1.166 +U_NAMESPACE_BEGIN 1.167 + 1.168 +// ------------------------------------- 1.169 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat) 1.170 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration) 1.171 + 1.172 +//-------------------------------------------------------------------- 1.173 + 1.174 +/** 1.175 + * Convert an integer value to a string and append the result to 1.176 + * the given UnicodeString. 1.177 + */ 1.178 +static UnicodeString& itos(int32_t i, UnicodeString& appendTo) { 1.179 + UChar temp[16]; 1.180 + uprv_itou(temp,16,i,10,0); // 10 == radix 1.181 + appendTo.append(temp, -1); 1.182 + return appendTo; 1.183 +} 1.184 + 1.185 + 1.186 +// AppendableWrapper: encapsulates the result of formatting, keeping track 1.187 +// of the string and its length. 1.188 +class AppendableWrapper : public UMemory { 1.189 +public: 1.190 + AppendableWrapper(Appendable& appendable) : app(appendable), len(0) { 1.191 + } 1.192 + void append(const UnicodeString& s) { 1.193 + app.appendString(s.getBuffer(), s.length()); 1.194 + len += s.length(); 1.195 + } 1.196 + void append(const UChar* s, const int32_t sLength) { 1.197 + app.appendString(s, sLength); 1.198 + len += sLength; 1.199 + } 1.200 + void append(const UnicodeString& s, int32_t start, int32_t length) { 1.201 + append(s.tempSubString(start, length)); 1.202 + } 1.203 + void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) { 1.204 + UnicodeString s; 1.205 + formatter->format(arg, s, ec); 1.206 + if (U_SUCCESS(ec)) { 1.207 + append(s); 1.208 + } 1.209 + } 1.210 + void formatAndAppend(const Format* formatter, const Formattable& arg, 1.211 + const UnicodeString &argString, UErrorCode& ec) { 1.212 + if (!argString.isEmpty()) { 1.213 + if (U_SUCCESS(ec)) { 1.214 + append(argString); 1.215 + } 1.216 + } else { 1.217 + formatAndAppend(formatter, arg, ec); 1.218 + } 1.219 + } 1.220 + int32_t length() { 1.221 + return len; 1.222 + } 1.223 +private: 1.224 + Appendable& app; 1.225 + int32_t len; 1.226 +}; 1.227 + 1.228 + 1.229 +// ------------------------------------- 1.230 +// Creates a MessageFormat instance based on the pattern. 1.231 + 1.232 +MessageFormat::MessageFormat(const UnicodeString& pattern, 1.233 + UErrorCode& success) 1.234 +: fLocale(Locale::getDefault()), // Uses the default locale 1.235 + msgPattern(success), 1.236 + formatAliases(NULL), 1.237 + formatAliasesCapacity(0), 1.238 + argTypes(NULL), 1.239 + argTypeCount(0), 1.240 + argTypeCapacity(0), 1.241 + hasArgTypeConflicts(FALSE), 1.242 + defaultNumberFormat(NULL), 1.243 + defaultDateFormat(NULL), 1.244 + cachedFormatters(NULL), 1.245 + customFormatArgStarts(NULL), 1.246 + pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 1.247 + ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 1.248 +{ 1.249 + setLocaleIDs(fLocale.getName(), fLocale.getName()); 1.250 + applyPattern(pattern, success); 1.251 +} 1.252 + 1.253 +MessageFormat::MessageFormat(const UnicodeString& pattern, 1.254 + const Locale& newLocale, 1.255 + UErrorCode& success) 1.256 +: fLocale(newLocale), 1.257 + msgPattern(success), 1.258 + formatAliases(NULL), 1.259 + formatAliasesCapacity(0), 1.260 + argTypes(NULL), 1.261 + argTypeCount(0), 1.262 + argTypeCapacity(0), 1.263 + hasArgTypeConflicts(FALSE), 1.264 + defaultNumberFormat(NULL), 1.265 + defaultDateFormat(NULL), 1.266 + cachedFormatters(NULL), 1.267 + customFormatArgStarts(NULL), 1.268 + pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 1.269 + ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 1.270 +{ 1.271 + setLocaleIDs(fLocale.getName(), fLocale.getName()); 1.272 + applyPattern(pattern, success); 1.273 +} 1.274 + 1.275 +MessageFormat::MessageFormat(const UnicodeString& pattern, 1.276 + const Locale& newLocale, 1.277 + UParseError& parseError, 1.278 + UErrorCode& success) 1.279 +: fLocale(newLocale), 1.280 + msgPattern(success), 1.281 + formatAliases(NULL), 1.282 + formatAliasesCapacity(0), 1.283 + argTypes(NULL), 1.284 + argTypeCount(0), 1.285 + argTypeCapacity(0), 1.286 + hasArgTypeConflicts(FALSE), 1.287 + defaultNumberFormat(NULL), 1.288 + defaultDateFormat(NULL), 1.289 + cachedFormatters(NULL), 1.290 + customFormatArgStarts(NULL), 1.291 + pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 1.292 + ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 1.293 +{ 1.294 + setLocaleIDs(fLocale.getName(), fLocale.getName()); 1.295 + applyPattern(pattern, parseError, success); 1.296 +} 1.297 + 1.298 +MessageFormat::MessageFormat(const MessageFormat& that) 1.299 +: 1.300 + Format(that), 1.301 + fLocale(that.fLocale), 1.302 + msgPattern(that.msgPattern), 1.303 + formatAliases(NULL), 1.304 + formatAliasesCapacity(0), 1.305 + argTypes(NULL), 1.306 + argTypeCount(0), 1.307 + argTypeCapacity(0), 1.308 + hasArgTypeConflicts(that.hasArgTypeConflicts), 1.309 + defaultNumberFormat(NULL), 1.310 + defaultDateFormat(NULL), 1.311 + cachedFormatters(NULL), 1.312 + customFormatArgStarts(NULL), 1.313 + pluralProvider(*this, UPLURAL_TYPE_CARDINAL), 1.314 + ordinalProvider(*this, UPLURAL_TYPE_ORDINAL) 1.315 +{ 1.316 + // This will take care of creating the hash tables (since they are NULL). 1.317 + UErrorCode ec = U_ZERO_ERROR; 1.318 + copyObjects(that, ec); 1.319 + if (U_FAILURE(ec)) { 1.320 + resetPattern(); 1.321 + } 1.322 +} 1.323 + 1.324 +MessageFormat::~MessageFormat() 1.325 +{ 1.326 + uhash_close(cachedFormatters); 1.327 + uhash_close(customFormatArgStarts); 1.328 + 1.329 + uprv_free(argTypes); 1.330 + uprv_free(formatAliases); 1.331 + delete defaultNumberFormat; 1.332 + delete defaultDateFormat; 1.333 +} 1.334 + 1.335 +//-------------------------------------------------------------------- 1.336 +// Variable-size array management 1.337 + 1.338 +/** 1.339 + * Allocate argTypes[] to at least the given capacity and return 1.340 + * TRUE if successful. If not, leave argTypes[] unchanged. 1.341 + * 1.342 + * If argTypes is NULL, allocate it. If it is not NULL, enlarge it 1.343 + * if necessary to be at least as large as specified. 1.344 + */ 1.345 +UBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) { 1.346 + if (U_FAILURE(status)) { 1.347 + return FALSE; 1.348 + } 1.349 + if (argTypeCapacity >= capacity) { 1.350 + return TRUE; 1.351 + } 1.352 + if (capacity < DEFAULT_INITIAL_CAPACITY) { 1.353 + capacity = DEFAULT_INITIAL_CAPACITY; 1.354 + } else if (capacity < 2*argTypeCapacity) { 1.355 + capacity = 2*argTypeCapacity; 1.356 + } 1.357 + Formattable::Type* a = (Formattable::Type*) 1.358 + uprv_realloc(argTypes, sizeof(*argTypes) * capacity); 1.359 + if (a == NULL) { 1.360 + status = U_MEMORY_ALLOCATION_ERROR; 1.361 + return FALSE; 1.362 + } 1.363 + argTypes = a; 1.364 + argTypeCapacity = capacity; 1.365 + return TRUE; 1.366 +} 1.367 + 1.368 +// ------------------------------------- 1.369 +// assignment operator 1.370 + 1.371 +const MessageFormat& 1.372 +MessageFormat::operator=(const MessageFormat& that) 1.373 +{ 1.374 + if (this != &that) { 1.375 + // Calls the super class for assignment first. 1.376 + Format::operator=(that); 1.377 + 1.378 + setLocale(that.fLocale); 1.379 + msgPattern = that.msgPattern; 1.380 + hasArgTypeConflicts = that.hasArgTypeConflicts; 1.381 + 1.382 + UErrorCode ec = U_ZERO_ERROR; 1.383 + copyObjects(that, ec); 1.384 + if (U_FAILURE(ec)) { 1.385 + resetPattern(); 1.386 + } 1.387 + } 1.388 + return *this; 1.389 +} 1.390 + 1.391 +UBool 1.392 +MessageFormat::operator==(const Format& rhs) const 1.393 +{ 1.394 + if (this == &rhs) return TRUE; 1.395 + 1.396 + MessageFormat& that = (MessageFormat&)rhs; 1.397 + 1.398 + // Check class ID before checking MessageFormat members 1.399 + if (!Format::operator==(rhs) || 1.400 + msgPattern != that.msgPattern || 1.401 + fLocale != that.fLocale) { 1.402 + return FALSE; 1.403 + } 1.404 + 1.405 + // Compare hashtables. 1.406 + if ((customFormatArgStarts == NULL) != (that.customFormatArgStarts == NULL)) { 1.407 + return FALSE; 1.408 + } 1.409 + if (customFormatArgStarts == NULL) { 1.410 + return TRUE; 1.411 + } 1.412 + 1.413 + UErrorCode ec = U_ZERO_ERROR; 1.414 + const int32_t count = uhash_count(customFormatArgStarts); 1.415 + const int32_t rhs_count = uhash_count(that.customFormatArgStarts); 1.416 + if (count != rhs_count) { 1.417 + return FALSE; 1.418 + } 1.419 + int32_t idx = 0, rhs_idx = 0, pos = -1, rhs_pos = -1; 1.420 + for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) { 1.421 + const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos); 1.422 + const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos); 1.423 + if (cur->key.integer != rhs_cur->key.integer) { 1.424 + return FALSE; 1.425 + } 1.426 + const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer); 1.427 + const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer); 1.428 + if (*format != *rhs_format) { 1.429 + return FALSE; 1.430 + } 1.431 + } 1.432 + return TRUE; 1.433 +} 1.434 + 1.435 +// ------------------------------------- 1.436 +// Creates a copy of this MessageFormat, the caller owns the copy. 1.437 + 1.438 +Format* 1.439 +MessageFormat::clone() const 1.440 +{ 1.441 + return new MessageFormat(*this); 1.442 +} 1.443 + 1.444 +// ------------------------------------- 1.445 +// Sets the locale of this MessageFormat object to theLocale. 1.446 + 1.447 +void 1.448 +MessageFormat::setLocale(const Locale& theLocale) 1.449 +{ 1.450 + if (fLocale != theLocale) { 1.451 + delete defaultNumberFormat; 1.452 + defaultNumberFormat = NULL; 1.453 + delete defaultDateFormat; 1.454 + defaultDateFormat = NULL; 1.455 + fLocale = theLocale; 1.456 + setLocaleIDs(fLocale.getName(), fLocale.getName()); 1.457 + pluralProvider.reset(); 1.458 + ordinalProvider.reset(); 1.459 + } 1.460 +} 1.461 + 1.462 +// ------------------------------------- 1.463 +// Gets the locale of this MessageFormat object. 1.464 + 1.465 +const Locale& 1.466 +MessageFormat::getLocale() const 1.467 +{ 1.468 + return fLocale; 1.469 +} 1.470 + 1.471 +void 1.472 +MessageFormat::applyPattern(const UnicodeString& newPattern, 1.473 + UErrorCode& status) 1.474 +{ 1.475 + UParseError parseError; 1.476 + applyPattern(newPattern,parseError,status); 1.477 +} 1.478 + 1.479 + 1.480 +// ------------------------------------- 1.481 +// Applies the new pattern and returns an error if the pattern 1.482 +// is not correct. 1.483 +void 1.484 +MessageFormat::applyPattern(const UnicodeString& pattern, 1.485 + UParseError& parseError, 1.486 + UErrorCode& ec) 1.487 +{ 1.488 + if(U_FAILURE(ec)) { 1.489 + return; 1.490 + } 1.491 + msgPattern.parse(pattern, &parseError, ec); 1.492 + cacheExplicitFormats(ec); 1.493 + 1.494 + if (U_FAILURE(ec)) { 1.495 + resetPattern(); 1.496 + } 1.497 +} 1.498 + 1.499 +void MessageFormat::resetPattern() { 1.500 + msgPattern.clear(); 1.501 + uhash_close(cachedFormatters); 1.502 + cachedFormatters = NULL; 1.503 + uhash_close(customFormatArgStarts); 1.504 + customFormatArgStarts = NULL; 1.505 + argTypeCount = 0; 1.506 + hasArgTypeConflicts = FALSE; 1.507 +} 1.508 + 1.509 +void 1.510 +MessageFormat::applyPattern(const UnicodeString& pattern, 1.511 + UMessagePatternApostropheMode aposMode, 1.512 + UParseError* parseError, 1.513 + UErrorCode& status) { 1.514 + if (aposMode != msgPattern.getApostropheMode()) { 1.515 + msgPattern.clearPatternAndSetApostropheMode(aposMode); 1.516 + } 1.517 + applyPattern(pattern, *parseError, status); 1.518 +} 1.519 + 1.520 +// ------------------------------------- 1.521 +// Converts this MessageFormat instance to a pattern. 1.522 + 1.523 +UnicodeString& 1.524 +MessageFormat::toPattern(UnicodeString& appendTo) const { 1.525 + if ((customFormatArgStarts != NULL && 0 != uhash_count(customFormatArgStarts)) || 1.526 + 0 == msgPattern.countParts() 1.527 + ) { 1.528 + appendTo.setToBogus(); 1.529 + return appendTo; 1.530 + } 1.531 + return appendTo.append(msgPattern.getPatternString()); 1.532 +} 1.533 + 1.534 +int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const { 1.535 + if (partIndex != 0) { 1.536 + partIndex = msgPattern.getLimitPartIndex(partIndex); 1.537 + } 1.538 + for (;;) { 1.539 + UMessagePatternPartType type = msgPattern.getPartType(++partIndex); 1.540 + if (type == UMSGPAT_PART_TYPE_ARG_START) { 1.541 + return partIndex; 1.542 + } 1.543 + if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { 1.544 + return -1; 1.545 + } 1.546 + } 1.547 +} 1.548 + 1.549 +void MessageFormat::setArgStartFormat(int32_t argStart, 1.550 + Format* formatter, 1.551 + UErrorCode& status) { 1.552 + if (U_FAILURE(status)) { 1.553 + delete formatter; 1.554 + return; 1.555 + } 1.556 + if (cachedFormatters == NULL) { 1.557 + cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong, 1.558 + equalFormatsForHash, &status); 1.559 + if (U_FAILURE(status)) { 1.560 + delete formatter; 1.561 + return; 1.562 + } 1.563 + uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject); 1.564 + } 1.565 + if (formatter == NULL) { 1.566 + formatter = new DummyFormat(); 1.567 + } 1.568 + uhash_iput(cachedFormatters, argStart, formatter, &status); 1.569 +} 1.570 + 1.571 + 1.572 +UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) { 1.573 + const MessagePattern::Part& part = msgPattern.getPart(partIndex); 1.574 + return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ? 1.575 + msgPattern.partSubstringMatches(part, argName) : 1.576 + part.getValue() == argNumber; // ARG_NUMBER 1.577 +} 1.578 + 1.579 +// Sets a custom formatter for a MessagePattern ARG_START part index. 1.580 +// "Custom" formatters are provided by the user via setFormat() or similar APIs. 1.581 +void MessageFormat::setCustomArgStartFormat(int32_t argStart, 1.582 + Format* formatter, 1.583 + UErrorCode& status) { 1.584 + setArgStartFormat(argStart, formatter, status); 1.585 + if (customFormatArgStarts == NULL) { 1.586 + customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong, 1.587 + NULL, &status); 1.588 + } 1.589 + uhash_iputi(customFormatArgStarts, argStart, 1, &status); 1.590 +} 1.591 + 1.592 +Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const { 1.593 + if (cachedFormatters == NULL) { 1.594 + return NULL; 1.595 + } 1.596 + void* ptr = uhash_iget(cachedFormatters, argumentNumber); 1.597 + if (ptr != NULL && dynamic_cast<DummyFormat*>((Format*)ptr) == NULL) { 1.598 + return (Format*) ptr; 1.599 + } else { 1.600 + // Not cached, or a DummyFormat representing setFormat(NULL). 1.601 + return NULL; 1.602 + } 1.603 +} 1.604 + 1.605 +// ------------------------------------- 1.606 +// Adopts the new formats array and updates the array count. 1.607 +// This MessageFormat instance owns the new formats. 1.608 +void 1.609 +MessageFormat::adoptFormats(Format** newFormats, 1.610 + int32_t count) { 1.611 + if (newFormats == NULL || count < 0) { 1.612 + return; 1.613 + } 1.614 + // Throw away any cached formatters. 1.615 + if (cachedFormatters != NULL) { 1.616 + uhash_removeAll(cachedFormatters); 1.617 + } 1.618 + if (customFormatArgStarts != NULL) { 1.619 + uhash_removeAll(customFormatArgStarts); 1.620 + } 1.621 + 1.622 + int32_t formatNumber = 0; 1.623 + UErrorCode status = U_ZERO_ERROR; 1.624 + for (int32_t partIndex = 0; 1.625 + formatNumber < count && U_SUCCESS(status) && 1.626 + (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.627 + setCustomArgStartFormat(partIndex, newFormats[formatNumber], status); 1.628 + ++formatNumber; 1.629 + } 1.630 + // Delete those that didn't get used (if any). 1.631 + for (; formatNumber < count; ++formatNumber) { 1.632 + delete newFormats[formatNumber]; 1.633 + } 1.634 + 1.635 +} 1.636 + 1.637 +// ------------------------------------- 1.638 +// Sets the new formats array and updates the array count. 1.639 +// This MessageFormat instance maks a copy of the new formats. 1.640 + 1.641 +void 1.642 +MessageFormat::setFormats(const Format** newFormats, 1.643 + int32_t count) { 1.644 + if (newFormats == NULL || count < 0) { 1.645 + return; 1.646 + } 1.647 + // Throw away any cached formatters. 1.648 + if (cachedFormatters != NULL) { 1.649 + uhash_removeAll(cachedFormatters); 1.650 + } 1.651 + if (customFormatArgStarts != NULL) { 1.652 + uhash_removeAll(customFormatArgStarts); 1.653 + } 1.654 + 1.655 + UErrorCode status = U_ZERO_ERROR; 1.656 + int32_t formatNumber = 0; 1.657 + for (int32_t partIndex = 0; 1.658 + formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.659 + Format* newFormat = NULL; 1.660 + if (newFormats[formatNumber] != NULL) { 1.661 + newFormat = newFormats[formatNumber]->clone(); 1.662 + if (newFormat == NULL) { 1.663 + status = U_MEMORY_ALLOCATION_ERROR; 1.664 + } 1.665 + } 1.666 + setCustomArgStartFormat(partIndex, newFormat, status); 1.667 + ++formatNumber; 1.668 + } 1.669 + if (U_FAILURE(status)) { 1.670 + resetPattern(); 1.671 + } 1.672 +} 1.673 + 1.674 +// ------------------------------------- 1.675 +// Adopt a single format by format number. 1.676 +// Do nothing if the format number is not less than the array count. 1.677 + 1.678 +void 1.679 +MessageFormat::adoptFormat(int32_t n, Format *newFormat) { 1.680 + LocalPointer<Format> p(newFormat); 1.681 + if (n >= 0) { 1.682 + int32_t formatNumber = 0; 1.683 + for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.684 + if (n == formatNumber) { 1.685 + UErrorCode status = U_ZERO_ERROR; 1.686 + setCustomArgStartFormat(partIndex, p.orphan(), status); 1.687 + return; 1.688 + } 1.689 + ++formatNumber; 1.690 + } 1.691 + } 1.692 +} 1.693 + 1.694 +// ------------------------------------- 1.695 +// Adopt a single format by format name. 1.696 +// Do nothing if there is no match of formatName. 1.697 +void 1.698 +MessageFormat::adoptFormat(const UnicodeString& formatName, 1.699 + Format* formatToAdopt, 1.700 + UErrorCode& status) { 1.701 + LocalPointer<Format> p(formatToAdopt); 1.702 + if (U_FAILURE(status)) { 1.703 + return; 1.704 + } 1.705 + int32_t argNumber = MessagePattern::validateArgumentName(formatName); 1.706 + if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) { 1.707 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.708 + return; 1.709 + } 1.710 + for (int32_t partIndex = 0; 1.711 + (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status); 1.712 + ) { 1.713 + if (argNameMatches(partIndex + 1, formatName, argNumber)) { 1.714 + Format* f; 1.715 + if (p.isValid()) { 1.716 + f = p.orphan(); 1.717 + } else if (formatToAdopt == NULL) { 1.718 + f = NULL; 1.719 + } else { 1.720 + f = formatToAdopt->clone(); 1.721 + if (f == NULL) { 1.722 + status = U_MEMORY_ALLOCATION_ERROR; 1.723 + return; 1.724 + } 1.725 + } 1.726 + setCustomArgStartFormat(partIndex, f, status); 1.727 + } 1.728 + } 1.729 +} 1.730 + 1.731 +// ------------------------------------- 1.732 +// Set a single format. 1.733 +// Do nothing if the variable is not less than the array count. 1.734 +void 1.735 +MessageFormat::setFormat(int32_t n, const Format& newFormat) { 1.736 + 1.737 + if (n >= 0) { 1.738 + int32_t formatNumber = 0; 1.739 + for (int32_t partIndex = 0; 1.740 + (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.741 + if (n == formatNumber) { 1.742 + Format* new_format = newFormat.clone(); 1.743 + if (new_format) { 1.744 + UErrorCode status = U_ZERO_ERROR; 1.745 + setCustomArgStartFormat(partIndex, new_format, status); 1.746 + } 1.747 + return; 1.748 + } 1.749 + ++formatNumber; 1.750 + } 1.751 + } 1.752 +} 1.753 + 1.754 +// ------------------------------------- 1.755 +// Get a single format by format name. 1.756 +// Do nothing if the variable is not less than the array count. 1.757 +Format * 1.758 +MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) { 1.759 + if (U_FAILURE(status) || cachedFormatters == NULL) return NULL; 1.760 + 1.761 + int32_t argNumber = MessagePattern::validateArgumentName(formatName); 1.762 + if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) { 1.763 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.764 + return NULL; 1.765 + } 1.766 + for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.767 + if (argNameMatches(partIndex + 1, formatName, argNumber)) { 1.768 + return getCachedFormatter(partIndex); 1.769 + } 1.770 + } 1.771 + return NULL; 1.772 +} 1.773 + 1.774 +// ------------------------------------- 1.775 +// Set a single format by format name 1.776 +// Do nothing if the variable is not less than the array count. 1.777 +void 1.778 +MessageFormat::setFormat(const UnicodeString& formatName, 1.779 + const Format& newFormat, 1.780 + UErrorCode& status) { 1.781 + if (U_FAILURE(status)) return; 1.782 + 1.783 + int32_t argNumber = MessagePattern::validateArgumentName(formatName); 1.784 + if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) { 1.785 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.786 + return; 1.787 + } 1.788 + for (int32_t partIndex = 0; 1.789 + (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status); 1.790 + ) { 1.791 + if (argNameMatches(partIndex + 1, formatName, argNumber)) { 1.792 + if (&newFormat == NULL) { 1.793 + setCustomArgStartFormat(partIndex, NULL, status); 1.794 + } else { 1.795 + Format* new_format = newFormat.clone(); 1.796 + if (new_format == NULL) { 1.797 + status = U_MEMORY_ALLOCATION_ERROR; 1.798 + return; 1.799 + } 1.800 + setCustomArgStartFormat(partIndex, new_format, status); 1.801 + } 1.802 + } 1.803 + } 1.804 +} 1.805 + 1.806 +// ------------------------------------- 1.807 +// Gets the format array. 1.808 +const Format** 1.809 +MessageFormat::getFormats(int32_t& cnt) const 1.810 +{ 1.811 + // This old API returns an array (which we hold) of Format* 1.812 + // pointers. The array is valid up to the next call to any 1.813 + // method on this object. We construct and resize an array 1.814 + // on demand that contains aliases to the subformats[i].format 1.815 + // pointers. 1.816 + MessageFormat* t = const_cast<MessageFormat*> (this); 1.817 + cnt = 0; 1.818 + if (formatAliases == NULL) { 1.819 + t->formatAliasesCapacity = (argTypeCount<10) ? 10 : argTypeCount; 1.820 + Format** a = (Format**) 1.821 + uprv_malloc(sizeof(Format*) * formatAliasesCapacity); 1.822 + if (a == NULL) { 1.823 + t->formatAliasesCapacity = 0; 1.824 + return NULL; 1.825 + } 1.826 + t->formatAliases = a; 1.827 + } else if (argTypeCount > formatAliasesCapacity) { 1.828 + Format** a = (Format**) 1.829 + uprv_realloc(formatAliases, sizeof(Format*) * argTypeCount); 1.830 + if (a == NULL) { 1.831 + t->formatAliasesCapacity = 0; 1.832 + return NULL; 1.833 + } 1.834 + t->formatAliases = a; 1.835 + t->formatAliasesCapacity = argTypeCount; 1.836 + } 1.837 + 1.838 + for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.839 + t->formatAliases[cnt++] = getCachedFormatter(partIndex); 1.840 + } 1.841 + 1.842 + return (const Format**)formatAliases; 1.843 +} 1.844 + 1.845 + 1.846 +UnicodeString MessageFormat::getArgName(int32_t partIndex) { 1.847 + const MessagePattern::Part& part = msgPattern.getPart(partIndex); 1.848 + return msgPattern.getSubstring(part); 1.849 +} 1.850 + 1.851 +StringEnumeration* 1.852 +MessageFormat::getFormatNames(UErrorCode& status) { 1.853 + if (U_FAILURE(status)) return NULL; 1.854 + 1.855 + UVector *fFormatNames = new UVector(status); 1.856 + if (U_FAILURE(status)) { 1.857 + status = U_MEMORY_ALLOCATION_ERROR; 1.858 + return NULL; 1.859 + } 1.860 + fFormatNames->setDeleter(uprv_deleteUObject); 1.861 + 1.862 + for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) { 1.863 + fFormatNames->addElement(new UnicodeString(getArgName(partIndex + 1)), status); 1.864 + } 1.865 + 1.866 + StringEnumeration* nameEnumerator = new FormatNameEnumeration(fFormatNames, status); 1.867 + return nameEnumerator; 1.868 +} 1.869 + 1.870 +// ------------------------------------- 1.871 +// Formats the source Formattable array and copy into the result buffer. 1.872 +// Ignore the FieldPosition result for error checking. 1.873 + 1.874 +UnicodeString& 1.875 +MessageFormat::format(const Formattable* source, 1.876 + int32_t cnt, 1.877 + UnicodeString& appendTo, 1.878 + FieldPosition& ignore, 1.879 + UErrorCode& success) const 1.880 +{ 1.881 + return format(source, NULL, cnt, appendTo, &ignore, success); 1.882 +} 1.883 + 1.884 +// ------------------------------------- 1.885 +// Internally creates a MessageFormat instance based on the 1.886 +// pattern and formats the arguments Formattable array and 1.887 +// copy into the appendTo buffer. 1.888 + 1.889 +UnicodeString& 1.890 +MessageFormat::format( const UnicodeString& pattern, 1.891 + const Formattable* arguments, 1.892 + int32_t cnt, 1.893 + UnicodeString& appendTo, 1.894 + UErrorCode& success) 1.895 +{ 1.896 + MessageFormat temp(pattern, success); 1.897 + return temp.format(arguments, NULL, cnt, appendTo, NULL, success); 1.898 +} 1.899 + 1.900 +// ------------------------------------- 1.901 +// Formats the source Formattable object and copy into the 1.902 +// appendTo buffer. The Formattable object must be an array 1.903 +// of Formattable instances, returns error otherwise. 1.904 + 1.905 +UnicodeString& 1.906 +MessageFormat::format(const Formattable& source, 1.907 + UnicodeString& appendTo, 1.908 + FieldPosition& ignore, 1.909 + UErrorCode& success) const 1.910 +{ 1.911 + if (U_FAILURE(success)) 1.912 + return appendTo; 1.913 + if (source.getType() != Formattable::kArray) { 1.914 + success = U_ILLEGAL_ARGUMENT_ERROR; 1.915 + return appendTo; 1.916 + } 1.917 + int32_t cnt; 1.918 + const Formattable* tmpPtr = source.getArray(cnt); 1.919 + return format(tmpPtr, NULL, cnt, appendTo, &ignore, success); 1.920 +} 1.921 + 1.922 +UnicodeString& 1.923 +MessageFormat::format(const UnicodeString* argumentNames, 1.924 + const Formattable* arguments, 1.925 + int32_t count, 1.926 + UnicodeString& appendTo, 1.927 + UErrorCode& success) const { 1.928 + return format(arguments, argumentNames, count, appendTo, NULL, success); 1.929 +} 1.930 + 1.931 +// Does linear search to find the match for an ArgName. 1.932 +const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments, 1.933 + const UnicodeString *argumentNames, 1.934 + int32_t cnt, UnicodeString& name) const { 1.935 + for (int32_t i = 0; i < cnt; ++i) { 1.936 + if (0 == argumentNames[i].compare(name)) { 1.937 + return arguments + i; 1.938 + } 1.939 + } 1.940 + return NULL; 1.941 +} 1.942 + 1.943 + 1.944 +UnicodeString& 1.945 +MessageFormat::format(const Formattable* arguments, 1.946 + const UnicodeString *argumentNames, 1.947 + int32_t cnt, 1.948 + UnicodeString& appendTo, 1.949 + FieldPosition* pos, 1.950 + UErrorCode& status) const { 1.951 + if (U_FAILURE(status)) { 1.952 + return appendTo; 1.953 + } 1.954 + 1.955 + UnicodeStringAppendable usapp(appendTo); 1.956 + AppendableWrapper app(usapp); 1.957 + format(0, NULL, arguments, argumentNames, cnt, app, pos, status); 1.958 + return appendTo; 1.959 +} 1.960 + 1.961 +namespace { 1.962 + 1.963 +/** 1.964 + * Mutable input/output values for the PluralSelectorProvider. 1.965 + * Separate so that it is possible to make MessageFormat Freezable. 1.966 + */ 1.967 +class PluralSelectorContext { 1.968 +public: 1.969 + PluralSelectorContext(int32_t start, const UnicodeString &name, 1.970 + const Formattable &num, double off, UErrorCode &errorCode) 1.971 + : startIndex(start), argName(name), offset(off), 1.972 + numberArgIndex(-1), formatter(NULL), forReplaceNumber(FALSE) { 1.973 + // number needs to be set even when select() is not called. 1.974 + // Keep it as a Number/Formattable: 1.975 + // For format() methods, and to preserve information (e.g., BigDecimal). 1.976 + if(off == 0) { 1.977 + number = num; 1.978 + } else { 1.979 + number = num.getDouble(errorCode) - off; 1.980 + } 1.981 + } 1.982 + 1.983 + // Input values for plural selection with decimals. 1.984 + int32_t startIndex; 1.985 + const UnicodeString &argName; 1.986 + /** argument number - plural offset */ 1.987 + Formattable number; 1.988 + double offset; 1.989 + // Output values for plural selection with decimals. 1.990 + /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */ 1.991 + int32_t numberArgIndex; 1.992 + const Format *formatter; 1.993 + /** formatted argument number - plural offset */ 1.994 + UnicodeString numberString; 1.995 + /** TRUE if number-offset was formatted with the stock number formatter */ 1.996 + UBool forReplaceNumber; 1.997 +}; 1.998 + 1.999 +} // namespace 1.1000 + 1.1001 +// if argumentNames is NULL, this means arguments is a numeric array. 1.1002 +// arguments can not be NULL. 1.1003 +// We use const void *plNumber rather than const PluralSelectorContext *pluralNumber 1.1004 +// so that we need not declare the PluralSelectorContext in the public header file. 1.1005 +void MessageFormat::format(int32_t msgStart, const void *plNumber, 1.1006 + const Formattable* arguments, 1.1007 + const UnicodeString *argumentNames, 1.1008 + int32_t cnt, 1.1009 + AppendableWrapper& appendTo, 1.1010 + FieldPosition* ignore, 1.1011 + UErrorCode& success) const { 1.1012 + if (U_FAILURE(success)) { 1.1013 + return; 1.1014 + } 1.1015 + 1.1016 + const UnicodeString& msgString = msgPattern.getPatternString(); 1.1017 + int32_t prevIndex = msgPattern.getPart(msgStart).getLimit(); 1.1018 + for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) { 1.1019 + const MessagePattern::Part* part = &msgPattern.getPart(i); 1.1020 + const UMessagePatternPartType type = part->getType(); 1.1021 + int32_t index = part->getIndex(); 1.1022 + appendTo.append(msgString, prevIndex, index - prevIndex); 1.1023 + if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { 1.1024 + return; 1.1025 + } 1.1026 + prevIndex = part->getLimit(); 1.1027 + if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) { 1.1028 + const PluralSelectorContext &pluralNumber = 1.1029 + *static_cast<const PluralSelectorContext *>(plNumber); 1.1030 + if(pluralNumber.forReplaceNumber) { 1.1031 + // number-offset was already formatted. 1.1032 + appendTo.formatAndAppend(pluralNumber.formatter, 1.1033 + pluralNumber.number, pluralNumber.numberString, success); 1.1034 + } else { 1.1035 + const NumberFormat* nf = getDefaultNumberFormat(success); 1.1036 + appendTo.formatAndAppend(nf, pluralNumber.number, success); 1.1037 + } 1.1038 + continue; 1.1039 + } 1.1040 + if (type != UMSGPAT_PART_TYPE_ARG_START) { 1.1041 + continue; 1.1042 + } 1.1043 + int32_t argLimit = msgPattern.getLimitPartIndex(i); 1.1044 + UMessagePatternArgType argType = part->getArgType(); 1.1045 + part = &msgPattern.getPart(++i); 1.1046 + const Formattable* arg; 1.1047 + UBool noArg = FALSE; 1.1048 + UnicodeString argName = msgPattern.getSubstring(*part); 1.1049 + if (argumentNames == NULL) { 1.1050 + int32_t argNumber = part->getValue(); // ARG_NUMBER 1.1051 + if (0 <= argNumber && argNumber < cnt) { 1.1052 + arg = arguments + argNumber; 1.1053 + } else { 1.1054 + arg = NULL; 1.1055 + noArg = TRUE; 1.1056 + } 1.1057 + } else { 1.1058 + arg = getArgFromListByName(arguments, argumentNames, cnt, argName); 1.1059 + if (arg == NULL) { 1.1060 + noArg = TRUE; 1.1061 + } 1.1062 + } 1.1063 + ++i; 1.1064 + int32_t prevDestLength = appendTo.length(); 1.1065 + const Format* formatter = NULL; 1.1066 + if (noArg) { 1.1067 + appendTo.append( 1.1068 + UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE)); 1.1069 + } else if (arg == NULL) { 1.1070 + appendTo.append(NULL_STRING, 4); 1.1071 + } else if(plNumber!=NULL && 1.1072 + static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) { 1.1073 + const PluralSelectorContext &pluralNumber = 1.1074 + *static_cast<const PluralSelectorContext *>(plNumber); 1.1075 + if(pluralNumber.offset == 0) { 1.1076 + // The number was already formatted with this formatter. 1.1077 + appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number, 1.1078 + pluralNumber.numberString, success); 1.1079 + } else { 1.1080 + // Do not use the formatted (number-offset) string for a named argument 1.1081 + // that formats the number without subtracting the offset. 1.1082 + appendTo.formatAndAppend(pluralNumber.formatter, *arg, success); 1.1083 + } 1.1084 + } else if ((formatter = getCachedFormatter(i -2))) { 1.1085 + // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings. 1.1086 + if (dynamic_cast<const ChoiceFormat*>(formatter) || 1.1087 + dynamic_cast<const PluralFormat*>(formatter) || 1.1088 + dynamic_cast<const SelectFormat*>(formatter)) { 1.1089 + // We only handle nested formats here if they were provided via 1.1090 + // setFormat() or its siblings. Otherwise they are not cached and instead 1.1091 + // handled below according to argType. 1.1092 + UnicodeString subMsgString; 1.1093 + formatter->format(*arg, subMsgString, success); 1.1094 + if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 || 1.1095 + (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern)) 1.1096 + ) { 1.1097 + MessageFormat subMsgFormat(subMsgString, fLocale, success); 1.1098 + subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, ignore, success); 1.1099 + } else { 1.1100 + appendTo.append(subMsgString); 1.1101 + } 1.1102 + } else { 1.1103 + appendTo.formatAndAppend(formatter, *arg, success); 1.1104 + } 1.1105 + } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) { 1.1106 + // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table. 1.1107 + // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check 1.1108 + // for the hash table containind DummyFormat. 1.1109 + if (arg->isNumeric()) { 1.1110 + const NumberFormat* nf = getDefaultNumberFormat(success); 1.1111 + appendTo.formatAndAppend(nf, *arg, success); 1.1112 + } else if (arg->getType() == Formattable::kDate) { 1.1113 + const DateFormat* df = getDefaultDateFormat(success); 1.1114 + appendTo.formatAndAppend(df, *arg, success); 1.1115 + } else { 1.1116 + appendTo.append(arg->getString(success)); 1.1117 + } 1.1118 + } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) { 1.1119 + if (!arg->isNumeric()) { 1.1120 + success = U_ILLEGAL_ARGUMENT_ERROR; 1.1121 + return; 1.1122 + } 1.1123 + // We must use the Formattable::getDouble() variant with the UErrorCode parameter 1.1124 + // because only this one converts non-double numeric types to double. 1.1125 + const double number = arg->getDouble(success); 1.1126 + int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number); 1.1127 + formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames, 1.1128 + cnt, appendTo, success); 1.1129 + } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) { 1.1130 + if (!arg->isNumeric()) { 1.1131 + success = U_ILLEGAL_ARGUMENT_ERROR; 1.1132 + return; 1.1133 + } 1.1134 + const PluralSelectorProvider &selector = 1.1135 + argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider; 1.1136 + // We must use the Formattable::getDouble() variant with the UErrorCode parameter 1.1137 + // because only this one converts non-double numeric types to double. 1.1138 + double offset = msgPattern.getPluralOffset(i); 1.1139 + PluralSelectorContext context(i, argName, *arg, offset, success); 1.1140 + int32_t subMsgStart = PluralFormat::findSubMessage( 1.1141 + msgPattern, i, selector, &context, arg->getDouble(success), success); 1.1142 + formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames, 1.1143 + cnt, appendTo, success); 1.1144 + } else if (argType == UMSGPAT_ARG_TYPE_SELECT) { 1.1145 + int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success); 1.1146 + formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames, 1.1147 + cnt, appendTo, success); 1.1148 + } else { 1.1149 + // This should never happen. 1.1150 + success = U_INTERNAL_PROGRAM_ERROR; 1.1151 + return; 1.1152 + } 1.1153 + ignore = updateMetaData(appendTo, prevDestLength, ignore, arg); 1.1154 + prevIndex = msgPattern.getPart(argLimit).getLimit(); 1.1155 + i = argLimit; 1.1156 + } 1.1157 +} 1.1158 + 1.1159 + 1.1160 +void MessageFormat::formatComplexSubMessage(int32_t msgStart, 1.1161 + const void *plNumber, 1.1162 + const Formattable* arguments, 1.1163 + const UnicodeString *argumentNames, 1.1164 + int32_t cnt, 1.1165 + AppendableWrapper& appendTo, 1.1166 + UErrorCode& success) const { 1.1167 + if (U_FAILURE(success)) { 1.1168 + return; 1.1169 + } 1.1170 + 1.1171 + if (!MessageImpl::jdkAposMode(msgPattern)) { 1.1172 + format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, NULL, success); 1.1173 + return; 1.1174 + } 1.1175 + 1.1176 + // JDK compatibility mode: (see JDK MessageFormat.format() API docs) 1.1177 + // - remove SKIP_SYNTAX; that is, remove half of the apostrophes 1.1178 + // - if the result string contains an open curly brace '{' then 1.1179 + // instantiate a temporary MessageFormat object and format again; 1.1180 + // otherwise just append the result string 1.1181 + const UnicodeString& msgString = msgPattern.getPatternString(); 1.1182 + UnicodeString sb; 1.1183 + int32_t prevIndex = msgPattern.getPart(msgStart).getLimit(); 1.1184 + for (int32_t i = msgStart;;) { 1.1185 + const MessagePattern::Part& part = msgPattern.getPart(++i); 1.1186 + const UMessagePatternPartType type = part.getType(); 1.1187 + int32_t index = part.getIndex(); 1.1188 + if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) { 1.1189 + sb.append(msgString, prevIndex, index - prevIndex); 1.1190 + break; 1.1191 + } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) { 1.1192 + sb.append(msgString, prevIndex, index - prevIndex); 1.1193 + if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) { 1.1194 + const PluralSelectorContext &pluralNumber = 1.1195 + *static_cast<const PluralSelectorContext *>(plNumber); 1.1196 + if(pluralNumber.forReplaceNumber) { 1.1197 + // number-offset was already formatted. 1.1198 + sb.append(pluralNumber.numberString); 1.1199 + } else { 1.1200 + const NumberFormat* nf = getDefaultNumberFormat(success); 1.1201 + sb.append(nf->format(pluralNumber.number, sb, success)); 1.1202 + } 1.1203 + } 1.1204 + prevIndex = part.getLimit(); 1.1205 + } else if (type == UMSGPAT_PART_TYPE_ARG_START) { 1.1206 + sb.append(msgString, prevIndex, index - prevIndex); 1.1207 + prevIndex = index; 1.1208 + i = msgPattern.getLimitPartIndex(i); 1.1209 + index = msgPattern.getPart(i).getLimit(); 1.1210 + MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb); 1.1211 + prevIndex = index; 1.1212 + } 1.1213 + } 1.1214 + if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) { 1.1215 + UnicodeString emptyPattern; // gcc 3.3.3 fails with "UnicodeString()" as the first parameter. 1.1216 + MessageFormat subMsgFormat(emptyPattern, fLocale, success); 1.1217 + subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, success); 1.1218 + subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, NULL, success); 1.1219 + } else { 1.1220 + appendTo.append(sb); 1.1221 + } 1.1222 +} 1.1223 + 1.1224 + 1.1225 +UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const { 1.1226 + const UnicodeString& msgString=msgPattern.getPatternString(); 1.1227 + int32_t prevIndex=msgPattern.getPart(from).getLimit(); 1.1228 + UnicodeString b; 1.1229 + for (int32_t i = from + 1; ; ++i) { 1.1230 + const MessagePattern::Part& part = msgPattern.getPart(i); 1.1231 + const UMessagePatternPartType type=part.getType(); 1.1232 + int32_t index=part.getIndex(); 1.1233 + b.append(msgString, prevIndex, index - prevIndex); 1.1234 + if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) { 1.1235 + return b; 1.1236 + } 1.1237 + // Unexpected Part "part" in parsed message. 1.1238 + U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR); 1.1239 + prevIndex=part.getLimit(); 1.1240 + } 1.1241 +} 1.1242 + 1.1243 + 1.1244 +FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/, 1.1245 + FieldPosition* /*fp*/, const Formattable* /*argId*/) const { 1.1246 + // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing. 1.1247 + return NULL; 1.1248 + /* 1.1249 + if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) { 1.1250 + fp->setBeginIndex(prevLength); 1.1251 + fp->setEndIndex(dest.get_length()); 1.1252 + return NULL; 1.1253 + } 1.1254 + return fp; 1.1255 + */ 1.1256 +} 1.1257 + 1.1258 +int32_t 1.1259 +MessageFormat::findOtherSubMessage(int32_t partIndex) const { 1.1260 + int32_t count=msgPattern.countParts(); 1.1261 + const MessagePattern::Part *part = &msgPattern.getPart(partIndex); 1.1262 + if(MessagePattern::Part::hasNumericValue(part->getType())) { 1.1263 + ++partIndex; 1.1264 + } 1.1265 + // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples 1.1266 + // until ARG_LIMIT or end of plural-only pattern. 1.1267 + UnicodeString other(FALSE, OTHER_STRING, 5); 1.1268 + do { 1.1269 + part=&msgPattern.getPart(partIndex++); 1.1270 + UMessagePatternPartType type=part->getType(); 1.1271 + if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { 1.1272 + break; 1.1273 + } 1.1274 + U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR); 1.1275 + // part is an ARG_SELECTOR followed by an optional explicit value, and then a message 1.1276 + if(msgPattern.partSubstringMatches(*part, other)) { 1.1277 + return partIndex; 1.1278 + } 1.1279 + if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) { 1.1280 + ++partIndex; // skip the numeric-value part of "=1" etc. 1.1281 + } 1.1282 + partIndex=msgPattern.getLimitPartIndex(partIndex); 1.1283 + } while(++partIndex<count); 1.1284 + return 0; 1.1285 +} 1.1286 + 1.1287 +int32_t 1.1288 +MessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const { 1.1289 + for(int32_t i=msgStart+1;; ++i) { 1.1290 + const MessagePattern::Part &part=msgPattern.getPart(i); 1.1291 + UMessagePatternPartType type=part.getType(); 1.1292 + if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) { 1.1293 + return 0; 1.1294 + } 1.1295 + if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) { 1.1296 + return -1; 1.1297 + } 1.1298 + if(type==UMSGPAT_PART_TYPE_ARG_START) { 1.1299 + UMessagePatternArgType argType=part.getArgType(); 1.1300 + if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) { 1.1301 + // ARG_NUMBER or ARG_NAME 1.1302 + if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) { 1.1303 + return i; 1.1304 + } 1.1305 + } 1.1306 + i=msgPattern.getLimitPartIndex(i); 1.1307 + } 1.1308 + } 1.1309 +} 1.1310 + 1.1311 +void MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) { 1.1312 + // Deep copy pointer fields. 1.1313 + // We need not copy the formatAliases because they are re-filled 1.1314 + // in each getFormats() call. 1.1315 + // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules 1.1316 + // also get created on demand. 1.1317 + argTypeCount = that.argTypeCount; 1.1318 + if (argTypeCount > 0) { 1.1319 + if (!allocateArgTypes(argTypeCount, ec)) { 1.1320 + return; 1.1321 + } 1.1322 + uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0])); 1.1323 + } 1.1324 + if (cachedFormatters != NULL) { 1.1325 + uhash_removeAll(cachedFormatters); 1.1326 + } 1.1327 + if (customFormatArgStarts != NULL) { 1.1328 + uhash_removeAll(customFormatArgStarts); 1.1329 + } 1.1330 + if (that.cachedFormatters) { 1.1331 + if (cachedFormatters == NULL) { 1.1332 + cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong, 1.1333 + equalFormatsForHash, &ec); 1.1334 + if (U_FAILURE(ec)) { 1.1335 + return; 1.1336 + } 1.1337 + uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject); 1.1338 + } 1.1339 + 1.1340 + const int32_t count = uhash_count(that.cachedFormatters); 1.1341 + int32_t pos, idx; 1.1342 + for (idx = 0, pos = -1; idx < count && U_SUCCESS(ec); ++idx) { 1.1343 + const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos); 1.1344 + Format* newFormat = ((Format*)(cur->value.pointer))->clone(); 1.1345 + if (newFormat) { 1.1346 + uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec); 1.1347 + } else { 1.1348 + ec = U_MEMORY_ALLOCATION_ERROR; 1.1349 + return; 1.1350 + } 1.1351 + } 1.1352 + } 1.1353 + if (that.customFormatArgStarts) { 1.1354 + if (customFormatArgStarts == NULL) { 1.1355 + customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong, 1.1356 + NULL, &ec); 1.1357 + } 1.1358 + const int32_t count = uhash_count(that.customFormatArgStarts); 1.1359 + int32_t pos, idx; 1.1360 + for (idx = 0, pos = -1; idx < count && U_SUCCESS(ec); ++idx) { 1.1361 + const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos); 1.1362 + uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec); 1.1363 + } 1.1364 + } 1.1365 +} 1.1366 + 1.1367 + 1.1368 +Formattable* 1.1369 +MessageFormat::parse(int32_t msgStart, 1.1370 + const UnicodeString& source, 1.1371 + ParsePosition& pos, 1.1372 + int32_t& count, 1.1373 + UErrorCode& ec) const { 1.1374 + count = 0; 1.1375 + if (U_FAILURE(ec)) { 1.1376 + pos.setErrorIndex(pos.getIndex()); 1.1377 + return NULL; 1.1378 + } 1.1379 + // parse() does not work with named arguments. 1.1380 + if (msgPattern.hasNamedArguments()) { 1.1381 + ec = U_ARGUMENT_TYPE_MISMATCH; 1.1382 + pos.setErrorIndex(pos.getIndex()); 1.1383 + return NULL; 1.1384 + } 1.1385 + LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]); 1.1386 + const UnicodeString& msgString=msgPattern.getPatternString(); 1.1387 + int32_t prevIndex=msgPattern.getPart(msgStart).getLimit(); 1.1388 + int32_t sourceOffset = pos.getIndex(); 1.1389 + ParsePosition tempStatus(0); 1.1390 + 1.1391 + for(int32_t i=msgStart+1; ; ++i) { 1.1392 + UBool haveArgResult = FALSE; 1.1393 + const MessagePattern::Part* part=&msgPattern.getPart(i); 1.1394 + const UMessagePatternPartType type=part->getType(); 1.1395 + int32_t index=part->getIndex(); 1.1396 + // Make sure the literal string matches. 1.1397 + int32_t len = index - prevIndex; 1.1398 + if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) { 1.1399 + sourceOffset += len; 1.1400 + prevIndex += len; 1.1401 + } else { 1.1402 + pos.setErrorIndex(sourceOffset); 1.1403 + return NULL; // leave index as is to signal error 1.1404 + } 1.1405 + if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) { 1.1406 + // Things went well! Done. 1.1407 + pos.setIndex(sourceOffset); 1.1408 + return resultArray.orphan(); 1.1409 + } 1.1410 + if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) { 1.1411 + prevIndex=part->getLimit(); 1.1412 + continue; 1.1413 + } 1.1414 + // We do not support parsing Plural formats. (No REPLACE_NUMBER here.) 1.1415 + // Unexpected Part "part" in parsed message. 1.1416 + U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START); 1.1417 + int32_t argLimit=msgPattern.getLimitPartIndex(i); 1.1418 + 1.1419 + UMessagePatternArgType argType=part->getArgType(); 1.1420 + part=&msgPattern.getPart(++i); 1.1421 + int32_t argNumber = part->getValue(); // ARG_NUMBER 1.1422 + UnicodeString key; 1.1423 + ++i; 1.1424 + const Format* formatter = NULL; 1.1425 + Formattable& argResult = resultArray[argNumber]; 1.1426 + 1.1427 + if(cachedFormatters!=NULL && (formatter = getCachedFormatter(i - 2))!=NULL) { 1.1428 + // Just parse using the formatter. 1.1429 + tempStatus.setIndex(sourceOffset); 1.1430 + formatter->parseObject(source, argResult, tempStatus); 1.1431 + if (tempStatus.getIndex() == sourceOffset) { 1.1432 + pos.setErrorIndex(sourceOffset); 1.1433 + return NULL; // leave index as is to signal error 1.1434 + } 1.1435 + sourceOffset = tempStatus.getIndex(); 1.1436 + haveArgResult = TRUE; 1.1437 + } else if( 1.1438 + argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) { 1.1439 + // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table. 1.1440 + // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check 1.1441 + // for the hash table containind DummyFormat. 1.1442 + 1.1443 + // Match as a string. 1.1444 + // if at end, use longest possible match 1.1445 + // otherwise uses first match to intervening string 1.1446 + // does NOT recursively try all possibilities 1.1447 + UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit); 1.1448 + int32_t next; 1.1449 + if (!stringAfterArgument.isEmpty()) { 1.1450 + next = source.indexOf(stringAfterArgument, sourceOffset); 1.1451 + } else { 1.1452 + next = source.length(); 1.1453 + } 1.1454 + if (next < 0) { 1.1455 + pos.setErrorIndex(sourceOffset); 1.1456 + return NULL; // leave index as is to signal error 1.1457 + } else { 1.1458 + UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset)); 1.1459 + UnicodeString compValue; 1.1460 + compValue.append(LEFT_CURLY_BRACE); 1.1461 + itos(argNumber, compValue); 1.1462 + compValue.append(RIGHT_CURLY_BRACE); 1.1463 + if (0 != strValue.compare(compValue)) { 1.1464 + argResult.setString(strValue); 1.1465 + haveArgResult = TRUE; 1.1466 + } 1.1467 + sourceOffset = next; 1.1468 + } 1.1469 + } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) { 1.1470 + tempStatus.setIndex(sourceOffset); 1.1471 + double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus); 1.1472 + if (tempStatus.getIndex() == sourceOffset) { 1.1473 + pos.setErrorIndex(sourceOffset); 1.1474 + return NULL; // leave index as is to signal error 1.1475 + } 1.1476 + argResult.setDouble(choiceResult); 1.1477 + haveArgResult = TRUE; 1.1478 + sourceOffset = tempStatus.getIndex(); 1.1479 + } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) { 1.1480 + // Parsing not supported. 1.1481 + ec = U_UNSUPPORTED_ERROR; 1.1482 + return NULL; 1.1483 + } else { 1.1484 + // This should never happen. 1.1485 + ec = U_INTERNAL_PROGRAM_ERROR; 1.1486 + return NULL; 1.1487 + } 1.1488 + if (haveArgResult && count <= argNumber) { 1.1489 + count = argNumber + 1; 1.1490 + } 1.1491 + prevIndex=msgPattern.getPart(argLimit).getLimit(); 1.1492 + i=argLimit; 1.1493 + } 1.1494 +} 1.1495 +// ------------------------------------- 1.1496 +// Parses the source pattern and returns the Formattable objects array, 1.1497 +// the array count and the ending parse position. The caller of this method 1.1498 +// owns the array. 1.1499 + 1.1500 +Formattable* 1.1501 +MessageFormat::parse(const UnicodeString& source, 1.1502 + ParsePosition& pos, 1.1503 + int32_t& count) const { 1.1504 + UErrorCode ec = U_ZERO_ERROR; 1.1505 + return parse(0, source, pos, count, ec); 1.1506 +} 1.1507 + 1.1508 +// ------------------------------------- 1.1509 +// Parses the source string and returns the array of 1.1510 +// Formattable objects and the array count. The caller 1.1511 +// owns the returned array. 1.1512 + 1.1513 +Formattable* 1.1514 +MessageFormat::parse(const UnicodeString& source, 1.1515 + int32_t& cnt, 1.1516 + UErrorCode& success) const 1.1517 +{ 1.1518 + if (msgPattern.hasNamedArguments()) { 1.1519 + success = U_ARGUMENT_TYPE_MISMATCH; 1.1520 + return NULL; 1.1521 + } 1.1522 + ParsePosition status(0); 1.1523 + // Calls the actual implementation method and starts 1.1524 + // from zero offset of the source text. 1.1525 + Formattable* result = parse(source, status, cnt); 1.1526 + if (status.getIndex() == 0) { 1.1527 + success = U_MESSAGE_PARSE_ERROR; 1.1528 + delete[] result; 1.1529 + return NULL; 1.1530 + } 1.1531 + return result; 1.1532 +} 1.1533 + 1.1534 +// ------------------------------------- 1.1535 +// Parses the source text and copy into the result buffer. 1.1536 + 1.1537 +void 1.1538 +MessageFormat::parseObject( const UnicodeString& source, 1.1539 + Formattable& result, 1.1540 + ParsePosition& status) const 1.1541 +{ 1.1542 + int32_t cnt = 0; 1.1543 + Formattable* tmpResult = parse(source, status, cnt); 1.1544 + if (tmpResult != NULL) 1.1545 + result.adoptArray(tmpResult, cnt); 1.1546 +} 1.1547 + 1.1548 +UnicodeString 1.1549 +MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) { 1.1550 + UnicodeString result; 1.1551 + if (U_SUCCESS(status)) { 1.1552 + int32_t plen = pattern.length(); 1.1553 + const UChar* pat = pattern.getBuffer(); 1.1554 + int32_t blen = plen * 2 + 1; // space for null termination, convenience 1.1555 + UChar* buf = result.getBuffer(blen); 1.1556 + if (buf == NULL) { 1.1557 + status = U_MEMORY_ALLOCATION_ERROR; 1.1558 + } else { 1.1559 + int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status); 1.1560 + result.releaseBuffer(U_SUCCESS(status) ? len : 0); 1.1561 + } 1.1562 + } 1.1563 + if (U_FAILURE(status)) { 1.1564 + result.setToBogus(); 1.1565 + } 1.1566 + return result; 1.1567 +} 1.1568 + 1.1569 +// ------------------------------------- 1.1570 + 1.1571 +static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) { 1.1572 + RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec); 1.1573 + if (fmt == NULL) { 1.1574 + ec = U_MEMORY_ALLOCATION_ERROR; 1.1575 + } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) { 1.1576 + UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set 1.1577 + fmt->setDefaultRuleSet(defaultRuleSet, localStatus); 1.1578 + } 1.1579 + return fmt; 1.1580 +} 1.1581 + 1.1582 +void MessageFormat::cacheExplicitFormats(UErrorCode& status) { 1.1583 + if (U_FAILURE(status)) { 1.1584 + return; 1.1585 + } 1.1586 + 1.1587 + if (cachedFormatters != NULL) { 1.1588 + uhash_removeAll(cachedFormatters); 1.1589 + } 1.1590 + if (customFormatArgStarts != NULL) { 1.1591 + uhash_removeAll(customFormatArgStarts); 1.1592 + } 1.1593 + 1.1594 + // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT 1.1595 + // which we need not examine. 1.1596 + int32_t limit = msgPattern.countParts() - 2; 1.1597 + argTypeCount = 0; 1.1598 + // We also need not look at the first two "parts" 1.1599 + // (at most MSG_START and ARG_START) in this loop. 1.1600 + // We determine the argTypeCount first so that we can allocateArgTypes 1.1601 + // so that the next loop can set argTypes[argNumber]. 1.1602 + // (This is for the C API which needs the argTypes to read its va_arg list.) 1.1603 + for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) { 1.1604 + const MessagePattern::Part& part = msgPattern.getPart(i); 1.1605 + if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) { 1.1606 + const int argNumber = part.getValue(); 1.1607 + if (argNumber >= argTypeCount) { 1.1608 + argTypeCount = argNumber + 1; 1.1609 + } 1.1610 + } 1.1611 + } 1.1612 + if (!allocateArgTypes(argTypeCount, status)) { 1.1613 + return; 1.1614 + } 1.1615 + // Set all argTypes to kObject, as a "none" value, for lack of any better value. 1.1616 + // We never use kObject for real arguments. 1.1617 + // We use it as "no argument yet" for the check for hasArgTypeConflicts. 1.1618 + for (int32_t i = 0; i < argTypeCount; ++i) { 1.1619 + argTypes[i] = Formattable::kObject; 1.1620 + } 1.1621 + hasArgTypeConflicts = FALSE; 1.1622 + 1.1623 + // This loop starts at part index 1 because we do need to examine 1.1624 + // ARG_START parts. (But we can ignore the MSG_START.) 1.1625 + for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) { 1.1626 + const MessagePattern::Part* part = &msgPattern.getPart(i); 1.1627 + if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) { 1.1628 + continue; 1.1629 + } 1.1630 + UMessagePatternArgType argType = part->getArgType(); 1.1631 + 1.1632 + int32_t argNumber = -1; 1.1633 + part = &msgPattern.getPart(i + 1); 1.1634 + if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) { 1.1635 + argNumber = part->getValue(); 1.1636 + } 1.1637 + Formattable::Type formattableType; 1.1638 + 1.1639 + switch (argType) { 1.1640 + case UMSGPAT_ARG_TYPE_NONE: 1.1641 + formattableType = Formattable::kString; 1.1642 + break; 1.1643 + case UMSGPAT_ARG_TYPE_SIMPLE: { 1.1644 + int32_t index = i; 1.1645 + i += 2; 1.1646 + UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++)); 1.1647 + UnicodeString style; 1.1648 + if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) { 1.1649 + style = msgPattern.getSubstring(*part); 1.1650 + ++i; 1.1651 + } 1.1652 + UParseError parseError; 1.1653 + Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status); 1.1654 + setArgStartFormat(index, formatter, status); 1.1655 + break; 1.1656 + } 1.1657 + case UMSGPAT_ARG_TYPE_CHOICE: 1.1658 + case UMSGPAT_ARG_TYPE_PLURAL: 1.1659 + case UMSGPAT_ARG_TYPE_SELECTORDINAL: 1.1660 + formattableType = Formattable::kDouble; 1.1661 + break; 1.1662 + case UMSGPAT_ARG_TYPE_SELECT: 1.1663 + formattableType = Formattable::kString; 1.1664 + break; 1.1665 + default: 1.1666 + status = U_INTERNAL_PROGRAM_ERROR; // Should be unreachable. 1.1667 + formattableType = Formattable::kString; 1.1668 + break; 1.1669 + } 1.1670 + if (argNumber != -1) { 1.1671 + if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) { 1.1672 + hasArgTypeConflicts = TRUE; 1.1673 + } 1.1674 + argTypes[argNumber] = formattableType; 1.1675 + } 1.1676 + } 1.1677 +} 1.1678 + 1.1679 + 1.1680 +Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style, 1.1681 + Formattable::Type& formattableType, UParseError& parseError, 1.1682 + UErrorCode& ec) { 1.1683 + if (U_FAILURE(ec)) { 1.1684 + return NULL; 1.1685 + } 1.1686 + Format* fmt = NULL; 1.1687 + int32_t typeID, styleID; 1.1688 + DateFormat::EStyle date_style; 1.1689 + 1.1690 + switch (typeID = findKeyword(type, TYPE_IDS)) { 1.1691 + case 0: // number 1.1692 + formattableType = Formattable::kDouble; 1.1693 + switch (findKeyword(style, NUMBER_STYLE_IDS)) { 1.1694 + case 0: // default 1.1695 + fmt = NumberFormat::createInstance(fLocale, ec); 1.1696 + break; 1.1697 + case 1: // currency 1.1698 + fmt = NumberFormat::createCurrencyInstance(fLocale, ec); 1.1699 + break; 1.1700 + case 2: // percent 1.1701 + fmt = NumberFormat::createPercentInstance(fLocale, ec); 1.1702 + break; 1.1703 + case 3: // integer 1.1704 + formattableType = Formattable::kLong; 1.1705 + fmt = createIntegerFormat(fLocale, ec); 1.1706 + break; 1.1707 + default: // pattern 1.1708 + fmt = NumberFormat::createInstance(fLocale, ec); 1.1709 + if (fmt) { 1.1710 + DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fmt); 1.1711 + if (decfmt != NULL) { 1.1712 + decfmt->applyPattern(style,parseError,ec); 1.1713 + } 1.1714 + } 1.1715 + break; 1.1716 + } 1.1717 + break; 1.1718 + 1.1719 + case 1: // date 1.1720 + case 2: // time 1.1721 + formattableType = Formattable::kDate; 1.1722 + styleID = findKeyword(style, DATE_STYLE_IDS); 1.1723 + date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault; 1.1724 + 1.1725 + if (typeID == 1) { 1.1726 + fmt = DateFormat::createDateInstance(date_style, fLocale); 1.1727 + } else { 1.1728 + fmt = DateFormat::createTimeInstance(date_style, fLocale); 1.1729 + } 1.1730 + 1.1731 + if (styleID < 0 && fmt != NULL) { 1.1732 + SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt); 1.1733 + if (sdtfmt != NULL) { 1.1734 + sdtfmt->applyPattern(style); 1.1735 + } 1.1736 + } 1.1737 + break; 1.1738 + 1.1739 + case 3: // spellout 1.1740 + formattableType = Formattable::kDouble; 1.1741 + fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec); 1.1742 + break; 1.1743 + case 4: // ordinal 1.1744 + formattableType = Formattable::kDouble; 1.1745 + fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec); 1.1746 + break; 1.1747 + case 5: // duration 1.1748 + formattableType = Formattable::kDouble; 1.1749 + fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec); 1.1750 + break; 1.1751 + default: 1.1752 + formattableType = Formattable::kString; 1.1753 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.1754 + break; 1.1755 + } 1.1756 + 1.1757 + return fmt; 1.1758 +} 1.1759 + 1.1760 + 1.1761 +//------------------------------------- 1.1762 +// Finds the string, s, in the string array, list. 1.1763 +int32_t MessageFormat::findKeyword(const UnicodeString& s, 1.1764 + const UChar * const *list) 1.1765 +{ 1.1766 + if (s.isEmpty()) { 1.1767 + return 0; // default 1.1768 + } 1.1769 + 1.1770 + int32_t length = s.length(); 1.1771 + const UChar *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length); 1.1772 + UnicodeString buffer(FALSE, ps, length); 1.1773 + // Trims the space characters and turns all characters 1.1774 + // in s to lower case. 1.1775 + buffer.toLower(""); 1.1776 + for (int32_t i = 0; list[i]; ++i) { 1.1777 + if (!buffer.compare(list[i], u_strlen(list[i]))) { 1.1778 + return i; 1.1779 + } 1.1780 + } 1.1781 + return -1; 1.1782 +} 1.1783 + 1.1784 +/** 1.1785 + * Convenience method that ought to be in NumberFormat 1.1786 + */ 1.1787 +NumberFormat* 1.1788 +MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const { 1.1789 + NumberFormat *temp = NumberFormat::createInstance(locale, status); 1.1790 + DecimalFormat *temp2; 1.1791 + if (temp != NULL && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != NULL) { 1.1792 + temp2->setMaximumFractionDigits(0); 1.1793 + temp2->setDecimalSeparatorAlwaysShown(FALSE); 1.1794 + temp2->setParseIntegerOnly(TRUE); 1.1795 + } 1.1796 + 1.1797 + return temp; 1.1798 +} 1.1799 + 1.1800 +/** 1.1801 + * Return the default number format. Used to format a numeric 1.1802 + * argument when subformats[i].format is NULL. Returns NULL 1.1803 + * on failure. 1.1804 + * 1.1805 + * Semantically const but may modify *this. 1.1806 + */ 1.1807 +const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const { 1.1808 + if (defaultNumberFormat == NULL) { 1.1809 + MessageFormat* t = (MessageFormat*) this; 1.1810 + t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec); 1.1811 + if (U_FAILURE(ec)) { 1.1812 + delete t->defaultNumberFormat; 1.1813 + t->defaultNumberFormat = NULL; 1.1814 + } else if (t->defaultNumberFormat == NULL) { 1.1815 + ec = U_MEMORY_ALLOCATION_ERROR; 1.1816 + } 1.1817 + } 1.1818 + return defaultNumberFormat; 1.1819 +} 1.1820 + 1.1821 +/** 1.1822 + * Return the default date format. Used to format a date 1.1823 + * argument when subformats[i].format is NULL. Returns NULL 1.1824 + * on failure. 1.1825 + * 1.1826 + * Semantically const but may modify *this. 1.1827 + */ 1.1828 +const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const { 1.1829 + if (defaultDateFormat == NULL) { 1.1830 + MessageFormat* t = (MessageFormat*) this; 1.1831 + t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale); 1.1832 + if (t->defaultDateFormat == NULL) { 1.1833 + ec = U_MEMORY_ALLOCATION_ERROR; 1.1834 + } 1.1835 + } 1.1836 + return defaultDateFormat; 1.1837 +} 1.1838 + 1.1839 +UBool 1.1840 +MessageFormat::usesNamedArguments() const { 1.1841 + return msgPattern.hasNamedArguments(); 1.1842 +} 1.1843 + 1.1844 +int32_t 1.1845 +MessageFormat::getArgTypeCount() const { 1.1846 + return argTypeCount; 1.1847 +} 1.1848 + 1.1849 +UBool MessageFormat::equalFormats(const void* left, const void* right) { 1.1850 + return *(const Format*)left==*(const Format*)right; 1.1851 +} 1.1852 + 1.1853 + 1.1854 +UBool MessageFormat::DummyFormat::operator==(const Format&) const { 1.1855 + return TRUE; 1.1856 +} 1.1857 + 1.1858 +Format* MessageFormat::DummyFormat::clone() const { 1.1859 + return new DummyFormat(); 1.1860 +} 1.1861 + 1.1862 +UnicodeString& MessageFormat::DummyFormat::format(const Formattable&, 1.1863 + UnicodeString& appendTo, 1.1864 + UErrorCode& status) const { 1.1865 + if (U_SUCCESS(status)) { 1.1866 + status = U_UNSUPPORTED_ERROR; 1.1867 + } 1.1868 + return appendTo; 1.1869 +} 1.1870 + 1.1871 +UnicodeString& MessageFormat::DummyFormat::format(const Formattable&, 1.1872 + UnicodeString& appendTo, 1.1873 + FieldPosition&, 1.1874 + UErrorCode& status) const { 1.1875 + if (U_SUCCESS(status)) { 1.1876 + status = U_UNSUPPORTED_ERROR; 1.1877 + } 1.1878 + return appendTo; 1.1879 +} 1.1880 + 1.1881 +UnicodeString& MessageFormat::DummyFormat::format(const Formattable&, 1.1882 + UnicodeString& appendTo, 1.1883 + FieldPositionIterator*, 1.1884 + UErrorCode& status) const { 1.1885 + if (U_SUCCESS(status)) { 1.1886 + status = U_UNSUPPORTED_ERROR; 1.1887 + } 1.1888 + return appendTo; 1.1889 +} 1.1890 + 1.1891 +void MessageFormat::DummyFormat::parseObject(const UnicodeString&, 1.1892 + Formattable&, 1.1893 + ParsePosition& ) const { 1.1894 +} 1.1895 + 1.1896 + 1.1897 +FormatNameEnumeration::FormatNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) { 1.1898 + pos=0; 1.1899 + fFormatNames = fNameList; 1.1900 +} 1.1901 + 1.1902 +const UnicodeString* 1.1903 +FormatNameEnumeration::snext(UErrorCode& status) { 1.1904 + if (U_SUCCESS(status) && pos < fFormatNames->size()) { 1.1905 + return (const UnicodeString*)fFormatNames->elementAt(pos++); 1.1906 + } 1.1907 + return NULL; 1.1908 +} 1.1909 + 1.1910 +void 1.1911 +FormatNameEnumeration::reset(UErrorCode& /*status*/) { 1.1912 + pos=0; 1.1913 +} 1.1914 + 1.1915 +int32_t 1.1916 +FormatNameEnumeration::count(UErrorCode& /*status*/) const { 1.1917 + return (fFormatNames==NULL) ? 0 : fFormatNames->size(); 1.1918 +} 1.1919 + 1.1920 +FormatNameEnumeration::~FormatNameEnumeration() { 1.1921 + delete fFormatNames; 1.1922 +} 1.1923 + 1.1924 +MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t) 1.1925 + : msgFormat(mf), rules(NULL), type(t) { 1.1926 +} 1.1927 + 1.1928 +MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() { 1.1929 + delete rules; 1.1930 +} 1.1931 + 1.1932 +UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number, 1.1933 + UErrorCode& ec) const { 1.1934 + if (U_FAILURE(ec)) { 1.1935 + return UnicodeString(FALSE, OTHER_STRING, 5); 1.1936 + } 1.1937 + MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this); 1.1938 + if(rules == NULL) { 1.1939 + t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec); 1.1940 + if (U_FAILURE(ec)) { 1.1941 + return UnicodeString(FALSE, OTHER_STRING, 5); 1.1942 + } 1.1943 + } 1.1944 + // Select a sub-message according to how the number is formatted, 1.1945 + // which is specified in the selected sub-message. 1.1946 + // We avoid this circle by looking at how 1.1947 + // the number is formatted in the "other" sub-message 1.1948 + // which must always be present and usually contains the number. 1.1949 + // Message authors should be consistent across sub-messages. 1.1950 + PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx); 1.1951 + int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex); 1.1952 + context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName); 1.1953 + if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != NULL) { 1.1954 + context.formatter = 1.1955 + (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex); 1.1956 + } 1.1957 + if(context.formatter == NULL) { 1.1958 + context.formatter = msgFormat.getDefaultNumberFormat(ec); 1.1959 + context.forReplaceNumber = TRUE; 1.1960 + } 1.1961 + U_ASSERT(context.number.getDouble(ec) == number); // argument number minus the offset 1.1962 + context.formatter->format(context.number, context.numberString, ec); 1.1963 + const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(context.formatter); 1.1964 + if(decFmt != NULL) { 1.1965 + FixedDecimal dec = decFmt->getFixedDecimal(context.number, ec); 1.1966 + return rules->select(dec); 1.1967 + } else { 1.1968 + return rules->select(number); 1.1969 + } 1.1970 +} 1.1971 + 1.1972 +void MessageFormat::PluralSelectorProvider::reset() { 1.1973 + delete rules; 1.1974 + rules = NULL; 1.1975 +} 1.1976 + 1.1977 + 1.1978 +U_NAMESPACE_END 1.1979 + 1.1980 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.1981 + 1.1982 +//eof