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