]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/ucurr.cpp
ICU-400.38.tar.gz
[apple/icu.git] / icuSources / i18n / ucurr.cpp
1 /*
2 **********************************************************************
3 * Copyright (c) 2002-2008, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 */
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_FORMATTING
11
12 #include "unicode/ucurr.h"
13 #include "unicode/locid.h"
14 #include "unicode/ures.h"
15 #include "unicode/ustring.h"
16 #include "unicode/choicfmt.h"
17 #include "unicode/parsepos.h"
18 #include "ustr_imp.h"
19 #include "cmemory.h"
20 #include "cstring.h"
21 #include "uassert.h"
22 #include "umutex.h"
23 #include "ucln_in.h"
24 #include "uenumimp.h"
25 #include "uresimp.h"
26
27 //------------------------------------------------------------
28 // Constants
29
30 // Default currency meta data of last resort. We try to use the
31 // defaults encoded in the meta data resource bundle. If there is a
32 // configuration/build error and these are not available, we use these
33 // hard-coded defaults (which should be identical).
34 static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
35
36 // POW10[i] = 10^i, i=0..MAX_POW10
37 static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
38 1000000, 10000000, 100000000, 1000000000 };
39
40 static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
41
42 #define ISO_COUNTRY_CODE_LENGTH 3
43
44 //------------------------------------------------------------
45 // Resource tags
46 //
47
48 static const char CURRENCY_DATA[] = "supplementalData";
49 // Tag for meta-data, in root.
50 static const char CURRENCY_META[] = "CurrencyMeta";
51
52 // Tag for map from countries to currencies, in root.
53 static const char CURRENCY_MAP[] = "CurrencyMap";
54
55 // Tag for default meta-data, in CURRENCY_META
56 static const char DEFAULT_META[] = "DEFAULT";
57
58 // Variant for legacy pre-euro mapping in CurrencyMap
59 static const char VAR_PRE_EURO[] = "PREEURO";
60
61 // Variant for legacy euro mapping in CurrencyMap
62 static const char VAR_EURO[] = "EURO";
63
64 // Variant delimiter
65 static const char VAR_DELIM = '_';
66 static const char VAR_DELIM_STR[] = "_";
67
68 // Variant for legacy euro mapping in CurrencyMap
69 //static const char VAR_DELIM_EURO[] = "_EURO";
70
71 #define VARIANT_IS_EMPTY 0
72 #define VARIANT_IS_EURO 0x1
73 #define VARIANT_IS_PREEURO 0x2
74
75 // Tag for localized display names (symbols) of currencies
76 static const char CURRENCIES[] = "Currencies";
77
78 // Marker character indicating that a display name is a ChoiceFormat
79 // pattern. Strings that start with one mark are ChoiceFormat
80 // patterns. Strings that start with 2 marks are static strings, and
81 // the first mark is deleted.
82 static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
83
84 static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
85
86 //------------------------------------------------------------
87 // Code
88
89 /**
90 * Unfortunately, we have to convert the UChar* currency code to char*
91 * to use it as a resource key.
92 */
93 static inline char*
94 myUCharsToChars(char* resultOfLen4, const UChar* currency) {
95 u_UCharsToChars(currency, resultOfLen4, ISO_COUNTRY_CODE_LENGTH);
96 resultOfLen4[ISO_COUNTRY_CODE_LENGTH] = 0;
97 return resultOfLen4;
98 }
99
100 /**
101 * Internal function to look up currency data. Result is an array of
102 * two integers. The first is the fraction digits. The second is the
103 * rounding increment, or 0 if none. The rounding increment is in
104 * units of 10^(-fraction_digits).
105 */
106 static const int32_t*
107 _findMetaData(const UChar* currency, UErrorCode& ec) {
108
109 if (currency == 0 || *currency == 0) {
110 if (U_SUCCESS(ec)) {
111 ec = U_ILLEGAL_ARGUMENT_ERROR;
112 }
113 return LAST_RESORT_DATA;
114 }
115
116 // Get CurrencyMeta resource out of root locale file. [This may
117 // move out of the root locale file later; if it does, update this
118 // code.]
119 UResourceBundle* currencyData = ures_openDirect(NULL, CURRENCY_DATA, &ec);
120 UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
121
122 if (U_FAILURE(ec)) {
123 ures_close(currencyMeta);
124 // Config/build error; return hard-coded defaults
125 return LAST_RESORT_DATA;
126 }
127
128 // Look up our currency, or if that's not available, then DEFAULT
129 char buf[ISO_COUNTRY_CODE_LENGTH+1];
130 UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
131 UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
132 if (U_FAILURE(ec2)) {
133 ures_close(rb);
134 rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
135 if (U_FAILURE(ec)) {
136 ures_close(currencyMeta);
137 ures_close(rb);
138 // Config/build error; return hard-coded defaults
139 return LAST_RESORT_DATA;
140 }
141 }
142
143 int32_t len;
144 const int32_t *data = ures_getIntVector(rb, &len, &ec);
145 if (U_FAILURE(ec) || len != 2) {
146 // Config/build error; return hard-coded defaults
147 if (U_SUCCESS(ec)) {
148 ec = U_INVALID_FORMAT_ERROR;
149 }
150 ures_close(currencyMeta);
151 ures_close(rb);
152 return LAST_RESORT_DATA;
153 }
154
155 ures_close(currencyMeta);
156 ures_close(rb);
157 return data;
158 }
159
160 // -------------------------------------
161
162 /**
163 * @see VARIANT_IS_EURO
164 * @see VARIANT_IS_PREEURO
165 */
166 static uint32_t
167 idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
168 {
169 uint32_t variantType = 0;
170 // !!! this is internal only, assumes buffer is not null and capacity is sufficient
171 // Extract the country name and variant name. We only
172 // recognize two variant names, EURO and PREEURO.
173 char variant[ULOC_FULLNAME_CAPACITY];
174 uloc_getCountry(locale, countryAndVariant, capacity, ec);
175 uloc_getVariant(locale, variant, sizeof(variant), ec);
176 if (variant[0] != 0) {
177 variantType = (0 == uprv_strcmp(variant, VAR_EURO))
178 | ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
179 if (variantType)
180 {
181 uprv_strcat(countryAndVariant, VAR_DELIM_STR);
182 uprv_strcat(countryAndVariant, variant);
183 }
184 }
185 return variantType;
186 }
187
188 // ------------------------------------------
189 //
190 // Registration
191 //
192 //-------------------------------------------
193
194 // don't use ICUService since we don't need fallback
195
196 #if !UCONFIG_NO_SERVICE
197 U_CDECL_BEGIN
198 static UBool U_CALLCONV currency_cleanup(void);
199 U_CDECL_END
200 struct CReg;
201
202 /* Remember to call umtx_init(&gCRegLock) before using it! */
203 static UMTX gCRegLock = 0;
204 static CReg* gCRegHead = 0;
205
206 struct CReg : public U_NAMESPACE_QUALIFIER UMemory {
207 CReg *next;
208 UChar iso[ISO_COUNTRY_CODE_LENGTH+1];
209 char id[ULOC_FULLNAME_CAPACITY];
210
211 CReg(const UChar* _iso, const char* _id)
212 : next(0)
213 {
214 int32_t len = (int32_t)uprv_strlen(_id);
215 if (len > (int32_t)(sizeof(id)-1)) {
216 len = (sizeof(id)-1);
217 }
218 uprv_strncpy(id, _id, len);
219 id[len] = 0;
220 uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar));
221 iso[ISO_COUNTRY_CODE_LENGTH] = 0;
222 }
223
224 static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
225 {
226 if (status && U_SUCCESS(*status) && _iso && _id) {
227 CReg* n = new CReg(_iso, _id);
228 if (n) {
229 umtx_init(&gCRegLock);
230 umtx_lock(&gCRegLock);
231 if (!gCRegHead) {
232 /* register for the first time */
233 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
234 }
235 n->next = gCRegHead;
236 gCRegHead = n;
237 umtx_unlock(&gCRegLock);
238 return n;
239 }
240 *status = U_MEMORY_ALLOCATION_ERROR;
241 }
242 return 0;
243 }
244
245 static UBool unreg(UCurrRegistryKey key) {
246 UBool found = FALSE;
247 umtx_init(&gCRegLock);
248 umtx_lock(&gCRegLock);
249
250 CReg** p = &gCRegHead;
251 while (*p) {
252 if (*p == key) {
253 *p = ((CReg*)key)->next;
254 delete (CReg*)key;
255 found = TRUE;
256 break;
257 }
258 p = &((*p)->next);
259 }
260
261 umtx_unlock(&gCRegLock);
262 return found;
263 }
264
265 static const UChar* get(const char* id) {
266 const UChar* result = NULL;
267 umtx_init(&gCRegLock);
268 umtx_lock(&gCRegLock);
269 CReg* p = gCRegHead;
270
271 /* register cleanup of the mutex */
272 ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
273 while (p) {
274 if (uprv_strcmp(id, p->id) == 0) {
275 result = p->iso;
276 break;
277 }
278 p = p->next;
279 }
280 umtx_unlock(&gCRegLock);
281 return result;
282 }
283
284 /* This doesn't need to be thread safe. It's for u_cleanup only. */
285 static void cleanup(void) {
286 while (gCRegHead) {
287 CReg* n = gCRegHead;
288 gCRegHead = gCRegHead->next;
289 delete n;
290 }
291 umtx_destroy(&gCRegLock);
292 }
293 };
294
295 /**
296 * Release all static memory held by currency.
297 */
298 U_CDECL_BEGIN
299 static UBool U_CALLCONV currency_cleanup(void) {
300 #if !UCONFIG_NO_SERVICE
301 CReg::cleanup();
302 #endif
303 return TRUE;
304 }
305 U_CDECL_END
306
307 // -------------------------------------
308
309 U_CAPI UCurrRegistryKey U_EXPORT2
310 ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
311 {
312 if (status && U_SUCCESS(*status)) {
313 char id[ULOC_FULLNAME_CAPACITY];
314 idForLocale(locale, id, sizeof(id), status);
315 return CReg::reg(isoCode, id, status);
316 }
317 return NULL;
318 }
319
320 // -------------------------------------
321
322 U_CAPI UBool U_EXPORT2
323 ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
324 {
325 if (status && U_SUCCESS(*status)) {
326 return CReg::unreg(key);
327 }
328 return FALSE;
329 }
330 #endif /* UCONFIG_NO_SERVICE */
331
332 // -------------------------------------
333
334 U_CAPI int32_t U_EXPORT2
335 ucurr_forLocale(const char* locale,
336 UChar* buff,
337 int32_t buffCapacity,
338 UErrorCode* ec)
339 {
340 int32_t resLen = 0;
341 const UChar* s = NULL;
342 if (ec != NULL && U_SUCCESS(*ec)) {
343 if ((buff && buffCapacity) || !buffCapacity) {
344 UErrorCode localStatus = U_ZERO_ERROR;
345 char id[ULOC_FULLNAME_CAPACITY];
346 if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
347 // there is a currency keyword. Try to see if it's valid
348 if(buffCapacity > resLen) {
349 u_charsToUChars(id, buff, resLen);
350 }
351 } else {
352 // get country or country_variant in `id'
353 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
354
355 if (U_FAILURE(*ec)) {
356 return 0;
357 }
358
359 #if !UCONFIG_NO_SERVICE
360 const UChar* result = CReg::get(id);
361 if (result) {
362 if(buffCapacity > u_strlen(result)) {
363 u_strcpy(buff, result);
364 }
365 return u_strlen(result);
366 }
367 #endif
368 // Remove variants, which is only needed for registration.
369 char *idDelim = strchr(id, VAR_DELIM);
370 if (idDelim) {
371 idDelim[0] = 0;
372 }
373
374 // Look up the CurrencyMap element in the root bundle.
375 UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
376 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
377 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
378 UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
379 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
380
381 /*
382 Get the second item when PREEURO is requested, and this is a known Euro country.
383 If the requested variant is PREEURO, and this isn't a Euro country, assume
384 that the country changed over to the Euro in the future. This is probably
385 an old version of ICU that hasn't been updated yet. The latest currency is
386 probably correct.
387 */
388 if (U_SUCCESS(localStatus)) {
389 if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
390 currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
391 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
392 }
393 else if ((variantType & VARIANT_IS_EURO)) {
394 s = EUR_STR;
395 }
396 }
397 ures_close(countryArray);
398 ures_close(currencyReq);
399
400 if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
401 {
402 // We don't know about it. Check to see if we support the variant.
403 uloc_getParent(locale, id, sizeof(id), ec);
404 *ec = U_USING_FALLBACK_WARNING;
405 return ucurr_forLocale(id, buff, buffCapacity, ec);
406 }
407 else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
408 // There is nothing to fallback to. Report the failure/warning if possible.
409 *ec = localStatus;
410 }
411 if (U_SUCCESS(*ec)) {
412 if(buffCapacity > resLen) {
413 u_strcpy(buff, s);
414 }
415 }
416 }
417 return u_terminateUChars(buff, buffCapacity, resLen, ec);
418 } else {
419 *ec = U_ILLEGAL_ARGUMENT_ERROR;
420 }
421 }
422 return resLen;
423 }
424
425 // end registration
426
427 /**
428 * Modify the given locale name by removing the rightmost _-delimited
429 * element. If there is none, empty the string ("" == root).
430 * NOTE: The string "root" is not recognized; do not use it.
431 * @return TRUE if the fallback happened; FALSE if locale is already
432 * root ("").
433 */
434 static UBool fallback(char *loc) {
435 if (!*loc) {
436 return FALSE;
437 }
438 UErrorCode status = U_ZERO_ERROR;
439 uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
440 /*
441 char *i = uprv_strrchr(loc, '_');
442 if (i == NULL) {
443 i = loc;
444 }
445 *i = 0;
446 */
447 return TRUE;
448 }
449
450
451 U_CAPI const UChar* U_EXPORT2
452 ucurr_getName(const UChar* currency,
453 const char* locale,
454 UCurrNameStyle nameStyle,
455 UBool* isChoiceFormat, // fillin
456 int32_t* len, // fillin
457 UErrorCode* ec) {
458
459 // Look up the Currencies resource for the given locale. The
460 // Currencies locale data looks like this:
461 //|en {
462 //| Currencies {
463 //| USD { "US$", "US Dollar" }
464 //| CHF { "Sw F", "Swiss Franc" }
465 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
466 //| //...
467 //| }
468 //|}
469
470 if (U_FAILURE(*ec)) {
471 return 0;
472 }
473
474 int32_t choice = (int32_t) nameStyle;
475 if (choice < 0 || choice > 1) {
476 *ec = U_ILLEGAL_ARGUMENT_ERROR;
477 return 0;
478 }
479
480 // In the future, resource bundles may implement multi-level
481 // fallback. That is, if a currency is not found in the en_US
482 // Currencies data, then the en Currencies data will be searched.
483 // Currently, if a Currencies datum exists in en_US and en, the
484 // en_US entry hides that in en.
485
486 // We want multi-level fallback for this resource, so we implement
487 // it manually.
488
489 // Use a separate UErrorCode here that does not propagate out of
490 // this function.
491 UErrorCode ec2 = U_ZERO_ERROR;
492
493 char loc[ULOC_FULLNAME_CAPACITY];
494 uloc_getName(locale, loc, sizeof(loc), &ec2);
495 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
496 *ec = U_ILLEGAL_ARGUMENT_ERROR;
497 return 0;
498 }
499
500 char buf[ISO_COUNTRY_CODE_LENGTH+1];
501 myUCharsToChars(buf, currency);
502
503 const UChar* s = NULL;
504 ec2 = U_ZERO_ERROR;
505 UResourceBundle* rb = ures_open(NULL, loc, &ec2);
506
507 rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
508
509 // Fetch resource with multi-level resource inheritance fallback
510 rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
511
512 s = ures_getStringByIndex(rb, choice, len, &ec2);
513 ures_close(rb);
514
515 // If we've succeeded we're done. Otherwise, try to fallback.
516 // If that fails (because we are already at root) then exit.
517 if (U_SUCCESS(ec2)) {
518 if (ec2 == U_USING_DEFAULT_WARNING
519 || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
520 *ec = ec2;
521 }
522 }
523
524 // Determine if this is a ChoiceFormat pattern. One leading mark
525 // indicates a ChoiceFormat. Two indicates a static string that
526 // starts with a mark. In either case, the first mark is ignored,
527 // if present. Marks in the rest of the string have no special
528 // meaning.
529 *isChoiceFormat = FALSE;
530 if (U_SUCCESS(ec2)) {
531 U_ASSERT(s != NULL);
532 int32_t i=0;
533 while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
534 ++i;
535 }
536 *isChoiceFormat = (i == 1);
537 if (i != 0) ++s; // Skip over first mark
538 return s;
539 }
540
541 // If we fail to find a match, use the ISO 4217 code
542 *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
543 *ec = U_USING_DEFAULT_WARNING;
544 return currency;
545 }
546
547 U_CFUNC void
548 uprv_parseCurrency(const char* locale,
549 const U_NAMESPACE_QUALIFIER UnicodeString& text,
550 U_NAMESPACE_QUALIFIER ParsePosition& pos,
551 UChar* result,
552 UErrorCode& ec)
553 {
554 U_NAMESPACE_USE
555
556 // TODO: There is a slight problem with the pseudo-multi-level
557 // fallback implemented here. More-specific locales don't
558 // properly shield duplicate entries in less-specific locales.
559 // This problem will go away when real multi-level fallback is
560 // implemented. We could also fix this by recording (in a
561 // hash) which codes are used at each level of fallback, but
562 // this doesn't seem warranted.
563
564 if (U_FAILURE(ec)) {
565 return;
566 }
567
568 // Look up the Currencies resource for the given locale. The
569 // Currencies locale data looks like this:
570 //|en {
571 //| Currencies {
572 //| USD { "US$", "US Dollar" }
573 //| CHF { "Sw F", "Swiss Franc" }
574 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
575 //| //...
576 //| }
577 //|}
578
579 // In the future, resource bundles may implement multi-level
580 // fallback. That is, if a currency is not found in the en_US
581 // Currencies data, then the en Currencies data will be searched.
582 // Currently, if a Currencies datum exists in en_US and en, the
583 // en_US entry hides that in en.
584
585 // We want multi-level fallback for this resource, so we implement
586 // it manually.
587
588 // Use a separate UErrorCode here that does not propagate out of
589 // this function.
590 UErrorCode ec2 = U_ZERO_ERROR;
591
592 char loc[ULOC_FULLNAME_CAPACITY];
593 uloc_getName(locale, loc, sizeof(loc), &ec2);
594 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
595 ec = U_ILLEGAL_ARGUMENT_ERROR;
596 return;
597 }
598
599 int32_t start = pos.getIndex();
600 const UChar* s = NULL;
601
602 const char* iso = NULL;
603 int32_t max = 0;
604
605 // Multi-level resource inheritance fallback loop
606 for (;;) {
607 ec2 = U_ZERO_ERROR;
608 UResourceBundle* rb = ures_open(NULL, loc, &ec2);
609 UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
610 int32_t n = ures_getSize(curr);
611 for (int32_t i=0; i<n; ++i) {
612 UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
613 int32_t len;
614 s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
615 UBool isChoice = FALSE;
616 if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
617 ++s;
618 --len;
619 if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
620 isChoice = TRUE;
621 }
622 }
623 if (isChoice) {
624 Formattable temp;
625 ChoiceFormat fmt(s, ec2);
626 fmt.parse(text, temp, pos);
627 len = pos.getIndex() - start;
628 pos.setIndex(start);
629 } else if (len > max &&
630 text.compare(pos.getIndex(), len, s) != 0) {
631 len = 0;
632 }
633 if (len > max) {
634 iso = ures_getKey(names);
635 max = len;
636 }
637 ures_close(names);
638 }
639 ures_close(curr);
640 ures_close(rb);
641
642 // Try to fallback. If that fails (because we are already at
643 // root) then exit.
644 if (!fallback(loc)) {
645 break;
646 }
647 }
648
649 if (iso != NULL) {
650 u_charsToUChars(iso, result, 4);
651 }
652
653 // If display name parse fails or if it matches fewer than 3
654 // characters, try to parse 3-letter ISO. Do this after the
655 // display name processing so 3-letter display names are
656 // preferred. Consider /[A-Z]{3}/ to be valid ISO, and parse
657 // it manually--UnicodeSet/regex are too slow and heavy.
658 if (max < 3 && (text.length() - start) >= 3) {
659 UBool valid = TRUE;
660 for (int32_t k=0; k<3; ++k) {
661 UChar ch = text.charAt(start + k); // 16-bit ok
662 if (ch < 0x41/*'A'*/ || ch > 0x5A/*'Z'*/) {
663 valid = FALSE;
664 break;
665 }
666 }
667 if (valid) {
668 text.extract(start, 3, result);
669 result[3] = 0;
670 max = 3;
671 }
672 }
673
674 pos.setIndex(start + max);
675 }
676
677 /**
678 * Internal method. Given a currency ISO code and a locale, return
679 * the "static" currency name. This is usually the same as the
680 * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
681 * format is applied to the number 2.0 (to yield the more common
682 * plural) to return a static name.
683 *
684 * This is used for backward compatibility with old currency logic in
685 * DecimalFormat and DecimalFormatSymbols.
686 */
687 U_CFUNC void
688 uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
689 U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec)
690 {
691 U_NAMESPACE_USE
692
693 UBool isChoiceFormat;
694 int32_t len;
695 const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
696 &isChoiceFormat, &len, &ec);
697 if (U_SUCCESS(ec)) {
698 // If this is a ChoiceFormat currency, then format an
699 // arbitrary value; pick something != 1; more common.
700 result.truncate(0);
701 if (isChoiceFormat) {
702 ChoiceFormat f(currname, ec);
703 if (U_SUCCESS(ec)) {
704 f.format(2.0, result);
705 } else {
706 result = iso;
707 }
708 } else {
709 result = currname;
710 }
711 }
712 }
713
714 U_CAPI int32_t U_EXPORT2
715 ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
716 return (_findMetaData(currency, *ec))[0];
717 }
718
719 U_CAPI double U_EXPORT2
720 ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
721 const int32_t *data = _findMetaData(currency, *ec);
722
723 // If the meta data is invalid, return 0.0.
724 if (data[0] < 0 || data[0] > MAX_POW10) {
725 if (U_SUCCESS(*ec)) {
726 *ec = U_INVALID_FORMAT_ERROR;
727 }
728 return 0.0;
729 }
730
731 // If there is no rounding, return 0.0 to indicate no rounding. A
732 // rounding value (data[1]) of 0 or 1 indicates no rounding.
733 if (data[1] < 2) {
734 return 0.0;
735 }
736
737 // Return data[1] / 10^(data[0]). The only actual rounding data,
738 // as of this writing, is CHF { 2, 5 }.
739 return double(data[1]) / POW10[data[0]];
740 }
741
742 U_CDECL_BEGIN
743
744 typedef struct UCurrencyContext {
745 uint32_t currType; /* UCurrCurrencyType */
746 uint32_t listIdx;
747 } UCurrencyContext;
748
749 /*
750 Please keep this list in alphabetical order.
751 You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
752 of these items.
753 ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
754 */
755 static const struct CurrencyList {
756 const char *currency;
757 uint32_t currType;
758 } gCurrencyList[] = {
759 {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
760 {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
761 {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
762 {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
763 {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
764 {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
765 {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
766 {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
767 {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
768 {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
769 {"AON", UCURR_COMMON|UCURR_DEPRECATED},
770 {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
771 {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
772 {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
773 {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
774 {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
775 {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
776 {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
777 {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
778 {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
779 {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
780 {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
781 {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
782 {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
783 {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
784 {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
785 {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
786 {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
787 {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
788 {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
789 {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
790 {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
791 {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
792 {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
793 {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
794 {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
795 {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
796 {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
797 {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
798 {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
799 {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
800 {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
801 {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
802 {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
803 {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
804 {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
805 {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
806 {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
807 {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
808 {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
809 {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
810 {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
811 {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
812 {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
813 {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
814 {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
815 {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
816 {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
817 {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
818 {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
819 {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
820 {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
821 {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
822 {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
823 {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
824 {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
825 {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
826 {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
827 {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
828 {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
829 {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
830 {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
831 {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
832 {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
833 {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
834 {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
835 {"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
836 {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
837 {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
838 {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
839 {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
840 {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
841 {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
842 {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
843 {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
844 {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
845 {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
846 {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
847 {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
848 {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
849 {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
850 {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
851 {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
852 {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
853 {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
854 {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
855 {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
856 {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
857 {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
858 {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
859 {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
860 {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
861 {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
862 {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
863 {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
864 {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
865 {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
866 {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
867 {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
868 {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
869 {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
870 {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
871 {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
872 {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
873 {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
874 {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
875 {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
876 {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
877 {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
878 {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
879 {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
880 {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
881 {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
882 {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
883 {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
884 {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
885 {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
886 {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
887 {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
888 {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
889 {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
890 {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
891 {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
892 {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
893 {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
894 {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
895 {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
896 {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
897 {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
898 {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
899 {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
900 {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
901 {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
902 {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
903 {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
904 {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
905 {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
906 {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
907 {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
908 {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
909 {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
910 {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
911 {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
912 {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
913 {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
914 {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
915 {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
916 {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
917 {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
918 {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
919 {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
920 {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
921 {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
922 {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
923 {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
924 {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
925 {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
926 {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
927 {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
928 {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
929 {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
930 {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
931 {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
932 {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
933 {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
934 {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
935 {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
936 {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
937 {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
938 {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
939 {"PES", UCURR_COMMON|UCURR_DEPRECATED},
940 {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
941 {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
942 {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
943 {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
944 {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
945 {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
946 {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
947 {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
948 {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
949 {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
950 {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
951 {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
952 {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
953 {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
954 {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
955 {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
956 {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
957 {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
958 {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
959 {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
960 {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
961 {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
962 {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
963 {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
964 {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
965 {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
966 {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
967 {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
968 {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
969 {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
970 {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
971 {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
972 {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
973 {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
974 {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
975 {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
976 {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
977 {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
978 {"TMM", UCURR_COMMON|UCURR_NON_DEPRECATED},
979 {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
980 {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
981 {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
982 {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
983 {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
984 {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
985 {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
986 {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
987 {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
988 {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
989 {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
990 {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
991 {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
992 {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
993 {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
994 {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
995 {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
996 {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
997 {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
998 {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
999 {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1000 {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1001 {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
1002 {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
1003 {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1004 {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1005 {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1006 {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1007 {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1008 {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1009 {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1010 {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1011 {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1012 {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
1013 {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1014 {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1015 {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1016 {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1017 {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1018 {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1019 {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1020 {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1021 {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1022 {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
1023 {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
1024 {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
1025 {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
1026 {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
1027 {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1028 {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1029 {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1030 {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
1031 {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
1032 {"ZWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1033 { NULL, 0 } // Leave here to denote the end of the list.
1034 };
1035
1036 #define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1037 ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
1038
1039 static int32_t U_CALLCONV
1040 ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1041 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1042 uint32_t currType = myContext->currType;
1043 int32_t count = 0;
1044
1045 /* Count the number of items matching the type we are looking for. */
1046 for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
1047 if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
1048 count++;
1049 }
1050 }
1051 return count;
1052 }
1053
1054 static const char* U_CALLCONV
1055 ucurr_nextCurrencyList(UEnumeration *enumerator,
1056 int32_t* resultLength,
1057 UErrorCode * /*pErrorCode*/)
1058 {
1059 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1060
1061 /* Find the next in the list that matches the type we are looking for. */
1062 while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
1063 const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
1064 if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
1065 {
1066 if (resultLength) {
1067 *resultLength = 3; /* Currency codes are only 3 chars long */
1068 }
1069 return currItem->currency;
1070 }
1071 }
1072 /* We enumerated too far. */
1073 if (resultLength) {
1074 *resultLength = 0;
1075 }
1076 return NULL;
1077 }
1078
1079 static void U_CALLCONV
1080 ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1081 ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
1082 }
1083
1084 static void U_CALLCONV
1085 ucurr_closeCurrencyList(UEnumeration *enumerator) {
1086 uprv_free(enumerator->context);
1087 uprv_free(enumerator);
1088 }
1089
1090 static const UEnumeration gEnumCurrencyList = {
1091 NULL,
1092 NULL,
1093 ucurr_closeCurrencyList,
1094 ucurr_countCurrencyList,
1095 uenum_unextDefault,
1096 ucurr_nextCurrencyList,
1097 ucurr_resetCurrencyList
1098 };
1099 U_CDECL_END
1100
1101 U_CAPI UEnumeration * U_EXPORT2
1102 ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
1103 UEnumeration *myEnum = NULL;
1104 UCurrencyContext *myContext;
1105
1106 myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
1107 if (myEnum == NULL) {
1108 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
1109 return NULL;
1110 }
1111 uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
1112 myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
1113 if (myContext == NULL) {
1114 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
1115 uprv_free(myEnum);
1116 return NULL;
1117 }
1118 myContext->currType = currType;
1119 myContext->listIdx = 0;
1120 myEnum->context = myContext;
1121 return myEnum;
1122 }
1123
1124 U_CAPI int32_t U_EXPORT2
1125 ucurr_countCurrencies(const char* locale,
1126 UDate date,
1127 UErrorCode* ec)
1128 {
1129 int32_t currCount = 0;
1130 int32_t resLen = 0;
1131 const UChar* s = NULL;
1132
1133 if (ec != NULL && U_SUCCESS(*ec))
1134 {
1135 // local variables
1136 UErrorCode localStatus = U_ZERO_ERROR;
1137 char id[ULOC_FULLNAME_CAPACITY];
1138 resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
1139
1140 // get country or country_variant in `id'
1141 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
1142 if (U_FAILURE(*ec))
1143 {
1144 return 0;
1145 }
1146
1147 // Remove variants, which is only needed for registration.
1148 char *idDelim = strchr(id, VAR_DELIM);
1149 if (idDelim)
1150 {
1151 idDelim[0] = 0;
1152 }
1153
1154 // Look up the CurrencyMap element in the root bundle.
1155 UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
1156 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
1157
1158 // Using the id derived from the local, get the currency data
1159 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
1160
1161 // process each currency to see which one is valid for the given date
1162 if (U_SUCCESS(localStatus))
1163 {
1164 for (int32_t i=0; i<ures_getSize(countryArray); i++)
1165 {
1166 // get the currency resource
1167 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
1168 s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
1169
1170 // get the from date
1171 int32_t fromLength = 0;
1172 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
1173 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
1174
1175 int64_t currDate64 = (int64_t)fromArray[0] << 32;
1176 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1177 UDate fromDate = (UDate)currDate64;
1178
1179 if (ures_getSize(currencyRes) > 2)
1180 {
1181 int32_t toLength = 0;
1182 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
1183 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
1184
1185 currDate64 = (int64_t)toArray[0] << 32;
1186 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1187 UDate toDate = (UDate)currDate64;
1188
1189 if ((fromDate <= date) && (date < toDate))
1190 {
1191 currCount++;
1192 }
1193
1194 ures_close(toRes);
1195 }
1196 else
1197 {
1198 if (fromDate <= date)
1199 {
1200 currCount++;
1201 }
1202 }
1203
1204 // close open resources
1205 ures_close(currencyRes);
1206 ures_close(fromRes);
1207
1208 } // end For loop
1209 } // end if (U_SUCCESS(localStatus))
1210
1211 ures_close(countryArray);
1212
1213 // Check for errors
1214 if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
1215 {
1216 // There is nothing to fallback to.
1217 // Report the failure/warning if possible.
1218 *ec = localStatus;
1219 }
1220
1221 if (U_SUCCESS(*ec))
1222 {
1223 // no errors
1224 return currCount;
1225 }
1226
1227 }
1228
1229 // If we got here, either error code is invalid or
1230 // some argument passed is no good.
1231 return 0;
1232 }
1233
1234 U_CAPI int32_t U_EXPORT2
1235 ucurr_forLocaleAndDate(const char* locale,
1236 UDate date,
1237 int32_t index,
1238 UChar* buff,
1239 int32_t buffCapacity,
1240 UErrorCode* ec)
1241 {
1242 int32_t resLen = 0;
1243 int32_t currIndex = 0;
1244 const UChar* s = NULL;
1245
1246 if (ec != NULL && U_SUCCESS(*ec))
1247 {
1248 // check the arguments passed
1249 if ((buff && buffCapacity) || !buffCapacity )
1250 {
1251 // local variables
1252 UErrorCode localStatus = U_ZERO_ERROR;
1253 char id[ULOC_FULLNAME_CAPACITY];
1254 resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
1255
1256 // get country or country_variant in `id'
1257 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
1258 if (U_FAILURE(*ec))
1259 {
1260 return 0;
1261 }
1262
1263 // Remove variants, which is only needed for registration.
1264 char *idDelim = strchr(id, VAR_DELIM);
1265 if (idDelim)
1266 {
1267 idDelim[0] = 0;
1268 }
1269
1270 // Look up the CurrencyMap element in the root bundle.
1271 UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
1272 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
1273
1274 // Using the id derived from the local, get the currency data
1275 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
1276
1277 // process each currency to see which one is valid for the given date
1278 bool matchFound = false;
1279 if (U_SUCCESS(localStatus))
1280 {
1281 if ((index <= 0) || (index > ures_getSize(countryArray)))
1282 {
1283 // requested index is out of bounds
1284 ures_close(countryArray);
1285 return 0;
1286 }
1287
1288 for (int32_t i=0; i<ures_getSize(countryArray); i++)
1289 {
1290 // get the currency resource
1291 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
1292 s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
1293
1294 // get the from date
1295 int32_t fromLength = 0;
1296 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
1297 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
1298
1299 int64_t currDate64 = (int64_t)fromArray[0] << 32;
1300 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1301 UDate fromDate = (UDate)currDate64;
1302
1303 if (ures_getSize(currencyRes) > 2)
1304 {
1305 int32_t toLength = 0;
1306 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
1307 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
1308
1309 currDate64 = (int64_t)toArray[0] << 32;
1310 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
1311 UDate toDate = (UDate)currDate64;
1312
1313 if ((fromDate <= date) && (date < toDate))
1314 {
1315 currIndex++;
1316 if (currIndex == index)
1317 {
1318 matchFound = true;
1319 }
1320 }
1321
1322 ures_close(toRes);
1323 }
1324 else
1325 {
1326 if (fromDate <= date)
1327 {
1328 currIndex++;
1329 if (currIndex == index)
1330 {
1331 matchFound = true;
1332 }
1333 }
1334 }
1335
1336 // close open resources
1337 ures_close(currencyRes);
1338 ures_close(fromRes);
1339
1340 // check for loop exit
1341 if (matchFound)
1342 {
1343 break;
1344 }
1345
1346 } // end For loop
1347 }
1348
1349 ures_close(countryArray);
1350
1351 // Check for errors
1352 if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
1353 {
1354 // There is nothing to fallback to.
1355 // Report the failure/warning if possible.
1356 *ec = localStatus;
1357 }
1358
1359 if (U_SUCCESS(*ec))
1360 {
1361 // no errors
1362 if((buffCapacity > resLen) && matchFound)
1363 {
1364 // write out the currency value
1365 u_strcpy(buff, s);
1366 }
1367 else
1368 {
1369 return 0;
1370 }
1371 }
1372
1373 // return null terminated currency string
1374 return u_terminateUChars(buff, buffCapacity, resLen, ec);
1375 }
1376 else
1377 {
1378 // illegal argument encountered
1379 *ec = U_ILLEGAL_ARGUMENT_ERROR;
1380 }
1381
1382 }
1383
1384 // If we got here, either error code is invalid or
1385 // some argument passed is no good.
1386 return resLen;
1387 }
1388
1389 #endif /* #if !UCONFIG_NO_FORMATTING */
1390
1391 //eof