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> 52static 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. 65static const UChar gLastResortDecimalPat[] = { 66 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */ 67}; 68static 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}; 71static const UChar gLastResortPercentPat[] = { 72 0x23, 0x30, 0x25, 0 /* "#0%" */ 73}; 74static const UChar gLastResortScientificPat[] = { 75 0x23, 0x45, 0x30, 0 /* "#E0" */ 76}; 77static 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}; 80static const UChar gLastResortPluralCurrencyPat[] = { 81 0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/ 82}; 83 84static const UChar gSingleCurrencySign[] = {0xA4, 0}; 85static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0}; 86 87static 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 92static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1; 93static const int32_t gMinIntegerDigits = 127; 94 95static 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 109U_NAMESPACE_BEGIN 110 111UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat) 112 113#if !UCONFIG_NO_SERVICE 114// ------------------------------------- 115// SimpleNumberFormatFactory implementation 116NumberFormatFactory::~NumberFormatFactory() {} 117SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible) 118 : _visible(visible) 119{ 120 LocaleUtility::initNameFromLocale(locale, _id); 121} 122 123SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {} 124 125UBool SimpleNumberFormatFactory::visible(void) const { 126 return _visible; 127} 128 129const UnicodeString * 130SimpleNumberFormatFactory::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 143NumberFormat::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 156NumberFormat::~NumberFormat() 157{ 158} 159 160// ------------------------------------- 161// copy constructor 162 163NumberFormat::NumberFormat(const NumberFormat &source) 164: Format(source) 165{ 166 *this = source; 167} 168 169// ------------------------------------- 170// assignment operator 171 172NumberFormat& 173NumberFormat::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 190UBool 191NumberFormat::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 244UnicodeString& 245NumberFormat::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 296UnicodeString& 297NumberFormat::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 309void 310NumberFormat::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 320UnicodeString& 321NumberFormat::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 330UnicodeString& 331NumberFormat::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 340UnicodeString& 341NumberFormat::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 353void 354NumberFormat::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 367Formattable& 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 393void 394NumberFormat::setParseIntegerOnly(UBool value) 395{ 396 fParseIntegerOnly = value; 397} 398 399// ------------------------------------- 400// Create a number style NumberFormat instance with the default locale. 401 402NumberFormat* U_EXPORT2 403NumberFormat::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 411NumberFormat* U_EXPORT2 412NumberFormat::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 420NumberFormat* U_EXPORT2 421NumberFormat::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 429NumberFormat* U_EXPORT2 430NumberFormat::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 438NumberFormat* U_EXPORT2 439NumberFormat::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 447NumberFormat* U_EXPORT2 448NumberFormat::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 456NumberFormat* U_EXPORT2 457NumberFormat::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 465NumberFormat* U_EXPORT2 466NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status) 467{ 468 return createInstance(inLocale, kScientificStyle, status); 469} 470 471// ------------------------------------- 472 473const Locale* U_EXPORT2 474NumberFormat::getAvailableLocales(int32_t& count) 475{ 476 return Locale::getAvailableLocales(count); 477} 478 479// ------------------------------------------ 480// 481// Registration 482// 483//------------------------------------------- 484 485#if !UCONFIG_NO_SERVICE 486static ICULocaleService* gService = NULL; 487 488/** 489 * Release all static memory held by numberformat. 490 */ 491U_CDECL_BEGIN 492static UBool U_CALLCONV numfmt_cleanup(void) { 493 if (gService) { 494 delete gService; 495 gService = NULL; 496 } 497 return TRUE; 498} 499U_CDECL_END 500 501// ------------------------------------- 502 503class ICUNumberFormatFactory : public ICUResourceBundleFactory { 504protected: 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 513class NFFactory : public LocaleKeyFactory { 514private: 515 NumberFormatFactory* _delegate; 516 Hashtable* _ids; 517 518public: 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 549protected: 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 574class ICUNumberFormatService : public ICULocaleService { 575public: 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 602static ICULocaleService* 603getNumberFormatService(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 629URegistryKey U_EXPORT2 630NumberFormat::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 645UBool U_EXPORT2 646NumberFormat::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// ------------------------------------- 660StringEnumeration* U_EXPORT2 661NumberFormat::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 672NumberFormat* U_EXPORT2 673NumberFormat::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 693UBool 694NumberFormat::isGroupingUsed() const 695{ 696 return fGroupingUsed; 697} 698 699// ------------------------------------- 700// Sets to use the thousand/10 thousand grouping in the 701// NumberFormat instance. 702 703void 704NumberFormat::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 713int32_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 722void 723NumberFormat::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 734int32_t 735NumberFormat::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 744void 745NumberFormat::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 756int32_t 757NumberFormat::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 766void 767NumberFormat::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 778int32_t 779NumberFormat::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 788void 789NumberFormat::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 798void 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 810const UChar* NumberFormat::getCurrency() const { 811 return fCurrency; 812} 813 814void 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 832NumberFormat* 833NumberFormat::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 989cleanup: 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 1015U_NAMESPACE_END 1016 1017#endif /* #if !UCONFIG_NO_FORMATTING */ 1018 1019//eof 1020