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