]>
Commit | Line | Data |
---|---|---|
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 |