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