1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/numfmt.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1395 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 1997-2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +* 1.10 +* File NUMFMT.CPP 1.11 +* 1.12 +* Modification History: 1.13 +* 1.14 +* Date Name Description 1.15 +* 02/19/97 aliu Converted from java. 1.16 +* 03/18/97 clhuang Implemented with C++ APIs. 1.17 +* 04/17/97 aliu Enlarged MAX_INTEGER_DIGITS to fully accomodate the 1.18 +* largest double, by default. 1.19 +* Changed DigitCount to int per code review. 1.20 +* 07/20/98 stephen Changed operator== to check for grouping 1.21 +* Changed setMaxIntegerDigits per Java implementation. 1.22 +* Changed setMinIntegerDigits per Java implementation. 1.23 +* Changed setMinFractionDigits per Java implementation. 1.24 +* Changed setMaxFractionDigits per Java implementation. 1.25 +******************************************************************************** 1.26 +*/ 1.27 + 1.28 +#include "unicode/utypes.h" 1.29 + 1.30 +#if !UCONFIG_NO_FORMATTING 1.31 + 1.32 +#include "unicode/numfmt.h" 1.33 +#include "unicode/locid.h" 1.34 +#include "unicode/dcfmtsym.h" 1.35 +#include "unicode/decimfmt.h" 1.36 +#include "unicode/ustring.h" 1.37 +#include "unicode/ucurr.h" 1.38 +#include "unicode/curramt.h" 1.39 +#include "unicode/numsys.h" 1.40 +#include "unicode/rbnf.h" 1.41 +#include "unicode/localpointer.h" 1.42 +#include "charstr.h" 1.43 +#include "winnmfmt.h" 1.44 +#include "uresimp.h" 1.45 +#include "uhash.h" 1.46 +#include "cmemory.h" 1.47 +#include "servloc.h" 1.48 +#include "ucln_in.h" 1.49 +#include "cstring.h" 1.50 +#include "putilimp.h" 1.51 +#include "uassert.h" 1.52 +#include "umutex.h" 1.53 +#include "mutex.h" 1.54 +#include "digitlst.h" 1.55 +#include <float.h> 1.56 + 1.57 +//#define FMT_DEBUG 1.58 + 1.59 +#ifdef FMT_DEBUG 1.60 +#include <stdio.h> 1.61 +static inline void debugout(UnicodeString s) { 1.62 + char buf[2000]; 1.63 + s.extract((int32_t) 0, s.length(), buf); 1.64 + printf("%s", buf); 1.65 +} 1.66 +#define debug(x) printf("%s", x); 1.67 +#else 1.68 +#define debugout(x) 1.69 +#define debug(x) 1.70 +#endif 1.71 + 1.72 +// If no number pattern can be located for a locale, this is the last 1.73 +// resort. 1.74 +static const UChar gLastResortDecimalPat[] = { 1.75 + 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */ 1.76 +}; 1.77 +static const UChar gLastResortCurrencyPat[] = { 1.78 + 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "$#0.00;($#0.00)" */ 1.79 +}; 1.80 +static const UChar gLastResortPercentPat[] = { 1.81 + 0x23, 0x30, 0x25, 0 /* "#0%" */ 1.82 +}; 1.83 +static const UChar gLastResortScientificPat[] = { 1.84 + 0x23, 0x45, 0x30, 0 /* "#E0" */ 1.85 +}; 1.86 +static const UChar gLastResortIsoCurrencyPat[] = { 1.87 + 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)" */ 1.88 +}; 1.89 +static const UChar gLastResortPluralCurrencyPat[] = { 1.90 + 0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/ 1.91 +}; 1.92 + 1.93 +static const UChar gSingleCurrencySign[] = {0xA4, 0}; 1.94 +static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0}; 1.95 + 1.96 +static const UChar gSlash = 0x2f; 1.97 + 1.98 +// If the maximum base 10 exponent were 4, then the largest number would 1.99 +// be 99,999 which has 5 digits. 1.100 +// On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit 1.101 +// With big decimal, the max exponent is 999,999,999 and the max number of digits is the same, 999,999,999 1.102 +const int32_t icu::NumberFormat::gDefaultMaxIntegerDigits = 2000000000; 1.103 +const int32_t icu::NumberFormat::gDefaultMinIntegerDigits = 127; 1.104 + 1.105 +static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] = { 1.106 + NULL, // UNUM_PATTERN_DECIMAL 1.107 + gLastResortDecimalPat, // UNUM_DECIMAL 1.108 + gLastResortCurrencyPat, // UNUM_CURRENCY 1.109 + gLastResortPercentPat, // UNUM_PERCENT 1.110 + gLastResortScientificPat, // UNUM_SCIENTIFIC 1.111 + NULL, // UNUM_SPELLOUT 1.112 + NULL, // UNUM_ORDINAL 1.113 + NULL, // UNUM_DURATION 1.114 + NULL, // UNUM_NUMBERING_SYSTEM 1.115 + NULL, // UNUM_PATTERN_RULEBASED 1.116 + gLastResortIsoCurrencyPat, // UNUM_CURRENCY_ISO 1.117 + gLastResortPluralCurrencyPat // UNUM_CURRENCY_PLURAL 1.118 +}; 1.119 + 1.120 +// Keys used for accessing resource bundles 1.121 + 1.122 +static const char *gNumberElements = "NumberElements"; 1.123 +static const char *gLatn = "latn"; 1.124 +static const char *gPatterns = "patterns"; 1.125 +static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = { 1.126 + NULL, // UNUM_PATTERN_DECIMAL 1.127 + "decimalFormat", // UNUM_DECIMAL 1.128 + "currencyFormat", // UNUM_CURRENCY 1.129 + "percentFormat", // UNUM_PERCENT 1.130 + "scientificFormat", // UNUM_SCIENTIFIC 1.131 + NULL, // UNUM_SPELLOUT 1.132 + NULL, // UNUM_ORDINAL 1.133 + NULL, // UNUM_DURATION 1.134 + NULL, // UNUM_NUMBERING_SYSTEM 1.135 + NULL, // UNUM_PATTERN_RULEBASED 1.136 + // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL, 1.137 + // the pattern is the same as the pattern of UNUM_CURRENCY 1.138 + // except for replacing the single currency sign with 1.139 + // double currency sign or triple currency sign. 1.140 + "currencyFormat", // UNUM_CURRENCY_ISO 1.141 + "currencyFormat" // UNUM_CURRENCY_PLURAL 1.142 +}; 1.143 + 1.144 +// Static hashtable cache of NumberingSystem objects used by NumberFormat 1.145 +static UHashtable * NumberingSystem_cache = NULL; 1.146 +static UMutex nscacheMutex = U_MUTEX_INITIALIZER; 1.147 +static icu::UInitOnce gNSCacheInitOnce = U_INITONCE_INITIALIZER; 1.148 + 1.149 +#if !UCONFIG_NO_SERVICE 1.150 +static icu::ICULocaleService* gService = NULL; 1.151 +static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER; 1.152 +#endif 1.153 + 1.154 +/** 1.155 + * Release all static memory held by Number Format. 1.156 + */ 1.157 +U_CDECL_BEGIN 1.158 +static void U_CALLCONV 1.159 +deleteNumberingSystem(void *obj) { 1.160 + delete (icu::NumberingSystem *)obj; 1.161 +} 1.162 + 1.163 +static UBool U_CALLCONV numfmt_cleanup(void) { 1.164 +#if !UCONFIG_NO_SERVICE 1.165 + gServiceInitOnce.reset(); 1.166 + if (gService) { 1.167 + delete gService; 1.168 + gService = NULL; 1.169 + } 1.170 +#endif 1.171 + gNSCacheInitOnce.reset(); 1.172 + if (NumberingSystem_cache) { 1.173 + // delete NumberingSystem_cache; 1.174 + uhash_close(NumberingSystem_cache); 1.175 + NumberingSystem_cache = NULL; 1.176 + } 1.177 + 1.178 + return TRUE; 1.179 +} 1.180 +U_CDECL_END 1.181 + 1.182 +// ***************************************************************************** 1.183 +// class NumberFormat 1.184 +// ***************************************************************************** 1.185 + 1.186 +U_NAMESPACE_BEGIN 1.187 + 1.188 +UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat) 1.189 + 1.190 +#if !UCONFIG_NO_SERVICE 1.191 +// ------------------------------------- 1.192 +// SimpleNumberFormatFactory implementation 1.193 +NumberFormatFactory::~NumberFormatFactory() {} 1.194 +SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible) 1.195 + : _visible(visible) 1.196 +{ 1.197 + LocaleUtility::initNameFromLocale(locale, _id); 1.198 +} 1.199 + 1.200 +SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {} 1.201 + 1.202 +UBool SimpleNumberFormatFactory::visible(void) const { 1.203 + return _visible; 1.204 +} 1.205 + 1.206 +const UnicodeString * 1.207 +SimpleNumberFormatFactory::getSupportedIDs(int32_t &count, UErrorCode& status) const 1.208 +{ 1.209 + if (U_SUCCESS(status)) { 1.210 + count = 1; 1.211 + return &_id; 1.212 + } 1.213 + count = 0; 1.214 + return NULL; 1.215 +} 1.216 +#endif /* #if !UCONFIG_NO_SERVICE */ 1.217 + 1.218 +// ------------------------------------- 1.219 +// default constructor 1.220 +NumberFormat::NumberFormat() 1.221 +: fGroupingUsed(TRUE), 1.222 + fMaxIntegerDigits(gDefaultMaxIntegerDigits), 1.223 + fMinIntegerDigits(1), 1.224 + fMaxFractionDigits(3), // invariant, >= minFractionDigits 1.225 + fMinFractionDigits(0), 1.226 + fParseIntegerOnly(FALSE), 1.227 + fLenient(FALSE) 1.228 +{ 1.229 + fCurrency[0] = 0; 1.230 +} 1.231 + 1.232 +// ------------------------------------- 1.233 + 1.234 +NumberFormat::~NumberFormat() 1.235 +{ 1.236 +} 1.237 + 1.238 +// ------------------------------------- 1.239 +// copy constructor 1.240 + 1.241 +NumberFormat::NumberFormat(const NumberFormat &source) 1.242 +: Format(source) 1.243 +{ 1.244 + *this = source; 1.245 +} 1.246 + 1.247 +// ------------------------------------- 1.248 +// assignment operator 1.249 + 1.250 +NumberFormat& 1.251 +NumberFormat::operator=(const NumberFormat& rhs) 1.252 +{ 1.253 + if (this != &rhs) 1.254 + { 1.255 + Format::operator=(rhs); 1.256 + fGroupingUsed = rhs.fGroupingUsed; 1.257 + fMaxIntegerDigits = rhs.fMaxIntegerDigits; 1.258 + fMinIntegerDigits = rhs.fMinIntegerDigits; 1.259 + fMaxFractionDigits = rhs.fMaxFractionDigits; 1.260 + fMinFractionDigits = rhs.fMinFractionDigits; 1.261 + fParseIntegerOnly = rhs.fParseIntegerOnly; 1.262 + u_strncpy(fCurrency, rhs.fCurrency, 4); 1.263 + fLenient = rhs.fLenient; 1.264 + } 1.265 + return *this; 1.266 +} 1.267 + 1.268 +// ------------------------------------- 1.269 + 1.270 +UBool 1.271 +NumberFormat::operator==(const Format& that) const 1.272 +{ 1.273 + // Format::operator== guarantees this cast is safe 1.274 + NumberFormat* other = (NumberFormat*)&that; 1.275 + 1.276 +#ifdef FMT_DEBUG 1.277 + // This code makes it easy to determine why two format objects that should 1.278 + // be equal aren't. 1.279 + UBool first = TRUE; 1.280 + if (!Format::operator==(that)) { 1.281 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.282 + debug("Format::!="); 1.283 + } 1.284 + if (!(fMaxIntegerDigits == other->fMaxIntegerDigits && 1.285 + fMinIntegerDigits == other->fMinIntegerDigits)) { 1.286 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.287 + debug("Integer digits !="); 1.288 + } 1.289 + if (!(fMaxFractionDigits == other->fMaxFractionDigits && 1.290 + fMinFractionDigits == other->fMinFractionDigits)) { 1.291 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.292 + debug("Fraction digits !="); 1.293 + } 1.294 + if (!(fGroupingUsed == other->fGroupingUsed)) { 1.295 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.296 + debug("fGroupingUsed != "); 1.297 + } 1.298 + if (!(fParseIntegerOnly == other->fParseIntegerOnly)) { 1.299 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.300 + debug("fParseIntegerOnly != "); 1.301 + } 1.302 + if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) { 1.303 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.304 + debug("fCurrency !="); 1.305 + } 1.306 + if (!(fLenient == other->fLenient)) { 1.307 + if (first) { printf("[ "); first = FALSE; } else { printf(", "); } 1.308 + debug("fLenient != "); 1.309 + } 1.310 + if (!first) { printf(" ]"); } 1.311 +#endif 1.312 + 1.313 + return ((this == &that) || 1.314 + ((Format::operator==(that) && 1.315 + fMaxIntegerDigits == other->fMaxIntegerDigits && 1.316 + fMinIntegerDigits == other->fMinIntegerDigits && 1.317 + fMaxFractionDigits == other->fMaxFractionDigits && 1.318 + fMinFractionDigits == other->fMinFractionDigits && 1.319 + fGroupingUsed == other->fGroupingUsed && 1.320 + fParseIntegerOnly == other->fParseIntegerOnly && 1.321 + u_strcmp(fCurrency, other->fCurrency) == 0 && 1.322 + fLenient == other->fLenient))); 1.323 +} 1.324 + 1.325 +// ------------------------------------- 1.326 +// Default implementation sets unsupported error; subclasses should 1.327 +// override. 1.328 + 1.329 +UnicodeString& 1.330 +NumberFormat::format(double /* unused number */, 1.331 + UnicodeString& toAppendTo, 1.332 + FieldPositionIterator* /* unused posIter */, 1.333 + UErrorCode& status) const 1.334 +{ 1.335 + if (!U_FAILURE(status)) { 1.336 + status = U_UNSUPPORTED_ERROR; 1.337 + } 1.338 + return toAppendTo; 1.339 +} 1.340 + 1.341 +// ------------------------------------- 1.342 +// Default implementation sets unsupported error; subclasses should 1.343 +// override. 1.344 + 1.345 +UnicodeString& 1.346 +NumberFormat::format(int32_t /* unused number */, 1.347 + UnicodeString& toAppendTo, 1.348 + FieldPositionIterator* /* unused posIter */, 1.349 + UErrorCode& status) const 1.350 +{ 1.351 + if (!U_FAILURE(status)) { 1.352 + status = U_UNSUPPORTED_ERROR; 1.353 + } 1.354 + return toAppendTo; 1.355 +} 1.356 + 1.357 +// ------------------------------------- 1.358 +// Default implementation sets unsupported error; subclasses should 1.359 +// override. 1.360 + 1.361 +UnicodeString& 1.362 +NumberFormat::format(int64_t /* unused number */, 1.363 + UnicodeString& toAppendTo, 1.364 + FieldPositionIterator* /* unused posIter */, 1.365 + UErrorCode& status) const 1.366 +{ 1.367 + if (!U_FAILURE(status)) { 1.368 + status = U_UNSUPPORTED_ERROR; 1.369 + } 1.370 + return toAppendTo; 1.371 +} 1.372 + 1.373 +// ------------------------------------------ 1.374 +// These functions add the status code, just fall back to the non-status versions 1.375 +UnicodeString& 1.376 +NumberFormat::format(double number, 1.377 + UnicodeString& appendTo, 1.378 + FieldPosition& pos, 1.379 + UErrorCode &status) const { 1.380 + if(U_SUCCESS(status)) { 1.381 + return format(number,appendTo,pos); 1.382 + } else { 1.383 + return appendTo; 1.384 + } 1.385 +} 1.386 + 1.387 +UnicodeString& 1.388 +NumberFormat::format(int32_t number, 1.389 + UnicodeString& appendTo, 1.390 + FieldPosition& pos, 1.391 + UErrorCode &status) const { 1.392 + if(U_SUCCESS(status)) { 1.393 + return format(number,appendTo,pos); 1.394 + } else { 1.395 + return appendTo; 1.396 + } 1.397 +} 1.398 + 1.399 +UnicodeString& 1.400 +NumberFormat::format(int64_t number, 1.401 + UnicodeString& appendTo, 1.402 + FieldPosition& pos, 1.403 + UErrorCode &status) const { 1.404 + if(U_SUCCESS(status)) { 1.405 + return format(number,appendTo,pos); 1.406 + } else { 1.407 + return appendTo; 1.408 + } 1.409 +} 1.410 + 1.411 + 1.412 + 1.413 +// ------------------------------------- 1.414 +// Decimal Number format() default implementation 1.415 +// Subclasses do not normally override this function, but rather the DigitList 1.416 +// formatting functions.. 1.417 +// The expected call chain from here is 1.418 +// this function -> 1.419 +// NumberFormat::format(Formattable -> 1.420 +// DecimalFormat::format(DigitList 1.421 +// 1.422 +// Or, for subclasses of Formattable that do not know about DigitList, 1.423 +// this Function -> 1.424 +// NumberFormat::format(Formattable -> 1.425 +// NumberFormat::format(DigitList -> 1.426 +// XXXFormat::format(double 1.427 + 1.428 +UnicodeString& 1.429 +NumberFormat::format(const StringPiece &decimalNum, 1.430 + UnicodeString& toAppendTo, 1.431 + FieldPositionIterator* fpi, 1.432 + UErrorCode& status) const 1.433 +{ 1.434 + Formattable f; 1.435 + f.setDecimalNumber(decimalNum, status); 1.436 + format(f, toAppendTo, fpi, status); 1.437 + return toAppendTo; 1.438 +} 1.439 + 1.440 +/** 1.441 + * 1.442 +// Formats the number object and save the format 1.443 +// result in the toAppendTo string buffer. 1.444 + 1.445 +// utility to save/restore state, used in two overloads 1.446 +// of format(const Formattable&...) below. 1.447 +* 1.448 +* Old purpose of ArgExtractor was to avoid const. Not thread safe! 1.449 +* 1.450 +* keeping it around as a shim. 1.451 +*/ 1.452 +class ArgExtractor { 1.453 + const Formattable* num; 1.454 + UChar save[4]; 1.455 + UBool fWasCurrency; 1.456 + 1.457 + public: 1.458 + ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status); 1.459 + ~ArgExtractor(); 1.460 + 1.461 + const Formattable* number(void) const; 1.462 + const UChar *iso(void) const; 1.463 + UBool wasCurrency(void) const; 1.464 +}; 1.465 + 1.466 +inline const Formattable* 1.467 +ArgExtractor::number(void) const { 1.468 + return num; 1.469 +} 1.470 + 1.471 +inline UBool 1.472 +ArgExtractor::wasCurrency(void) const { 1.473 + return fWasCurrency; 1.474 +} 1.475 + 1.476 +inline const UChar * 1.477 +ArgExtractor::iso(void) const { 1.478 + return save; 1.479 +} 1.480 + 1.481 +ArgExtractor::ArgExtractor(const NumberFormat& /*nf*/, const Formattable& obj, UErrorCode& /*status*/) 1.482 + : num(&obj), fWasCurrency(FALSE) { 1.483 + 1.484 + const UObject* o = obj.getObject(); // most commonly o==NULL 1.485 + const CurrencyAmount* amt; 1.486 + if (o != NULL && (amt = dynamic_cast<const CurrencyAmount*>(o)) != NULL) { 1.487 + // getISOCurrency() returns a pointer to internal storage, so we 1.488 + // copy it to retain it across the call to setCurrency(). 1.489 + //const UChar* curr = amt->getISOCurrency(); 1.490 + u_strcpy(save, amt->getISOCurrency()); 1.491 + num = &amt->getNumber(); 1.492 + fWasCurrency=TRUE; 1.493 + } else { 1.494 + save[0]=0; 1.495 + } 1.496 +} 1.497 + 1.498 +ArgExtractor::~ArgExtractor() { 1.499 +} 1.500 + 1.501 +UnicodeString& NumberFormat::format(const DigitList &number, 1.502 + UnicodeString& appendTo, 1.503 + FieldPositionIterator* posIter, 1.504 + UErrorCode& status) const { 1.505 + // DecimalFormat overrides this function, and handles DigitList based big decimals. 1.506 + // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists, 1.507 + // so this default implementation falls back to formatting decimal numbers as doubles. 1.508 + if (U_FAILURE(status)) { 1.509 + return appendTo; 1.510 + } 1.511 + double dnum = number.getDouble(); 1.512 + format(dnum, appendTo, posIter, status); 1.513 + return appendTo; 1.514 +} 1.515 + 1.516 + 1.517 + 1.518 +UnicodeString& 1.519 +NumberFormat::format(const DigitList &number, 1.520 + UnicodeString& appendTo, 1.521 + FieldPosition& pos, 1.522 + UErrorCode &status) const { 1.523 + // DecimalFormat overrides this function, and handles DigitList based big decimals. 1.524 + // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists, 1.525 + // so this default implementation falls back to formatting decimal numbers as doubles. 1.526 + if (U_FAILURE(status)) { 1.527 + return appendTo; 1.528 + } 1.529 + double dnum = number.getDouble(); 1.530 + format(dnum, appendTo, pos, status); 1.531 + return appendTo; 1.532 +} 1.533 + 1.534 +UnicodeString& 1.535 +NumberFormat::format(const Formattable& obj, 1.536 + UnicodeString& appendTo, 1.537 + FieldPosition& pos, 1.538 + UErrorCode& status) const 1.539 +{ 1.540 + if (U_FAILURE(status)) return appendTo; 1.541 + 1.542 + ArgExtractor arg(*this, obj, status); 1.543 + const Formattable *n = arg.number(); 1.544 + const UChar *iso = arg.iso(); 1.545 + 1.546 + if(arg.wasCurrency() && u_strcmp(iso, getCurrency())) { 1.547 + // trying to format a different currency. 1.548 + // Right now, we clone. 1.549 + LocalPointer<NumberFormat> cloneFmt((NumberFormat*)this->clone()); 1.550 + cloneFmt->setCurrency(iso, status); 1.551 + // next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount. 1.552 + return cloneFmt->format(*n, appendTo, pos, status); 1.553 + } 1.554 + 1.555 + if (n->isNumeric() && n->getDigitList() != NULL) { 1.556 + // Decimal Number. We will have a DigitList available if the value was 1.557 + // set to a decimal number, or if the value originated with a parse. 1.558 + // 1.559 + // The default implementation for formatting a DigitList converts it 1.560 + // to a double, and formats that, allowing formatting classes that don't 1.561 + // know about DigitList to continue to operate as they had. 1.562 + // 1.563 + // DecimalFormat overrides the DigitList formatting functions. 1.564 + format(*n->getDigitList(), appendTo, pos, status); 1.565 + } else { 1.566 + switch (n->getType()) { 1.567 + case Formattable::kDouble: 1.568 + format(n->getDouble(), appendTo, pos); 1.569 + break; 1.570 + case Formattable::kLong: 1.571 + format(n->getLong(), appendTo, pos); 1.572 + break; 1.573 + case Formattable::kInt64: 1.574 + format(n->getInt64(), appendTo, pos); 1.575 + break; 1.576 + default: 1.577 + status = U_INVALID_FORMAT_ERROR; 1.578 + break; 1.579 + } 1.580 + } 1.581 + 1.582 + return appendTo; 1.583 +} 1.584 + 1.585 +// -------------------------------------x 1.586 +// Formats the number object and save the format 1.587 +// result in the toAppendTo string buffer. 1.588 + 1.589 +UnicodeString& 1.590 +NumberFormat::format(const Formattable& obj, 1.591 + UnicodeString& appendTo, 1.592 + FieldPositionIterator* posIter, 1.593 + UErrorCode& status) const 1.594 +{ 1.595 + if (U_FAILURE(status)) return appendTo; 1.596 + 1.597 + ArgExtractor arg(*this, obj, status); 1.598 + const Formattable *n = arg.number(); 1.599 + const UChar *iso = arg.iso(); 1.600 + 1.601 + if(arg.wasCurrency() && u_strcmp(iso, getCurrency())) { 1.602 + // trying to format a different currency. 1.603 + // Right now, we clone. 1.604 + LocalPointer<NumberFormat> cloneFmt((NumberFormat*)this->clone()); 1.605 + cloneFmt->setCurrency(iso, status); 1.606 + // next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount. 1.607 + return cloneFmt->format(*n, appendTo, posIter, status); 1.608 + } 1.609 + 1.610 + if (n->isNumeric() && n->getDigitList() != NULL) { 1.611 + // Decimal Number 1.612 + format(*n->getDigitList(), appendTo, posIter, status); 1.613 + } else { 1.614 + switch (n->getType()) { 1.615 + case Formattable::kDouble: 1.616 + format(n->getDouble(), appendTo, posIter, status); 1.617 + break; 1.618 + case Formattable::kLong: 1.619 + format(n->getLong(), appendTo, posIter, status); 1.620 + break; 1.621 + case Formattable::kInt64: 1.622 + format(n->getInt64(), appendTo, posIter, status); 1.623 + break; 1.624 + default: 1.625 + status = U_INVALID_FORMAT_ERROR; 1.626 + break; 1.627 + } 1.628 + } 1.629 + 1.630 + return appendTo; 1.631 +} 1.632 + 1.633 +// ------------------------------------- 1.634 + 1.635 +UnicodeString& 1.636 +NumberFormat::format(int64_t number, 1.637 + UnicodeString& appendTo, 1.638 + FieldPosition& pos) const 1.639 +{ 1.640 + // default so we don't introduce a new abstract method 1.641 + return format((int32_t)number, appendTo, pos); 1.642 +} 1.643 + 1.644 +// ------------------------------------- 1.645 +// Parses the string and save the result object as well 1.646 +// as the final parsed position. 1.647 + 1.648 +void 1.649 +NumberFormat::parseObject(const UnicodeString& source, 1.650 + Formattable& result, 1.651 + ParsePosition& parse_pos) const 1.652 +{ 1.653 + parse(source, result, parse_pos); 1.654 +} 1.655 + 1.656 +// ------------------------------------- 1.657 +// Formats a double number and save the result in a string. 1.658 + 1.659 +UnicodeString& 1.660 +NumberFormat::format(double number, UnicodeString& appendTo) const 1.661 +{ 1.662 + FieldPosition pos(0); 1.663 + return format(number, appendTo, pos); 1.664 +} 1.665 + 1.666 +// ------------------------------------- 1.667 +// Formats a long number and save the result in a string. 1.668 + 1.669 +UnicodeString& 1.670 +NumberFormat::format(int32_t number, UnicodeString& appendTo) const 1.671 +{ 1.672 + FieldPosition pos(0); 1.673 + return format(number, appendTo, pos); 1.674 +} 1.675 + 1.676 +// ------------------------------------- 1.677 +// Formats a long number and save the result in a string. 1.678 + 1.679 +UnicodeString& 1.680 +NumberFormat::format(int64_t number, UnicodeString& appendTo) const 1.681 +{ 1.682 + FieldPosition pos(0); 1.683 + return format(number, appendTo, pos); 1.684 +} 1.685 + 1.686 +// ------------------------------------- 1.687 +// Parses the text and save the result object. If the returned 1.688 +// parse position is 0, that means the parsing failed, the status 1.689 +// code needs to be set to failure. Ignores the returned parse 1.690 +// position, otherwise. 1.691 + 1.692 +void 1.693 +NumberFormat::parse(const UnicodeString& text, 1.694 + Formattable& result, 1.695 + UErrorCode& status) const 1.696 +{ 1.697 + if (U_FAILURE(status)) return; 1.698 + 1.699 + ParsePosition parsePosition(0); 1.700 + parse(text, result, parsePosition); 1.701 + if (parsePosition.getIndex() == 0) { 1.702 + status = U_INVALID_FORMAT_ERROR; 1.703 + } 1.704 +} 1.705 + 1.706 +CurrencyAmount* NumberFormat::parseCurrency(const UnicodeString& text, 1.707 + ParsePosition& pos) const { 1.708 + // Default implementation only -- subclasses should override 1.709 + Formattable parseResult; 1.710 + int32_t start = pos.getIndex(); 1.711 + parse(text, parseResult, pos); 1.712 + if (pos.getIndex() != start) { 1.713 + UChar curr[4]; 1.714 + UErrorCode ec = U_ZERO_ERROR; 1.715 + getEffectiveCurrency(curr, ec); 1.716 + if (U_SUCCESS(ec)) { 1.717 + LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curr, ec)); 1.718 + if (U_FAILURE(ec)) { 1.719 + pos.setIndex(start); // indicate failure 1.720 + } else { 1.721 + return currAmt.orphan(); 1.722 + } 1.723 + } 1.724 + } 1.725 + return NULL; 1.726 +} 1.727 + 1.728 +// ------------------------------------- 1.729 +// Sets to only parse integers. 1.730 + 1.731 +void 1.732 +NumberFormat::setParseIntegerOnly(UBool value) 1.733 +{ 1.734 + fParseIntegerOnly = value; 1.735 +} 1.736 + 1.737 +// ------------------------------------- 1.738 +// Sets whether lenient parse is enabled. 1.739 + 1.740 +void 1.741 +NumberFormat::setLenient(UBool enable) 1.742 +{ 1.743 + fLenient = enable; 1.744 +} 1.745 + 1.746 +// ------------------------------------- 1.747 +// Create a number style NumberFormat instance with the default locale. 1.748 + 1.749 +NumberFormat* U_EXPORT2 1.750 +NumberFormat::createInstance(UErrorCode& status) 1.751 +{ 1.752 + return createInstance(Locale::getDefault(), UNUM_DECIMAL, status); 1.753 +} 1.754 + 1.755 +// ------------------------------------- 1.756 +// Create a number style NumberFormat instance with the inLocale locale. 1.757 + 1.758 +NumberFormat* U_EXPORT2 1.759 +NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status) 1.760 +{ 1.761 + return createInstance(inLocale, UNUM_DECIMAL, status); 1.762 +} 1.763 + 1.764 +// ------------------------------------- 1.765 +// Create a currency style NumberFormat instance with the default locale. 1.766 + 1.767 +NumberFormat* U_EXPORT2 1.768 +NumberFormat::createCurrencyInstance(UErrorCode& status) 1.769 +{ 1.770 + return createCurrencyInstance(Locale::getDefault(), status); 1.771 +} 1.772 + 1.773 +// ------------------------------------- 1.774 +// Create a currency style NumberFormat instance with the inLocale locale. 1.775 + 1.776 +NumberFormat* U_EXPORT2 1.777 +NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status) 1.778 +{ 1.779 + return createInstance(inLocale, UNUM_CURRENCY, status); 1.780 +} 1.781 + 1.782 +// ------------------------------------- 1.783 +// Create a percent style NumberFormat instance with the default locale. 1.784 + 1.785 +NumberFormat* U_EXPORT2 1.786 +NumberFormat::createPercentInstance(UErrorCode& status) 1.787 +{ 1.788 + return createInstance(Locale::getDefault(), UNUM_PERCENT, status); 1.789 +} 1.790 + 1.791 +// ------------------------------------- 1.792 +// Create a percent style NumberFormat instance with the inLocale locale. 1.793 + 1.794 +NumberFormat* U_EXPORT2 1.795 +NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status) 1.796 +{ 1.797 + return createInstance(inLocale, UNUM_PERCENT, status); 1.798 +} 1.799 + 1.800 +// ------------------------------------- 1.801 +// Create a scientific style NumberFormat instance with the default locale. 1.802 + 1.803 +NumberFormat* U_EXPORT2 1.804 +NumberFormat::createScientificInstance(UErrorCode& status) 1.805 +{ 1.806 + return createInstance(Locale::getDefault(), UNUM_SCIENTIFIC, status); 1.807 +} 1.808 + 1.809 +// ------------------------------------- 1.810 +// Create a scientific style NumberFormat instance with the inLocale locale. 1.811 + 1.812 +NumberFormat* U_EXPORT2 1.813 +NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status) 1.814 +{ 1.815 + return createInstance(inLocale, UNUM_SCIENTIFIC, status); 1.816 +} 1.817 + 1.818 +// ------------------------------------- 1.819 + 1.820 +const Locale* U_EXPORT2 1.821 +NumberFormat::getAvailableLocales(int32_t& count) 1.822 +{ 1.823 + return Locale::getAvailableLocales(count); 1.824 +} 1.825 + 1.826 +// ------------------------------------------ 1.827 +// 1.828 +// Registration 1.829 +// 1.830 +//------------------------------------------- 1.831 + 1.832 +#if !UCONFIG_NO_SERVICE 1.833 + 1.834 +// ------------------------------------- 1.835 + 1.836 +class ICUNumberFormatFactory : public ICUResourceBundleFactory { 1.837 +public: 1.838 + virtual ~ICUNumberFormatFactory(); 1.839 +protected: 1.840 + virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const { 1.841 + return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status); 1.842 + } 1.843 +}; 1.844 + 1.845 +ICUNumberFormatFactory::~ICUNumberFormatFactory() {} 1.846 + 1.847 +// ------------------------------------- 1.848 + 1.849 +class NFFactory : public LocaleKeyFactory { 1.850 +private: 1.851 + NumberFormatFactory* _delegate; 1.852 + Hashtable* _ids; 1.853 + 1.854 +public: 1.855 + NFFactory(NumberFormatFactory* delegate) 1.856 + : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE) 1.857 + , _delegate(delegate) 1.858 + , _ids(NULL) 1.859 + { 1.860 + } 1.861 + 1.862 + virtual ~NFFactory(); 1.863 + 1.864 + virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 1.865 + { 1.866 + if (handlesKey(key, status)) { 1.867 + const LocaleKey& lkey = (const LocaleKey&)key; 1.868 + Locale loc; 1.869 + lkey.canonicalLocale(loc); 1.870 + int32_t kind = lkey.kind(); 1.871 + 1.872 + UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)kind); 1.873 + if (result == NULL) { 1.874 + result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status); 1.875 + } 1.876 + return result; 1.877 + } 1.878 + return NULL; 1.879 + } 1.880 + 1.881 +protected: 1.882 + /** 1.883 + * Return the set of ids that this factory supports (visible or 1.884 + * otherwise). This can be called often and might need to be 1.885 + * cached if it is expensive to create. 1.886 + */ 1.887 + virtual const Hashtable* getSupportedIDs(UErrorCode& status) const 1.888 + { 1.889 + if (U_SUCCESS(status)) { 1.890 + if (!_ids) { 1.891 + int32_t count = 0; 1.892 + const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status); 1.893 + ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */ 1.894 + if (_ids) { 1.895 + for (int i = 0; i < count; ++i) { 1.896 + _ids->put(idlist[i], (void*)this, status); 1.897 + } 1.898 + } 1.899 + } 1.900 + return _ids; 1.901 + } 1.902 + return NULL; 1.903 + } 1.904 +}; 1.905 + 1.906 +NFFactory::~NFFactory() 1.907 +{ 1.908 + delete _delegate; 1.909 + delete _ids; 1.910 +} 1.911 + 1.912 +class ICUNumberFormatService : public ICULocaleService { 1.913 +public: 1.914 + ICUNumberFormatService() 1.915 + : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format")) 1.916 + { 1.917 + UErrorCode status = U_ZERO_ERROR; 1.918 + registerFactory(new ICUNumberFormatFactory(), status); 1.919 + } 1.920 + 1.921 + virtual ~ICUNumberFormatService(); 1.922 + 1.923 + virtual UObject* cloneInstance(UObject* instance) const { 1.924 + return ((NumberFormat*)instance)->clone(); 1.925 + } 1.926 + 1.927 + virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const { 1.928 + LocaleKey& lkey = (LocaleKey&)key; 1.929 + int32_t kind = lkey.kind(); 1.930 + Locale loc; 1.931 + lkey.currentLocale(loc); 1.932 + return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status); 1.933 + } 1.934 + 1.935 + virtual UBool isDefault() const { 1.936 + return countFactories() == 1; 1.937 + } 1.938 +}; 1.939 + 1.940 +ICUNumberFormatService::~ICUNumberFormatService() {} 1.941 + 1.942 +// ------------------------------------- 1.943 + 1.944 +static void U_CALLCONV initNumberFormatService() { 1.945 + U_ASSERT(gService == NULL); 1.946 + ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); 1.947 + gService = new ICUNumberFormatService(); 1.948 +} 1.949 + 1.950 +static ICULocaleService* 1.951 +getNumberFormatService(void) 1.952 +{ 1.953 + umtx_initOnce(gServiceInitOnce, &initNumberFormatService); 1.954 + return gService; 1.955 +} 1.956 + 1.957 +static UBool haveService() { 1.958 + return !gServiceInitOnce.isReset() && (getNumberFormatService() != NULL); 1.959 +} 1.960 + 1.961 +// ------------------------------------- 1.962 + 1.963 +URegistryKey U_EXPORT2 1.964 +NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status) 1.965 +{ 1.966 + ICULocaleService *service = getNumberFormatService(); 1.967 + if (service) { 1.968 + NFFactory *tempnnf = new NFFactory(toAdopt); 1.969 + if (tempnnf != NULL) { 1.970 + return service->registerFactory(tempnnf, status); 1.971 + } 1.972 + } 1.973 + status = U_MEMORY_ALLOCATION_ERROR; 1.974 + return NULL; 1.975 +} 1.976 + 1.977 +// ------------------------------------- 1.978 + 1.979 +UBool U_EXPORT2 1.980 +NumberFormat::unregister(URegistryKey key, UErrorCode& status) 1.981 +{ 1.982 + if (U_FAILURE(status)) { 1.983 + return FALSE; 1.984 + } 1.985 + if (haveService()) { 1.986 + return gService->unregister(key, status); 1.987 + } else { 1.988 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.989 + return FALSE; 1.990 + } 1.991 +} 1.992 + 1.993 +// ------------------------------------- 1.994 +StringEnumeration* U_EXPORT2 1.995 +NumberFormat::getAvailableLocales(void) 1.996 +{ 1.997 + ICULocaleService *service = getNumberFormatService(); 1.998 + if (service) { 1.999 + return service->getAvailableLocales(); 1.1000 + } 1.1001 + return NULL; // no way to return error condition 1.1002 +} 1.1003 +#endif /* UCONFIG_NO_SERVICE */ 1.1004 +// ------------------------------------- 1.1005 + 1.1006 +NumberFormat* U_EXPORT2 1.1007 +NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) { 1.1008 +#if !UCONFIG_NO_SERVICE 1.1009 + if (haveService()) { 1.1010 + return (NumberFormat*)gService->get(loc, kind, status); 1.1011 + } 1.1012 +#endif 1.1013 + return makeInstance(loc, kind, status); 1.1014 +} 1.1015 + 1.1016 + 1.1017 +// ------------------------------------- 1.1018 +// Checks if the thousand/10 thousand grouping is used in the 1.1019 +// NumberFormat instance. 1.1020 + 1.1021 +UBool 1.1022 +NumberFormat::isGroupingUsed() const 1.1023 +{ 1.1024 + return fGroupingUsed; 1.1025 +} 1.1026 + 1.1027 +// ------------------------------------- 1.1028 +// Sets to use the thousand/10 thousand grouping in the 1.1029 +// NumberFormat instance. 1.1030 + 1.1031 +void 1.1032 +NumberFormat::setGroupingUsed(UBool newValue) 1.1033 +{ 1.1034 + fGroupingUsed = newValue; 1.1035 +} 1.1036 + 1.1037 +// ------------------------------------- 1.1038 +// Gets the maximum number of digits for the integral part for 1.1039 +// this NumberFormat instance. 1.1040 + 1.1041 +int32_t NumberFormat::getMaximumIntegerDigits() const 1.1042 +{ 1.1043 + return fMaxIntegerDigits; 1.1044 +} 1.1045 + 1.1046 +// ------------------------------------- 1.1047 +// Sets the maximum number of digits for the integral part for 1.1048 +// this NumberFormat instance. 1.1049 + 1.1050 +void 1.1051 +NumberFormat::setMaximumIntegerDigits(int32_t newValue) 1.1052 +{ 1.1053 + fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gDefaultMaxIntegerDigits)); 1.1054 + if(fMinIntegerDigits > fMaxIntegerDigits) 1.1055 + fMinIntegerDigits = fMaxIntegerDigits; 1.1056 +} 1.1057 + 1.1058 +// ------------------------------------- 1.1059 +// Gets the minimum number of digits for the integral part for 1.1060 +// this NumberFormat instance. 1.1061 + 1.1062 +int32_t 1.1063 +NumberFormat::getMinimumIntegerDigits() const 1.1064 +{ 1.1065 + return fMinIntegerDigits; 1.1066 +} 1.1067 + 1.1068 +// ------------------------------------- 1.1069 +// Sets the minimum number of digits for the integral part for 1.1070 +// this NumberFormat instance. 1.1071 + 1.1072 +void 1.1073 +NumberFormat::setMinimumIntegerDigits(int32_t newValue) 1.1074 +{ 1.1075 + fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gDefaultMinIntegerDigits)); 1.1076 + if(fMinIntegerDigits > fMaxIntegerDigits) 1.1077 + fMaxIntegerDigits = fMinIntegerDigits; 1.1078 +} 1.1079 + 1.1080 +// ------------------------------------- 1.1081 +// Gets the maximum number of digits for the fractional part for 1.1082 +// this NumberFormat instance. 1.1083 + 1.1084 +int32_t 1.1085 +NumberFormat::getMaximumFractionDigits() const 1.1086 +{ 1.1087 + return fMaxFractionDigits; 1.1088 +} 1.1089 + 1.1090 +// ------------------------------------- 1.1091 +// Sets the maximum number of digits for the fractional part for 1.1092 +// this NumberFormat instance. 1.1093 + 1.1094 +void 1.1095 +NumberFormat::setMaximumFractionDigits(int32_t newValue) 1.1096 +{ 1.1097 + fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gDefaultMaxIntegerDigits)); 1.1098 + if(fMaxFractionDigits < fMinFractionDigits) 1.1099 + fMinFractionDigits = fMaxFractionDigits; 1.1100 +} 1.1101 + 1.1102 +// ------------------------------------- 1.1103 +// Gets the minimum number of digits for the fractional part for 1.1104 +// this NumberFormat instance. 1.1105 + 1.1106 +int32_t 1.1107 +NumberFormat::getMinimumFractionDigits() const 1.1108 +{ 1.1109 + return fMinFractionDigits; 1.1110 +} 1.1111 + 1.1112 +// ------------------------------------- 1.1113 +// Sets the minimum number of digits for the fractional part for 1.1114 +// this NumberFormat instance. 1.1115 + 1.1116 +void 1.1117 +NumberFormat::setMinimumFractionDigits(int32_t newValue) 1.1118 +{ 1.1119 + fMinFractionDigits = uprv_max(0, uprv_min(newValue, gDefaultMinIntegerDigits)); 1.1120 + if (fMaxFractionDigits < fMinFractionDigits) 1.1121 + fMaxFractionDigits = fMinFractionDigits; 1.1122 +} 1.1123 + 1.1124 +// ------------------------------------- 1.1125 + 1.1126 +void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { 1.1127 + if (U_FAILURE(ec)) { 1.1128 + return; 1.1129 + } 1.1130 + if (theCurrency) { 1.1131 + u_strncpy(fCurrency, theCurrency, 3); 1.1132 + fCurrency[3] = 0; 1.1133 + } else { 1.1134 + fCurrency[0] = 0; 1.1135 + } 1.1136 +} 1.1137 + 1.1138 +const UChar* NumberFormat::getCurrency() const { 1.1139 + return fCurrency; 1.1140 +} 1.1141 + 1.1142 +void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { 1.1143 + const UChar* c = getCurrency(); 1.1144 + if (*c != 0) { 1.1145 + u_strncpy(result, c, 3); 1.1146 + result[3] = 0; 1.1147 + } else { 1.1148 + const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec); 1.1149 + if (loc == NULL) { 1.1150 + loc = uloc_getDefault(); 1.1151 + } 1.1152 + ucurr_forLocale(loc, result, 4, &ec); 1.1153 + } 1.1154 +} 1.1155 + 1.1156 +// ------------------------------------- 1.1157 +// Creates the NumberFormat instance of the specified style (number, currency, 1.1158 +// or percent) for the desired locale. 1.1159 + 1.1160 +static void U_CALLCONV nscacheInit() { 1.1161 + U_ASSERT(NumberingSystem_cache == NULL); 1.1162 + ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); 1.1163 + UErrorCode status = U_ZERO_ERROR; 1.1164 + NumberingSystem_cache = uhash_open(uhash_hashLong, 1.1165 + uhash_compareLong, 1.1166 + NULL, 1.1167 + &status); 1.1168 + if (U_FAILURE(status)) { 1.1169 + // Number Format code will run with no cache if creation fails. 1.1170 + NumberingSystem_cache = NULL; 1.1171 + return; 1.1172 + } 1.1173 + uhash_setValueDeleter(NumberingSystem_cache, deleteNumberingSystem); 1.1174 +} 1.1175 + 1.1176 +UBool 1.1177 +NumberFormat::isStyleSupported(UNumberFormatStyle style) { 1.1178 + return gLastResortNumberPatterns[style] != NULL; 1.1179 +} 1.1180 + 1.1181 +NumberFormat* 1.1182 +NumberFormat::makeInstance(const Locale& desiredLocale, 1.1183 + UNumberFormatStyle style, 1.1184 + UErrorCode& status) { 1.1185 + return makeInstance(desiredLocale, style, false, status); 1.1186 +} 1.1187 + 1.1188 +NumberFormat* 1.1189 +NumberFormat::makeInstance(const Locale& desiredLocale, 1.1190 + UNumberFormatStyle style, 1.1191 + UBool mustBeDecimalFormat, 1.1192 + UErrorCode& status) { 1.1193 + if (U_FAILURE(status)) return NULL; 1.1194 + 1.1195 + if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) { 1.1196 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.1197 + return NULL; 1.1198 + } 1.1199 + 1.1200 + // Some styles are not supported. This is a result of merging 1.1201 + // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle. 1.1202 + // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations: 1.1203 + // this one and unum_open(). 1.1204 + // The UNUM_PATTERN_ styles are not supported here 1.1205 + // because this method does not take a pattern string. 1.1206 + if (!isStyleSupported(style)) { 1.1207 + status = U_UNSUPPORTED_ERROR; 1.1208 + return NULL; 1.1209 + } 1.1210 + 1.1211 +#if U_PLATFORM_USES_ONLY_WIN32_API 1.1212 + if (!mustBeDecimalFormat) { 1.1213 + char buffer[8]; 1.1214 + int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); 1.1215 + 1.1216 + // if the locale has "@compat=host", create a host-specific NumberFormat 1.1217 + if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { 1.1218 + Win32NumberFormat *f = NULL; 1.1219 + UBool curr = TRUE; 1.1220 + 1.1221 + switch (style) { 1.1222 + case UNUM_DECIMAL: 1.1223 + curr = FALSE; 1.1224 + // fall-through 1.1225 + 1.1226 + case UNUM_CURRENCY: 1.1227 + case UNUM_CURRENCY_ISO: // do not support plural formatting here 1.1228 + case UNUM_CURRENCY_PLURAL: 1.1229 + f = new Win32NumberFormat(desiredLocale, curr, status); 1.1230 + 1.1231 + if (U_SUCCESS(status)) { 1.1232 + return f; 1.1233 + } 1.1234 + 1.1235 + delete f; 1.1236 + break; 1.1237 + default: 1.1238 + break; 1.1239 + } 1.1240 + } 1.1241 + } 1.1242 +#endif 1.1243 + // Use numbering system cache hashtable 1.1244 + umtx_initOnce(gNSCacheInitOnce, &nscacheInit); 1.1245 + 1.1246 + // Get cached numbering system 1.1247 + LocalPointer<NumberingSystem> ownedNs; 1.1248 + NumberingSystem *ns = NULL; 1.1249 + if (NumberingSystem_cache != NULL) { 1.1250 + // TODO: Bad hash key usage, see ticket #8504. 1.1251 + int32_t hashKey = desiredLocale.hashCode(); 1.1252 + 1.1253 + Mutex lock(&nscacheMutex); 1.1254 + ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey); 1.1255 + if (ns == NULL) { 1.1256 + ns = NumberingSystem::createInstance(desiredLocale,status); 1.1257 + uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status); 1.1258 + } 1.1259 + } else { 1.1260 + ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); 1.1261 + ns = ownedNs.getAlias(); 1.1262 + } 1.1263 + 1.1264 + // check results of getting a numbering system 1.1265 + if (U_FAILURE(status)) { 1.1266 + return NULL; 1.1267 + } 1.1268 + 1.1269 + if (mustBeDecimalFormat && ns->isAlgorithmic()) { 1.1270 + status = U_UNSUPPORTED_ERROR; 1.1271 + return NULL; 1.1272 + } 1.1273 + 1.1274 + LocalPointer<DecimalFormatSymbols> symbolsToAdopt; 1.1275 + UnicodeString pattern; 1.1276 + LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status)); 1.1277 + if (U_FAILURE(status)) { 1.1278 + // We don't appear to have resource data available -- use the last-resort data 1.1279 + status = U_USING_FALLBACK_WARNING; 1.1280 + // When the data is unavailable, and locale isn't passed in, last resort data is used. 1.1281 + symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status)); 1.1282 + if (symbolsToAdopt.isNull()) { 1.1283 + status = U_MEMORY_ALLOCATION_ERROR; 1.1284 + return NULL; 1.1285 + } 1.1286 + 1.1287 + // Creates a DecimalFormat instance with the last resort number patterns. 1.1288 + pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); 1.1289 + } 1.1290 + else { 1.1291 + // Loads the decimal symbols of the desired locale. 1.1292 + symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status)); 1.1293 + if (symbolsToAdopt.isNull()) { 1.1294 + status = U_MEMORY_ALLOCATION_ERROR; 1.1295 + return NULL; 1.1296 + } 1.1297 + 1.1298 + UResourceBundle *resource = ownedResource.orphan(); 1.1299 + UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status); 1.1300 + resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status); 1.1301 + resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); 1.1302 + ownedResource.adoptInstead(resource); 1.1303 + 1.1304 + int32_t patLen = 0; 1.1305 + const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); 1.1306 + 1.1307 + // Didn't find a pattern specific to the numbering system, so fall back to "latn" 1.1308 + if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) { 1.1309 + status = U_ZERO_ERROR; 1.1310 + resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status); 1.1311 + resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); 1.1312 + patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); 1.1313 + } 1.1314 + 1.1315 + ures_close(numElements); 1.1316 + 1.1317 + // Creates the specified decimal format style of the desired locale. 1.1318 + pattern.setTo(TRUE, patResStr, patLen); 1.1319 + } 1.1320 + if (U_FAILURE(status)) { 1.1321 + return NULL; 1.1322 + } 1.1323 + if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){ 1.1324 + const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); 1.1325 + if(currPattern!=NULL){ 1.1326 + pattern.setTo(currPattern, u_strlen(currPattern)); 1.1327 + } 1.1328 + } 1.1329 + 1.1330 + 1.1331 + NumberFormat *f; 1.1332 + if (ns->isAlgorithmic()) { 1.1333 + UnicodeString nsDesc; 1.1334 + UnicodeString nsRuleSetGroup; 1.1335 + UnicodeString nsRuleSetName; 1.1336 + Locale nsLoc; 1.1337 + URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; 1.1338 + 1.1339 + nsDesc.setTo(ns->getDescription()); 1.1340 + int32_t firstSlash = nsDesc.indexOf(gSlash); 1.1341 + int32_t lastSlash = nsDesc.lastIndexOf(gSlash); 1.1342 + if ( lastSlash > firstSlash ) { 1.1343 + CharString nsLocID; 1.1344 + 1.1345 + nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status); 1.1346 + nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); 1.1347 + nsRuleSetName.setTo(nsDesc,lastSlash+1); 1.1348 + 1.1349 + nsLoc = Locale::createFromName(nsLocID.data()); 1.1350 + 1.1351 + UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); 1.1352 + if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { 1.1353 + desiredRulesType = URBNF_SPELLOUT; 1.1354 + } 1.1355 + } else { 1.1356 + nsLoc = desiredLocale; 1.1357 + nsRuleSetName.setTo(nsDesc); 1.1358 + } 1.1359 + 1.1360 + RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); 1.1361 + if (r == NULL) { 1.1362 + status = U_MEMORY_ALLOCATION_ERROR; 1.1363 + return NULL; 1.1364 + } 1.1365 + r->setDefaultRuleSet(nsRuleSetName,status); 1.1366 + f = r; 1.1367 + } else { 1.1368 + // replace single currency sign in the pattern with double currency sign 1.1369 + // if the style is UNUM_CURRENCY_ISO 1.1370 + if (style == UNUM_CURRENCY_ISO) { 1.1371 + pattern.findAndReplace(UnicodeString(TRUE, gSingleCurrencySign, 1), 1.1372 + UnicodeString(TRUE, gDoubleCurrencySign, 2)); 1.1373 + } 1.1374 + 1.1375 + // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. 1.1376 + DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); 1.1377 + f = new DecimalFormat(pattern, syms, style, status); 1.1378 + if (f == NULL) { 1.1379 + delete syms; 1.1380 + status = U_MEMORY_ALLOCATION_ERROR; 1.1381 + return NULL; 1.1382 + } 1.1383 + } 1.1384 + 1.1385 + f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), 1.1386 + ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); 1.1387 + if (U_FAILURE(status)) { 1.1388 + delete f; 1.1389 + return NULL; 1.1390 + } 1.1391 + return f; 1.1392 +} 1.1393 + 1.1394 +U_NAMESPACE_END 1.1395 + 1.1396 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.1397 + 1.1398 +//eof