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