1 /* 2 ******************************************************************************* 3 * Copyright (C) 1997-2009, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 * 7 * File NUMFMT.CPP 8 * 9 * Modification History: 10 * 11 * Date Name Description 12 * 02/19/97 aliu Converted from java. 13 * 03/18/97 clhuang Implemented with C++ APIs. 14 * 04/17/97 aliu Enlarged MAX_INTEGER_DIGITS to fully accomodate the 15 * largest double, by default. 16 * Changed DigitCount to int per code review. 17 * 07/20/98 stephen Changed operator== to check for grouping 18 * Changed setMaxIntegerDigits per Java implementation. 19 * Changed setMinIntegerDigits per Java implementation. 20 * Changed setMinFractionDigits per Java implementation. 21 * Changed setMaxFractionDigits per Java implementation. 22 ******************************************************************************** 23 */ 24 25 #include "unicode/utypes.h" 26 27 #if !UCONFIG_NO_FORMATTING 28 29 #include "unicode/numfmt.h" 30 #include "unicode/locid.h" 31 #include "unicode/dcfmtsym.h" 32 #include "unicode/decimfmt.h" 33 #include "unicode/ustring.h" 34 #include "unicode/ucurr.h" 35 #include "unicode/curramt.h" 36 #include "unicode/numsys.h" 37 #include "unicode/rbnf.h" 38 #include "winnmfmt.h" 39 #include "uresimp.h" 40 #include "uhash.h" 41 #include "cmemory.h" 42 #include "servloc.h" 43 #include "ucln_in.h" 44 #include "cstring.h" 45 #include "putilimp.h" 46 #include <float.h> 47 48 //#define FMT_DEBUG 49 50 #ifdef FMT_DEBUG 51 #include <stdio.h> 52 static void debugout(UnicodeString s) { 53 char buf[2000]; 54 s.extract((int32_t) 0, s.length(), buf); 55 printf("%s", buf); 56 } 57 #define debug(x) printf("%s", x); 58 #else 59 #define debugout(x) 60 #define debug(x) 61 #endif 62 63 // If no number pattern can be located for a locale, this is the last 64 // resort. 65 static const UChar gLastResortDecimalPat[] = { 66 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */ 67 }; 68 static const UChar gLastResortCurrencyPat[] = { 69 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "$#0.00;($#0.00)" */ 70 }; 71 static const UChar gLastResortPercentPat[] = { 72 0x23, 0x30, 0x25, 0 /* "#0%" */ 73 }; 74 static const UChar gLastResortScientificPat[] = { 75 0x23, 0x45, 0x30, 0 /* "#E0" */ 76 }; 77 static const UChar gLastResortIsoCurrencyPat[] = { 78 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "\u00A4\u00A4#0.00;(\u00A4\u00A4#0.00)" */ 79 }; 80 static const UChar gLastResortPluralCurrencyPat[] = { 81 0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/ 82 }; 83 84 static const UChar gSingleCurrencySign[] = {0xA4, 0}; 85 static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0}; 86 87 static const UChar gSlash = 0x2f; 88 89 // If the maximum base 10 exponent were 4, then the largest number would 90 // be 99,999 which has 5 digits. 91 // On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit 92 static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1; 93 static const int32_t gMinIntegerDigits = 127; 94 95 static const UChar * const gLastResortNumberPatterns[] = 96 { 97 gLastResortDecimalPat, 98 gLastResortCurrencyPat, 99 gLastResortPercentPat, 100 gLastResortScientificPat, 101 gLastResortIsoCurrencyPat, 102 gLastResortPluralCurrencyPat, 103 }; 104 105 // ***************************************************************************** 106 // class NumberFormat 107 // ***************************************************************************** 108 109 U_NAMESPACE_BEGIN 110 111 UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat) 112 113 #if !UCONFIG_NO_SERVICE 114 // ------------------------------------- 115 // SimpleNumberFormatFactory implementation 116 NumberFormatFactory::~NumberFormatFactory() {} 117 SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible) 118 : _visible(visible) 119 { 120 LocaleUtility::initNameFromLocale(locale, _id); 121 } 122 123 SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {} 124 125 UBool SimpleNumberFormatFactory::visible(void) const { 126 return _visible; 127 } 128 129 const UnicodeString * 130 SimpleNumberFormatFactory::getSupportedIDs(int32_t &count, UErrorCode& status) const 131 { 132 if (U_SUCCESS(status)) { 133 count = 1; 134 return &_id; 135 } 136 count = 0; 137 return NULL; 138 } 139 #endif /* #if !UCONFIG_NO_SERVICE */ 140 141 // ------------------------------------- 142 // default constructor 143 NumberFormat::NumberFormat() 144 : fGroupingUsed(TRUE), 145 fMaxIntegerDigits(gMaxIntegerDigits), 146 fMinIntegerDigits(1), 147 fMaxFractionDigits(3), // invariant, >= minFractionDigits 148 fMinFractionDigits(0), 149 fParseIntegerOnly(FALSE) 150 { 151 fCurrency[0] = 0; 152 } 153 154 // ------------------------------------- 155 156 NumberFormat::~NumberFormat() 157 { 158 } 159 160 // ------------------------------------- 161 // copy constructor 162 163 NumberFormat::NumberFormat(const NumberFormat &source) 164 : Format(source) 165 { 166 *this = source; 167 } 168 169 // ------------------------------------- 170 // assignment operator 171 172 NumberFormat& 173 NumberFormat::operator=(const NumberFormat& rhs) 174 { 175 if (this != &rhs) 176 { 177 fGroupingUsed = rhs.fGroupingUsed; 178 fMaxIntegerDigits = rhs.fMaxIntegerDigits; 179 fMinIntegerDigits = rhs.fMinIntegerDigits; 180 fMaxFractionDigits = rhs.fMaxFractionDigits; 181 fMinFractionDigits = rhs.fMinFractionDigits; 182 fParseIntegerOnly = rhs.fParseIntegerOnly; 183 u_strncpy(fCurrency, rhs.fCurrency, 4); 184 } 185 return *this; 186 } 187 188 // ------------------------------------- 189 190 UBool 191 NumberFormat::operator==(const Format& that) const 192 { 193 // Format::operator== guarantees this cast is safe 194 NumberFormat* other = (NumberFormat*)&that; 195 196 #ifdef FMT_DEBUG 197 // This code makes it easy to determine why two format objects that should 198 // be equal aren't. 199 UBool first = TRUE; 200 if (!Format::operator==(that)) { 201 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 202 debug("Format::!="); 203 } 204 if (!(fMaxIntegerDigits == other->fMaxIntegerDigits && 205 fMinIntegerDigits == other->fMinIntegerDigits)) { 206 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 207 debug("Integer digits !="); 208 } 209 if (!(fMaxFractionDigits == other->fMaxFractionDigits && 210 fMinFractionDigits == other->fMinFractionDigits)) { 211 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 212 debug("Fraction digits !="); 213 } 214 if (!(fGroupingUsed == other->fGroupingUsed)) { 215 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 216 debug("fGroupingUsed != "); 217 } 218 if (!(fParseIntegerOnly == other->fParseIntegerOnly)) { 219 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 220 debug("fParseIntegerOnly != "); 221 } 222 if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) { 223 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 224 debug("fCurrency !="); 225 } 226 if (!first) { printf(" ]"); } 227 #endif 228 229 return ((this == &that) || 230 ((Format::operator==(that) && 231 fMaxIntegerDigits == other->fMaxIntegerDigits && 232 fMinIntegerDigits == other->fMinIntegerDigits && 233 fMaxFractionDigits == other->fMaxFractionDigits && 234 fMinFractionDigits == other->fMinFractionDigits && 235 fGroupingUsed == other->fGroupingUsed && 236 fParseIntegerOnly == other->fParseIntegerOnly && 237 u_strcmp(fCurrency, other->fCurrency) == 0))); 238 } 239 240 // -------------------------------------x 241 // Formats the number object and save the format 242 // result in the toAppendTo string buffer. 243 244 UnicodeString& 245 NumberFormat::format(const Formattable& obj, 246 UnicodeString& appendTo, 247 FieldPosition& pos, 248 UErrorCode& status) const 249 { 250 if (U_FAILURE(status)) return appendTo; 251 252 NumberFormat* nonconst = (NumberFormat*) this; 253 const Formattable* n = &obj; 254 255 UChar save[4]; 256 UBool setCurr = FALSE; 257 const UObject* o = obj.getObject(); // most commonly o==NULL 258 if (o != NULL && 259 o->getDynamicClassID() == CurrencyAmount::getStaticClassID()) { 260 // getISOCurrency() returns a pointer to internal storage, so we 261 // copy it to retain it across the call to setCurrency(). 262 const CurrencyAmount* amt = (const CurrencyAmount*) o; 263 const UChar* curr = amt->getISOCurrency(); 264 u_strcpy(save, getCurrency()); 265 setCurr = (u_strcmp(curr, save) != 0); 266 if (setCurr) { 267 nonconst->setCurrency(curr, status); 268 } 269 n = &amt->getNumber(); 270 } 271 272 switch (n->getType()) { 273 case Formattable::kDouble: 274 format(n->getDouble(), appendTo, pos); 275 break; 276 case Formattable::kLong: 277 format(n->getLong(), appendTo, pos); 278 break; 279 case Formattable::kInt64: 280 format(n->getInt64(), appendTo, pos); 281 break; 282 default: 283 status = U_INVALID_FORMAT_ERROR; 284 break; 285 } 286 287 if (setCurr) { 288 UErrorCode ok = U_ZERO_ERROR; 289 nonconst->setCurrency(save, ok); // always restore currency 290 } 291 return appendTo; 292 } 293 294 // ------------------------------------- 295 296 UnicodeString& 297 NumberFormat::format(int64_t number, 298 UnicodeString& appendTo, 299 FieldPosition& pos) const 300 { 301 // default so we don't introduce a new abstract method 302 return format((int32_t)number, appendTo, pos); 303 } 304 305 // ------------------------------------- 306 // Parses the string and save the result object as well 307 // as the final parsed position. 308 309 void 310 NumberFormat::parseObject(const UnicodeString& source, 311 Formattable& result, 312 ParsePosition& parse_pos) const 313 { 314 parse(source, result, parse_pos); 315 } 316 317 // ------------------------------------- 318 // Formats a double number and save the result in a string. 319 320 UnicodeString& 321 NumberFormat::format(double number, UnicodeString& appendTo) const 322 { 323 FieldPosition pos(0); 324 return format(number, appendTo, pos); 325 } 326 327 // ------------------------------------- 328 // Formats a long number and save the result in a string. 329 330 UnicodeString& 331 NumberFormat::format(int32_t number, UnicodeString& appendTo) const 332 { 333 FieldPosition pos(0); 334 return format(number, appendTo, pos); 335 } 336 337 // ------------------------------------- 338 // Formats a long number and save the result in a string. 339 340 UnicodeString& 341 NumberFormat::format(int64_t number, UnicodeString& appendTo) const 342 { 343 FieldPosition pos(0); 344 return format(number, appendTo, pos); 345 } 346 347 // ------------------------------------- 348 // Parses the text and save the result object. If the returned 349 // parse position is 0, that means the parsing failed, the status 350 // code needs to be set to failure. Ignores the returned parse 351 // position, otherwise. 352 353 void 354 NumberFormat::parse(const UnicodeString& text, 355 Formattable& result, 356 UErrorCode& status) const 357 { 358 if (U_FAILURE(status)) return; 359 360 ParsePosition parsePosition(0); 361 parse(text, result, parsePosition); 362 if (parsePosition.getIndex() == 0) { 363 status = U_INVALID_FORMAT_ERROR; 364 } 365 } 366 367 Formattable& NumberFormat::parseCurrency(const UnicodeString& text, 368 Formattable& result, 369 ParsePosition& pos) const { 370 // Default implementation only -- subclasses should override 371 int32_t start = pos.getIndex(); 372 parse(text, result, pos); 373 if (pos.getIndex() != start) { 374 UChar curr[4]; 375 UErrorCode ec = U_ZERO_ERROR; 376 getEffectiveCurrency(curr, ec); 377 if (U_SUCCESS(ec)) { 378 Formattable n(result); 379 CurrencyAmount *tempCurAmnt = new CurrencyAmount(n, curr, ec); // Use for null testing. 380 if (U_FAILURE(ec) || tempCurAmnt == NULL) { 381 pos.setIndex(start); // indicate failure 382 } else { 383 result.adoptObject(tempCurAmnt); 384 } 385 } 386 } 387 return result; 388 } 389 390 // ------------------------------------- 391 // Sets to only parse integers. 392 393 void 394 NumberFormat::setParseIntegerOnly(UBool value) 395 { 396 fParseIntegerOnly = value; 397 } 398 399 // ------------------------------------- 400 // Create a number style NumberFormat instance with the default locale. 401 402 NumberFormat* U_EXPORT2 403 NumberFormat::createInstance(UErrorCode& status) 404 { 405 return createInstance(Locale::getDefault(), kNumberStyle, status); 406 } 407 408 // ------------------------------------- 409 // Create a number style NumberFormat instance with the inLocale locale. 410 411 NumberFormat* U_EXPORT2 412 NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status) 413 { 414 return createInstance(inLocale, kNumberStyle, status); 415 } 416 417 // ------------------------------------- 418 // Create a currency style NumberFormat instance with the default locale. 419 420 NumberFormat* U_EXPORT2 421 NumberFormat::createCurrencyInstance(UErrorCode& status) 422 { 423 return createCurrencyInstance(Locale::getDefault(), status); 424 } 425 426 // ------------------------------------- 427 // Create a currency style NumberFormat instance with the inLocale locale. 428 429 NumberFormat* U_EXPORT2 430 NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status) 431 { 432 return createInstance(inLocale, kCurrencyStyle, status); 433 } 434 435 // ------------------------------------- 436 // Create a percent style NumberFormat instance with the default locale. 437 438 NumberFormat* U_EXPORT2 439 NumberFormat::createPercentInstance(UErrorCode& status) 440 { 441 return createInstance(Locale::getDefault(), kPercentStyle, status); 442 } 443 444 // ------------------------------------- 445 // Create a percent style NumberFormat instance with the inLocale locale. 446 447 NumberFormat* U_EXPORT2 448 NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status) 449 { 450 return createInstance(inLocale, kPercentStyle, status); 451 } 452 453 // ------------------------------------- 454 // Create a scientific style NumberFormat instance with the default locale. 455 456 NumberFormat* U_EXPORT2 457 NumberFormat::createScientificInstance(UErrorCode& status) 458 { 459 return createInstance(Locale::getDefault(), kScientificStyle, status); 460 } 461 462 // ------------------------------------- 463 // Create a scientific style NumberFormat instance with the inLocale locale. 464 465 NumberFormat* U_EXPORT2 466 NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status) 467 { 468 return createInstance(inLocale, kScientificStyle, status); 469 } 470 471 // ------------------------------------- 472 473 const Locale* U_EXPORT2 474 NumberFormat::getAvailableLocales(int32_t& count) 475 { 476 return Locale::getAvailableLocales(count); 477 } 478 479 // ------------------------------------------ 480 // 481 // Registration 482 // 483 //------------------------------------------- 484 485 #if !UCONFIG_NO_SERVICE 486 static ICULocaleService* gService = NULL; 487 488 /** 489 * Release all static memory held by numberformat. 490 */ 491 U_CDECL_BEGIN 492 static UBool U_CALLCONV numfmt_cleanup(void) { 493 if (gService) { 494 delete gService; 495 gService = NULL; 496 } 497 return TRUE; 498 } 499 U_CDECL_END 500 501 // ------------------------------------- 502 503 class ICUNumberFormatFactory : public ICUResourceBundleFactory { 504 protected: 505 virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const { 506 // !!! kind is not an EStyles, need to determine how to handle this 507 return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status); 508 } 509 }; 510 511 // ------------------------------------- 512 513 class NFFactory : public LocaleKeyFactory { 514 private: 515 NumberFormatFactory* _delegate; 516 Hashtable* _ids; 517 518 public: 519 NFFactory(NumberFormatFactory* delegate) 520 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE) 521 , _delegate(delegate) 522 , _ids(NULL) 523 { 524 } 525 526 virtual ~NFFactory() 527 { 528 delete _delegate; 529 delete _ids; 530 } 531 532 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 533 { 534 if (handlesKey(key, status)) { 535 const LocaleKey& lkey = (const LocaleKey&)key; 536 Locale loc; 537 lkey.canonicalLocale(loc); 538 int32_t kind = lkey.kind(); 539 540 UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1)); 541 if (result == NULL) { 542 result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status); 543 } 544 return result; 545 } 546 return NULL; 547 } 548 549 protected: 550 /** 551 * Return the set of ids that this factory supports (visible or 552 * otherwise). This can be called often and might need to be 553 * cached if it is expensive to create. 554 */ 555 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const 556 { 557 if (U_SUCCESS(status)) { 558 if (!_ids) { 559 int32_t count = 0; 560 const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status); 561 ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */ 562 if (_ids) { 563 for (int i = 0; i < count; ++i) { 564 _ids->put(idlist[i], (void*)this, status); 565 } 566 } 567 } 568 return _ids; 569 } 570 return NULL; 571 } 572 }; 573 574 class ICUNumberFormatService : public ICULocaleService { 575 public: 576 ICUNumberFormatService() 577 : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format")) 578 { 579 UErrorCode status = U_ZERO_ERROR; 580 registerFactory(new ICUNumberFormatFactory(), status); 581 } 582 583 virtual UObject* cloneInstance(UObject* instance) const { 584 return ((NumberFormat*)instance)->clone(); 585 } 586 587 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const { 588 LocaleKey& lkey = (LocaleKey&)key; 589 int32_t kind = lkey.kind(); 590 Locale loc; 591 lkey.currentLocale(loc); 592 return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status); 593 } 594 595 virtual UBool isDefault() const { 596 return countFactories() == 1; 597 } 598 }; 599 600 // ------------------------------------- 601 602 static ICULocaleService* 603 getNumberFormatService(void) 604 { 605 UBool needInit; 606 UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit); 607 if (needInit) { 608 ICULocaleService * newservice = new ICUNumberFormatService(); 609 if (newservice) { 610 umtx_lock(NULL); 611 if (gService == NULL) { 612 gService = newservice; 613 newservice = NULL; 614 } 615 umtx_unlock(NULL); 616 } 617 if (newservice) { 618 delete newservice; 619 } else { 620 // we won the contention, this thread can register cleanup. 621 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); 622 } 623 } 624 return gService; 625 } 626 627 // ------------------------------------- 628 629 URegistryKey U_EXPORT2 630 NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status) 631 { 632 ICULocaleService *service = getNumberFormatService(); 633 if (service) { 634 NFFactory *tempnnf = new NFFactory(toAdopt); 635 if (tempnnf != NULL) { 636 return service->registerFactory(tempnnf, status); 637 } 638 } 639 status = U_MEMORY_ALLOCATION_ERROR; 640 return NULL; 641 } 642 643 // ------------------------------------- 644 645 UBool U_EXPORT2 646 NumberFormat::unregister(URegistryKey key, UErrorCode& status) 647 { 648 if (U_SUCCESS(status)) { 649 UBool haveService; 650 UMTX_CHECK(NULL, gService != NULL, haveService); 651 if (haveService) { 652 return gService->unregister(key, status); 653 } 654 status = U_ILLEGAL_ARGUMENT_ERROR; 655 } 656 return FALSE; 657 } 658 659 // ------------------------------------- 660 StringEnumeration* U_EXPORT2 661 NumberFormat::getAvailableLocales(void) 662 { 663 ICULocaleService *service = getNumberFormatService(); 664 if (service) { 665 return service->getAvailableLocales(); 666 } 667 return NULL; // no way to return error condition 668 } 669 #endif /* UCONFIG_NO_SERVICE */ 670 // ------------------------------------- 671 672 NumberFormat* U_EXPORT2 673 NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status) 674 { 675 #if !UCONFIG_NO_SERVICE 676 UBool haveService; 677 UMTX_CHECK(NULL, gService != NULL, haveService); 678 if (haveService) { 679 return (NumberFormat*)gService->get(loc, kind, status); 680 } 681 else 682 #endif 683 { 684 return makeInstance(loc, kind, status); 685 } 686 } 687 688 689 // ------------------------------------- 690 // Checks if the thousand/10 thousand grouping is used in the 691 // NumberFormat instance. 692 693 UBool 694 NumberFormat::isGroupingUsed() const 695 { 696 return fGroupingUsed; 697 } 698 699 // ------------------------------------- 700 // Sets to use the thousand/10 thousand grouping in the 701 // NumberFormat instance. 702 703 void 704 NumberFormat::setGroupingUsed(UBool newValue) 705 { 706 fGroupingUsed = newValue; 707 } 708 709 // ------------------------------------- 710 // Gets the maximum number of digits for the integral part for 711 // this NumberFormat instance. 712 713 int32_t NumberFormat::getMaximumIntegerDigits() const 714 { 715 return fMaxIntegerDigits; 716 } 717 718 // ------------------------------------- 719 // Sets the maximum number of digits for the integral part for 720 // this NumberFormat instance. 721 722 void 723 NumberFormat::setMaximumIntegerDigits(int32_t newValue) 724 { 725 fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits)); 726 if(fMinIntegerDigits > fMaxIntegerDigits) 727 fMinIntegerDigits = fMaxIntegerDigits; 728 } 729 730 // ------------------------------------- 731 // Gets the minimum number of digits for the integral part for 732 // this NumberFormat instance. 733 734 int32_t 735 NumberFormat::getMinimumIntegerDigits() const 736 { 737 return fMinIntegerDigits; 738 } 739 740 // ------------------------------------- 741 // Sets the minimum number of digits for the integral part for 742 // this NumberFormat instance. 743 744 void 745 NumberFormat::setMinimumIntegerDigits(int32_t newValue) 746 { 747 fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits)); 748 if(fMinIntegerDigits > fMaxIntegerDigits) 749 fMaxIntegerDigits = fMinIntegerDigits; 750 } 751 752 // ------------------------------------- 753 // Gets the maximum number of digits for the fractional part for 754 // this NumberFormat instance. 755 756 int32_t 757 NumberFormat::getMaximumFractionDigits() const 758 { 759 return fMaxFractionDigits; 760 } 761 762 // ------------------------------------- 763 // Sets the maximum number of digits for the fractional part for 764 // this NumberFormat instance. 765 766 void 767 NumberFormat::setMaximumFractionDigits(int32_t newValue) 768 { 769 fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits)); 770 if(fMaxFractionDigits < fMinFractionDigits) 771 fMinFractionDigits = fMaxFractionDigits; 772 } 773 774 // ------------------------------------- 775 // Gets the minimum number of digits for the fractional part for 776 // this NumberFormat instance. 777 778 int32_t 779 NumberFormat::getMinimumFractionDigits() const 780 { 781 return fMinFractionDigits; 782 } 783 784 // ------------------------------------- 785 // Sets the minimum number of digits for the fractional part for 786 // this NumberFormat instance. 787 788 void 789 NumberFormat::setMinimumFractionDigits(int32_t newValue) 790 { 791 fMinFractionDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits)); 792 if (fMaxFractionDigits < fMinFractionDigits) 793 fMaxFractionDigits = fMinFractionDigits; 794 } 795 796 // ------------------------------------- 797 798 void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { 799 if (U_FAILURE(ec)) { 800 return; 801 } 802 if (theCurrency) { 803 u_strncpy(fCurrency, theCurrency, 3); 804 fCurrency[3] = 0; 805 } else { 806 fCurrency[0] = 0; 807 } 808 } 809 810 const UChar* NumberFormat::getCurrency() const { 811 return fCurrency; 812 } 813 814 void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { 815 const UChar* c = getCurrency(); 816 if (*c != 0) { 817 u_strncpy(result, c, 3); 818 result[3] = 0; 819 } else { 820 const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec); 821 if (loc == NULL) { 822 loc = uloc_getDefault(); 823 } 824 ucurr_forLocale(loc, result, 4, &ec); 825 } 826 } 827 828 // ------------------------------------- 829 // Creates the NumberFormat instance of the specified style (number, currency, 830 // or percent) for the desired locale. 831 832 NumberFormat* 833 NumberFormat::makeInstance(const Locale& desiredLocale, 834 EStyles style, 835 UErrorCode& status) 836 { 837 if (U_FAILURE(status)) return NULL; 838 839 if (style < 0 || style >= kStyleCount) { 840 status = U_ILLEGAL_ARGUMENT_ERROR; 841 return NULL; 842 } 843 844 #ifdef U_WINDOWS 845 char buffer[8]; 846 int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); 847 848 // if the locale has "@compat=host", create a host-specific NumberFormat 849 if (count > 0 && uprv_strcmp(buffer, "host") == 0) { 850 Win32NumberFormat *f = NULL; 851 UBool curr = TRUE; 852 853 switch (style) { 854 case kNumberStyle: 855 curr = FALSE; 856 // fall-through 857 858 case kCurrencyStyle: 859 case kIsoCurrencyStyle: // do not support plural formatting here 860 case kPluralCurrencyStyle: 861 f = new Win32NumberFormat(desiredLocale, curr, status); 862 863 if (U_SUCCESS(status)) { 864 return f; 865 } 866 867 delete f; 868 break; 869 870 default: 871 break; 872 } 873 } 874 #endif 875 876 NumberFormat* f = NULL; 877 DecimalFormatSymbols* symbolsToAdopt = NULL; 878 UnicodeString pattern; 879 UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status); 880 UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status); 881 NumberingSystem *ns = NULL; 882 UBool deleteSymbols = TRUE; 883 884 if (U_FAILURE(status)) { 885 // We don't appear to have resource data available -- use the last-resort data 886 status = U_USING_FALLBACK_WARNING; 887 // When the data is unavailable, and locale isn't passed in, last resort data is used. 888 symbolsToAdopt = new DecimalFormatSymbols(status); 889 890 // Creates a DecimalFormat instance with the last resort number patterns. 891 pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); 892 } 893 else { 894 // If not all the styled patterns exists for the NumberFormat in this locale, 895 // sets the status code to failure and returns nil. 896 if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0])) -2 ) { //minus 2: ISO and plural 897 status = U_INVALID_FORMAT_ERROR; 898 goto cleanup; 899 } 900 901 // Loads the decimal symbols of the desired locale. 902 symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status); 903 904 int32_t patLen = 0; 905 906 /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE, 907 * the pattern is the same as the pattern of CURRENCYSTYLE 908 * but by replacing the single currency sign with 909 * double currency sign or triple currency sign. 910 */ 911 int styleInNumberPattern = ((style == kIsoCurrencyStyle || 912 style == kPluralCurrencyStyle) ? 913 kCurrencyStyle : style); 914 915 const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)styleInNumberPattern, &patLen, &status); 916 917 // Creates the specified decimal format style of the desired locale. 918 pattern.setTo(TRUE, patResStr, patLen); 919 } 920 if (U_FAILURE(status) || symbolsToAdopt == NULL) { 921 goto cleanup; 922 } 923 if(style==kCurrencyStyle || style == kIsoCurrencyStyle){ 924 const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); 925 if(currPattern!=NULL){ 926 pattern.setTo(currPattern, u_strlen(currPattern)); 927 } 928 } 929 930 ns = NumberingSystem::createInstance(desiredLocale,status); 931 932 if (U_FAILURE(status)) { 933 goto cleanup; 934 } 935 936 if (ns->isAlgorithmic()) { 937 UnicodeString nsDesc; 938 UnicodeString nsRuleSetGroup; 939 UnicodeString nsRuleSetName; 940 Locale nsLoc; 941 URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; 942 943 nsDesc.setTo(ns->getDescription()); 944 int32_t firstSlash = nsDesc.indexOf(gSlash); 945 int32_t lastSlash = nsDesc.lastIndexOf(gSlash); 946 if ( lastSlash > firstSlash ) { 947 char nsLocID[ULOC_FULLNAME_CAPACITY]; 948 949 nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV); 950 nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); 951 nsRuleSetName.setTo(nsDesc,lastSlash+1); 952 953 nsLoc = Locale::createFromName(nsLocID); 954 955 UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); 956 if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { 957 desiredRulesType = URBNF_SPELLOUT; 958 } 959 } else { 960 nsLoc = desiredLocale; 961 nsRuleSetName.setTo(nsDesc); 962 } 963 964 RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); 965 966 if (U_FAILURE(status) || r == NULL) { 967 goto cleanup; 968 } 969 r->setDefaultRuleSet(nsRuleSetName,status); 970 f = (NumberFormat *) r; 971 972 } else { 973 // replace single currency sign in the pattern with double currency sign 974 // if the style is kIsoCurrencyStyle 975 if (style == kIsoCurrencyStyle) { 976 pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign); 977 } 978 979 f = new DecimalFormat(pattern, symbolsToAdopt, style, status); 980 if (U_FAILURE(status) || f == NULL) { 981 goto cleanup; 982 } 983 deleteSymbols = FALSE; 984 } 985 986 f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status), 987 ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status)); 988 989 cleanup: 990 ures_close(numberPatterns); 991 ures_close(resource); 992 if (ns) { 993 delete ns; 994 } 995 if (U_FAILURE(status)) { 996 /* If f exists, then it will delete the symbols */ 997 if (f==NULL) { 998 delete symbolsToAdopt; 999 } 1000 else { 1001 delete f; 1002 } 1003 return NULL; 1004 } 1005 if (f == NULL || symbolsToAdopt == NULL) { 1006 status = U_MEMORY_ALLOCATION_ERROR; 1007 f = NULL; 1008 } 1009 if (deleteSymbols && symbolsToAdopt != NULL) { 1010 delete symbolsToAdopt; 1011 } 1012 return f; 1013 } 1014 1015 U_NAMESPACE_END 1016 1017 #endif /* #if !UCONFIG_NO_FORMATTING */ 1018 1019 //eof 1020