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