]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/numfmt.cpp
ICU-6.2.15.tar.gz
[apple/icu.git] / icuSources / i18n / numfmt.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2004, 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/ures.h"
32 #include "unicode/dcfmtsym.h"
33 #include "unicode/decimfmt.h"
34 #include "unicode/ustring.h"
35 #include "unicode/ucurr.h"
36 #include "unicode/curramt.h"
37 #include "uhash.h"
38 #include "cmemory.h"
39 #include "iculserv.h"
40 #include "ucln_in.h"
41 #include "cstring.h"
42 #include "putilimp.h"
43 #include <float.h>
44
45 //#define FMT_DEBUG
46
47 #ifdef FMT_DEBUG
48 #include <stdio.h>
49 static 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
60 // If no number pattern can be located for a locale, this is the last
61 // resort.
62 static const UChar gLastResortDecimalPat[] = {
63 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */
64 };
65 static 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 };
68 static const UChar gLastResortPercentPat[] = {
69 0x23, 0x30, 0x25, 0 /* "#0%" */
70 };
71 static const UChar gLastResortScientificPat[] = {
72 0x23, 0x45, 0x30, 0 /* "#E0" */
73 };
74 // *****************************************************************************
75 // class NumberFormat
76 // *****************************************************************************
77
78 U_NAMESPACE_BEGIN
79
80 UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat)
81 // If the maximum base 10 exponent were 4, then the largest number would
82 // be 99,999 which has 5 digits.
83 const int32_t NumberFormat::fgMaxIntegerDigits = DBL_MAX_10_EXP + 1; // Should be ~40 ? --srl
84 const int32_t NumberFormat::fgMinIntegerDigits = 127;
85
86 const int32_t NumberFormat::fgNumberPatternsCount = 3;
87
88 const UChar * const NumberFormat::fgLastResortNumberPatterns[] =
89 {
90 gLastResortDecimalPat,
91 gLastResortCurrencyPat,
92 gLastResortPercentPat,
93 gLastResortScientificPat
94 };
95
96 #if !UCONFIG_NO_SERVICE
97 // -------------------------------------
98 // SimpleNumberFormatFactory implementation
99 NumberFormatFactory::~NumberFormatFactory() {}
100 SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible)
101 : _visible(visible)
102 , _id(locale.getName())
103 {
104 }
105
106 SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {}
107
108 UBool SimpleNumberFormatFactory::visible(void) const {
109 return _visible;
110 }
111
112 const UnicodeString *
113 SimpleNumberFormatFactory::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 */
123
124 // -------------------------------------
125 // default constructor
126 NumberFormat::NumberFormat()
127 : fGroupingUsed(TRUE),
128 fMaxIntegerDigits(fgMaxIntegerDigits),
129 fMinIntegerDigits(1),
130 fMaxFractionDigits(3), // invariant, >= minFractionDigits
131 fMinFractionDigits(0),
132 fParseIntegerOnly(FALSE)
133 {
134 fCurrency[0] = 0;
135 }
136
137 // -------------------------------------
138
139 NumberFormat::~NumberFormat()
140 {
141 }
142
143 // -------------------------------------
144 // copy constructor
145
146 NumberFormat::NumberFormat(const NumberFormat &source)
147 : Format(source)
148 {
149 *this = source;
150 }
151
152 // -------------------------------------
153 // assignment operator
154
155 NumberFormat&
156 NumberFormat::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;
166 u_strncpy(fCurrency, rhs.fCurrency, 4);
167 }
168 return *this;
169 }
170
171 // -------------------------------------
172
173 UBool
174 NumberFormat::operator==(const Format& that) const
175 {
176 // Format::operator== guarantees this cast is safe
177 NumberFormat* other = (NumberFormat*)&that;
178
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
212 return ((this == &that) ||
213 ((Format::operator==(that) &&
214 fMaxIntegerDigits == other->fMaxIntegerDigits &&
215 fMinIntegerDigits == other->fMinIntegerDigits &&
216 fMaxFractionDigits == other->fMaxFractionDigits &&
217 fMinFractionDigits == other->fMinFractionDigits &&
218 fGroupingUsed == other->fGroupingUsed &&
219 fParseIntegerOnly == other->fParseIntegerOnly &&
220 u_strcmp(fCurrency, other->fCurrency) == 0)));
221 }
222
223 // -------------------------------------x
224 // Formats the number object and save the format
225 // result in the toAppendTo string buffer.
226
227 UnicodeString&
228 NumberFormat::format(const Formattable& obj,
229 UnicodeString& appendTo,
230 FieldPosition& pos,
231 UErrorCode& status) const
232 {
233 if (U_FAILURE(status)) return appendTo;
234
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();
253 }
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:
266 status = U_INVALID_FORMAT_ERROR;
267 break;
268 }
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
279 UnicodeString&
280 NumberFormat::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);
286 }
287
288 // -------------------------------------
289 // Parses the string and save the result object as well
290 // as the final parsed position.
291
292 void
293 NumberFormat::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
303 UnicodeString&
304 NumberFormat::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
313 UnicodeString&
314 NumberFormat::format(int32_t number, UnicodeString& appendTo) const
315 {
316 FieldPosition pos(0);
317 return format(number, appendTo, pos);
318 }
319
320 // -------------------------------------
321 // Formats a long number and save the result in a string.
322
323 UnicodeString&
324 NumberFormat::format(int64_t number, UnicodeString& appendTo) const
325 {
326 FieldPosition pos(0);
327 return format(number, appendTo, pos);
328 }
329
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
336 void
337 NumberFormat::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
350 Formattable& 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
371 // -------------------------------------
372 // Sets to only parse integers.
373
374 void
375 NumberFormat::setParseIntegerOnly(UBool value)
376 {
377 fParseIntegerOnly = value;
378 }
379
380 // -------------------------------------
381 // Create a number style NumberFormat instance with the default locale.
382
383 NumberFormat* U_EXPORT2
384 NumberFormat::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
392 NumberFormat* U_EXPORT2
393 NumberFormat::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
401 NumberFormat* U_EXPORT2
402 NumberFormat::createCurrencyInstance(UErrorCode& status)
403 {
404 return createCurrencyInstance(Locale::getDefault(), status);
405 }
406
407 // -------------------------------------
408 // Create a currency style NumberFormat instance with the inLocale locale.
409
410 NumberFormat* U_EXPORT2
411 NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
412 {
413 return createInstance(inLocale, kCurrencyStyle, status);
414 }
415
416 // -------------------------------------
417 // Create a percent style NumberFormat instance with the default locale.
418
419 NumberFormat* U_EXPORT2
420 NumberFormat::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
428 NumberFormat* U_EXPORT2
429 NumberFormat::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
437 NumberFormat* U_EXPORT2
438 NumberFormat::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
446 NumberFormat* U_EXPORT2
447 NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
448 {
449 return createInstance(inLocale, kScientificStyle, status);
450 }
451
452 // -------------------------------------
453
454 const Locale* U_EXPORT2
455 NumberFormat::getAvailableLocales(int32_t& count)
456 {
457 return Locale::getAvailableLocales(count);
458 }
459
460 // ------------------------------------------
461 //
462 // Registration
463 //
464 //-------------------------------------------
465
466 #if !UCONFIG_NO_SERVICE
467 static ICULocaleService* gService = NULL;
468
469 /**
470 * Release all static memory held by numberformat.
471 */
472 U_CDECL_BEGIN
473 static UBool U_CALLCONV numfmt_cleanup(void) {
474 if (gService) {
475 delete gService;
476 gService = NULL;
477 }
478 return TRUE;
479 }
480 U_CDECL_END
481
482 // -------------------------------------
483
484 class ICUNumberFormatFactory : public ICUResourceBundleFactory {
485 protected:
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 }
490 };
491
492 // -------------------------------------
493
494 class NFFactory : public LocaleKeyFactory {
495 private:
496 NumberFormatFactory* _delegate;
497 Hashtable* _ids;
498
499 public:
500 NFFactory(NumberFormatFactory* delegate)
501 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
502 , _delegate(delegate)
503 , _ids(NULL)
504 {
505 }
506
507 virtual ~NFFactory()
508 {
509 delete _delegate;
510 delete _ids;
511 }
512
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;
528 }
529
530 protected:
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;
550 }
551 return NULL;
552 }
553 };
554
555 class ICUNumberFormatService : public ICULocaleService {
556 public:
557 ICUNumberFormatService()
558 : ICULocaleService("Number Format")
559 {
560 UErrorCode status = U_ZERO_ERROR;
561 registerFactory(new ICUNumberFormatFactory(), status);
562 }
563
564 virtual UObject* cloneInstance(UObject* instance) const {
565 return ((NumberFormat*)instance)->clone();
566 }
567
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 }
575
576 virtual UBool isDefault() const {
577 return countFactories() == 1;
578 }
579 };
580
581 // -------------------------------------
582
583 static ICULocaleService*
584 getNumberFormatService(void)
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.
604 #if !UCONFIG_NO_SERVICE
605 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
606 #endif
607 }
608 }
609 return gService;
610 }
611
612 // -------------------------------------
613
614 URegistryKey U_EXPORT2
615 NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
616 {
617 ICULocaleService *service = getNumberFormatService();
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
627 UBool U_EXPORT2
628 NumberFormat::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 // -------------------------------------
643 StringEnumeration* U_EXPORT2
644 NumberFormat::getAvailableLocales(void)
645 {
646 ICULocaleService *service = getNumberFormatService();
647 if (service) {
648 return service->getAvailableLocales();
649 }
650 return NULL; // no way to return error condition
651 }
652 #endif /* UCONFIG_NO_SERVICE */
653 // -------------------------------------
654
655 NumberFormat* U_EXPORT2
656 NumberFormat::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
672
673 // -------------------------------------
674 // Checks if the thousand/10 thousand grouping is used in the
675 // NumberFormat instance.
676
677 UBool
678 NumberFormat::isGroupingUsed() const
679 {
680 return fGroupingUsed;
681 }
682
683 // -------------------------------------
684 // Sets to use the thousand/10 thousand grouping in the
685 // NumberFormat instance.
686
687 void
688 NumberFormat::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
697 int32_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
706 void
707 NumberFormat::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
718 int32_t
719 NumberFormat::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
728 void
729 NumberFormat::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
740 int32_t
741 NumberFormat::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
750 void
751 NumberFormat::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
762 int32_t
763 NumberFormat::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
772 void
773 NumberFormat::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
782 void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
783 if (U_FAILURE(ec)) {
784 return;
785 }
786 if (theCurrency) {
787 u_strncpy(fCurrency, theCurrency, 3);
788 fCurrency[3] = 0;
789 } else {
790 fCurrency[0] = 0;
791 }
792 }
793
794 const UChar* NumberFormat::getCurrency() const {
795 return fCurrency;
796 }
797
798 void 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 }
810 }
811
812 // -------------------------------------
813 // Creates the NumberFormat instance of the specified style (number, currency,
814 // or percent) for the desired locale.
815
816 NumberFormat*
817 NumberFormat::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
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);
833
834 if (U_FAILURE(status)) {
835 // We don't appear to have resource data available -- use the last-resort data
836 status = U_USING_FALLBACK_WARNING;
837 // When the data is unavailable, and locale isn't passed in, last resort data is used.
838 symbolsToAdopt = new DecimalFormatSymbols(status);
839
840 // Creates a DecimalFormat instance with the last resort number patterns.
841 pattern.setTo(TRUE, fgLastResortNumberPatterns[style], -1);
842 }
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 }
850
851 // Loads the decimal symbols of the desired locale.
852 symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
853
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);
858 }
859 if (U_FAILURE(status) || symbolsToAdopt == NULL) {
860 goto cleanup;
861 }
862
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. */
891 }
892 /* else no currency keyword used. */
893 }
894 f = new DecimalFormat(pattern, symbolsToAdopt, status);
895 if (U_FAILURE(status) || f == NULL) {
896 goto cleanup;
897 }
898
899 f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status),
900 ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status));
901 cleanup:
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 }
912 return NULL;
913 }
914 if (f == NULL || symbolsToAdopt == NULL) {
915 status = U_MEMORY_ALLOCATION_ERROR;
916 f = NULL;
917 }
918 return f;
919 }
920
921 U_NAMESPACE_END
922
923 #endif /* #if !UCONFIG_NO_FORMATTING */
924
925 //eof