intl/icu/source/i18n/numfmt.cpp

changeset 0
6474c204b198
     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

mercurial