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