]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/numfmt.cpp
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / i18n / numfmt.cpp
CommitLineData
b75a7d8f
A
1/*
2*******************************************************************************
729e4ab9 3* Copyright (C) 1997-2010, 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"
729e4ab9
A
36#include "unicode/numsys.h"
37#include "unicode/rbnf.h"
73c04bcf
A
38#include "winnmfmt.h"
39#include "uresimp.h"
b75a7d8f 40#include "uhash.h"
374ca955 41#include "cmemory.h"
73c04bcf 42#include "servloc.h"
b75a7d8f 43#include "ucln_in.h"
374ca955
A
44#include "cstring.h"
45#include "putilimp.h"
729e4ab9
A
46#include "umutex.h"
47#include "digitlst.h"
b75a7d8f
A
48#include <float.h>
49
374ca955
A
50//#define FMT_DEBUG
51
52#ifdef FMT_DEBUG
53#include <stdio.h>
54static void debugout(UnicodeString s) {
55 char buf[2000];
56 s.extract((int32_t) 0, s.length(), buf);
57 printf("%s", buf);
58}
59#define debug(x) printf("%s", x);
60#else
61#define debugout(x)
62#define debug(x)
63#endif
64
b75a7d8f
A
65// If no number pattern can be located for a locale, this is the last
66// resort.
67static const UChar gLastResortDecimalPat[] = {
68 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */
69};
70static const UChar gLastResortCurrencyPat[] = {
71 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "$#0.00;($#0.00)" */
72};
73static const UChar gLastResortPercentPat[] = {
74 0x23, 0x30, 0x25, 0 /* "#0%" */
75};
76static const UChar gLastResortScientificPat[] = {
77 0x23, 0x45, 0x30, 0 /* "#E0" */
78};
729e4ab9
A
79static const UChar gLastResortIsoCurrencyPat[] = {
80 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0xA4, 0xA4, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "\u00A4\u00A4#0.00;(\u00A4\u00A4#0.00)" */
81};
82static const UChar gLastResortPluralCurrencyPat[] = {
83 0x23, 0x30, 0x2E, 0x30, 0x30, 0xA0, 0xA4, 0xA4, 0xA4, 0 /* "#0.00\u00A0\u00A4\u00A4\u00A4*/
84};
85
86static const UChar gSingleCurrencySign[] = {0xA4, 0};
87static const UChar gDoubleCurrencySign[] = {0xA4, 0xA4, 0};
88
89static const UChar gSlash = 0x2f;
b75a7d8f 90
b75a7d8f
A
91// If the maximum base 10 exponent were 4, then the largest number would
92// be 99,999 which has 5 digits.
46f4442e
A
93// On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit
94static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1;
73c04bcf 95static const int32_t gMinIntegerDigits = 127;
b75a7d8f 96
73c04bcf 97static const UChar * const gLastResortNumberPatterns[] =
b75a7d8f
A
98{
99 gLastResortDecimalPat,
100 gLastResortCurrencyPat,
101 gLastResortPercentPat,
729e4ab9
A
102 gLastResortScientificPat,
103 gLastResortIsoCurrencyPat,
104 gLastResortPluralCurrencyPat,
b75a7d8f
A
105};
106
729e4ab9
A
107// Keys used for accessing resource bundles
108
109static const char *gNumberElements = "NumberElements";
110static const char *gLatn = "latn";
111static const char *gPatterns = "patterns";
112static const char *gFormatKeys[] = { "decimalFormat", "currencyFormat", "percentFormat", "scientificFormat" };
113
114// Static hashtable cache of NumberingSystem objects used by NumberFormat
115static UHashtable * NumberingSystem_cache = NULL;
116
117static UMTX nscacheMutex = NULL;
118
119#if !UCONFIG_NO_SERVICE
120static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
121#endif
122
123/**
124 * Release all static memory held by Number Format.
125 */
126U_CDECL_BEGIN
127static void U_CALLCONV
128deleteNumberingSystem(void *obj) {
129 delete (U_NAMESPACE_QUALIFIER NumberingSystem *)obj;
130}
131
132static UBool U_CALLCONV numfmt_cleanup(void) {
133#if !UCONFIG_NO_SERVICE
134 if (gService) {
135 delete gService;
136 gService = NULL;
137 }
138#endif
139 if (NumberingSystem_cache) {
140 // delete NumberingSystem_cache;
141 uhash_close(NumberingSystem_cache);
142 NumberingSystem_cache = NULL;
143 }
144
145 return TRUE;
146}
147U_CDECL_END
148
73c04bcf
A
149// *****************************************************************************
150// class NumberFormat
151// *****************************************************************************
152
153U_NAMESPACE_BEGIN
154
155UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat)
156
374ca955 157#if !UCONFIG_NO_SERVICE
b75a7d8f 158// -------------------------------------
374ca955
A
159// SimpleNumberFormatFactory implementation
160NumberFormatFactory::~NumberFormatFactory() {}
161SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible)
162 : _visible(visible)
374ca955 163{
73c04bcf 164 LocaleUtility::initNameFromLocale(locale, _id);
374ca955
A
165}
166
167SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {}
168
169UBool SimpleNumberFormatFactory::visible(void) const {
170 return _visible;
171}
172
173const UnicodeString *
729e4ab9 174SimpleNumberFormatFactory::getSupportedIDs(int32_t &count, UErrorCode& status) const
374ca955
A
175{
176 if (U_SUCCESS(status)) {
177 count = 1;
178 return &_id;
179 }
180 count = 0;
181 return NULL;
182}
183#endif /* #if !UCONFIG_NO_SERVICE */
b75a7d8f 184
374ca955
A
185// -------------------------------------
186// default constructor
b75a7d8f
A
187NumberFormat::NumberFormat()
188: fGroupingUsed(TRUE),
73c04bcf 189 fMaxIntegerDigits(gMaxIntegerDigits),
b75a7d8f
A
190 fMinIntegerDigits(1),
191 fMaxFractionDigits(3), // invariant, >= minFractionDigits
192 fMinFractionDigits(0),
46f4442e
A
193 fParseIntegerOnly(FALSE),
194 fParseStrict(TRUE) // TODO: Should this be FALSE?
b75a7d8f 195{
374ca955 196 fCurrency[0] = 0;
b75a7d8f
A
197}
198
199// -------------------------------------
200
201NumberFormat::~NumberFormat()
202{
203}
204
205// -------------------------------------
206// copy constructor
207
208NumberFormat::NumberFormat(const NumberFormat &source)
209: Format(source)
210{
211 *this = source;
212}
213
214// -------------------------------------
215// assignment operator
216
217NumberFormat&
218NumberFormat::operator=(const NumberFormat& rhs)
219{
220 if (this != &rhs)
221 {
729e4ab9 222 Format::operator=(rhs);
b75a7d8f
A
223 fGroupingUsed = rhs.fGroupingUsed;
224 fMaxIntegerDigits = rhs.fMaxIntegerDigits;
225 fMinIntegerDigits = rhs.fMinIntegerDigits;
226 fMaxFractionDigits = rhs.fMaxFractionDigits;
227 fMinFractionDigits = rhs.fMinFractionDigits;
228 fParseIntegerOnly = rhs.fParseIntegerOnly;
374ca955 229 u_strncpy(fCurrency, rhs.fCurrency, 4);
b75a7d8f
A
230 }
231 return *this;
232}
233
234// -------------------------------------
235
236UBool
237NumberFormat::operator==(const Format& that) const
238{
374ca955 239 // Format::operator== guarantees this cast is safe
b75a7d8f
A
240 NumberFormat* other = (NumberFormat*)&that;
241
374ca955
A
242#ifdef FMT_DEBUG
243 // This code makes it easy to determine why two format objects that should
244 // be equal aren't.
245 UBool first = TRUE;
246 if (!Format::operator==(that)) {
247 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
248 debug("Format::!=");
249 }
250 if (!(fMaxIntegerDigits == other->fMaxIntegerDigits &&
251 fMinIntegerDigits == other->fMinIntegerDigits)) {
252 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
253 debug("Integer digits !=");
254 }
255 if (!(fMaxFractionDigits == other->fMaxFractionDigits &&
256 fMinFractionDigits == other->fMinFractionDigits)) {
257 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
258 debug("Fraction digits !=");
259 }
260 if (!(fGroupingUsed == other->fGroupingUsed)) {
261 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
262 debug("fGroupingUsed != ");
263 }
264 if (!(fParseIntegerOnly == other->fParseIntegerOnly)) {
265 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
266 debug("fParseIntegerOnly != ");
267 }
268 if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) {
269 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
270 debug("fCurrency !=");
271 }
729e4ab9 272 if (!first) { printf(" ]"); }
374ca955
A
273#endif
274
b75a7d8f
A
275 return ((this == &that) ||
276 ((Format::operator==(that) &&
b75a7d8f
A
277 fMaxIntegerDigits == other->fMaxIntegerDigits &&
278 fMinIntegerDigits == other->fMinIntegerDigits &&
279 fMaxFractionDigits == other->fMaxFractionDigits &&
280 fMinFractionDigits == other->fMinFractionDigits &&
281 fGroupingUsed == other->fGroupingUsed &&
374ca955
A
282 fParseIntegerOnly == other->fParseIntegerOnly &&
283 u_strcmp(fCurrency, other->fCurrency) == 0)));
b75a7d8f
A
284}
285
729e4ab9
A
286// -------------------------------------
287// Default implementation sets unsupported error; subclasses should
288// override.
b75a7d8f
A
289
290UnicodeString&
729e4ab9
A
291NumberFormat::format(double /* unused number */,
292 UnicodeString& toAppendTo,
293 FieldPositionIterator* /* unused posIter */,
294 UErrorCode& status) const
b75a7d8f 295{
729e4ab9
A
296 if (!U_FAILURE(status)) {
297 status = U_UNSUPPORTED_ERROR;
298 }
299 return toAppendTo;
300}
301
302// -------------------------------------
303// Default implementation sets unsupported error; subclasses should
304// override.
305
306UnicodeString&
307NumberFormat::format(int32_t /* unused number */,
308 UnicodeString& toAppendTo,
309 FieldPositionIterator* /* unused posIter */,
310 UErrorCode& status) const
311{
312 if (!U_FAILURE(status)) {
313 status = U_UNSUPPORTED_ERROR;
314 }
315 return toAppendTo;
316}
317
318// -------------------------------------
319// Default implementation sets unsupported error; subclasses should
320// override.
321
322UnicodeString&
323NumberFormat::format(int64_t /* unused number */,
324 UnicodeString& toAppendTo,
325 FieldPositionIterator* /* unused posIter */,
326 UErrorCode& status) const
327{
328 if (!U_FAILURE(status)) {
329 status = U_UNSUPPORTED_ERROR;
330 }
331 return toAppendTo;
332}
b75a7d8f 333
729e4ab9
A
334// -------------------------------------
335// Decimal Number format() default implementation
336// Subclasses do not normally override this function, but rather the DigitList
337// formatting functions..
338// The expected call chain from here is
339// this function ->
340// NumberFormat::format(Formattable ->
341// DecimalFormat::format(DigitList
342//
343// Or, for subclasses of Formattable that do not know about DigitList,
344// this Function ->
345// NumberFormat::format(Formattable ->
346// NumberFormat::format(DigitList ->
347// XXXFormat::format(double
348
349UnicodeString&
350NumberFormat::format(const StringPiece &decimalNum,
351 UnicodeString& toAppendTo,
352 FieldPositionIterator* fpi,
353 UErrorCode& status) const
354{
355 Formattable f;
356 f.setDecimalNumber(decimalNum, status);
357 format(f, toAppendTo, fpi, status);
358 return toAppendTo;
359}
360
361// -------------------------------------
362// Formats the number object and save the format
363// result in the toAppendTo string buffer.
364
365// utility to save/restore state, used in two overloads
366// of format(const Formattable&...) below.
367
368class ArgExtractor {
369 NumberFormat *ncnf;
370 const Formattable* num;
371 UBool setCurr;
372 UChar save[4];
373
374 public:
375 ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status);
376 ~ArgExtractor();
377
378 const Formattable* number(void) const;
379};
380
381inline const Formattable*
382ArgExtractor::number(void) const {
383 return num;
384}
385
386ArgExtractor::ArgExtractor(const NumberFormat& nf, const Formattable& obj, UErrorCode& status)
387 : ncnf((NumberFormat*) &nf), num(&obj), setCurr(FALSE) {
374ca955 388
374ca955 389 const UObject* o = obj.getObject(); // most commonly o==NULL
729e4ab9
A
390 const CurrencyAmount* amt;
391 if (o != NULL && (amt = dynamic_cast<const CurrencyAmount*>(o)) != NULL) {
374ca955
A
392 // getISOCurrency() returns a pointer to internal storage, so we
393 // copy it to retain it across the call to setCurrency().
374ca955 394 const UChar* curr = amt->getISOCurrency();
729e4ab9 395 u_strcpy(save, nf.getCurrency());
374ca955
A
396 setCurr = (u_strcmp(curr, save) != 0);
397 if (setCurr) {
729e4ab9 398 ncnf->setCurrency(curr, status);
374ca955 399 }
729e4ab9 400 num = &amt->getNumber();
b75a7d8f 401 }
729e4ab9 402}
374ca955 403
729e4ab9 404ArgExtractor::~ArgExtractor() {
374ca955
A
405 if (setCurr) {
406 UErrorCode ok = U_ZERO_ERROR;
729e4ab9
A
407 ncnf->setCurrency(save, ok); // always restore currency
408 }
409}
410
411UnicodeString& NumberFormat::format(const DigitList &number,
412 UnicodeString& appendTo,
413 FieldPositionIterator* posIter,
414 UErrorCode& status) const {
415 // DecimalFormat overrides this function, and handles DigitList based big decimals.
416 // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
417 // so this default implementation falls back to formatting decimal numbers as doubles.
418 if (U_FAILURE(status)) {
419 return appendTo;
420 }
421 double dnum = number.getDouble();
422 format(dnum, appendTo, posIter, status);
423 return appendTo;
424}
425
426
427
428UnicodeString&
429NumberFormat::format(const DigitList &number,
430 UnicodeString& appendTo,
431 FieldPosition& pos,
432 UErrorCode &status) const {
433 // DecimalFormat overrides this function, and handles DigitList based big decimals.
434 // Other subclasses (ChoiceFormat, RuleBasedNumberFormat) do not (yet) handle DigitLists,
435 // so this default implementation falls back to formatting decimal numbers as doubles.
436 if (U_FAILURE(status)) {
437 return appendTo;
438 }
439 double dnum = number.getDouble();
440 format(dnum, appendTo, pos, status);
441 return appendTo;
442}
443
444UnicodeString&
445NumberFormat::format(const Formattable& obj,
446 UnicodeString& appendTo,
447 FieldPosition& pos,
448 UErrorCode& status) const
449{
450 if (U_FAILURE(status)) return appendTo;
451
452 ArgExtractor arg(*this, obj, status);
453 const Formattable *n = arg.number();
454
455 if (n->isNumeric() && n->getDigitList() != NULL) {
456 // Decimal Number. We will have a DigitList available if the value was
457 // set to a decimal number, or if the value originated with a parse.
458 //
459 // The default implementation for formatting a DigitList converts it
460 // to a double, and formats that, allowing formatting classes that don't
461 // know about DigitList to continue to operate as they had.
462 //
463 // DecimalFormat overrides the DigitList formatting functions.
464 format(*n->getDigitList(), appendTo, pos, status);
465 } else {
466 switch (n->getType()) {
467 case Formattable::kDouble:
468 format(n->getDouble(), appendTo, pos);
469 break;
470 case Formattable::kLong:
471 format(n->getLong(), appendTo, pos);
472 break;
473 case Formattable::kInt64:
474 format(n->getInt64(), appendTo, pos);
475 break;
476 default:
477 status = U_INVALID_FORMAT_ERROR;
478 break;
479 }
480 }
481
482 return appendTo;
483}
484
485// -------------------------------------x
486// Formats the number object and save the format
487// result in the toAppendTo string buffer.
488
489UnicodeString&
490NumberFormat::format(const Formattable& obj,
491 UnicodeString& appendTo,
492 FieldPositionIterator* posIter,
493 UErrorCode& status) const
494{
495 if (U_FAILURE(status)) return appendTo;
496
497 ArgExtractor arg(*this, obj, status);
498 const Formattable *n = arg.number();
499
500 if (n->isNumeric() && n->getDigitList() != NULL) {
501 // Decimal Number
502 format(*n->getDigitList(), appendTo, posIter, status);
503 } else {
504 switch (n->getType()) {
505 case Formattable::kDouble:
506 format(n->getDouble(), appendTo, posIter, status);
507 break;
508 case Formattable::kLong:
509 format(n->getLong(), appendTo, posIter, status);
510 break;
511 case Formattable::kInt64:
512 format(n->getInt64(), appendTo, posIter, status);
513 break;
514 default:
515 status = U_INVALID_FORMAT_ERROR;
516 break;
517 }
374ca955 518 }
729e4ab9 519
374ca955
A
520 return appendTo;
521}
522
523// -------------------------------------
524
729e4ab9 525UnicodeString&
374ca955
A
526NumberFormat::format(int64_t number,
527 UnicodeString& appendTo,
528 FieldPosition& pos) const
529{
530 // default so we don't introduce a new abstract method
531 return format((int32_t)number, appendTo, pos);
b75a7d8f
A
532}
533
534// -------------------------------------
535// Parses the string and save the result object as well
536// as the final parsed position.
537
538void
539NumberFormat::parseObject(const UnicodeString& source,
540 Formattable& result,
541 ParsePosition& parse_pos) const
542{
543 parse(source, result, parse_pos);
544}
545
546// -------------------------------------
547// Formats a double number and save the result in a string.
548
549UnicodeString&
550NumberFormat::format(double number, UnicodeString& appendTo) const
551{
552 FieldPosition pos(0);
553 return format(number, appendTo, pos);
554}
555
556// -------------------------------------
557// Formats a long number and save the result in a string.
558
559UnicodeString&
560NumberFormat::format(int32_t number, UnicodeString& appendTo) const
561{
562 FieldPosition pos(0);
563 return format(number, appendTo, pos);
564}
565
374ca955
A
566// -------------------------------------
567// Formats a long number and save the result in a string.
568
569UnicodeString&
570NumberFormat::format(int64_t number, UnicodeString& appendTo) const
571{
572 FieldPosition pos(0);
573 return format(number, appendTo, pos);
574}
575
b75a7d8f
A
576// -------------------------------------
577// Parses the text and save the result object. If the returned
578// parse position is 0, that means the parsing failed, the status
579// code needs to be set to failure. Ignores the returned parse
580// position, otherwise.
581
582void
583NumberFormat::parse(const UnicodeString& text,
584 Formattable& result,
585 UErrorCode& status) const
586{
587 if (U_FAILURE(status)) return;
588
589 ParsePosition parsePosition(0);
590 parse(text, result, parsePosition);
591 if (parsePosition.getIndex() == 0) {
592 status = U_INVALID_FORMAT_ERROR;
593 }
594}
595
374ca955
A
596Formattable& NumberFormat::parseCurrency(const UnicodeString& text,
597 Formattable& result,
598 ParsePosition& pos) const {
599 // Default implementation only -- subclasses should override
600 int32_t start = pos.getIndex();
601 parse(text, result, pos);
602 if (pos.getIndex() != start) {
603 UChar curr[4];
604 UErrorCode ec = U_ZERO_ERROR;
605 getEffectiveCurrency(curr, ec);
606 if (U_SUCCESS(ec)) {
607 Formattable n(result);
46f4442e
A
608 CurrencyAmount *tempCurAmnt = new CurrencyAmount(n, curr, ec); // Use for null testing.
609 if (U_FAILURE(ec) || tempCurAmnt == NULL) {
374ca955 610 pos.setIndex(start); // indicate failure
46f4442e
A
611 } else {
612 result.adoptObject(tempCurAmnt);
374ca955
A
613 }
614 }
615 }
616 return result;
617}
618
b75a7d8f
A
619// -------------------------------------
620// Sets to only parse integers.
621
622void
623NumberFormat::setParseIntegerOnly(UBool value)
624{
625 fParseIntegerOnly = value;
626}
627
46f4442e
A
628// -------------------------------------
629// Sets whether or not parse is strict.
630
631void
632NumberFormat::setParseStrict(UBool value)
633{
634 fParseStrict = value;
635}
636
b75a7d8f
A
637// -------------------------------------
638// Create a number style NumberFormat instance with the default locale.
639
374ca955 640NumberFormat* U_EXPORT2
b75a7d8f
A
641NumberFormat::createInstance(UErrorCode& status)
642{
643 return createInstance(Locale::getDefault(), kNumberStyle, status);
644}
645
646// -------------------------------------
647// Create a number style NumberFormat instance with the inLocale locale.
648
374ca955 649NumberFormat* U_EXPORT2
b75a7d8f
A
650NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
651{
652 return createInstance(inLocale, kNumberStyle, status);
653}
654
655// -------------------------------------
656// Create a currency style NumberFormat instance with the default locale.
657
374ca955 658NumberFormat* U_EXPORT2
b75a7d8f
A
659NumberFormat::createCurrencyInstance(UErrorCode& status)
660{
374ca955 661 return createCurrencyInstance(Locale::getDefault(), status);
b75a7d8f
A
662}
663
664// -------------------------------------
665// Create a currency style NumberFormat instance with the inLocale locale.
666
374ca955 667NumberFormat* U_EXPORT2
b75a7d8f 668NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
729e4ab9 669{
b75a7d8f
A
670 return createInstance(inLocale, kCurrencyStyle, status);
671}
672
673// -------------------------------------
674// Create a percent style NumberFormat instance with the default locale.
675
374ca955 676NumberFormat* U_EXPORT2
b75a7d8f
A
677NumberFormat::createPercentInstance(UErrorCode& status)
678{
679 return createInstance(Locale::getDefault(), kPercentStyle, status);
680}
681
682// -------------------------------------
683// Create a percent style NumberFormat instance with the inLocale locale.
684
374ca955 685NumberFormat* U_EXPORT2
b75a7d8f
A
686NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
687{
688 return createInstance(inLocale, kPercentStyle, status);
689}
690
691// -------------------------------------
692// Create a scientific style NumberFormat instance with the default locale.
693
374ca955 694NumberFormat* U_EXPORT2
b75a7d8f
A
695NumberFormat::createScientificInstance(UErrorCode& status)
696{
697 return createInstance(Locale::getDefault(), kScientificStyle, status);
698}
699
700// -------------------------------------
701// Create a scientific style NumberFormat instance with the inLocale locale.
702
374ca955 703NumberFormat* U_EXPORT2
b75a7d8f
A
704NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
705{
706 return createInstance(inLocale, kScientificStyle, status);
707}
708
709// -------------------------------------
710
374ca955 711const Locale* U_EXPORT2
b75a7d8f
A
712NumberFormat::getAvailableLocales(int32_t& count)
713{
714 return Locale::getAvailableLocales(count);
715}
716
717// ------------------------------------------
718//
719// Registration
720//
721//-------------------------------------------
722
374ca955 723#if !UCONFIG_NO_SERVICE
374ca955 724
b75a7d8f
A
725// -------------------------------------
726
727class ICUNumberFormatFactory : public ICUResourceBundleFactory {
728protected:
374ca955
A
729 virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
730 // !!! kind is not an EStyles, need to determine how to handle this
731 return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
732 }
b75a7d8f
A
733};
734
735// -------------------------------------
736
737class NFFactory : public LocaleKeyFactory {
738private:
374ca955
A
739 NumberFormatFactory* _delegate;
740 Hashtable* _ids;
b75a7d8f
A
741
742public:
729e4ab9 743 NFFactory(NumberFormatFactory* delegate)
374ca955
A
744 : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
745 , _delegate(delegate)
746 , _ids(NULL)
747 {
748 }
b75a7d8f 749
374ca955
A
750 virtual ~NFFactory()
751 {
752 delete _delegate;
753 delete _ids;
754 }
b75a7d8f 755
374ca955
A
756 virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
757 {
758 if (handlesKey(key, status)) {
759 const LocaleKey& lkey = (const LocaleKey&)key;
760 Locale loc;
761 lkey.canonicalLocale(loc);
762 int32_t kind = lkey.kind();
763
764 UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1));
765 if (result == NULL) {
766 result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
767 }
768 return result;
769 }
770 return NULL;
b75a7d8f 771 }
b75a7d8f
A
772
773protected:
374ca955 774 /**
729e4ab9 775 * Return the set of ids that this factory supports (visible or
374ca955
A
776 * otherwise). This can be called often and might need to be
777 * cached if it is expensive to create.
778 */
779 virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
780 {
781 if (U_SUCCESS(status)) {
782 if (!_ids) {
783 int32_t count = 0;
784 const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status);
785 ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */
786 if (_ids) {
787 for (int i = 0; i < count; ++i) {
788 _ids->put(idlist[i], (void*)this, status);
789 }
790 }
791 }
792 return _ids;
b75a7d8f 793 }
374ca955 794 return NULL;
b75a7d8f 795 }
b75a7d8f
A
796};
797
798class ICUNumberFormatService : public ICULocaleService {
799public:
374ca955 800 ICUNumberFormatService()
73c04bcf 801 : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format"))
374ca955
A
802 {
803 UErrorCode status = U_ZERO_ERROR;
804 registerFactory(new ICUNumberFormatFactory(), status);
805 }
b75a7d8f 806
374ca955
A
807 virtual UObject* cloneInstance(UObject* instance) const {
808 return ((NumberFormat*)instance)->clone();
809 }
b75a7d8f 810
374ca955
A
811 virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const {
812 LocaleKey& lkey = (LocaleKey&)key;
813 int32_t kind = lkey.kind();
814 Locale loc;
815 lkey.currentLocale(loc);
816 return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
817 }
b75a7d8f 818
374ca955
A
819 virtual UBool isDefault() const {
820 return countFactories() == 1;
821 }
b75a7d8f
A
822};
823
824// -------------------------------------
825
729e4ab9 826static ICULocaleService*
374ca955 827getNumberFormatService(void)
b75a7d8f
A
828{
829 UBool needInit;
46f4442e 830 UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
b75a7d8f
A
831 if (needInit) {
832 ICULocaleService * newservice = new ICUNumberFormatService();
833 if (newservice) {
46f4442e 834 umtx_lock(NULL);
b75a7d8f
A
835 if (gService == NULL) {
836 gService = newservice;
837 newservice = NULL;
838 }
46f4442e 839 umtx_unlock(NULL);
b75a7d8f
A
840 }
841 if (newservice) {
842 delete newservice;
843 } else {
844 // we won the contention, this thread can register cleanup.
374ca955 845 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
b75a7d8f
A
846 }
847 }
848 return gService;
849}
850
851// -------------------------------------
852
374ca955 853URegistryKey U_EXPORT2
b75a7d8f
A
854NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
855{
374ca955 856 ICULocaleService *service = getNumberFormatService();
b75a7d8f 857 if (service) {
46f4442e
A
858 NFFactory *tempnnf = new NFFactory(toAdopt);
859 if (tempnnf != NULL) {
860 return service->registerFactory(tempnnf, status);
861 }
b75a7d8f
A
862 }
863 status = U_MEMORY_ALLOCATION_ERROR;
864 return NULL;
865}
866
867// -------------------------------------
868
374ca955 869UBool U_EXPORT2
b75a7d8f
A
870NumberFormat::unregister(URegistryKey key, UErrorCode& status)
871{
872 if (U_SUCCESS(status)) {
46f4442e
A
873 UBool haveService;
874 UMTX_CHECK(NULL, gService != NULL, haveService);
b75a7d8f
A
875 if (haveService) {
876 return gService->unregister(key, status);
877 }
878 status = U_ILLEGAL_ARGUMENT_ERROR;
879 }
880 return FALSE;
881}
882
883// -------------------------------------
374ca955 884StringEnumeration* U_EXPORT2
b75a7d8f
A
885NumberFormat::getAvailableLocales(void)
886{
374ca955 887 ICULocaleService *service = getNumberFormatService();
b75a7d8f
A
888 if (service) {
889 return service->getAvailableLocales();
890 }
891 return NULL; // no way to return error condition
892}
374ca955
A
893#endif /* UCONFIG_NO_SERVICE */
894// -------------------------------------
895
896NumberFormat* U_EXPORT2
897NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status)
898{
899#if !UCONFIG_NO_SERVICE
46f4442e
A
900 UBool haveService;
901 UMTX_CHECK(NULL, gService != NULL, haveService);
374ca955
A
902 if (haveService) {
903 return (NumberFormat*)gService->get(loc, kind, status);
904 }
905 else
906#endif
907 {
908 return makeInstance(loc, kind, status);
909 }
910}
911
b75a7d8f
A
912
913// -------------------------------------
914// Checks if the thousand/10 thousand grouping is used in the
915// NumberFormat instance.
916
917UBool
918NumberFormat::isGroupingUsed() const
919{
920 return fGroupingUsed;
921}
922
923// -------------------------------------
924// Sets to use the thousand/10 thousand grouping in the
925// NumberFormat instance.
926
927void
928NumberFormat::setGroupingUsed(UBool newValue)
929{
930 fGroupingUsed = newValue;
931}
932
933// -------------------------------------
934// Gets the maximum number of digits for the integral part for
935// this NumberFormat instance.
936
937int32_t NumberFormat::getMaximumIntegerDigits() const
938{
939 return fMaxIntegerDigits;
940}
941
942// -------------------------------------
943// Sets the maximum number of digits for the integral part for
944// this NumberFormat instance.
945
946void
947NumberFormat::setMaximumIntegerDigits(int32_t newValue)
948{
73c04bcf 949 fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
b75a7d8f
A
950 if(fMinIntegerDigits > fMaxIntegerDigits)
951 fMinIntegerDigits = fMaxIntegerDigits;
952}
953
954// -------------------------------------
955// Gets the minimum number of digits for the integral part for
956// this NumberFormat instance.
957
958int32_t
959NumberFormat::getMinimumIntegerDigits() const
960{
961 return fMinIntegerDigits;
962}
963
964// -------------------------------------
965// Sets the minimum number of digits for the integral part for
966// this NumberFormat instance.
967
968void
969NumberFormat::setMinimumIntegerDigits(int32_t newValue)
970{
73c04bcf 971 fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
b75a7d8f
A
972 if(fMinIntegerDigits > fMaxIntegerDigits)
973 fMaxIntegerDigits = fMinIntegerDigits;
974}
975
976// -------------------------------------
977// Gets the maximum number of digits for the fractional part for
978// this NumberFormat instance.
979
980int32_t
981NumberFormat::getMaximumFractionDigits() const
982{
983 return fMaxFractionDigits;
984}
985
986// -------------------------------------
987// Sets the maximum number of digits for the fractional part for
988// this NumberFormat instance.
989
990void
991NumberFormat::setMaximumFractionDigits(int32_t newValue)
992{
73c04bcf 993 fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
b75a7d8f
A
994 if(fMaxFractionDigits < fMinFractionDigits)
995 fMinFractionDigits = fMaxFractionDigits;
996}
997
998// -------------------------------------
999// Gets the minimum number of digits for the fractional part for
1000// this NumberFormat instance.
1001
1002int32_t
1003NumberFormat::getMinimumFractionDigits() const
1004{
1005 return fMinFractionDigits;
1006}
1007
1008// -------------------------------------
1009// Sets the minimum number of digits for the fractional part for
1010// this NumberFormat instance.
1011
1012void
1013NumberFormat::setMinimumFractionDigits(int32_t newValue)
1014{
73c04bcf 1015 fMinFractionDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
b75a7d8f
A
1016 if (fMaxFractionDigits < fMinFractionDigits)
1017 fMaxFractionDigits = fMinFractionDigits;
1018}
1019
1020// -------------------------------------
1021
374ca955
A
1022void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
1023 if (U_FAILURE(ec)) {
1024 return;
1025 }
b75a7d8f 1026 if (theCurrency) {
374ca955
A
1027 u_strncpy(fCurrency, theCurrency, 3);
1028 fCurrency[3] = 0;
b75a7d8f 1029 } else {
374ca955 1030 fCurrency[0] = 0;
b75a7d8f
A
1031 }
1032}
1033
1034const UChar* NumberFormat::getCurrency() const {
374ca955
A
1035 return fCurrency;
1036}
1037
1038void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
1039 const UChar* c = getCurrency();
1040 if (*c != 0) {
1041 u_strncpy(result, c, 3);
1042 result[3] = 0;
1043 } else {
1044 const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
1045 if (loc == NULL) {
1046 loc = uloc_getDefault();
1047 }
1048 ucurr_forLocale(loc, result, 4, &ec);
1049 }
b75a7d8f
A
1050}
1051
1052// -------------------------------------
1053// Creates the NumberFormat instance of the specified style (number, currency,
1054// or percent) for the desired locale.
1055
1056NumberFormat*
1057NumberFormat::makeInstance(const Locale& desiredLocale,
1058 EStyles style,
1059 UErrorCode& status)
1060{
1061 if (U_FAILURE(status)) return NULL;
1062
1063 if (style < 0 || style >= kStyleCount) {
1064 status = U_ILLEGAL_ARGUMENT_ERROR;
1065 return NULL;
1066 }
1067
73c04bcf
A
1068#ifdef U_WINDOWS
1069 char buffer[8];
1070 int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
1071
1072 // if the locale has "@compat=host", create a host-specific NumberFormat
1073 if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
1074 Win32NumberFormat *f = NULL;
1075 UBool curr = TRUE;
1076
1077 switch (style) {
1078 case kNumberStyle:
1079 curr = FALSE;
1080 // fall-through
1081
1082 case kCurrencyStyle:
729e4ab9
A
1083 case kIsoCurrencyStyle: // do not support plural formatting here
1084 case kPluralCurrencyStyle:
73c04bcf
A
1085 f = new Win32NumberFormat(desiredLocale, curr, status);
1086
1087 if (U_SUCCESS(status)) {
1088 return f;
1089 }
1090
1091 delete f;
1092 break;
729e4ab9 1093
73c04bcf
A
1094 default:
1095 break;
1096 }
1097 }
1098#endif
1099
374ca955
A
1100 NumberFormat* f = NULL;
1101 DecimalFormatSymbols* symbolsToAdopt = NULL;
1102 UnicodeString pattern;
729e4ab9
A
1103 UResourceBundle *resource = ures_open(NULL, desiredLocale.getName(), &status);
1104 NumberingSystem *ns = NULL;
1105 UBool deleteSymbols = TRUE;
1106 UHashtable * cache = NULL;
1107 int32_t hashKey;
1108 UBool getCache = FALSE;
1109 UBool deleteNS = FALSE;
b75a7d8f 1110
374ca955 1111 if (U_FAILURE(status)) {
b75a7d8f
A
1112 // We don't appear to have resource data available -- use the last-resort data
1113 status = U_USING_FALLBACK_WARNING;
374ca955
A
1114 // When the data is unavailable, and locale isn't passed in, last resort data is used.
1115 symbolsToAdopt = new DecimalFormatSymbols(status);
b75a7d8f
A
1116
1117 // Creates a DecimalFormat instance with the last resort number patterns.
73c04bcf 1118 pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
b75a7d8f 1119 }
374ca955 1120 else {
374ca955
A
1121 // Loads the decimal symbols of the desired locale.
1122 symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
b75a7d8f 1123
374ca955 1124 int32_t patLen = 0;
729e4ab9
A
1125
1126 /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
1127 * the pattern is the same as the pattern of CURRENCYSTYLE
1128 * but by replacing the single currency sign with
1129 * double currency sign or triple currency sign.
1130 */
1131 int styleInNumberPattern = ((style == kIsoCurrencyStyle ||
1132 style == kPluralCurrencyStyle) ?
1133 kCurrencyStyle : style);
1134
1135 resource = ures_getByKeyWithFallback(resource, gNumberElements, resource, &status);
1136 // TODO : Get patterns on a per numbering system basis, for right now assumes "latn" for patterns
1137 resource = ures_getByKeyWithFallback(resource, gLatn, resource, &status);
1138 resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status);
1139
1140 const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[styleInNumberPattern], &patLen, &status);
1141
374ca955
A
1142 // Creates the specified decimal format style of the desired locale.
1143 pattern.setTo(TRUE, patResStr, patLen);
b75a7d8f 1144 }
374ca955
A
1145 if (U_FAILURE(status) || symbolsToAdopt == NULL) {
1146 goto cleanup;
b75a7d8f 1147 }
729e4ab9 1148 if(style==kCurrencyStyle || style == kIsoCurrencyStyle){
73c04bcf
A
1149 const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
1150 if(currPattern!=NULL){
1151 pattern.setTo(currPattern, u_strlen(currPattern));
b75a7d8f
A
1152 }
1153 }
729e4ab9
A
1154
1155 // Use numbering system cache hashtable
1156 UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache);
1157 if (getCache) {
1158 umtx_lock(&nscacheMutex);
1159 cache = NumberingSystem_cache;
1160 umtx_unlock(&nscacheMutex);
1161 }
1162
1163 // Check cache we got, create if non-existant
1164 status = U_ZERO_ERROR;
1165 if (cache == NULL) {
1166 cache = uhash_open(uhash_hashLong,
1167 uhash_compareLong,
1168 NULL,
1169 &status);
1170
1171 if (cache == NULL || U_FAILURE(status)) {
1172 // cache not created - out of memory
1173 cache = NULL;
1174 }
1175 else {
1176 // cache created
1177 uhash_setValueDeleter(cache, deleteNumberingSystem);
1178
1179 // set final NumberingSystem_cache value
1180 UHashtable* h = NULL;
1181
1182 UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache);
1183 if (getCache) {
1184 umtx_lock(&nscacheMutex);
1185 h = NumberingSystem_cache;
1186 umtx_unlock(&nscacheMutex);
1187 }
1188 if (h == NULL) {
1189 umtx_lock(&nscacheMutex);
1190 NumberingSystem_cache = h = cache;
1191 cache = NULL;
1192 ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
1193 umtx_unlock(&nscacheMutex);
1194 }
1195
1196 if(cache != NULL) {
1197 uhash_close(cache);
1198 }
1199 cache = h;
1200 }
1201 }
1202
1203 // Get cached numbering system
1204 if (cache != NULL) {
1205 hashKey = desiredLocale.hashCode();
1206
1207 umtx_lock(&nscacheMutex);
1208 ns = (NumberingSystem *)uhash_iget(cache, hashKey);
1209 if (ns == NULL) {
1210 ns = NumberingSystem::createInstance(desiredLocale,status);
1211 uhash_iput(cache, hashKey, (void*)ns, &status);
1212 }
1213 umtx_unlock(&nscacheMutex);
1214 }
1215 else {
1216 ns = NumberingSystem::createInstance(desiredLocale,status);
1217 deleteNS = TRUE;
1218 }
1219
1220 // check results of getting a numbering system
1221 if ((ns == NULL) || (U_FAILURE(status))) {
374ca955 1222 goto cleanup;
b75a7d8f
A
1223 }
1224
729e4ab9
A
1225 if (ns->isAlgorithmic()) {
1226 UnicodeString nsDesc;
1227 UnicodeString nsRuleSetGroup;
1228 UnicodeString nsRuleSetName;
1229 Locale nsLoc;
1230 URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM;
1231
1232 nsDesc.setTo(ns->getDescription());
1233 int32_t firstSlash = nsDesc.indexOf(gSlash);
1234 int32_t lastSlash = nsDesc.lastIndexOf(gSlash);
1235 if ( lastSlash > firstSlash ) {
1236 char nsLocID[ULOC_FULLNAME_CAPACITY];
1237
1238 nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV);
1239 nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1);
1240 nsRuleSetName.setTo(nsDesc,lastSlash+1);
1241
1242 nsLoc = Locale::createFromName(nsLocID);
1243
1244 UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules");
1245 if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) {
1246 desiredRulesType = URBNF_SPELLOUT;
1247 }
1248 } else {
1249 nsLoc = desiredLocale;
1250 nsRuleSetName.setTo(nsDesc);
1251 }
1252
1253 RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status);
1254
1255 if (U_FAILURE(status) || r == NULL) {
1256 goto cleanup;
1257 }
1258 r->setDefaultRuleSet(nsRuleSetName,status);
1259 f = (NumberFormat *) r;
1260
1261 } else {
1262 // replace single currency sign in the pattern with double currency sign
1263 // if the style is kIsoCurrencyStyle
1264 if (style == kIsoCurrencyStyle) {
1265 pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign);
1266 }
1267
1268 f = new DecimalFormat(pattern, symbolsToAdopt, style, status);
1269 if (U_FAILURE(status) || f == NULL) {
1270 goto cleanup;
1271 }
1272 deleteSymbols = FALSE;
1273 }
1274
1275 f->setLocaleIDs(ures_getLocaleByType(resource, ULOC_VALID_LOCALE, &status),
1276 ures_getLocaleByType(resource, ULOC_ACTUAL_LOCALE, &status));
1277
374ca955 1278cleanup:
374ca955 1279 ures_close(resource);
729e4ab9
A
1280
1281 if (deleteNS && ns) {
1282 delete ns;
1283 }
1284
374ca955
A
1285 if (U_FAILURE(status)) {
1286 /* If f exists, then it will delete the symbols */
1287 if (f==NULL) {
1288 delete symbolsToAdopt;
1289 }
1290 else {
1291 delete f;
1292 }
b75a7d8f
A
1293 return NULL;
1294 }
374ca955
A
1295 if (f == NULL || symbolsToAdopt == NULL) {
1296 status = U_MEMORY_ALLOCATION_ERROR;
b75a7d8f
A
1297 f = NULL;
1298 }
729e4ab9
A
1299 if (deleteSymbols && symbolsToAdopt != NULL) {
1300 delete symbolsToAdopt;
1301 }
b75a7d8f
A
1302 return f;
1303}
1304
1305U_NAMESPACE_END
1306
b75a7d8f
A
1307#endif /* #if !UCONFIG_NO_FORMATTING */
1308
1309//eof