1/*
2*******************************************************************************
3* Copyright (C) 1997-2009, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7* File NUMFMT.CPP
8*
9* Modification History:
10*
11*   Date        Name        Description
12*   02/19/97    aliu        Converted from java.
13*   03/18/97    clhuang     Implemented with C++ APIs.
14*   04/17/97    aliu        Enlarged MAX_INTEGER_DIGITS to fully accomodate the
15*                           largest double, by default.
16*                           Changed DigitCount to int per code review.
17*    07/20/98    stephen        Changed operator== to check for grouping
18*                            Changed setMaxIntegerDigits per Java implementation.
19*                            Changed setMinIntegerDigits per Java implementation.
20*                            Changed setMinFractionDigits per Java implementation.
21*                            Changed setMaxFractionDigits per Java implementation.
22********************************************************************************
23*/
24
25#include "unicode/utypes.h"
26
27#if !UCONFIG_NO_FORMATTING
28
29#include "unicode/numfmt.h"
30#include "unicode/locid.h"
31#include "unicode/dcfmtsym.h"
32#include "unicode/decimfmt.h"
33#include "unicode/ustring.h"
34#include "unicode/ucurr.h"
35#include "unicode/curramt.h"
36#include "unicode/numsys.h"
37#include "unicode/rbnf.h"
38#include "winnmfmt.h"
39#include "uresimp.h"
40#include "uhash.h"
41#include "cmemory.h"
42#include "servloc.h"
43#include "ucln_in.h"
44#include "cstring.h"
45#include "putilimp.h"
46#include <float.h>
47
48//#define FMT_DEBUG
49
50#ifdef FMT_DEBUG
51#include <stdio.h>
52static void debugout(UnicodeString s) {
53    char buf[2000];
54    s.extract((int32_t) 0, s.length(), buf);
55    printf("%s", buf);
56}
57#define debug(x) printf("%s", x);
58#else
59#define debugout(x)
60#define debug(x)
61#endif
62
63// If no number pattern can be located for a locale, this is the last
64// resort.
65static const UChar gLastResortDecimalPat[] = {
66    0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */
67};
68static const UChar gLastResortCurrencyPat[] = {
69    0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "$#0.00;($#0.00)" */
70};
71static const UChar gLastResortPercentPat[] = {
72    0x23, 0x30, 0x25, 0 /* "#0%" */
73};
74static const UChar gLastResortScientificPat[] = {
75    0x23, 0x45, 0x30, 0 /* "#E0" */
76};
77static const UChar gLastResortIsoCurrencyPat[] = {
78    0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "\u00A4\u00A4#0.00;(\u00A4\u00A4#0.00)" */
79};
80static const UChar gLastResortPluralCurrencyPat[] = {
81    0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/
82};
83
84static const UChar gSingleCurrencySign[] = {0xA4, 0};
85static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0};
86
87static const UChar gSlash = 0x2f;
88
89// If the maximum base 10 exponent were 4, then the largest number would
90// be 99,999 which has 5 digits.
91// On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit
92static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1;
93static const int32_t gMinIntegerDigits = 127;
94
95static const UChar * const gLastResortNumberPatterns[] =
96{
97    gLastResortDecimalPat,
98    gLastResortCurrencyPat,
99    gLastResortPercentPat,
100    gLastResortScientificPat,
101    gLastResortIsoCurrencyPat,
102    gLastResortPluralCurrencyPat,
103};
104
105// *****************************************************************************
106// class NumberFormat
107// *****************************************************************************
108
109U_NAMESPACE_BEGIN
110
111UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat)
112
113#if !UCONFIG_NO_SERVICE
114// -------------------------------------
115// SimpleNumberFormatFactory implementation
116NumberFormatFactory::~NumberFormatFactory() {}
117SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible)
118    : _visible(visible)
119{
120    LocaleUtility::initNameFromLocale(locale, _id);
121}
122
123SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {}
124
125UBool SimpleNumberFormatFactory::visible(void) const {
126    return _visible;
127}
128
129const UnicodeString *
130SimpleNumberFormatFactory::getSupportedIDs(int32_t &count, UErrorCode& status) const
131{
132    if (U_SUCCESS(status)) {
133        count = 1;
134        return &_id;
135    }
136    count = 0;
137    return NULL;
138}
139#endif /* #if !UCONFIG_NO_SERVICE */
140
141// -------------------------------------
142// default constructor
143NumberFormat::NumberFormat()
144:   fGroupingUsed(TRUE),
145    fMaxIntegerDigits(gMaxIntegerDigits),
146    fMinIntegerDigits(1),
147    fMaxFractionDigits(3), // invariant, >= minFractionDigits
148    fMinFractionDigits(0),
149    fParseIntegerOnly(FALSE)
150{
151    fCurrency[0] = 0;
152}
153
154// -------------------------------------
155
156NumberFormat::~NumberFormat()
157{
158}
159
160// -------------------------------------
161// copy constructor
162
163NumberFormat::NumberFormat(const NumberFormat &source)
164:   Format(source)
165{
166    *this = source;
167}
168
169// -------------------------------------
170// assignment operator
171
172NumberFormat&
173NumberFormat::operator=(const NumberFormat& rhs)
174{
175    if (this != &rhs)
176    {
177        fGroupingUsed = rhs.fGroupingUsed;
178        fMaxIntegerDigits = rhs.fMaxIntegerDigits;
179        fMinIntegerDigits = rhs.fMinIntegerDigits;
180        fMaxFractionDigits = rhs.fMaxFractionDigits;
181        fMinFractionDigits = rhs.fMinFractionDigits;
182        fParseIntegerOnly = rhs.fParseIntegerOnly;
183        u_strncpy(fCurrency, rhs.fCurrency, 4);
184    }
185    return *this;
186}
187
188// -------------------------------------
189
190UBool
191NumberFormat::operator==(const Format& that) const
192{
193    // Format::operator== guarantees this cast is safe
194    NumberFormat* other = (NumberFormat*)&that;
195
196#ifdef FMT_DEBUG
197    // This code makes it easy to determine why two format objects that should
198    // be equal aren't.
199    UBool first = TRUE;
200    if (!Format::operator==(that)) {
201        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
202        debug("Format::!=");
203    }
204    if (!(fMaxIntegerDigits == other->fMaxIntegerDigits &&
205          fMinIntegerDigits == other->fMinIntegerDigits)) {
206        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
207        debug("Integer digits !=");
208    }
209    if (!(fMaxFractionDigits == other->fMaxFractionDigits &&
210          fMinFractionDigits == other->fMinFractionDigits)) {
211        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
212        debug("Fraction digits !=");
213    }
214    if (!(fGroupingUsed == other->fGroupingUsed)) {
215        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
216        debug("fGroupingUsed != ");
217    }
218    if (!(fParseIntegerOnly == other->fParseIntegerOnly)) {
219        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
220        debug("fParseIntegerOnly != ");
221    }
222    if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) {
223        if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
224        debug("fCurrency !=");
225    }
226    if (!first) { printf(" ]"); }
227#endif
228
229    return ((this == &that) ||
230            ((Format::operator==(that) &&
231              fMaxIntegerDigits == other->fMaxIntegerDigits &&
232              fMinIntegerDigits == other->fMinIntegerDigits &&
233              fMaxFractionDigits == other->fMaxFractionDigits &&
234              fMinFractionDigits == other->fMinFractionDigits &&
235              fGroupingUsed == other->fGroupingUsed &&
236              fParseIntegerOnly == other->fParseIntegerOnly &&
237              u_strcmp(fCurrency, other->fCurrency) == 0)));
238}
239
240// -------------------------------------x
241// Formats the number object and save the format
242// result in the toAppendTo string buffer.
243
244UnicodeString&
245NumberFormat::format(const Formattable& obj,
246                        UnicodeString& appendTo,
247                        FieldPosition& pos,
248                        UErrorCode& status) const
249{
250    if (U_FAILURE(status)) return appendTo;
251
252    NumberFormat* nonconst = (NumberFormat*) this;
253    const Formattable* n = &obj;
254
255    UChar save[4];
256    UBool setCurr = FALSE;
257    const UObject* o = obj.getObject(); // most commonly o==NULL
258    if (o != NULL &&
259        o->getDynamicClassID() == CurrencyAmount::getStaticClassID()) {
260        // getISOCurrency() returns a pointer to internal storage, so we
261        // copy it to retain it across the call to setCurrency().
262        const CurrencyAmount* amt = (const CurrencyAmount*) o;
263        const UChar* curr = amt->getISOCurrency();
264        u_strcpy(save, getCurrency());
265        setCurr = (u_strcmp(curr, save) != 0);
266        if (setCurr) {
267            nonconst->setCurrency(curr, status);
268        }
269        n = &amt->getNumber();
270    }
271
272    switch (n->getType()) {
273    case Formattable::kDouble:
274        format(n->getDouble(), appendTo, pos);
275        break;
276    case Formattable::kLong:
277        format(n->getLong(), appendTo, pos);
278        break;
279    case Formattable::kInt64:
280        format(n->getInt64(), appendTo, pos);
281        break;
282    default:
283        status = U_INVALID_FORMAT_ERROR;
284        break;
285    }
286
287    if (setCurr) {
288        UErrorCode ok = U_ZERO_ERROR;
289        nonconst->setCurrency(save, ok); // always restore currency
290    }
291    return appendTo;
292}
293
294// -------------------------------------
295
296UnicodeString&
297NumberFormat::format(int64_t number,
298                     UnicodeString& appendTo,
299                     FieldPosition& pos) const
300{
301    // default so we don't introduce a new abstract method
302    return format((int32_t)number, appendTo, pos);
303}
304
305// -------------------------------------
306// Parses the string and save the result object as well
307// as the final parsed position.
308
309void
310NumberFormat::parseObject(const UnicodeString& source,
311                             Formattable& result,
312                             ParsePosition& parse_pos) const
313{
314    parse(source, result, parse_pos);
315}
316
317// -------------------------------------
318// Formats a double number and save the result in a string.
319
320UnicodeString&
321NumberFormat::format(double number, UnicodeString& appendTo) const
322{
323    FieldPosition pos(0);
324    return format(number, appendTo, pos);
325}
326
327// -------------------------------------
328// Formats a long number and save the result in a string.
329
330UnicodeString&
331NumberFormat::format(int32_t number, UnicodeString& appendTo) const
332{
333    FieldPosition pos(0);
334    return format(number, appendTo, pos);
335}
336
337// -------------------------------------
338// Formats a long number and save the result in a string.
339
340UnicodeString&
341NumberFormat::format(int64_t number, UnicodeString& appendTo) const
342{
343    FieldPosition pos(0);
344    return format(number, appendTo, pos);
345}
346
347// -------------------------------------
348// Parses the text and save the result object.  If the returned
349// parse position is 0, that means the parsing failed, the status
350// code needs to be set to failure.  Ignores the returned parse
351// position, otherwise.
352
353void
354NumberFormat::parse(const UnicodeString& text,
355                        Formattable& result,
356                        UErrorCode& status) const
357{
358    if (U_FAILURE(status)) return;
359
360    ParsePosition parsePosition(0);
361    parse(text, result, parsePosition);
362    if (parsePosition.getIndex() == 0) {
363        status = U_INVALID_FORMAT_ERROR;
364    }
365}
366
367Formattable& NumberFormat::parseCurrency(const UnicodeString& text,
368                                         Formattable& result,
369                                         ParsePosition& pos) const {
370    // Default implementation only -- subclasses should override
371    int32_t start = pos.getIndex();
372    parse(text, result, pos);
373    if (pos.getIndex() != start) {
374        UChar curr[4];
375        UErrorCode ec = U_ZERO_ERROR;
376        getEffectiveCurrency(curr, ec);
377        if (U_SUCCESS(ec)) {
378            Formattable n(result);
379            CurrencyAmount *tempCurAmnt = new CurrencyAmount(n, curr, ec);  // Use for null testing.
380            if (U_FAILURE(ec) || tempCurAmnt == NULL) {
381                pos.setIndex(start); // indicate failure
382            } else {
383            	result.adoptObject(tempCurAmnt);
384            }
385        }
386    }
387    return result;
388}
389
390// -------------------------------------
391// Sets to only parse integers.
392
393void
394NumberFormat::setParseIntegerOnly(UBool value)
395{
396    fParseIntegerOnly = value;
397}
398
399// -------------------------------------
400// Create a number style NumberFormat instance with the default locale.
401
402NumberFormat* U_EXPORT2
403NumberFormat::createInstance(UErrorCode& status)
404{
405    return createInstance(Locale::getDefault(), kNumberStyle, status);
406}
407
408// -------------------------------------
409// Create a number style NumberFormat instance with the inLocale locale.
410
411NumberFormat* U_EXPORT2
412NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
413{
414    return createInstance(inLocale, kNumberStyle, status);
415}
416
417// -------------------------------------
418// Create a currency style NumberFormat instance with the default locale.
419
420NumberFormat* U_EXPORT2
421NumberFormat::createCurrencyInstance(UErrorCode& status)
422{
423    return createCurrencyInstance(Locale::getDefault(),  status);
424}
425
426// -------------------------------------
427// Create a currency style NumberFormat instance with the inLocale locale.
428
429NumberFormat* U_EXPORT2
430NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
431{
432    return createInstance(inLocale, kCurrencyStyle, status);
433}
434
435// -------------------------------------
436// Create a percent style NumberFormat instance with the default locale.
437
438NumberFormat* U_EXPORT2
439NumberFormat::createPercentInstance(UErrorCode& status)
440{
441    return createInstance(Locale::getDefault(), kPercentStyle, status);
442}
443
444// -------------------------------------
445// Create a percent style NumberFormat instance with the inLocale locale.
446
447NumberFormat* U_EXPORT2
448NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
449{
450    return createInstance(inLocale, kPercentStyle, status);
451}
452
453// -------------------------------------
454// Create a scientific style NumberFormat instance with the default locale.
455
456NumberFormat* U_EXPORT2
457NumberFormat::createScientificInstance(UErrorCode& status)
458{
459    return createInstance(Locale::getDefault(), kScientificStyle, status);
460}
461
462// -------------------------------------
463// Create a scientific style NumberFormat instance with the inLocale locale.
464
465NumberFormat* U_EXPORT2
466NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
467{
468    return createInstance(inLocale, kScientificStyle, status);
469}
470
471// -------------------------------------
472
473const Locale* U_EXPORT2
474NumberFormat::getAvailableLocales(int32_t& count)
475{
476    return Locale::getAvailableLocales(count);
477}
478
479// ------------------------------------------
480//
481// Registration
482//
483//-------------------------------------------
484
485#if !UCONFIG_NO_SERVICE
486static ICULocaleService* gService = NULL;
487
488/**
489 * Release all static memory held by numberformat.
490 */
491U_CDECL_BEGIN
492static UBool U_CALLCONV numfmt_cleanup(void) {
493    if (gService) {
494        delete gService;
495        gService = NULL;
496    }
497    return TRUE;
498}
499U_CDECL_END
500
501// -------------------------------------
502
503class ICUNumberFormatFactory : public ICUResourceBundleFactory {
504protected:
505    virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
506        // !!! kind is not an EStyles, need to determine how to handle this
507        return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
508    }
509};
510
511// -------------------------------------
512
513class NFFactory : public LocaleKeyFactory {
514private:
515    NumberFormatFactory* _delegate;
516    Hashtable* _ids;
517
518public:
519    NFFactory(NumberFormatFactory* delegate)
520        : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
521        , _delegate(delegate)
522        , _ids(NULL)
523    {
524    }
525
526    virtual ~NFFactory()
527    {
528        delete _delegate;
529        delete _ids;
530    }
531
532    virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
533    {
534        if (handlesKey(key, status)) {
535            const LocaleKey& lkey = (const LocaleKey&)key;
536            Locale loc;
537            lkey.canonicalLocale(loc);
538            int32_t kind = lkey.kind();
539
540            UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1));
541            if (result == NULL) {
542                result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
543            }
544            return result;
545        }
546        return NULL;
547    }
548
549protected:
550    /**
551     * Return the set of ids that this factory supports (visible or
552     * otherwise).  This can be called often and might need to be
553     * cached if it is expensive to create.
554     */
555    virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
556    {
557        if (U_SUCCESS(status)) {
558            if (!_ids) {
559                int32_t count = 0;
560                const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status);
561                ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */
562                if (_ids) {
563                    for (int i = 0; i < count; ++i) {
564                        _ids->put(idlist[i], (void*)this, status);
565                    }
566                }
567            }
568            return _ids;
569        }
570        return NULL;
571    }
572};
573
574class ICUNumberFormatService : public ICULocaleService {
575public:
576    ICUNumberFormatService()
577        : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format"))
578    {
579        UErrorCode status = U_ZERO_ERROR;
580        registerFactory(new ICUNumberFormatFactory(), status);
581    }
582
583    virtual UObject* cloneInstance(UObject* instance) const {
584        return ((NumberFormat*)instance)->clone();
585    }
586
587    virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const {
588        LocaleKey& lkey = (LocaleKey&)key;
589        int32_t kind = lkey.kind();
590        Locale loc;
591        lkey.currentLocale(loc);
592        return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
593    }
594
595    virtual UBool isDefault() const {
596        return countFactories() == 1;
597    }
598};
599
600// -------------------------------------
601
602static ICULocaleService*
603getNumberFormatService(void)
604{
605    UBool needInit;
606    UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
607    if (needInit) {
608        ICULocaleService * newservice = new ICUNumberFormatService();
609        if (newservice) {
610            umtx_lock(NULL);
611            if (gService == NULL) {
612                gService = newservice;
613                newservice = NULL;
614            }
615            umtx_unlock(NULL);
616        }
617        if (newservice) {
618            delete newservice;
619        } else {
620            // we won the contention, this thread can register cleanup.
621            ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
622        }
623    }
624    return gService;
625}
626
627// -------------------------------------
628
629URegistryKey U_EXPORT2
630NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
631{
632  ICULocaleService *service = getNumberFormatService();
633  if (service) {
634	  NFFactory *tempnnf = new NFFactory(toAdopt);
635	  if (tempnnf != NULL) {
636		  return service->registerFactory(tempnnf, status);
637	  }
638  }
639  status = U_MEMORY_ALLOCATION_ERROR;
640  return NULL;
641}
642
643// -------------------------------------
644
645UBool U_EXPORT2
646NumberFormat::unregister(URegistryKey key, UErrorCode& status)
647{
648    if (U_SUCCESS(status)) {
649        UBool haveService;
650        UMTX_CHECK(NULL, gService != NULL, haveService);
651        if (haveService) {
652            return gService->unregister(key, status);
653        }
654        status = U_ILLEGAL_ARGUMENT_ERROR;
655    }
656    return FALSE;
657}
658
659// -------------------------------------
660StringEnumeration* U_EXPORT2
661NumberFormat::getAvailableLocales(void)
662{
663  ICULocaleService *service = getNumberFormatService();
664  if (service) {
665    return service->getAvailableLocales();
666  }
667  return NULL; // no way to return error condition
668}
669#endif /* UCONFIG_NO_SERVICE */
670// -------------------------------------
671
672NumberFormat* U_EXPORT2
673NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status)
674{
675#if !UCONFIG_NO_SERVICE
676    UBool haveService;
677    UMTX_CHECK(NULL, gService != NULL, haveService);
678    if (haveService) {
679        return (NumberFormat*)gService->get(loc, kind, status);
680    }
681    else
682#endif
683    {
684        return makeInstance(loc, kind, status);
685    }
686}
687
688
689// -------------------------------------
690// Checks if the thousand/10 thousand grouping is used in the
691// NumberFormat instance.
692
693UBool
694NumberFormat::isGroupingUsed() const
695{
696    return fGroupingUsed;
697}
698
699// -------------------------------------
700// Sets to use the thousand/10 thousand grouping in the
701// NumberFormat instance.
702
703void
704NumberFormat::setGroupingUsed(UBool newValue)
705{
706    fGroupingUsed = newValue;
707}
708
709// -------------------------------------
710// Gets the maximum number of digits for the integral part for
711// this NumberFormat instance.
712
713int32_t NumberFormat::getMaximumIntegerDigits() const
714{
715    return fMaxIntegerDigits;
716}
717
718// -------------------------------------
719// Sets the maximum number of digits for the integral part for
720// this NumberFormat instance.
721
722void
723NumberFormat::setMaximumIntegerDigits(int32_t newValue)
724{
725    fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
726    if(fMinIntegerDigits > fMaxIntegerDigits)
727        fMinIntegerDigits = fMaxIntegerDigits;
728}
729
730// -------------------------------------
731// Gets the minimum number of digits for the integral part for
732// this NumberFormat instance.
733
734int32_t
735NumberFormat::getMinimumIntegerDigits() const
736{
737    return fMinIntegerDigits;
738}
739
740// -------------------------------------
741// Sets the minimum number of digits for the integral part for
742// this NumberFormat instance.
743
744void
745NumberFormat::setMinimumIntegerDigits(int32_t newValue)
746{
747    fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
748    if(fMinIntegerDigits > fMaxIntegerDigits)
749        fMaxIntegerDigits = fMinIntegerDigits;
750}
751
752// -------------------------------------
753// Gets the maximum number of digits for the fractional part for
754// this NumberFormat instance.
755
756int32_t
757NumberFormat::getMaximumFractionDigits() const
758{
759    return fMaxFractionDigits;
760}
761
762// -------------------------------------
763// Sets the maximum number of digits for the fractional part for
764// this NumberFormat instance.
765
766void
767NumberFormat::setMaximumFractionDigits(int32_t newValue)
768{
769    fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
770    if(fMaxFractionDigits < fMinFractionDigits)
771        fMinFractionDigits = fMaxFractionDigits;
772}
773
774// -------------------------------------
775// Gets the minimum number of digits for the fractional part for
776// this NumberFormat instance.
777
778int32_t
779NumberFormat::getMinimumFractionDigits() const
780{
781    return fMinFractionDigits;
782}
783
784// -------------------------------------
785// Sets the minimum number of digits for the fractional part for
786// this NumberFormat instance.
787
788void
789NumberFormat::setMinimumFractionDigits(int32_t newValue)
790{
791    fMinFractionDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
792    if (fMaxFractionDigits < fMinFractionDigits)
793        fMaxFractionDigits = fMinFractionDigits;
794}
795
796// -------------------------------------
797
798void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
799    if (U_FAILURE(ec)) {
800        return;
801    }
802    if (theCurrency) {
803        u_strncpy(fCurrency, theCurrency, 3);
804        fCurrency[3] = 0;
805    } else {
806        fCurrency[0] = 0;
807    }
808}
809
810const UChar* NumberFormat::getCurrency() const {
811    return fCurrency;
812}
813
814void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
815    const UChar* c = getCurrency();
816    if (*c != 0) {
817        u_strncpy(result, c, 3);
818        result[3] = 0;
819    } else {
820        const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
821        if (loc == NULL) {
822            loc = uloc_getDefault();
823        }
824        ucurr_forLocale(loc, result, 4, &ec);
825    }
826}
827
828// -------------------------------------
829// Creates the NumberFormat instance of the specified style (number, currency,
830// or percent) for the desired locale.
831
832NumberFormat*
833NumberFormat::makeInstance(const Locale& desiredLocale,
834                           EStyles style,
835                           UErrorCode& status)
836{
837    if (U_FAILURE(status)) return NULL;
838
839    if (style < 0 || style >= kStyleCount) {
840        status = U_ILLEGAL_ARGUMENT_ERROR;
841        return NULL;
842    }
843
844#ifdef U_WINDOWS
845    char buffer[8];
846    int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
847
848    // if the locale has "@compat=host", create a host-specific NumberFormat
849    if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
850        Win32NumberFormat *f = NULL;
851        UBool curr = TRUE;
852
853        switch (style) {
854        case kNumberStyle:
855            curr = FALSE;
856            // fall-through
857
858        case kCurrencyStyle:
859        case kIsoCurrencyStyle: // do not support plural formatting here
860        case kPluralCurrencyStyle:
861            f = new Win32NumberFormat(desiredLocale, curr, status);
862
863            if (U_SUCCESS(status)) {
864                return f;
865            }
866
867            delete f;
868            break;
869
870        default:
871            break;
872        }
873    }
874#endif
875
876    NumberFormat* f = NULL;
877    DecimalFormatSymbols* symbolsToAdopt = NULL;
878    UnicodeString pattern;
879    UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status);
880    UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status);
881    NumberingSystem *ns = NULL;
882    UBool deleteSymbols = TRUE;
883
884    if (U_FAILURE(status)) {
885        // We don't appear to have resource data available -- use the last-resort data
886        status = U_USING_FALLBACK_WARNING;
887        // When the data is unavailable, and locale isn't passed in, last resort data is used.
888        symbolsToAdopt = new DecimalFormatSymbols(status);
889
890        // Creates a DecimalFormat instance with the last resort number patterns.
891        pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
892    }
893    else {
894        // If not all the styled patterns exists for the NumberFormat in this locale,
895        // sets the status code to failure and returns nil.
896        if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0])) -2 ) { //minus 2: ISO and plural
897            status = U_INVALID_FORMAT_ERROR;
898            goto cleanup;
899        }
900
901        // Loads the decimal symbols of the desired locale.
902        symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
903
904        int32_t patLen = 0;
905
906        /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
907         * the pattern is the same as the pattern of CURRENCYSTYLE
908         * but by replacing the single currency sign with
909         * double currency sign or triple currency sign.
910         */
911        int styleInNumberPattern = ((style == kIsoCurrencyStyle ||
912                                     style == kPluralCurrencyStyle) ?
913                                    kCurrencyStyle : style);
914
915        const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)styleInNumberPattern, &patLen, &status);
916
917        // Creates the specified decimal format style of the desired locale.
918        pattern.setTo(TRUE, patResStr, patLen);
919    }
920    if (U_FAILURE(status) || symbolsToAdopt == NULL) {
921        goto cleanup;
922    }
923    if(style==kCurrencyStyle || style == kIsoCurrencyStyle){
924        const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
925        if(currPattern!=NULL){
926            pattern.setTo(currPattern, u_strlen(currPattern));
927        }
928    }
929
930    ns = NumberingSystem::createInstance(desiredLocale,status);
931
932    if (U_FAILURE(status)) {
933        goto cleanup;
934    }
935
936    if (ns->isAlgorithmic()) {
937        UnicodeString nsDesc;
938        UnicodeString nsRuleSetGroup;
939        UnicodeString nsRuleSetName;
940        Locale nsLoc;
941        URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM;
942
943        nsDesc.setTo(ns->getDescription());
944        int32_t firstSlash = nsDesc.indexOf(gSlash);
945        int32_t lastSlash = nsDesc.lastIndexOf(gSlash);
946        if ( lastSlash > firstSlash ) {
947            char nsLocID[ULOC_FULLNAME_CAPACITY];
948
949            nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV);
950            nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1);
951            nsRuleSetName.setTo(nsDesc,lastSlash+1);
952
953            nsLoc = Locale::createFromName(nsLocID);
954
955            UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules");
956            if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) {
957                desiredRulesType = URBNF_SPELLOUT;
958            }
959        } else {
960            nsLoc = desiredLocale;
961            nsRuleSetName.setTo(nsDesc);
962        }
963
964        RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status);
965
966        if (U_FAILURE(status) || r == NULL) {
967            goto cleanup;
968        }
969        r->setDefaultRuleSet(nsRuleSetName,status);
970        f = (NumberFormat *) r;
971
972    } else {
973        // replace single currency sign in the pattern with double currency sign
974        // if the style is kIsoCurrencyStyle
975        if (style == kIsoCurrencyStyle) {
976            pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign);
977        }
978
979        f = new DecimalFormat(pattern, symbolsToAdopt, style, status);
980        if (U_FAILURE(status) || f == NULL) {
981            goto cleanup;
982        }
983        deleteSymbols = FALSE;
984    }
985
986    f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status),
987                    ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status));
988
989cleanup:
990    ures_close(numberPatterns);
991    ures_close(resource);
992    if (ns) {
993       delete ns;
994    }
995    if (U_FAILURE(status)) {
996        /* If f exists, then it will delete the symbols */
997        if (f==NULL) {
998            delete symbolsToAdopt;
999        }
1000        else {
1001            delete f;
1002        }
1003        return NULL;
1004    }
1005    if (f == NULL || symbolsToAdopt == NULL) {
1006        status = U_MEMORY_ALLOCATION_ERROR;
1007        f = NULL;
1008    }
1009    if (deleteSymbols && symbolsToAdopt != NULL) {
1010        delete symbolsToAdopt;
1011    }
1012    return f;
1013}
1014
1015U_NAMESPACE_END
1016
1017#endif /* #if !UCONFIG_NO_FORMATTING */
1018
1019//eof
1020