intl/icu/source/i18n/numfmt.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 * Copyright (C) 1997-2013, International Business Machines Corporation and
michael@0 4 * others. All Rights Reserved.
michael@0 5 *******************************************************************************
michael@0 6 *
michael@0 7 * File NUMFMT.CPP
michael@0 8 *
michael@0 9 * Modification History:
michael@0 10 *
michael@0 11 * Date Name Description
michael@0 12 * 02/19/97 aliu Converted from java.
michael@0 13 * 03/18/97 clhuang Implemented with C++ APIs.
michael@0 14 * 04/17/97 aliu Enlarged MAX_INTEGER_DIGITS to fully accomodate the
michael@0 15 * largest double, by default.
michael@0 16 * Changed DigitCount to int per code review.
michael@0 17 * 07/20/98 stephen Changed operator== to check for grouping
michael@0 18 * Changed setMaxIntegerDigits per Java implementation.
michael@0 19 * Changed setMinIntegerDigits per Java implementation.
michael@0 20 * Changed setMinFractionDigits per Java implementation.
michael@0 21 * Changed setMaxFractionDigits per Java implementation.
michael@0 22 ********************************************************************************
michael@0 23 */
michael@0 24
michael@0 25 #include "unicode/utypes.h"
michael@0 26
michael@0 27 #if !UCONFIG_NO_FORMATTING
michael@0 28
michael@0 29 #include "unicode/numfmt.h"
michael@0 30 #include "unicode/locid.h"
michael@0 31 #include "unicode/dcfmtsym.h"
michael@0 32 #include "unicode/decimfmt.h"
michael@0 33 #include "unicode/ustring.h"
michael@0 34 #include "unicode/ucurr.h"
michael@0 35 #include "unicode/curramt.h"
michael@0 36 #include "unicode/numsys.h"
michael@0 37 #include "unicode/rbnf.h"
michael@0 38 #include "unicode/localpointer.h"
michael@0 39 #include "charstr.h"
michael@0 40 #include "winnmfmt.h"
michael@0 41 #include "uresimp.h"
michael@0 42 #include "uhash.h"
michael@0 43 #include "cmemory.h"
michael@0 44 #include "servloc.h"
michael@0 45 #include "ucln_in.h"
michael@0 46 #include "cstring.h"
michael@0 47 #include "putilimp.h"
michael@0 48 #include "uassert.h"
michael@0 49 #include "umutex.h"
michael@0 50 #include "mutex.h"
michael@0 51 #include "digitlst.h"
michael@0 52 #include <float.h>
michael@0 53
michael@0 54 //#define FMT_DEBUG
michael@0 55
michael@0 56 #ifdef FMT_DEBUG
michael@0 57 #include <stdio.h>
michael@0 58 static inline void debugout(UnicodeString s) {
michael@0 59 char buf[2000];
michael@0 60 s.extract((int32_t) 0, s.length(), buf);
michael@0 61 printf("%s", buf);
michael@0 62 }
michael@0 63 #define debug(x) printf("%s", x);
michael@0 64 #else
michael@0 65 #define debugout(x)
michael@0 66 #define debug(x)
michael@0 67 #endif
michael@0 68
michael@0 69 // If no number pattern can be located for a locale, this is the last
michael@0 70 // resort.
michael@0 71 static const UChar gLastResortDecimalPat[] = {
michael@0 72 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */
michael@0 73 };
michael@0 74 static const UChar gLastResortCurrencyPat[] = {
michael@0 75 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "$#0.00;($#0.00)" */
michael@0 76 };
michael@0 77 static const UChar gLastResortPercentPat[] = {
michael@0 78 0x23, 0x30, 0x25, 0 /* "#0%" */
michael@0 79 };
michael@0 80 static const UChar gLastResortScientificPat[] = {
michael@0 81 0x23, 0x45, 0x30, 0 /* "#E0" */
michael@0 82 };
michael@0 83 static const UChar gLastResortIsoCurrencyPat[] = {
michael@0 84 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)" */
michael@0 85 };
michael@0 86 static const UChar gLastResortPluralCurrencyPat[] = {
michael@0 87 0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/
michael@0 88 };
michael@0 89
michael@0 90 static const UChar gSingleCurrencySign[] = {0xA4, 0};
michael@0 91 static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0};
michael@0 92
michael@0 93 static const UChar gSlash = 0x2f;
michael@0 94
michael@0 95 // If the maximum base 10 exponent were 4, then the largest number would
michael@0 96 // be 99,999 which has 5 digits.
michael@0 97 // On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit
michael@0 98 // With big decimal, the max exponent is 999,999,999 and the max number of digits is the same, 999,999,999
michael@0 99 const int32_t icu::NumberFormat::gDefaultMaxIntegerDigits = 2000000000;
michael@0 100 const int32_t icu::NumberFormat::gDefaultMinIntegerDigits = 127;
michael@0 101
michael@0 102 static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] = {
michael@0 103 NULL, // UNUM_PATTERN_DECIMAL
michael@0 104 gLastResortDecimalPat, // UNUM_DECIMAL
michael@0 105 gLastResortCurrencyPat, // UNUM_CURRENCY
michael@0 106 gLastResortPercentPat, // UNUM_PERCENT
michael@0 107 gLastResortScientificPat, // UNUM_SCIENTIFIC
michael@0 108 NULL, // UNUM_SPELLOUT
michael@0 109 NULL, // UNUM_ORDINAL
michael@0 110 NULL, // UNUM_DURATION
michael@0 111 NULL, // UNUM_NUMBERING_SYSTEM
michael@0 112 NULL, // UNUM_PATTERN_RULEBASED
michael@0 113 gLastResortIsoCurrencyPat, // UNUM_CURRENCY_ISO
michael@0 114 gLastResortPluralCurrencyPat // UNUM_CURRENCY_PLURAL
michael@0 115 };
michael@0 116
michael@0 117 // Keys used for accessing resource bundles
michael@0 118
michael@0 119 static const char *gNumberElements = "NumberElements";
michael@0 120 static const char *gLatn = "latn";
michael@0 121 static const char *gPatterns = "patterns";
michael@0 122 static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = {
michael@0 123 NULL, // UNUM_PATTERN_DECIMAL
michael@0 124 "decimalFormat", // UNUM_DECIMAL
michael@0 125 "currencyFormat", // UNUM_CURRENCY
michael@0 126 "percentFormat", // UNUM_PERCENT
michael@0 127 "scientificFormat", // UNUM_SCIENTIFIC
michael@0 128 NULL, // UNUM_SPELLOUT
michael@0 129 NULL, // UNUM_ORDINAL
michael@0 130 NULL, // UNUM_DURATION
michael@0 131 NULL, // UNUM_NUMBERING_SYSTEM
michael@0 132 NULL, // UNUM_PATTERN_RULEBASED
michael@0 133 // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL,
michael@0 134 // the pattern is the same as the pattern of UNUM_CURRENCY
michael@0 135 // except for replacing the single currency sign with
michael@0 136 // double currency sign or triple currency sign.
michael@0 137 "currencyFormat", // UNUM_CURRENCY_ISO
michael@0 138 "currencyFormat" // UNUM_CURRENCY_PLURAL
michael@0 139 };
michael@0 140
michael@0 141 // Static hashtable cache of NumberingSystem objects used by NumberFormat
michael@0 142 static UHashtable * NumberingSystem_cache = NULL;
michael@0 143 static UMutex nscacheMutex = U_MUTEX_INITIALIZER;
michael@0 144 static icu::UInitOnce gNSCacheInitOnce = U_INITONCE_INITIALIZER;
michael@0 145
michael@0 146 #if !UCONFIG_NO_SERVICE
michael@0 147 static icu::ICULocaleService* gService = NULL;
michael@0 148 static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
michael@0 149 #endif
michael@0 150
michael@0 151 /**
michael@0 152 * Release all static memory held by Number Format.
michael@0 153 */
michael@0 154 U_CDECL_BEGIN
michael@0 155 static void U_CALLCONV
michael@0 156 deleteNumberingSystem(void *obj) {
michael@0 157 delete (icu::NumberingSystem *)obj;
michael@0 158 }
michael@0 159
michael@0 160 static UBool U_CALLCONV numfmt_cleanup(void) {
michael@0 161 #if !UCONFIG_NO_SERVICE
michael@0 162 gServiceInitOnce.reset();
michael@0 163 if (gService) {
michael@0 164 delete gService;
michael@0 165 gService = NULL;
michael@0 166 }
michael@0 167 #endif
michael@0 168 gNSCacheInitOnce.reset();
michael@0 169 if (NumberingSystem_cache) {
michael@0 170 // delete NumberingSystem_cache;
michael@0 171 uhash_close(NumberingSystem_cache);
michael@0 172 NumberingSystem_cache = NULL;
michael@0 173 }
michael@0 174
michael@0 175 return TRUE;
michael@0 176 }
michael@0 177 U_CDECL_END
michael@0 178
michael@0 179 // *****************************************************************************
michael@0 180 // class NumberFormat
michael@0 181 // *****************************************************************************
michael@0 182
michael@0 183 U_NAMESPACE_BEGIN
michael@0 184
michael@0 185 UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat)
michael@0 186
michael@0 187 #if !UCONFIG_NO_SERVICE
michael@0 188 // -------------------------------------
michael@0 189 // SimpleNumberFormatFactory implementation
michael@0 190 NumberFormatFactory::~NumberFormatFactory() {}
michael@0 191 SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible)
michael@0 192 : _visible(visible)
michael@0 193 {
michael@0 194 LocaleUtility::initNameFromLocale(locale, _id);
michael@0 195 }
michael@0 196
michael@0 197 SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {}
michael@0 198
michael@0 199 UBool SimpleNumberFormatFactory::visible(void) const {
michael@0 200 return _visible;
michael@0 201 }
michael@0 202
michael@0 203 const UnicodeString *
michael@0 204 SimpleNumberFormatFactory::getSupportedIDs(int32_t &count, UErrorCode& status) const
michael@0 205 {
michael@0 206 if (U_SUCCESS(status)) {
michael@0 207 count = 1;
michael@0 208 return &_id;
michael@0 209 }
michael@0 210 count = 0;
michael@0 211 return NULL;
michael@0 212 }
michael@0 213 #endif /* #if !UCONFIG_NO_SERVICE */
michael@0 214
michael@0 215 // -------------------------------------
michael@0 216 // default constructor
michael@0 217 NumberFormat::NumberFormat()
michael@0 218 : fGroupingUsed(TRUE),
michael@0 219 fMaxIntegerDigits(gDefaultMaxIntegerDigits),
michael@0 220 fMinIntegerDigits(1),
michael@0 221 fMaxFractionDigits(3), // invariant, >= minFractionDigits
michael@0 222 fMinFractionDigits(0),
michael@0 223 fParseIntegerOnly(FALSE),
michael@0 224 fLenient(FALSE)
michael@0 225 {
michael@0 226 fCurrency[0] = 0;
michael@0 227 }
michael@0 228
michael@0 229 // -------------------------------------
michael@0 230
michael@0 231 NumberFormat::~NumberFormat()
michael@0 232 {
michael@0 233 }
michael@0 234
michael@0 235 // -------------------------------------
michael@0 236 // copy constructor
michael@0 237
michael@0 238 NumberFormat::NumberFormat(const NumberFormat &source)
michael@0 239 : Format(source)
michael@0 240 {
michael@0 241 *this = source;
michael@0 242 }
michael@0 243
michael@0 244 // -------------------------------------
michael@0 245 // assignment operator
michael@0 246
michael@0 247 NumberFormat&
michael@0 248 NumberFormat::operator=(const NumberFormat& rhs)
michael@0 249 {
michael@0 250 if (this != &rhs)
michael@0 251 {
michael@0 252 Format::operator=(rhs);
michael@0 253 fGroupingUsed = rhs.fGroupingUsed;
michael@0 254 fMaxIntegerDigits = rhs.fMaxIntegerDigits;
michael@0 255 fMinIntegerDigits = rhs.fMinIntegerDigits;
michael@0 256 fMaxFractionDigits = rhs.fMaxFractionDigits;
michael@0 257 fMinFractionDigits = rhs.fMinFractionDigits;
michael@0 258 fParseIntegerOnly = rhs.fParseIntegerOnly;
michael@0 259 u_strncpy(fCurrency, rhs.fCurrency, 4);
michael@0 260 fLenient = rhs.fLenient;
michael@0 261 }
michael@0 262 return *this;
michael@0 263 }
michael@0 264
michael@0 265 // -------------------------------------
michael@0 266
michael@0 267 UBool
michael@0 268 NumberFormat::operator==(const Format& that) const
michael@0 269 {
michael@0 270 // Format::operator== guarantees this cast is safe
michael@0 271 NumberFormat* other = (NumberFormat*)&that;
michael@0 272
michael@0 273 #ifdef FMT_DEBUG
michael@0 274 // This code makes it easy to determine why two format objects that should
michael@0 275 // be equal aren't.
michael@0 276 UBool first = TRUE;
michael@0 277 if (!Format::operator==(that)) {
michael@0 278 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 279 debug("Format::!=");
michael@0 280 }
michael@0 281 if (!(fMaxIntegerDigits == other->fMaxIntegerDigits &&
michael@0 282 fMinIntegerDigits == other->fMinIntegerDigits)) {
michael@0 283 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 284 debug("Integer digits !=");
michael@0 285 }
michael@0 286 if (!(fMaxFractionDigits == other->fMaxFractionDigits &&
michael@0 287 fMinFractionDigits == other->fMinFractionDigits)) {
michael@0 288 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 289 debug("Fraction digits !=");
michael@0 290 }
michael@0 291 if (!(fGroupingUsed == other->fGroupingUsed)) {
michael@0 292 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 293 debug("fGroupingUsed != ");
michael@0 294 }
michael@0 295 if (!(fParseIntegerOnly == other->fParseIntegerOnly)) {
michael@0 296 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 297 debug("fParseIntegerOnly != ");
michael@0 298 }
michael@0 299 if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) {
michael@0 300 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 301 debug("fCurrency !=");
michael@0 302 }
michael@0 303 if (!(fLenient == other->fLenient)) {
michael@0 304 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 305 debug("fLenient != ");
michael@0 306 }
michael@0 307 if (!first) { printf(" ]"); }
michael@0 308 #endif
michael@0 309
michael@0 310 return ((this == &that) ||
michael@0 311 ((Format::operator==(that) &&
michael@0 312 fMaxIntegerDigits == other->fMaxIntegerDigits &&
michael@0 313 fMinIntegerDigits == other->fMinIntegerDigits &&
michael@0 314 fMaxFractionDigits == other->fMaxFractionDigits &&
michael@0 315 fMinFractionDigits == other->fMinFractionDigits &&
michael@0 316 fGroupingUsed == other->fGroupingUsed &&
michael@0 317 fParseIntegerOnly == other->fParseIntegerOnly &&
michael@0 318 u_strcmp(fCurrency, other->fCurrency) == 0 &&
michael@0 319 fLenient == other->fLenient)));
michael@0 320 }
michael@0 321
michael@0 322 // -------------------------------------
michael@0 323 // Default implementation sets unsupported error; subclasses should
michael@0 324 // override.
michael@0 325
michael@0 326 UnicodeString&
michael@0 327 NumberFormat::format(double /* unused number */,
michael@0 328 UnicodeString& toAppendTo,
michael@0 329 FieldPositionIterator* /* unused posIter */,
michael@0 330 UErrorCode& status) const
michael@0 331 {
michael@0 332 if (!U_FAILURE(status)) {
michael@0 333 status = U_UNSUPPORTED_ERROR;
michael@0 334 }
michael@0 335 return toAppendTo;
michael@0 336 }
michael@0 337
michael@0 338 // -------------------------------------
michael@0 339 // Default implementation sets unsupported error; subclasses should
michael@0 340 // override.
michael@0 341
michael@0 342 UnicodeString&
michael@0 343 NumberFormat::format(int32_t /* unused number */,
michael@0 344 UnicodeString& toAppendTo,
michael@0 345 FieldPositionIterator* /* unused posIter */,
michael@0 346 UErrorCode& status) const
michael@0 347 {
michael@0 348 if (!U_FAILURE(status)) {
michael@0 349 status = U_UNSUPPORTED_ERROR;
michael@0 350 }
michael@0 351 return toAppendTo;
michael@0 352 }
michael@0 353
michael@0 354 // -------------------------------------
michael@0 355 // Default implementation sets unsupported error; subclasses should
michael@0 356 // override.
michael@0 357
michael@0 358 UnicodeString&
michael@0 359 NumberFormat::format(int64_t /* unused number */,
michael@0 360 UnicodeString& toAppendTo,
michael@0 361 FieldPositionIterator* /* unused posIter */,
michael@0 362 UErrorCode& status) const
michael@0 363 {
michael@0 364 if (!U_FAILURE(status)) {
michael@0 365 status = U_UNSUPPORTED_ERROR;
michael@0 366 }
michael@0 367 return toAppendTo;
michael@0 368 }
michael@0 369
michael@0 370 // ------------------------------------------
michael@0 371 // These functions add the status code, just fall back to the non-status versions
michael@0 372 UnicodeString&
michael@0 373 NumberFormat::format(double number,
michael@0 374 UnicodeString& appendTo,
michael@0 375 FieldPosition& pos,
michael@0 376 UErrorCode &status) const {
michael@0 377 if(U_SUCCESS(status)) {
michael@0 378 return format(number,appendTo,pos);
michael@0 379 } else {
michael@0 380 return appendTo;
michael@0 381 }
michael@0 382 }
michael@0 383
michael@0 384 UnicodeString&
michael@0 385 NumberFormat::format(int32_t number,
michael@0 386 UnicodeString& appendTo,
michael@0 387 FieldPosition& pos,
michael@0 388 UErrorCode &status) const {
michael@0 389 if(U_SUCCESS(status)) {
michael@0 390 return format(number,appendTo,pos);
michael@0 391 } else {
michael@0 392 return appendTo;
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396 UnicodeString&
michael@0 397 NumberFormat::format(int64_t number,
michael@0 398 UnicodeString& appendTo,
michael@0 399 FieldPosition& pos,
michael@0 400 UErrorCode &status) const {
michael@0 401 if(U_SUCCESS(status)) {
michael@0 402 return format(number,appendTo,pos);
michael@0 403 } else {
michael@0 404 return appendTo;
michael@0 405 }
michael@0 406 }
michael@0 407
michael@0 408
michael@0 409
michael@0 410 // -------------------------------------
michael@0 411 // Decimal Number format() default implementation
michael@0 412 // Subclasses do not normally override this function, but rather the DigitList
michael@0 413 // formatting functions..
michael@0 414 // The expected call chain from here is
michael@0 415 // this function ->
michael@0 416 // NumberFormat::format(Formattable ->
michael@0 417 // DecimalFormat::format(DigitList
michael@0 418 //
michael@0 419 // Or, for subclasses of Formattable that do not know about DigitList,
michael@0 420 // this Function ->
michael@0 421 // NumberFormat::format(Formattable ->
michael@0 422 // NumberFormat::format(DigitList ->
michael@0 423 // XXXFormat::format(double
michael@0 424
michael@0 425 UnicodeString&
michael@0 426 NumberFormat::format(const StringPiece &decimalNum,
michael@0 427 UnicodeString& toAppendTo,
michael@0 428 FieldPositionIterator* fpi,
michael@0 429 UErrorCode& status) const
michael@0 430 {
michael@0 431 Formattable f;
michael@0 432 f.setDecimalNumber(decimalNum, status);
michael@0 433 format(f, toAppendTo, fpi, status);
michael@0 434 return toAppendTo;
michael@0 435 }
michael@0 436
michael@0 437 /**
michael@0 438 *
michael@0 439 // Formats the number object and save the format
michael@0 440 // result in the toAppendTo string buffer.
michael@0 441
michael@0 442 // utility to save/restore state, used in two overloads
michael@0 443 // of format(const Formattable&...) below.
michael@0 444 *
michael@0 445 * Old purpose of ArgExtractor was to avoid const. Not thread safe!
michael@0 446 *
michael@0 447 * keeping it around as a shim.
michael@0 448 */
michael@0 449 class ArgExtractor {
michael@0 450 const Formattable* num;
michael@0 451 UChar save[4];
michael@0 452 UBool fWasCurrency;
michael@0 453
michael@0 454 public:
michael@0 455 ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status);
michael@0 456 ~ArgExtractor();
michael@0 457
michael@0 458 const Formattable* number(void) const;
michael@0 459 const UChar *iso(void) const;
michael@0 460 UBool wasCurrency(void) const;
michael@0 461 };
michael@0 462
michael@0 463 inline const Formattable*
michael@0 464 ArgExtractor::number(void) const {
michael@0 465 return num;
michael@0 466 }
michael@0 467
michael@0 468 inline UBool
michael@0 469 ArgExtractor::wasCurrency(void) const {
michael@0 470 return fWasCurrency;
michael@0 471 }
michael@0 472
michael@0 473 inline const UChar *
michael@0 474 ArgExtractor::iso(void) const {
michael@0 475 return save;
michael@0 476 }
michael@0 477
michael@0 478 ArgExtractor::ArgExtractor(const NumberFormat& /*nf*/, const Formattable& obj, UErrorCode& /*status*/)
michael@0 479 : num(&obj), fWasCurrency(FALSE) {
michael@0 480
michael@0 481 const UObject* o = obj.getObject(); // most commonly o==NULL
michael@0 482 const CurrencyAmount* amt;
michael@0 483 if (o != NULL && (amt = dynamic_cast<const CurrencyAmount*>(o)) != NULL) {
michael@0 484 // getISOCurrency() returns a pointer to internal storage, so we
michael@0 485 // copy it to retain it across the call to setCurrency().
michael@0 486 //const UChar* curr = amt->getISOCurrency();
michael@0 487 u_strcpy(save, amt->getISOCurrency());
michael@0 488 num = &amt->getNumber();
michael@0 489 fWasCurrency=TRUE;
michael@0 490 } else {
michael@0 491 save[0]=0;
michael@0 492 }
michael@0 493 }
michael@0 494
michael@0 495 ArgExtractor::~ArgExtractor() {
michael@0 496 }
michael@0 497
michael@0 498 UnicodeString& NumberFormat::format(const DigitList &number,
michael@0 499 UnicodeString& appendTo,
michael@0 500 FieldPositionIterator* posIter,
michael@0 501 UErrorCode& status) const {
michael@0 502 // DecimalFormat overrides this function, and handles DigitList based big decimals.
michael@0 503 // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
michael@0 504 // so this default implementation falls back to formatting decimal numbers as doubles.
michael@0 505 if (U_FAILURE(status)) {
michael@0 506 return appendTo;
michael@0 507 }
michael@0 508 double dnum = number.getDouble();
michael@0 509 format(dnum, appendTo, posIter, status);
michael@0 510 return appendTo;
michael@0 511 }
michael@0 512
michael@0 513
michael@0 514
michael@0 515 UnicodeString&
michael@0 516 NumberFormat::format(const DigitList &number,
michael@0 517 UnicodeString& appendTo,
michael@0 518 FieldPosition& pos,
michael@0 519 UErrorCode &status) const {
michael@0 520 // DecimalFormat overrides this function, and handles DigitList based big decimals.
michael@0 521 // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
michael@0 522 // so this default implementation falls back to formatting decimal numbers as doubles.
michael@0 523 if (U_FAILURE(status)) {
michael@0 524 return appendTo;
michael@0 525 }
michael@0 526 double dnum = number.getDouble();
michael@0 527 format(dnum, appendTo, pos, status);
michael@0 528 return appendTo;
michael@0 529 }
michael@0 530
michael@0 531 UnicodeString&
michael@0 532 NumberFormat::format(const Formattable& obj,
michael@0 533 UnicodeString& appendTo,
michael@0 534 FieldPosition& pos,
michael@0 535 UErrorCode& status) const
michael@0 536 {
michael@0 537 if (U_FAILURE(status)) return appendTo;
michael@0 538
michael@0 539 ArgExtractor arg(*this, obj, status);
michael@0 540 const Formattable *n = arg.number();
michael@0 541 const UChar *iso = arg.iso();
michael@0 542
michael@0 543 if(arg.wasCurrency() && u_strcmp(iso, getCurrency())) {
michael@0 544 // trying to format a different currency.
michael@0 545 // Right now, we clone.
michael@0 546 LocalPointer<NumberFormat> cloneFmt((NumberFormat*)this->clone());
michael@0 547 cloneFmt->setCurrency(iso, status);
michael@0 548 // next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount.
michael@0 549 return cloneFmt->format(*n, appendTo, pos, status);
michael@0 550 }
michael@0 551
michael@0 552 if (n->isNumeric() && n->getDigitList() != NULL) {
michael@0 553 // Decimal Number. We will have a DigitList available if the value was
michael@0 554 // set to a decimal number, or if the value originated with a parse.
michael@0 555 //
michael@0 556 // The default implementation for formatting a DigitList converts it
michael@0 557 // to a double, and formats that, allowing formatting classes that don't
michael@0 558 // know about DigitList to continue to operate as they had.
michael@0 559 //
michael@0 560 // DecimalFormat overrides the DigitList formatting functions.
michael@0 561 format(*n->getDigitList(), appendTo, pos, status);
michael@0 562 } else {
michael@0 563 switch (n->getType()) {
michael@0 564 case Formattable::kDouble:
michael@0 565 format(n->getDouble(), appendTo, pos);
michael@0 566 break;
michael@0 567 case Formattable::kLong:
michael@0 568 format(n->getLong(), appendTo, pos);
michael@0 569 break;
michael@0 570 case Formattable::kInt64:
michael@0 571 format(n->getInt64(), appendTo, pos);
michael@0 572 break;
michael@0 573 default:
michael@0 574 status = U_INVALID_FORMAT_ERROR;
michael@0 575 break;
michael@0 576 }
michael@0 577 }
michael@0 578
michael@0 579 return appendTo;
michael@0 580 }
michael@0 581
michael@0 582 // -------------------------------------x
michael@0 583 // Formats the number object and save the format
michael@0 584 // result in the toAppendTo string buffer.
michael@0 585
michael@0 586 UnicodeString&
michael@0 587 NumberFormat::format(const Formattable& obj,
michael@0 588 UnicodeString& appendTo,
michael@0 589 FieldPositionIterator* posIter,
michael@0 590 UErrorCode& status) const
michael@0 591 {
michael@0 592 if (U_FAILURE(status)) return appendTo;
michael@0 593
michael@0 594 ArgExtractor arg(*this, obj, status);
michael@0 595 const Formattable *n = arg.number();
michael@0 596 const UChar *iso = arg.iso();
michael@0 597
michael@0 598 if(arg.wasCurrency() && u_strcmp(iso, getCurrency())) {
michael@0 599 // trying to format a different currency.
michael@0 600 // Right now, we clone.
michael@0 601 LocalPointer<NumberFormat> cloneFmt((NumberFormat*)this->clone());
michael@0 602 cloneFmt->setCurrency(iso, status);
michael@0 603 // next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount.
michael@0 604 return cloneFmt->format(*n, appendTo, posIter, status);
michael@0 605 }
michael@0 606
michael@0 607 if (n->isNumeric() && n->getDigitList() != NULL) {
michael@0 608 // Decimal Number
michael@0 609 format(*n->getDigitList(), appendTo, posIter, status);
michael@0 610 } else {
michael@0 611 switch (n->getType()) {
michael@0 612 case Formattable::kDouble:
michael@0 613 format(n->getDouble(), appendTo, posIter, status);
michael@0 614 break;
michael@0 615 case Formattable::kLong:
michael@0 616 format(n->getLong(), appendTo, posIter, status);
michael@0 617 break;
michael@0 618 case Formattable::kInt64:
michael@0 619 format(n->getInt64(), appendTo, posIter, status);
michael@0 620 break;
michael@0 621 default:
michael@0 622 status = U_INVALID_FORMAT_ERROR;
michael@0 623 break;
michael@0 624 }
michael@0 625 }
michael@0 626
michael@0 627 return appendTo;
michael@0 628 }
michael@0 629
michael@0 630 // -------------------------------------
michael@0 631
michael@0 632 UnicodeString&
michael@0 633 NumberFormat::format(int64_t number,
michael@0 634 UnicodeString& appendTo,
michael@0 635 FieldPosition& pos) const
michael@0 636 {
michael@0 637 // default so we don't introduce a new abstract method
michael@0 638 return format((int32_t)number, appendTo, pos);
michael@0 639 }
michael@0 640
michael@0 641 // -------------------------------------
michael@0 642 // Parses the string and save the result object as well
michael@0 643 // as the final parsed position.
michael@0 644
michael@0 645 void
michael@0 646 NumberFormat::parseObject(const UnicodeString& source,
michael@0 647 Formattable& result,
michael@0 648 ParsePosition& parse_pos) const
michael@0 649 {
michael@0 650 parse(source, result, parse_pos);
michael@0 651 }
michael@0 652
michael@0 653 // -------------------------------------
michael@0 654 // Formats a double number and save the result in a string.
michael@0 655
michael@0 656 UnicodeString&
michael@0 657 NumberFormat::format(double number, UnicodeString& appendTo) const
michael@0 658 {
michael@0 659 FieldPosition pos(0);
michael@0 660 return format(number, appendTo, pos);
michael@0 661 }
michael@0 662
michael@0 663 // -------------------------------------
michael@0 664 // Formats a long number and save the result in a string.
michael@0 665
michael@0 666 UnicodeString&
michael@0 667 NumberFormat::format(int32_t number, UnicodeString& appendTo) const
michael@0 668 {
michael@0 669 FieldPosition pos(0);
michael@0 670 return format(number, appendTo, pos);
michael@0 671 }
michael@0 672
michael@0 673 // -------------------------------------
michael@0 674 // Formats a long number and save the result in a string.
michael@0 675
michael@0 676 UnicodeString&
michael@0 677 NumberFormat::format(int64_t number, UnicodeString& appendTo) const
michael@0 678 {
michael@0 679 FieldPosition pos(0);
michael@0 680 return format(number, appendTo, pos);
michael@0 681 }
michael@0 682
michael@0 683 // -------------------------------------
michael@0 684 // Parses the text and save the result object. If the returned
michael@0 685 // parse position is 0, that means the parsing failed, the status
michael@0 686 // code needs to be set to failure. Ignores the returned parse
michael@0 687 // position, otherwise.
michael@0 688
michael@0 689 void
michael@0 690 NumberFormat::parse(const UnicodeString& text,
michael@0 691 Formattable& result,
michael@0 692 UErrorCode& status) const
michael@0 693 {
michael@0 694 if (U_FAILURE(status)) return;
michael@0 695
michael@0 696 ParsePosition parsePosition(0);
michael@0 697 parse(text, result, parsePosition);
michael@0 698 if (parsePosition.getIndex() == 0) {
michael@0 699 status = U_INVALID_FORMAT_ERROR;
michael@0 700 }
michael@0 701 }
michael@0 702
michael@0 703 CurrencyAmount* NumberFormat::parseCurrency(const UnicodeString& text,
michael@0 704 ParsePosition& pos) const {
michael@0 705 // Default implementation only -- subclasses should override
michael@0 706 Formattable parseResult;
michael@0 707 int32_t start = pos.getIndex();
michael@0 708 parse(text, parseResult, pos);
michael@0 709 if (pos.getIndex() != start) {
michael@0 710 UChar curr[4];
michael@0 711 UErrorCode ec = U_ZERO_ERROR;
michael@0 712 getEffectiveCurrency(curr, ec);
michael@0 713 if (U_SUCCESS(ec)) {
michael@0 714 LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curr, ec));
michael@0 715 if (U_FAILURE(ec)) {
michael@0 716 pos.setIndex(start); // indicate failure
michael@0 717 } else {
michael@0 718 return currAmt.orphan();
michael@0 719 }
michael@0 720 }
michael@0 721 }
michael@0 722 return NULL;
michael@0 723 }
michael@0 724
michael@0 725 // -------------------------------------
michael@0 726 // Sets to only parse integers.
michael@0 727
michael@0 728 void
michael@0 729 NumberFormat::setParseIntegerOnly(UBool value)
michael@0 730 {
michael@0 731 fParseIntegerOnly = value;
michael@0 732 }
michael@0 733
michael@0 734 // -------------------------------------
michael@0 735 // Sets whether lenient parse is enabled.
michael@0 736
michael@0 737 void
michael@0 738 NumberFormat::setLenient(UBool enable)
michael@0 739 {
michael@0 740 fLenient = enable;
michael@0 741 }
michael@0 742
michael@0 743 // -------------------------------------
michael@0 744 // Create a number style NumberFormat instance with the default locale.
michael@0 745
michael@0 746 NumberFormat* U_EXPORT2
michael@0 747 NumberFormat::createInstance(UErrorCode& status)
michael@0 748 {
michael@0 749 return createInstance(Locale::getDefault(), UNUM_DECIMAL, status);
michael@0 750 }
michael@0 751
michael@0 752 // -------------------------------------
michael@0 753 // Create a number style NumberFormat instance with the inLocale locale.
michael@0 754
michael@0 755 NumberFormat* U_EXPORT2
michael@0 756 NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
michael@0 757 {
michael@0 758 return createInstance(inLocale, UNUM_DECIMAL, status);
michael@0 759 }
michael@0 760
michael@0 761 // -------------------------------------
michael@0 762 // Create a currency style NumberFormat instance with the default locale.
michael@0 763
michael@0 764 NumberFormat* U_EXPORT2
michael@0 765 NumberFormat::createCurrencyInstance(UErrorCode& status)
michael@0 766 {
michael@0 767 return createCurrencyInstance(Locale::getDefault(), status);
michael@0 768 }
michael@0 769
michael@0 770 // -------------------------------------
michael@0 771 // Create a currency style NumberFormat instance with the inLocale locale.
michael@0 772
michael@0 773 NumberFormat* U_EXPORT2
michael@0 774 NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
michael@0 775 {
michael@0 776 return createInstance(inLocale, UNUM_CURRENCY, status);
michael@0 777 }
michael@0 778
michael@0 779 // -------------------------------------
michael@0 780 // Create a percent style NumberFormat instance with the default locale.
michael@0 781
michael@0 782 NumberFormat* U_EXPORT2
michael@0 783 NumberFormat::createPercentInstance(UErrorCode& status)
michael@0 784 {
michael@0 785 return createInstance(Locale::getDefault(), UNUM_PERCENT, status);
michael@0 786 }
michael@0 787
michael@0 788 // -------------------------------------
michael@0 789 // Create a percent style NumberFormat instance with the inLocale locale.
michael@0 790
michael@0 791 NumberFormat* U_EXPORT2
michael@0 792 NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
michael@0 793 {
michael@0 794 return createInstance(inLocale, UNUM_PERCENT, status);
michael@0 795 }
michael@0 796
michael@0 797 // -------------------------------------
michael@0 798 // Create a scientific style NumberFormat instance with the default locale.
michael@0 799
michael@0 800 NumberFormat* U_EXPORT2
michael@0 801 NumberFormat::createScientificInstance(UErrorCode& status)
michael@0 802 {
michael@0 803 return createInstance(Locale::getDefault(), UNUM_SCIENTIFIC, status);
michael@0 804 }
michael@0 805
michael@0 806 // -------------------------------------
michael@0 807 // Create a scientific style NumberFormat instance with the inLocale locale.
michael@0 808
michael@0 809 NumberFormat* U_EXPORT2
michael@0 810 NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
michael@0 811 {
michael@0 812 return createInstance(inLocale, UNUM_SCIENTIFIC, status);
michael@0 813 }
michael@0 814
michael@0 815 // -------------------------------------
michael@0 816
michael@0 817 const Locale* U_EXPORT2
michael@0 818 NumberFormat::getAvailableLocales(int32_t& count)
michael@0 819 {
michael@0 820 return Locale::getAvailableLocales(count);
michael@0 821 }
michael@0 822
michael@0 823 // ------------------------------------------
michael@0 824 //
michael@0 825 // Registration
michael@0 826 //
michael@0 827 //-------------------------------------------
michael@0 828
michael@0 829 #if !UCONFIG_NO_SERVICE
michael@0 830
michael@0 831 // -------------------------------------
michael@0 832
michael@0 833 class ICUNumberFormatFactory : public ICUResourceBundleFactory {
michael@0 834 public:
michael@0 835 virtual ~ICUNumberFormatFactory();
michael@0 836 protected:
michael@0 837 virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
michael@0 838 return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status);
michael@0 839 }
michael@0 840 };
michael@0 841
michael@0 842 ICUNumberFormatFactory::~ICUNumberFormatFactory() {}
michael@0 843
michael@0 844 // -------------------------------------
michael@0 845
michael@0 846 class NFFactory : public LocaleKeyFactory {
michael@0 847 private:
michael@0 848 NumberFormatFactory* _delegate;
michael@0 849 Hashtable* _ids;
michael@0 850
michael@0 851 public:
michael@0 852 NFFactory(NumberFormatFactory* delegate)
michael@0 853 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
michael@0 854 , _delegate(delegate)
michael@0 855 , _ids(NULL)
michael@0 856 {
michael@0 857 }
michael@0 858
michael@0 859 virtual ~NFFactory();
michael@0 860
michael@0 861 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
michael@0 862 {
michael@0 863 if (handlesKey(key, status)) {
michael@0 864 const LocaleKey& lkey = (const LocaleKey&)key;
michael@0 865 Locale loc;
michael@0 866 lkey.canonicalLocale(loc);
michael@0 867 int32_t kind = lkey.kind();
michael@0 868
michael@0 869 UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)kind);
michael@0 870 if (result == NULL) {
michael@0 871 result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
michael@0 872 }
michael@0 873 return result;
michael@0 874 }
michael@0 875 return NULL;
michael@0 876 }
michael@0 877
michael@0 878 protected:
michael@0 879 /**
michael@0 880 * Return the set of ids that this factory supports (visible or
michael@0 881 * otherwise). This can be called often and might need to be
michael@0 882 * cached if it is expensive to create.
michael@0 883 */
michael@0 884 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
michael@0 885 {
michael@0 886 if (U_SUCCESS(status)) {
michael@0 887 if (!_ids) {
michael@0 888 int32_t count = 0;
michael@0 889 const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status);
michael@0 890 ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */
michael@0 891 if (_ids) {
michael@0 892 for (int i = 0; i < count; ++i) {
michael@0 893 _ids->put(idlist[i], (void*)this, status);
michael@0 894 }
michael@0 895 }
michael@0 896 }
michael@0 897 return _ids;
michael@0 898 }
michael@0 899 return NULL;
michael@0 900 }
michael@0 901 };
michael@0 902
michael@0 903 NFFactory::~NFFactory()
michael@0 904 {
michael@0 905 delete _delegate;
michael@0 906 delete _ids;
michael@0 907 }
michael@0 908
michael@0 909 class ICUNumberFormatService : public ICULocaleService {
michael@0 910 public:
michael@0 911 ICUNumberFormatService()
michael@0 912 : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format"))
michael@0 913 {
michael@0 914 UErrorCode status = U_ZERO_ERROR;
michael@0 915 registerFactory(new ICUNumberFormatFactory(), status);
michael@0 916 }
michael@0 917
michael@0 918 virtual ~ICUNumberFormatService();
michael@0 919
michael@0 920 virtual UObject* cloneInstance(UObject* instance) const {
michael@0 921 return ((NumberFormat*)instance)->clone();
michael@0 922 }
michael@0 923
michael@0 924 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const {
michael@0 925 LocaleKey& lkey = (LocaleKey&)key;
michael@0 926 int32_t kind = lkey.kind();
michael@0 927 Locale loc;
michael@0 928 lkey.currentLocale(loc);
michael@0 929 return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status);
michael@0 930 }
michael@0 931
michael@0 932 virtual UBool isDefault() const {
michael@0 933 return countFactories() == 1;
michael@0 934 }
michael@0 935 };
michael@0 936
michael@0 937 ICUNumberFormatService::~ICUNumberFormatService() {}
michael@0 938
michael@0 939 // -------------------------------------
michael@0 940
michael@0 941 static void U_CALLCONV initNumberFormatService() {
michael@0 942 U_ASSERT(gService == NULL);
michael@0 943 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
michael@0 944 gService = new ICUNumberFormatService();
michael@0 945 }
michael@0 946
michael@0 947 static ICULocaleService*
michael@0 948 getNumberFormatService(void)
michael@0 949 {
michael@0 950 umtx_initOnce(gServiceInitOnce, &initNumberFormatService);
michael@0 951 return gService;
michael@0 952 }
michael@0 953
michael@0 954 static UBool haveService() {
michael@0 955 return !gServiceInitOnce.isReset() && (getNumberFormatService() != NULL);
michael@0 956 }
michael@0 957
michael@0 958 // -------------------------------------
michael@0 959
michael@0 960 URegistryKey U_EXPORT2
michael@0 961 NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
michael@0 962 {
michael@0 963 ICULocaleService *service = getNumberFormatService();
michael@0 964 if (service) {
michael@0 965 NFFactory *tempnnf = new NFFactory(toAdopt);
michael@0 966 if (tempnnf != NULL) {
michael@0 967 return service->registerFactory(tempnnf, status);
michael@0 968 }
michael@0 969 }
michael@0 970 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 971 return NULL;
michael@0 972 }
michael@0 973
michael@0 974 // -------------------------------------
michael@0 975
michael@0 976 UBool U_EXPORT2
michael@0 977 NumberFormat::unregister(URegistryKey key, UErrorCode& status)
michael@0 978 {
michael@0 979 if (U_FAILURE(status)) {
michael@0 980 return FALSE;
michael@0 981 }
michael@0 982 if (haveService()) {
michael@0 983 return gService->unregister(key, status);
michael@0 984 } else {
michael@0 985 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 986 return FALSE;
michael@0 987 }
michael@0 988 }
michael@0 989
michael@0 990 // -------------------------------------
michael@0 991 StringEnumeration* U_EXPORT2
michael@0 992 NumberFormat::getAvailableLocales(void)
michael@0 993 {
michael@0 994 ICULocaleService *service = getNumberFormatService();
michael@0 995 if (service) {
michael@0 996 return service->getAvailableLocales();
michael@0 997 }
michael@0 998 return NULL; // no way to return error condition
michael@0 999 }
michael@0 1000 #endif /* UCONFIG_NO_SERVICE */
michael@0 1001 // -------------------------------------
michael@0 1002
michael@0 1003 NumberFormat* U_EXPORT2
michael@0 1004 NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) {
michael@0 1005 #if !UCONFIG_NO_SERVICE
michael@0 1006 if (haveService()) {
michael@0 1007 return (NumberFormat*)gService->get(loc, kind, status);
michael@0 1008 }
michael@0 1009 #endif
michael@0 1010 return makeInstance(loc, kind, status);
michael@0 1011 }
michael@0 1012
michael@0 1013
michael@0 1014 // -------------------------------------
michael@0 1015 // Checks if the thousand/10 thousand grouping is used in the
michael@0 1016 // NumberFormat instance.
michael@0 1017
michael@0 1018 UBool
michael@0 1019 NumberFormat::isGroupingUsed() const
michael@0 1020 {
michael@0 1021 return fGroupingUsed;
michael@0 1022 }
michael@0 1023
michael@0 1024 // -------------------------------------
michael@0 1025 // Sets to use the thousand/10 thousand grouping in the
michael@0 1026 // NumberFormat instance.
michael@0 1027
michael@0 1028 void
michael@0 1029 NumberFormat::setGroupingUsed(UBool newValue)
michael@0 1030 {
michael@0 1031 fGroupingUsed = newValue;
michael@0 1032 }
michael@0 1033
michael@0 1034 // -------------------------------------
michael@0 1035 // Gets the maximum number of digits for the integral part for
michael@0 1036 // this NumberFormat instance.
michael@0 1037
michael@0 1038 int32_t NumberFormat::getMaximumIntegerDigits() const
michael@0 1039 {
michael@0 1040 return fMaxIntegerDigits;
michael@0 1041 }
michael@0 1042
michael@0 1043 // -------------------------------------
michael@0 1044 // Sets the maximum number of digits for the integral part for
michael@0 1045 // this NumberFormat instance.
michael@0 1046
michael@0 1047 void
michael@0 1048 NumberFormat::setMaximumIntegerDigits(int32_t newValue)
michael@0 1049 {
michael@0 1050 fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gDefaultMaxIntegerDigits));
michael@0 1051 if(fMinIntegerDigits > fMaxIntegerDigits)
michael@0 1052 fMinIntegerDigits = fMaxIntegerDigits;
michael@0 1053 }
michael@0 1054
michael@0 1055 // -------------------------------------
michael@0 1056 // Gets the minimum number of digits for the integral part for
michael@0 1057 // this NumberFormat instance.
michael@0 1058
michael@0 1059 int32_t
michael@0 1060 NumberFormat::getMinimumIntegerDigits() const
michael@0 1061 {
michael@0 1062 return fMinIntegerDigits;
michael@0 1063 }
michael@0 1064
michael@0 1065 // -------------------------------------
michael@0 1066 // Sets the minimum number of digits for the integral part for
michael@0 1067 // this NumberFormat instance.
michael@0 1068
michael@0 1069 void
michael@0 1070 NumberFormat::setMinimumIntegerDigits(int32_t newValue)
michael@0 1071 {
michael@0 1072 fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gDefaultMinIntegerDigits));
michael@0 1073 if(fMinIntegerDigits > fMaxIntegerDigits)
michael@0 1074 fMaxIntegerDigits = fMinIntegerDigits;
michael@0 1075 }
michael@0 1076
michael@0 1077 // -------------------------------------
michael@0 1078 // Gets the maximum number of digits for the fractional part for
michael@0 1079 // this NumberFormat instance.
michael@0 1080
michael@0 1081 int32_t
michael@0 1082 NumberFormat::getMaximumFractionDigits() const
michael@0 1083 {
michael@0 1084 return fMaxFractionDigits;
michael@0 1085 }
michael@0 1086
michael@0 1087 // -------------------------------------
michael@0 1088 // Sets the maximum number of digits for the fractional part for
michael@0 1089 // this NumberFormat instance.
michael@0 1090
michael@0 1091 void
michael@0 1092 NumberFormat::setMaximumFractionDigits(int32_t newValue)
michael@0 1093 {
michael@0 1094 fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gDefaultMaxIntegerDigits));
michael@0 1095 if(fMaxFractionDigits < fMinFractionDigits)
michael@0 1096 fMinFractionDigits = fMaxFractionDigits;
michael@0 1097 }
michael@0 1098
michael@0 1099 // -------------------------------------
michael@0 1100 // Gets the minimum number of digits for the fractional part for
michael@0 1101 // this NumberFormat instance.
michael@0 1102
michael@0 1103 int32_t
michael@0 1104 NumberFormat::getMinimumFractionDigits() const
michael@0 1105 {
michael@0 1106 return fMinFractionDigits;
michael@0 1107 }
michael@0 1108
michael@0 1109 // -------------------------------------
michael@0 1110 // Sets the minimum number of digits for the fractional part for
michael@0 1111 // this NumberFormat instance.
michael@0 1112
michael@0 1113 void
michael@0 1114 NumberFormat::setMinimumFractionDigits(int32_t newValue)
michael@0 1115 {
michael@0 1116 fMinFractionDigits = uprv_max(0, uprv_min(newValue, gDefaultMinIntegerDigits));
michael@0 1117 if (fMaxFractionDigits < fMinFractionDigits)
michael@0 1118 fMaxFractionDigits = fMinFractionDigits;
michael@0 1119 }
michael@0 1120
michael@0 1121 // -------------------------------------
michael@0 1122
michael@0 1123 void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
michael@0 1124 if (U_FAILURE(ec)) {
michael@0 1125 return;
michael@0 1126 }
michael@0 1127 if (theCurrency) {
michael@0 1128 u_strncpy(fCurrency, theCurrency, 3);
michael@0 1129 fCurrency[3] = 0;
michael@0 1130 } else {
michael@0 1131 fCurrency[0] = 0;
michael@0 1132 }
michael@0 1133 }
michael@0 1134
michael@0 1135 const UChar* NumberFormat::getCurrency() const {
michael@0 1136 return fCurrency;
michael@0 1137 }
michael@0 1138
michael@0 1139 void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
michael@0 1140 const UChar* c = getCurrency();
michael@0 1141 if (*c != 0) {
michael@0 1142 u_strncpy(result, c, 3);
michael@0 1143 result[3] = 0;
michael@0 1144 } else {
michael@0 1145 const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
michael@0 1146 if (loc == NULL) {
michael@0 1147 loc = uloc_getDefault();
michael@0 1148 }
michael@0 1149 ucurr_forLocale(loc, result, 4, &ec);
michael@0 1150 }
michael@0 1151 }
michael@0 1152
michael@0 1153 // -------------------------------------
michael@0 1154 // Creates the NumberFormat instance of the specified style (number, currency,
michael@0 1155 // or percent) for the desired locale.
michael@0 1156
michael@0 1157 static void U_CALLCONV nscacheInit() {
michael@0 1158 U_ASSERT(NumberingSystem_cache == NULL);
michael@0 1159 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
michael@0 1160 UErrorCode status = U_ZERO_ERROR;
michael@0 1161 NumberingSystem_cache = uhash_open(uhash_hashLong,
michael@0 1162 uhash_compareLong,
michael@0 1163 NULL,
michael@0 1164 &status);
michael@0 1165 if (U_FAILURE(status)) {
michael@0 1166 // Number Format code will run with no cache if creation fails.
michael@0 1167 NumberingSystem_cache = NULL;
michael@0 1168 return;
michael@0 1169 }
michael@0 1170 uhash_setValueDeleter(NumberingSystem_cache, deleteNumberingSystem);
michael@0 1171 }
michael@0 1172
michael@0 1173 UBool
michael@0 1174 NumberFormat::isStyleSupported(UNumberFormatStyle style) {
michael@0 1175 return gLastResortNumberPatterns[style] != NULL;
michael@0 1176 }
michael@0 1177
michael@0 1178 NumberFormat*
michael@0 1179 NumberFormat::makeInstance(const Locale& desiredLocale,
michael@0 1180 UNumberFormatStyle style,
michael@0 1181 UErrorCode& status) {
michael@0 1182 return makeInstance(desiredLocale, style, false, status);
michael@0 1183 }
michael@0 1184
michael@0 1185 NumberFormat*
michael@0 1186 NumberFormat::makeInstance(const Locale& desiredLocale,
michael@0 1187 UNumberFormatStyle style,
michael@0 1188 UBool mustBeDecimalFormat,
michael@0 1189 UErrorCode& status) {
michael@0 1190 if (U_FAILURE(status)) return NULL;
michael@0 1191
michael@0 1192 if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) {
michael@0 1193 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 1194 return NULL;
michael@0 1195 }
michael@0 1196
michael@0 1197 // Some styles are not supported. This is a result of merging
michael@0 1198 // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle.
michael@0 1199 // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations:
michael@0 1200 // this one and unum_open().
michael@0 1201 // The UNUM_PATTERN_ styles are not supported here
michael@0 1202 // because this method does not take a pattern string.
michael@0 1203 if (!isStyleSupported(style)) {
michael@0 1204 status = U_UNSUPPORTED_ERROR;
michael@0 1205 return NULL;
michael@0 1206 }
michael@0 1207
michael@0 1208 #if U_PLATFORM_USES_ONLY_WIN32_API
michael@0 1209 if (!mustBeDecimalFormat) {
michael@0 1210 char buffer[8];
michael@0 1211 int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
michael@0 1212
michael@0 1213 // if the locale has "@compat=host", create a host-specific NumberFormat
michael@0 1214 if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) {
michael@0 1215 Win32NumberFormat *f = NULL;
michael@0 1216 UBool curr = TRUE;
michael@0 1217
michael@0 1218 switch (style) {
michael@0 1219 case UNUM_DECIMAL:
michael@0 1220 curr = FALSE;
michael@0 1221 // fall-through
michael@0 1222
michael@0 1223 case UNUM_CURRENCY:
michael@0 1224 case UNUM_CURRENCY_ISO: // do not support plural formatting here
michael@0 1225 case UNUM_CURRENCY_PLURAL:
michael@0 1226 f = new Win32NumberFormat(desiredLocale, curr, status);
michael@0 1227
michael@0 1228 if (U_SUCCESS(status)) {
michael@0 1229 return f;
michael@0 1230 }
michael@0 1231
michael@0 1232 delete f;
michael@0 1233 break;
michael@0 1234 default:
michael@0 1235 break;
michael@0 1236 }
michael@0 1237 }
michael@0 1238 }
michael@0 1239 #endif
michael@0 1240 // Use numbering system cache hashtable
michael@0 1241 umtx_initOnce(gNSCacheInitOnce, &nscacheInit);
michael@0 1242
michael@0 1243 // Get cached numbering system
michael@0 1244 LocalPointer<NumberingSystem> ownedNs;
michael@0 1245 NumberingSystem *ns = NULL;
michael@0 1246 if (NumberingSystem_cache != NULL) {
michael@0 1247 // TODO: Bad hash key usage, see ticket #8504.
michael@0 1248 int32_t hashKey = desiredLocale.hashCode();
michael@0 1249
michael@0 1250 Mutex lock(&nscacheMutex);
michael@0 1251 ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey);
michael@0 1252 if (ns == NULL) {
michael@0 1253 ns = NumberingSystem::createInstance(desiredLocale,status);
michael@0 1254 uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status);
michael@0 1255 }
michael@0 1256 } else {
michael@0 1257 ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status));
michael@0 1258 ns = ownedNs.getAlias();
michael@0 1259 }
michael@0 1260
michael@0 1261 // check results of getting a numbering system
michael@0 1262 if (U_FAILURE(status)) {
michael@0 1263 return NULL;
michael@0 1264 }
michael@0 1265
michael@0 1266 if (mustBeDecimalFormat && ns->isAlgorithmic()) {
michael@0 1267 status = U_UNSUPPORTED_ERROR;
michael@0 1268 return NULL;
michael@0 1269 }
michael@0 1270
michael@0 1271 LocalPointer<DecimalFormatSymbols> symbolsToAdopt;
michael@0 1272 UnicodeString pattern;
michael@0 1273 LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status));
michael@0 1274 if (U_FAILURE(status)) {
michael@0 1275 // We don't appear to have resource data available -- use the last-resort data
michael@0 1276 status = U_USING_FALLBACK_WARNING;
michael@0 1277 // When the data is unavailable, and locale isn't passed in, last resort data is used.
michael@0 1278 symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status));
michael@0 1279 if (symbolsToAdopt.isNull()) {
michael@0 1280 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 1281 return NULL;
michael@0 1282 }
michael@0 1283
michael@0 1284 // Creates a DecimalFormat instance with the last resort number patterns.
michael@0 1285 pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
michael@0 1286 }
michael@0 1287 else {
michael@0 1288 // Loads the decimal symbols of the desired locale.
michael@0 1289 symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status));
michael@0 1290 if (symbolsToAdopt.isNull()) {
michael@0 1291 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 1292 return NULL;
michael@0 1293 }
michael@0 1294
michael@0 1295 UResourceBundle *resource = ownedResource.orphan();
michael@0 1296 UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status);
michael@0 1297 resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status);
michael@0 1298 resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
michael@0 1299 ownedResource.adoptInstead(resource);
michael@0 1300
michael@0 1301 int32_t patLen = 0;
michael@0 1302 const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
michael@0 1303
michael@0 1304 // Didn't find a pattern specific to the numbering system, so fall back to "latn"
michael@0 1305 if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) {
michael@0 1306 status = U_ZERO_ERROR;
michael@0 1307 resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status);
michael@0 1308 resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
michael@0 1309 patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status);
michael@0 1310 }
michael@0 1311
michael@0 1312 ures_close(numElements);
michael@0 1313
michael@0 1314 // Creates the specified decimal format style of the desired locale.
michael@0 1315 pattern.setTo(TRUE, patResStr, patLen);
michael@0 1316 }
michael@0 1317 if (U_FAILURE(status)) {
michael@0 1318 return NULL;
michael@0 1319 }
michael@0 1320 if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){
michael@0 1321 const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
michael@0 1322 if(currPattern!=NULL){
michael@0 1323 pattern.setTo(currPattern, u_strlen(currPattern));
michael@0 1324 }
michael@0 1325 }
michael@0 1326
michael@0 1327
michael@0 1328 NumberFormat *f;
michael@0 1329 if (ns->isAlgorithmic()) {
michael@0 1330 UnicodeString nsDesc;
michael@0 1331 UnicodeString nsRuleSetGroup;
michael@0 1332 UnicodeString nsRuleSetName;
michael@0 1333 Locale nsLoc;
michael@0 1334 URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM;
michael@0 1335
michael@0 1336 nsDesc.setTo(ns->getDescription());
michael@0 1337 int32_t firstSlash = nsDesc.indexOf(gSlash);
michael@0 1338 int32_t lastSlash = nsDesc.lastIndexOf(gSlash);
michael@0 1339 if ( lastSlash > firstSlash ) {
michael@0 1340 CharString nsLocID;
michael@0 1341
michael@0 1342 nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status);
michael@0 1343 nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1);
michael@0 1344 nsRuleSetName.setTo(nsDesc,lastSlash+1);
michael@0 1345
michael@0 1346 nsLoc = Locale::createFromName(nsLocID.data());
michael@0 1347
michael@0 1348 UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules");
michael@0 1349 if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) {
michael@0 1350 desiredRulesType = URBNF_SPELLOUT;
michael@0 1351 }
michael@0 1352 } else {
michael@0 1353 nsLoc = desiredLocale;
michael@0 1354 nsRuleSetName.setTo(nsDesc);
michael@0 1355 }
michael@0 1356
michael@0 1357 RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status);
michael@0 1358 if (r == NULL) {
michael@0 1359 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 1360 return NULL;
michael@0 1361 }
michael@0 1362 r->setDefaultRuleSet(nsRuleSetName,status);
michael@0 1363 f = r;
michael@0 1364 } else {
michael@0 1365 // replace single currency sign in the pattern with double currency sign
michael@0 1366 // if the style is UNUM_CURRENCY_ISO
michael@0 1367 if (style == UNUM_CURRENCY_ISO) {
michael@0 1368 pattern.findAndReplace(UnicodeString(TRUE, gSingleCurrencySign, 1),
michael@0 1369 UnicodeString(TRUE, gDoubleCurrencySign, 2));
michael@0 1370 }
michael@0 1371
michael@0 1372 // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails.
michael@0 1373 DecimalFormatSymbols *syms = symbolsToAdopt.orphan();
michael@0 1374 f = new DecimalFormat(pattern, syms, style, status);
michael@0 1375 if (f == NULL) {
michael@0 1376 delete syms;
michael@0 1377 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 1378 return NULL;
michael@0 1379 }
michael@0 1380 }
michael@0 1381
michael@0 1382 f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status),
michael@0 1383 ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status));
michael@0 1384 if (U_FAILURE(status)) {
michael@0 1385 delete f;
michael@0 1386 return NULL;
michael@0 1387 }
michael@0 1388 return f;
michael@0 1389 }
michael@0 1390
michael@0 1391 U_NAMESPACE_END
michael@0 1392
michael@0 1393 #endif /* #if !UCONFIG_NO_FORMATTING */
michael@0 1394
michael@0 1395 //eof

mercurial