]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/ucurr.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / common / ucurr.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4**********************************************************************
2ca993e8 5* Copyright (c) 2002-2016, International Business Machines
b75a7d8f
A
6* Corporation and others. All Rights Reserved.
7**********************************************************************
8*/
9
10#include "unicode/utypes.h"
11
12#if !UCONFIG_NO_FORMATTING
13
14#include "unicode/ucurr.h"
15#include "unicode/locid.h"
374ca955 16#include "unicode/ures.h"
b75a7d8f 17#include "unicode/ustring.h"
374ca955
A
18#include "unicode/parsepos.h"
19#include "ustr_imp.h"
b75a7d8f
A
20#include "cmemory.h"
21#include "cstring.h"
22#include "uassert.h"
46f4442e 23#include "umutex.h"
2ca993e8 24#include "ucln_cmn.h"
73c04bcf 25#include "uenumimp.h"
729e4ab9 26#include "uhash.h"
57a6839d 27#include "hash.h"
46f4442e 28#include "uresimp.h"
729e4ab9
A
29#include "ulist.h"
30#include "ureslocs.h"
2ca993e8 31#include "ulocimp.h"
729e4ab9 32
57a6839d
A
33//#define UCURR_DEBUG_EQUIV 1
34#ifdef UCURR_DEBUG_EQUIV
35#include "stdio.h"
36#endif
37//#define UCURR_DEBUG 1
729e4ab9
A
38#ifdef UCURR_DEBUG
39#include "stdio.h"
40#endif
b75a7d8f 41
4388f060
A
42typedef struct IsoCodeEntry {
43 const UChar *isoCode; /* const because it's a reference to a resource bundle string. */
44 UDate from;
45 UDate to;
46} IsoCodeEntry;
47
b75a7d8f
A
48//------------------------------------------------------------
49// Constants
50
51// Default currency meta data of last resort. We try to use the
52// defaults encoded in the meta data resource bundle. If there is a
53// configuration/build error and these are not available, we use these
54// hard-coded defaults (which should be identical).
57a6839d 55static const int32_t LAST_RESORT_DATA[] = { 2, 0, 2, 0 };
b75a7d8f
A
56
57// POW10[i] = 10^i, i=0..MAX_POW10
58static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
59 1000000, 10000000, 100000000, 1000000000 };
60
2ca993e8 61static const int32_t MAX_POW10 = UPRV_LENGTHOF(POW10) - 1;
b75a7d8f 62
57a6839d
A
63// Defines equivalent currency symbols.
64static const char *EQUIV_CURRENCY_SYMBOLS[][2] = {
65 {"\\u00a5", "\\uffe5"},
66 {"$", "\\ufe69"},
67 {"$", "\\uff04"},
68 {"\\u20a8", "\\u20b9"},
69 {"\\u00a3", "\\u20a4"}};
70
4388f060 71#define ISO_CURRENCY_CODE_LENGTH 3
b75a7d8f
A
72
73//------------------------------------------------------------
74// Resource tags
374ca955 75//
b75a7d8f 76
46f4442e 77static const char CURRENCY_DATA[] = "supplementalData";
b75a7d8f
A
78// Tag for meta-data, in root.
79static const char CURRENCY_META[] = "CurrencyMeta";
80
81// Tag for map from countries to currencies, in root.
82static const char CURRENCY_MAP[] = "CurrencyMap";
83
84// Tag for default meta-data, in CURRENCY_META
85static const char DEFAULT_META[] = "DEFAULT";
86
87// Variant for legacy pre-euro mapping in CurrencyMap
88static const char VAR_PRE_EURO[] = "PREEURO";
89
90// Variant for legacy euro mapping in CurrencyMap
91static const char VAR_EURO[] = "EURO";
92
93// Variant delimiter
46f4442e
A
94static const char VAR_DELIM = '_';
95static const char VAR_DELIM_STR[] = "_";
b75a7d8f 96
374ca955 97// Variant for legacy euro mapping in CurrencyMap
46f4442e 98//static const char VAR_DELIM_EURO[] = "_EURO";
374ca955
A
99
100#define VARIANT_IS_EMPTY 0
101#define VARIANT_IS_EURO 0x1
102#define VARIANT_IS_PREEURO 0x2
103
b75a7d8f
A
104// Tag for localized display names (symbols) of currencies
105static const char CURRENCIES[] = "Currencies";
729e4ab9 106static const char CURRENCYPLURALS[] = "CurrencyPlurals";
b75a7d8f 107
46f4442e
A
108static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
109
4388f060 110// ISO codes mapping table
57a6839d
A
111static const UHashtable* gIsoCodes = NULL;
112static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
113
114// Currency symbol equivalances
115static const icu::Hashtable* gCurrSymbolsEquiv = NULL;
116static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER;
117
b331163b
A
118U_NAMESPACE_BEGIN
119
57a6839d
A
120// EquivIterator iterates over all strings that are equivalent to a given
121// string, s. Note that EquivIterator will never yield s itself.
f3c0d7a5 122class EquivIterator : public icu::UMemory {
57a6839d
A
123public:
124 // Constructor. hash stores the equivalence relationships; s is the string
125 // for which we find equivalent strings.
126 inline EquivIterator(const icu::Hashtable& hash, const icu::UnicodeString& s)
127 : _hash(hash) {
128 _start = _current = &s;
129 }
130 inline ~EquivIterator() { }
131
132 // next returns the next equivalent string or NULL if there are no more.
133 // If s has no equivalent strings, next returns NULL on the first call.
134 const icu::UnicodeString *next();
135private:
136 const icu::Hashtable& _hash;
137 const icu::UnicodeString* _start;
138 const icu::UnicodeString* _current;
139};
140
141const icu::UnicodeString *
142EquivIterator::next() {
143 const icu::UnicodeString* _next = (const icu::UnicodeString*) _hash.get(*_current);
144 if (_next == NULL) {
145 U_ASSERT(_current == _start);
146 return NULL;
147 }
148 if (*_next == *_start) {
149 return NULL;
150 }
151 _current = _next;
152 return _next;
153}
154
b331163b
A
155U_NAMESPACE_END
156
57a6839d
A
157// makeEquivalent makes lhs and rhs equivalent by updating the equivalence
158// relations in hash accordingly.
159static void makeEquivalent(
160 const icu::UnicodeString &lhs,
161 const icu::UnicodeString &rhs,
162 icu::Hashtable* hash, UErrorCode &status) {
163 if (U_FAILURE(status)) {
164 return;
165 }
166 if (lhs == rhs) {
167 // already equivalent
168 return;
169 }
b331163b
A
170 icu::EquivIterator leftIter(*hash, lhs);
171 icu::EquivIterator rightIter(*hash, rhs);
57a6839d
A
172 const icu::UnicodeString *firstLeft = leftIter.next();
173 const icu::UnicodeString *firstRight = rightIter.next();
174 const icu::UnicodeString *nextLeft = firstLeft;
175 const icu::UnicodeString *nextRight = firstRight;
176 while (nextLeft != NULL && nextRight != NULL) {
177 if (*nextLeft == rhs || *nextRight == lhs) {
178 // Already equivalent
179 return;
180 }
181 nextLeft = leftIter.next();
182 nextRight = rightIter.next();
183 }
184 // Not equivalent. Must join.
185 icu::UnicodeString *newFirstLeft;
186 icu::UnicodeString *newFirstRight;
187 if (firstRight == NULL && firstLeft == NULL) {
188 // Neither lhs or rhs belong to an equivalence circle, so we form
189 // a new equivalnce circle of just lhs and rhs.
190 newFirstLeft = new icu::UnicodeString(rhs);
191 newFirstRight = new icu::UnicodeString(lhs);
192 } else if (firstRight == NULL) {
193 // lhs belongs to an equivalence circle, but rhs does not, so we link
194 // rhs into lhs' circle.
195 newFirstLeft = new icu::UnicodeString(rhs);
196 newFirstRight = new icu::UnicodeString(*firstLeft);
197 } else if (firstLeft == NULL) {
198 // rhs belongs to an equivlance circle, but lhs does not, so we link
199 // lhs into rhs' circle.
200 newFirstLeft = new icu::UnicodeString(*firstRight);
201 newFirstRight = new icu::UnicodeString(lhs);
202 } else {
203 // Both lhs and rhs belong to different equivalnce circles. We link
204 // them together to form one single, larger equivalnce circle.
205 newFirstLeft = new icu::UnicodeString(*firstRight);
206 newFirstRight = new icu::UnicodeString(*firstLeft);
207 }
208 if (newFirstLeft == NULL || newFirstRight == NULL) {
209 delete newFirstLeft;
210 delete newFirstRight;
211 status = U_MEMORY_ALLOCATION_ERROR;
212 return;
213 }
214 hash->put(lhs, (void *) newFirstLeft, status);
215 hash->put(rhs, (void *) newFirstRight, status);
216}
217
218// countEquivalent counts how many strings are equivalent to s.
219// hash stores all the equivalnce relations.
220// countEquivalent does not include s itself in the count.
221static int32_t countEquivalent(const icu::Hashtable &hash, const icu::UnicodeString &s) {
222 int32_t result = 0;
b331163b 223 icu::EquivIterator iter(hash, s);
57a6839d
A
224 while (iter.next() != NULL) {
225 ++result;
226 }
227#ifdef UCURR_DEBUG_EQUIV
228 {
229 char tmp[200];
230 s.extract(0,s.length(),tmp, "UTF-8");
231 printf("CountEquivalent('%s') = %d\n", tmp, result);
232 }
233#endif
234 return result;
235}
4388f060 236
57a6839d 237static const icu::Hashtable* getCurrSymbolsEquiv();
4388f060 238
b75a7d8f
A
239//------------------------------------------------------------
240// Code
241
4388f060
A
242/**
243 * Cleanup callback func
244 */
245static UBool U_CALLCONV
246isoCodes_cleanup(void)
247{
4388f060 248 if (gIsoCodes != NULL) {
57a6839d 249 uhash_close(const_cast<UHashtable *>(gIsoCodes));
4388f060
A
250 gIsoCodes = NULL;
251 }
57a6839d
A
252 gIsoCodesInitOnce.reset();
253 return TRUE;
254}
4388f060 255
57a6839d
A
256/**
257 * Cleanup callback func
258 */
259static UBool U_CALLCONV
260currSymbolsEquiv_cleanup(void)
261{
262 delete const_cast<icu::Hashtable *>(gCurrSymbolsEquiv);
263 gCurrSymbolsEquiv = NULL;
264 gCurrSymbolsEquivInitOnce.reset();
4388f060
A
265 return TRUE;
266}
267
268/**
269 * Deleter for OlsonToMetaMappingEntry
270 */
271static void U_CALLCONV
272deleteIsoCodeEntry(void *obj) {
273 IsoCodeEntry *entry = (IsoCodeEntry*)obj;
274 uprv_free(entry);
275}
276
57a6839d
A
277/**
278 * Deleter for gCurrSymbolsEquiv.
279 */
280static void U_CALLCONV
281deleteUnicode(void *obj) {
282 icu::UnicodeString *entry = (icu::UnicodeString*)obj;
283 delete entry;
284}
285
b75a7d8f
A
286/**
287 * Unfortunately, we have to convert the UChar* currency code to char*
288 * to use it as a resource key.
289 */
290static inline char*
291myUCharsToChars(char* resultOfLen4, const UChar* currency) {
4388f060
A
292 u_UCharsToChars(currency, resultOfLen4, ISO_CURRENCY_CODE_LENGTH);
293 resultOfLen4[ISO_CURRENCY_CODE_LENGTH] = 0;
b75a7d8f
A
294 return resultOfLen4;
295}
296
297/**
298 * Internal function to look up currency data. Result is an array of
57a6839d 299 * four integers. The first is the fraction digits. The second is the
b75a7d8f 300 * rounding increment, or 0 if none. The rounding increment is in
57a6839d
A
301 * units of 10^(-fraction_digits). The third and fourth are the same
302 * except that they are those used in cash transations ( cashDigits
303 * and cashRounding ).
b75a7d8f
A
304 */
305static const int32_t*
374ca955
A
306_findMetaData(const UChar* currency, UErrorCode& ec) {
307
308 if (currency == 0 || *currency == 0) {
309 if (U_SUCCESS(ec)) {
310 ec = U_ILLEGAL_ARGUMENT_ERROR;
311 }
312 return LAST_RESORT_DATA;
313 }
b75a7d8f
A
314
315 // Get CurrencyMeta resource out of root locale file. [This may
316 // move out of the root locale file later; if it does, update this
317 // code.]
729e4ab9 318 UResourceBundle* currencyData = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &ec);
374ca955
A
319 UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
320
b75a7d8f 321 if (U_FAILURE(ec)) {
374ca955 322 ures_close(currencyMeta);
b75a7d8f
A
323 // Config/build error; return hard-coded defaults
324 return LAST_RESORT_DATA;
325 }
326
327 // Look up our currency, or if that's not available, then DEFAULT
4388f060 328 char buf[ISO_CURRENCY_CODE_LENGTH+1];
374ca955
A
329 UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
330 UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
331 if (U_FAILURE(ec2)) {
332 ures_close(rb);
333 rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
b75a7d8f 334 if (U_FAILURE(ec)) {
374ca955
A
335 ures_close(currencyMeta);
336 ures_close(rb);
b75a7d8f
A
337 // Config/build error; return hard-coded defaults
338 return LAST_RESORT_DATA;
339 }
340 }
341
342 int32_t len;
374ca955 343 const int32_t *data = ures_getIntVector(rb, &len, &ec);
57a6839d 344 if (U_FAILURE(ec) || len != 4) {
b75a7d8f 345 // Config/build error; return hard-coded defaults
374ca955
A
346 if (U_SUCCESS(ec)) {
347 ec = U_INVALID_FORMAT_ERROR;
348 }
349 ures_close(currencyMeta);
350 ures_close(rb);
b75a7d8f
A
351 return LAST_RESORT_DATA;
352 }
353
374ca955
A
354 ures_close(currencyMeta);
355 ures_close(rb);
b75a7d8f
A
356 return data;
357}
358
374ca955
A
359// -------------------------------------
360
361/**
362 * @see VARIANT_IS_EURO
363 * @see VARIANT_IS_PREEURO
364 */
365static uint32_t
366idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
367{
368 uint32_t variantType = 0;
369 // !!! this is internal only, assumes buffer is not null and capacity is sufficient
370 // Extract the country name and variant name. We only
371 // recognize two variant names, EURO and PREEURO.
372 char variant[ULOC_FULLNAME_CAPACITY];
2ca993e8 373 ulocimp_getRegionForSupplementalData(locale, FALSE, countryAndVariant, capacity, ec);
374ca955
A
374 uloc_getVariant(locale, variant, sizeof(variant), ec);
375 if (variant[0] != 0) {
51004dcb
A
376 variantType = (uint32_t)(0 == uprv_strcmp(variant, VAR_EURO))
377 | ((uint32_t)(0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
374ca955
A
378 if (variantType)
379 {
46f4442e 380 uprv_strcat(countryAndVariant, VAR_DELIM_STR);
374ca955
A
381 uprv_strcat(countryAndVariant, variant);
382 }
383 }
384 return variantType;
385}
b75a7d8f
A
386
387// ------------------------------------------
388//
389// Registration
390//
391//-------------------------------------------
392
393// don't use ICUService since we don't need fallback
394
374ca955
A
395U_CDECL_BEGIN
396static UBool U_CALLCONV currency_cleanup(void);
397U_CDECL_END
4388f060
A
398
399#if !UCONFIG_NO_SERVICE
b75a7d8f
A
400struct CReg;
401
51004dcb 402static UMutex gCRegLock = U_MUTEX_INITIALIZER;
b75a7d8f
A
403static CReg* gCRegHead = 0;
404
4388f060 405struct CReg : public icu::UMemory {
b75a7d8f 406 CReg *next;
4388f060 407 UChar iso[ISO_CURRENCY_CODE_LENGTH+1];
b75a7d8f 408 char id[ULOC_FULLNAME_CAPACITY];
374ca955 409
b75a7d8f
A
410 CReg(const UChar* _iso, const char* _id)
411 : next(0)
412 {
374ca955 413 int32_t len = (int32_t)uprv_strlen(_id);
b75a7d8f
A
414 if (len > (int32_t)(sizeof(id)-1)) {
415 len = (sizeof(id)-1);
416 }
417 uprv_strncpy(id, _id, len);
418 id[len] = 0;
a62d09fc 419 u_memcpy(iso, _iso, ISO_CURRENCY_CODE_LENGTH);
4388f060 420 iso[ISO_CURRENCY_CODE_LENGTH] = 0;
b75a7d8f 421 }
374ca955 422
b75a7d8f
A
423 static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
424 {
425 if (status && U_SUCCESS(*status) && _iso && _id) {
426 CReg* n = new CReg(_iso, _id);
427 if (n) {
46f4442e 428 umtx_lock(&gCRegLock);
b75a7d8f 429 if (!gCRegHead) {
374ca955 430 /* register for the first time */
2ca993e8 431 ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
b75a7d8f
A
432 }
433 n->next = gCRegHead;
434 gCRegHead = n;
46f4442e 435 umtx_unlock(&gCRegLock);
b75a7d8f
A
436 return n;
437 }
438 *status = U_MEMORY_ALLOCATION_ERROR;
439 }
440 return 0;
441 }
374ca955 442
b75a7d8f 443 static UBool unreg(UCurrRegistryKey key) {
46f4442e 444 UBool found = FALSE;
46f4442e 445 umtx_lock(&gCRegLock);
374ca955 446
46f4442e
A
447 CReg** p = &gCRegHead;
448 while (*p) {
449 if (*p == key) {
450 *p = ((CReg*)key)->next;
374ca955 451 delete (CReg*)key;
46f4442e
A
452 found = TRUE;
453 break;
b75a7d8f 454 }
46f4442e 455 p = &((*p)->next);
b75a7d8f 456 }
374ca955 457
46f4442e
A
458 umtx_unlock(&gCRegLock);
459 return found;
b75a7d8f 460 }
374ca955 461
b75a7d8f 462 static const UChar* get(const char* id) {
46f4442e 463 const UChar* result = NULL;
46f4442e 464 umtx_lock(&gCRegLock);
b75a7d8f 465 CReg* p = gCRegHead;
374ca955
A
466
467 /* register cleanup of the mutex */
2ca993e8 468 ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
b75a7d8f
A
469 while (p) {
470 if (uprv_strcmp(id, p->id) == 0) {
46f4442e
A
471 result = p->iso;
472 break;
b75a7d8f
A
473 }
474 p = p->next;
475 }
46f4442e
A
476 umtx_unlock(&gCRegLock);
477 return result;
b75a7d8f
A
478 }
479
480 /* This doesn't need to be thread safe. It's for u_cleanup only. */
481 static void cleanup(void) {
482 while (gCRegHead) {
483 CReg* n = gCRegHead;
484 gCRegHead = gCRegHead->next;
485 delete n;
486 }
b75a7d8f
A
487 }
488};
489
b75a7d8f
A
490// -------------------------------------
491
492U_CAPI UCurrRegistryKey U_EXPORT2
374ca955 493ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
b75a7d8f
A
494{
495 if (status && U_SUCCESS(*status)) {
496 char id[ULOC_FULLNAME_CAPACITY];
497 idForLocale(locale, id, sizeof(id), status);
498 return CReg::reg(isoCode, id, status);
499 }
500 return NULL;
501}
502
503// -------------------------------------
504
505U_CAPI UBool U_EXPORT2
374ca955 506ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
b75a7d8f
A
507{
508 if (status && U_SUCCESS(*status)) {
509 return CReg::unreg(key);
510 }
511 return FALSE;
512}
374ca955 513#endif /* UCONFIG_NO_SERVICE */
b75a7d8f
A
514
515// -------------------------------------
516
4388f060
A
517/**
518 * Release all static memory held by currency.
519 */
520/*The declaration here is needed so currency_cleanup(void)
521 * can call this function.
522 */
523static UBool U_CALLCONV
524currency_cache_cleanup(void);
525
526U_CDECL_BEGIN
527static UBool U_CALLCONV currency_cleanup(void) {
528#if !UCONFIG_NO_SERVICE
529 CReg::cleanup();
530#endif
531 /*
532 * There might be some cached currency data or isoCodes data.
533 */
534 currency_cache_cleanup();
535 isoCodes_cleanup();
57a6839d 536 currSymbolsEquiv_cleanup();
4388f060
A
537
538 return TRUE;
539}
540U_CDECL_END
541
542// -------------------------------------
543
374ca955
A
544U_CAPI int32_t U_EXPORT2
545ucurr_forLocale(const char* locale,
546 UChar* buff,
547 int32_t buffCapacity,
548 UErrorCode* ec)
549{
550 int32_t resLen = 0;
551 const UChar* s = NULL;
b75a7d8f 552 if (ec != NULL && U_SUCCESS(*ec)) {
374ca955
A
553 if ((buff && buffCapacity) || !buffCapacity) {
554 UErrorCode localStatus = U_ZERO_ERROR;
555 char id[ULOC_FULLNAME_CAPACITY];
556 if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
557 // there is a currency keyword. Try to see if it's valid
558 if(buffCapacity > resLen) {
729e4ab9
A
559 /* Normalize the currency keyword value to upper case. */
560 T_CString_toUpperCase(id);
374ca955
A
561 u_charsToUChars(id, buff, resLen);
562 }
563 } else {
564 // get country or country_variant in `id'
565 uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
566
567 if (U_FAILURE(*ec)) {
568 return 0;
569 }
570
571#if !UCONFIG_NO_SERVICE
572 const UChar* result = CReg::get(id);
573 if (result) {
574 if(buffCapacity > u_strlen(result)) {
575 u_strcpy(buff, result);
576 }
577 return u_strlen(result);
578 }
579#endif
46f4442e
A
580 // Remove variants, which is only needed for registration.
581 char *idDelim = strchr(id, VAR_DELIM);
582 if (idDelim) {
583 idDelim[0] = 0;
584 }
374ca955
A
585
586 // Look up the CurrencyMap element in the root bundle.
729e4ab9 587 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
374ca955 588 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
46f4442e
A
589 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
590 UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
591 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
592
593 /*
594 Get the second item when PREEURO is requested, and this is a known Euro country.
595 If the requested variant is PREEURO, and this isn't a Euro country, assume
596 that the country changed over to the Euro in the future. This is probably
597 an old version of ICU that hasn't been updated yet. The latest currency is
598 probably correct.
599 */
600 if (U_SUCCESS(localStatus)) {
601 if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
602 currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
603 s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
604 }
605 else if ((variantType & VARIANT_IS_EURO)) {
606 s = EUR_STR;
607 }
608 }
609 ures_close(countryArray);
610 ures_close(currencyReq);
374ca955 611
46f4442e 612 if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
374ca955
A
613 {
614 // We don't know about it. Check to see if we support the variant.
46f4442e
A
615 uloc_getParent(locale, id, sizeof(id), ec);
616 *ec = U_USING_FALLBACK_WARNING;
617 return ucurr_forLocale(id, buff, buffCapacity, ec);
374ca955
A
618 }
619 else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
620 // There is nothing to fallback to. Report the failure/warning if possible.
621 *ec = localStatus;
622 }
623 if (U_SUCCESS(*ec)) {
624 if(buffCapacity > resLen) {
625 u_strcpy(buff, s);
626 }
627 }
374ca955
A
628 }
629 return u_terminateUChars(buff, buffCapacity, resLen, ec);
630 } else {
631 *ec = U_ILLEGAL_ARGUMENT_ERROR;
b75a7d8f
A
632 }
633 }
374ca955 634 return resLen;
b75a7d8f
A
635}
636
637// end registration
638
639/**
640 * Modify the given locale name by removing the rightmost _-delimited
641 * element. If there is none, empty the string ("" == root).
642 * NOTE: The string "root" is not recognized; do not use it.
643 * @return TRUE if the fallback happened; FALSE if locale is already
644 * root ("").
645 */
646static UBool fallback(char *loc) {
647 if (!*loc) {
648 return FALSE;
649 }
650 UErrorCode status = U_ZERO_ERROR;
374ca955 651 uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
b75a7d8f
A
652 /*
653 char *i = uprv_strrchr(loc, '_');
654 if (i == NULL) {
655 i = loc;
656 }
657 *i = 0;
658 */
659 return TRUE;
660}
661
662
663U_CAPI const UChar* U_EXPORT2
664ucurr_getName(const UChar* currency,
665 const char* locale,
666 UCurrNameStyle nameStyle,
667 UBool* isChoiceFormat, // fillin
668 int32_t* len, // fillin
669 UErrorCode* ec) {
670
671 // Look up the Currencies resource for the given locale. The
672 // Currencies locale data looks like this:
673 //|en {
374ca955 674 //| Currencies {
b75a7d8f
A
675 //| USD { "US$", "US Dollar" }
676 //| CHF { "Sw F", "Swiss Franc" }
677 //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
678 //| //...
679 //| }
680 //|}
681
374ca955 682 if (U_FAILURE(*ec)) {
b75a7d8f
A
683 return 0;
684 }
685
686 int32_t choice = (int32_t) nameStyle;
687 if (choice < 0 || choice > 1) {
688 *ec = U_ILLEGAL_ARGUMENT_ERROR;
689 return 0;
690 }
374ca955 691
b75a7d8f
A
692 // In the future, resource bundles may implement multi-level
693 // fallback. That is, if a currency is not found in the en_US
694 // Currencies data, then the en Currencies data will be searched.
695 // Currently, if a Currencies datum exists in en_US and en, the
696 // en_US entry hides that in en.
697
698 // We want multi-level fallback for this resource, so we implement
699 // it manually.
700
701 // Use a separate UErrorCode here that does not propagate out of
702 // this function.
703 UErrorCode ec2 = U_ZERO_ERROR;
704
705 char loc[ULOC_FULLNAME_CAPACITY];
706 uloc_getName(locale, loc, sizeof(loc), &ec2);
707 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
708 *ec = U_ILLEGAL_ARGUMENT_ERROR;
709 return 0;
710 }
711
4388f060 712 char buf[ISO_CURRENCY_CODE_LENGTH+1];
b75a7d8f 713 myUCharsToChars(buf, currency);
729e4ab9
A
714
715 /* Normalize the keyword value to uppercase */
716 T_CString_toUpperCase(buf);
717
b75a7d8f 718 const UChar* s = NULL;
46f4442e 719 ec2 = U_ZERO_ERROR;
729e4ab9 720 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
b75a7d8f 721
46f4442e 722 rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
b75a7d8f 723
46f4442e
A
724 // Fetch resource with multi-level resource inheritance fallback
725 rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
726
727 s = ures_getStringByIndex(rb, choice, len, &ec2);
728 ures_close(rb);
729
730 // If we've succeeded we're done. Otherwise, try to fallback.
731 // If that fails (because we are already at root) then exit.
732 if (U_SUCCESS(ec2)) {
733 if (ec2 == U_USING_DEFAULT_WARNING
734 || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
735 *ec = ec2;
b75a7d8f
A
736 }
737 }
738
2ca993e8
A
739 // We no longer support choice format data in names. Data should not contain
740 // choice patterns.
b75a7d8f
A
741 *isChoiceFormat = FALSE;
742 if (U_SUCCESS(ec2)) {
743 U_ASSERT(s != NULL);
b75a7d8f
A
744 return s;
745 }
746
747 // If we fail to find a match, use the ISO 4217 code
4388f060 748 *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
374ca955 749 *ec = U_USING_DEFAULT_WARNING;
b75a7d8f
A
750 return currency;
751}
752
729e4ab9
A
753U_CAPI const UChar* U_EXPORT2
754ucurr_getPluralName(const UChar* currency,
755 const char* locale,
756 UBool* isChoiceFormat,
757 const char* pluralCount,
758 int32_t* len, // fillin
759 UErrorCode* ec) {
374ca955
A
760 // Look up the Currencies resource for the given locale. The
761 // Currencies locale data looks like this:
762 //|en {
729e4ab9
A
763 //| CurrencyPlurals {
764 //| USD{
765 //| one{"US dollar"}
766 //| other{"US dollars"}
767 //| }
374ca955
A
768 //| }
769 //|}
770
729e4ab9
A
771 if (U_FAILURE(*ec)) {
772 return 0;
773 }
374ca955
A
774
775 // Use a separate UErrorCode here that does not propagate out of
776 // this function.
777 UErrorCode ec2 = U_ZERO_ERROR;
778
779 char loc[ULOC_FULLNAME_CAPACITY];
780 uloc_getName(locale, loc, sizeof(loc), &ec2);
781 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
729e4ab9
A
782 *ec = U_ILLEGAL_ARGUMENT_ERROR;
783 return 0;
374ca955
A
784 }
785
4388f060 786 char buf[ISO_CURRENCY_CODE_LENGTH+1];
729e4ab9
A
787 myUCharsToChars(buf, currency);
788
374ca955 789 const UChar* s = NULL;
729e4ab9
A
790 ec2 = U_ZERO_ERROR;
791 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
792
793 rb = ures_getByKey(rb, CURRENCYPLURALS, rb, &ec2);
794
795 // Fetch resource with multi-level resource inheritance fallback
796 rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
797
798 s = ures_getStringByKeyWithFallback(rb, pluralCount, len, &ec2);
799 if (U_FAILURE(ec2)) {
800 // fall back to "other"
801 ec2 = U_ZERO_ERROR;
802 s = ures_getStringByKeyWithFallback(rb, "other", len, &ec2);
803 if (U_FAILURE(ec2)) {
804 ures_close(rb);
805 // fall back to long name in Currencies
806 return ucurr_getName(currency, locale, UCURR_LONG_NAME,
807 isChoiceFormat, len, ec);
808 }
809 }
810 ures_close(rb);
811
812 // If we've succeeded we're done. Otherwise, try to fallback.
813 // If that fails (because we are already at root) then exit.
814 if (U_SUCCESS(ec2)) {
815 if (ec2 == U_USING_DEFAULT_WARNING
816 || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
817 *ec = ec2;
818 }
819 U_ASSERT(s != NULL);
820 return s;
821 }
822
823 // If we fail to find a match, use the ISO 4217 code
4388f060 824 *len = u_strlen(currency); // Should == ISO_CURRENCY_CODE_LENGTH, but maybe not...?
729e4ab9
A
825 *ec = U_USING_DEFAULT_WARNING;
826 return currency;
827}
828
829
830//========================================================================
831// Following are structure and function for parsing currency names
832
833#define NEED_TO_BE_DELETED 0x1
834
835// TODO: a better way to define this?
836#define MAX_CURRENCY_NAME_LEN 100
837
838typedef struct {
839 const char* IsoCode; // key
840 UChar* currencyName; // value
841 int32_t currencyNameLen; // value length
842 int32_t flag; // flags
843} CurrencyNameStruct;
844
845
846#ifndef MIN
847#define MIN(a,b) (((a)<(b)) ? (a) : (b))
848#endif
849
850#ifndef MAX
851#define MAX(a,b) (((a)<(b)) ? (b) : (a))
852#endif
853
854
855// Comparason function used in quick sort.
856static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
857 const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
858 const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
859 for (int32_t i = 0;
860 i < MIN(currName_1->currencyNameLen, currName_2->currencyNameLen);
861 ++i) {
862 if (currName_1->currencyName[i] < currName_2->currencyName[i]) {
863 return -1;
864 }
865 if (currName_1->currencyName[i] > currName_2->currencyName[i]) {
866 return 1;
867 }
868 }
869 if (currName_1->currencyNameLen < currName_2->currencyNameLen) {
870 return -1;
871 } else if (currName_1->currencyNameLen > currName_2->currencyNameLen) {
872 return 1;
873 }
874 return 0;
875}
374ca955 876
374ca955 877
729e4ab9
A
878// Give a locale, return the maximum number of currency names associated with
879// this locale.
880// It gets currency names from resource bundles using fallback.
881// It is the maximum number because in the fallback chain, some of the
882// currency names are duplicated.
883// For example, given locale as "en_US", the currency names get from resource
884// bundle in "en_US" and "en" are duplicated. The fallback mechanism will count
885// all currency names in "en_US" and "en".
886static void
887getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_t* total_currency_symbol_count) {
888 U_NAMESPACE_USE
889 *total_currency_name_count = 0;
890 *total_currency_symbol_count = 0;
891 const UChar* s = NULL;
892 char locale[ULOC_FULLNAME_CAPACITY];
893 uprv_strcpy(locale, loc);
57a6839d 894 const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
374ca955 895 for (;;) {
729e4ab9
A
896 UErrorCode ec2 = U_ZERO_ERROR;
897 // TODO: ures_openDirect?
898 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, locale, &ec2);
899 UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
900 int32_t n = ures_getSize(curr);
901 for (int32_t i=0; i<n; ++i) {
902 UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
903 int32_t len;
904 s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
2ca993e8
A
905 ++(*total_currency_symbol_count); // currency symbol
906 if (currencySymbolsEquiv != NULL) {
907 *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
729e4ab9 908 }
729e4ab9
A
909 ++(*total_currency_symbol_count); // iso code
910 ++(*total_currency_name_count); // long name
911 ures_close(names);
912 }
913
914 // currency plurals
915 UErrorCode ec3 = U_ZERO_ERROR;
916 UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
917 n = ures_getSize(curr_p);
918 for (int32_t i=0; i<n; ++i) {
919 UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
920 *total_currency_name_count += ures_getSize(names);
921 ures_close(names);
922 }
923 ures_close(curr_p);
924 ures_close(curr);
925 ures_close(rb);
926
927 if (!fallback(locale)) {
928 break;
929 }
930 }
931}
932
729e4ab9 933static UChar*
4388f060 934toUpperCase(const UChar* source, int32_t len, const char* locale) {
729e4ab9
A
935 UChar* dest = NULL;
936 UErrorCode ec = U_ZERO_ERROR;
4388f060 937 int32_t destLen = u_strToUpper(dest, 0, source, len, locale, &ec);
729e4ab9
A
938
939 ec = U_ZERO_ERROR;
940 dest = (UChar*)uprv_malloc(sizeof(UChar) * MAX(destLen, len));
4388f060 941 u_strToUpper(dest, destLen, source, len, locale, &ec);
729e4ab9 942 if (U_FAILURE(ec)) {
a62d09fc 943 u_memcpy(dest, source, len);
729e4ab9
A
944 }
945 return dest;
946}
947
948
4388f060 949// Collect all available currency names associated with the given locale
729e4ab9
A
950// (enable fallback chain).
951// Read currenc names defined in resource bundle "Currencies" and
952// "CurrencyPlural", enable fallback chain.
953// return the malloc-ed currency name arrays and the total number of currency
954// names in the array.
955static void
956collectCurrencyNames(const char* locale,
957 CurrencyNameStruct** currencyNames,
958 int32_t* total_currency_name_count,
959 CurrencyNameStruct** currencySymbols,
960 int32_t* total_currency_symbol_count,
961 UErrorCode& ec) {
962 U_NAMESPACE_USE
57a6839d 963 const icu::Hashtable *currencySymbolsEquiv = getCurrSymbolsEquiv();
729e4ab9
A
964 // Look up the Currencies resource for the given locale.
965 UErrorCode ec2 = U_ZERO_ERROR;
966
967 char loc[ULOC_FULLNAME_CAPACITY];
968 uloc_getName(locale, loc, sizeof(loc), &ec2);
969 if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
970 ec = U_ILLEGAL_ARGUMENT_ERROR;
971 }
972
973 // Get maximum currency name count first.
974 getCurrencyNameCount(loc, total_currency_name_count, total_currency_symbol_count);
975
976 *currencyNames = (CurrencyNameStruct*)uprv_malloc
977 (sizeof(CurrencyNameStruct) * (*total_currency_name_count));
978 *currencySymbols = (CurrencyNameStruct*)uprv_malloc
979 (sizeof(CurrencyNameStruct) * (*total_currency_symbol_count));
980
b331163b
A
981 if(currencyNames == NULL || currencySymbols == NULL) {
982 ec = U_MEMORY_ALLOCATION_ERROR;
983 }
984
985 if (U_FAILURE(ec)) return;
986
729e4ab9
A
987 const UChar* s = NULL; // currency name
988 char* iso = NULL; // currency ISO code
989
990 *total_currency_name_count = 0;
991 *total_currency_symbol_count = 0;
992
993 UErrorCode ec3 = U_ZERO_ERROR;
994 UErrorCode ec4 = U_ZERO_ERROR;
995
996 // Using hash to remove duplicates caused by locale fallback
997 UHashtable* currencyIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec3);
998 UHashtable* currencyPluralIsoCodes = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &ec4);
999 for (int32_t localeLevel = 0; ; ++localeLevel) {
374ca955 1000 ec2 = U_ZERO_ERROR;
729e4ab9
A
1001 // TODO: ures_openDirect
1002 UResourceBundle* rb = ures_open(U_ICUDATA_CURR, loc, &ec2);
374ca955
A
1003 UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
1004 int32_t n = ures_getSize(curr);
1005 for (int32_t i=0; i<n; ++i) {
1006 UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
1007 int32_t len;
1008 s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
729e4ab9
A
1009 // TODO: uhash_put wont change key/value?
1010 iso = (char*)ures_getKey(names);
1011 if (localeLevel == 0) {
1012 uhash_put(currencyIsoCodes, iso, iso, &ec3);
1013 } else {
1014 if (uhash_get(currencyIsoCodes, iso) != NULL) {
1015 ures_close(names);
1016 continue;
1017 } else {
1018 uhash_put(currencyIsoCodes, iso, iso, &ec3);
1019 }
1020 }
2ca993e8
A
1021 // Add currency symbol.
1022 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
1023 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)s;
1024 (*currencySymbols)[*total_currency_symbol_count].flag = 0;
1025 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
1026 // Add equivalent symbols
1027 if (currencySymbolsEquiv != NULL) {
f3c0d7a5
A
1028 UnicodeString str(TRUE, s, len);
1029 icu::EquivIterator iter(*currencySymbolsEquiv, str);
2ca993e8
A
1030 const UnicodeString *symbol;
1031 while ((symbol = iter.next()) != NULL) {
729e4ab9 1032 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
f3c0d7a5
A
1033 (*currencySymbols)[*total_currency_symbol_count].currencyName =
1034 const_cast<UChar*>(symbol->getBuffer());
2ca993e8
A
1035 (*currencySymbols)[*total_currency_symbol_count].flag = 0;
1036 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = symbol->length();
57a6839d 1037 }
729e4ab9
A
1038 }
1039
1040 // Add currency long name.
1041 s = ures_getStringByIndex(names, UCURR_LONG_NAME, &len, &ec2);
1042 (*currencyNames)[*total_currency_name_count].IsoCode = iso;
4388f060 1043 UChar* upperName = toUpperCase(s, len, locale);
729e4ab9
A
1044 (*currencyNames)[*total_currency_name_count].currencyName = upperName;
1045 (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
1046 (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
1047
1048 // put (iso, 3, and iso) in to array
1049 // Add currency ISO code.
1050 (*currencySymbols)[*total_currency_symbol_count].IsoCode = iso;
1051 (*currencySymbols)[*total_currency_symbol_count].currencyName = (UChar*)uprv_malloc(sizeof(UChar)*3);
1052 // Must convert iso[] into Unicode
1053 u_charsToUChars(iso, (*currencySymbols)[*total_currency_symbol_count].currencyName, 3);
1054 (*currencySymbols)[*total_currency_symbol_count].flag = NEED_TO_BE_DELETED;
1055 (*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = 3;
1056
1057 ures_close(names);
1058 }
1059
1060 // currency plurals
1061 UErrorCode ec3 = U_ZERO_ERROR;
1062 UResourceBundle* curr_p = ures_getByKey(rb, CURRENCYPLURALS, NULL, &ec3);
1063 n = ures_getSize(curr_p);
1064 for (int32_t i=0; i<n; ++i) {
1065 UResourceBundle* names = ures_getByIndex(curr_p, i, NULL, &ec3);
1066 iso = (char*)ures_getKey(names);
1067 // Using hash to remove duplicated ISO codes in fallback chain.
1068 if (localeLevel == 0) {
1069 uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
1070 } else {
1071 if (uhash_get(currencyPluralIsoCodes, iso) != NULL) {
1072 ures_close(names);
1073 continue;
1074 } else {
1075 uhash_put(currencyPluralIsoCodes, iso, iso, &ec4);
1076 }
374ca955 1077 }
729e4ab9
A
1078 int32_t num = ures_getSize(names);
1079 int32_t len;
1080 for (int32_t j = 0; j < num; ++j) {
1081 // TODO: remove duplicates between singular name and
1082 // currency long name?
1083 s = ures_getStringByIndex(names, j, &len, &ec3);
1084 (*currencyNames)[*total_currency_name_count].IsoCode = iso;
4388f060 1085 UChar* upperName = toUpperCase(s, len, locale);
729e4ab9
A
1086 (*currencyNames)[*total_currency_name_count].currencyName = upperName;
1087 (*currencyNames)[*total_currency_name_count].flag = NEED_TO_BE_DELETED;
1088 (*currencyNames)[(*total_currency_name_count)++].currencyNameLen = len;
374ca955
A
1089 }
1090 ures_close(names);
1091 }
729e4ab9 1092 ures_close(curr_p);
374ca955
A
1093 ures_close(curr);
1094 ures_close(rb);
1095
374ca955
A
1096 if (!fallback(loc)) {
1097 break;
1098 }
1099 }
1100
729e4ab9
A
1101 uhash_close(currencyIsoCodes);
1102 uhash_close(currencyPluralIsoCodes);
1103
1104 // quick sort the struct
1105 qsort(*currencyNames, *total_currency_name_count,
1106 sizeof(CurrencyNameStruct), currencyNameComparator);
1107 qsort(*currencySymbols, *total_currency_symbol_count,
1108 sizeof(CurrencyNameStruct), currencyNameComparator);
1109
1110#ifdef UCURR_DEBUG
1111 printf("currency name count: %d\n", *total_currency_name_count);
1112 for (int32_t index = 0; index < *total_currency_name_count; ++index) {
1113 printf("index: %d\n", index);
1114 printf("iso: %s\n", (*currencyNames)[index].IsoCode);
57a6839d
A
1115 char curNameBuf[1024];
1116 memset(curNameBuf, 0, 1024);
1117 u_austrncpy(curNameBuf, (*currencyNames)[index].currencyName, (*currencyNames)[index].currencyNameLen);
1118 printf("currencyName: %s\n", curNameBuf);
729e4ab9 1119 printf("len: %d\n", (*currencyNames)[index].currencyNameLen);
374ca955 1120 }
729e4ab9
A
1121 printf("currency symbol count: %d\n", *total_currency_symbol_count);
1122 for (int32_t index = 0; index < *total_currency_symbol_count; ++index) {
1123 printf("index: %d\n", index);
1124 printf("iso: %s\n", (*currencySymbols)[index].IsoCode);
57a6839d
A
1125 char curNameBuf[1024];
1126 memset(curNameBuf, 0, 1024);
1127 u_austrncpy(curNameBuf, (*currencySymbols)[index].currencyName, (*currencySymbols)[index].currencyNameLen);
1128 printf("currencySymbol: %s\n", curNameBuf);
729e4ab9
A
1129 printf("len: %d\n", (*currencySymbols)[index].currencyNameLen);
1130 }
1131#endif
b331163b
A
1132 // fail on hashtable errors
1133 if (U_FAILURE(ec3)) {
1134 ec = ec3;
1135 return;
1136 }
1137 if (U_FAILURE(ec4)) {
1138 ec = ec4;
1139 return;
1140 }
729e4ab9
A
1141}
1142
1143// @param currencyNames: currency names array
1144// @param indexInCurrencyNames: the index of the character in currency names
1145// array against which the comparison is done
1146// @param key: input text char to compare against
1147// @param begin(IN/OUT): the begin index of matching range in currency names array
1148// @param end(IN/OUT): the end index of matching range in currency names array.
1149static int32_t
1150binarySearch(const CurrencyNameStruct* currencyNames,
1151 int32_t indexInCurrencyNames,
1152 const UChar key,
1153 int32_t* begin, int32_t* end) {
1154#ifdef UCURR_DEBUG
1155 printf("key = %x\n", key);
1156#endif
1157 int32_t first = *begin;
1158 int32_t last = *end;
1159 while (first <= last) {
1160 int32_t mid = (first + last) / 2; // compute mid point.
1161 if (indexInCurrencyNames >= currencyNames[mid].currencyNameLen) {
1162 first = mid + 1;
1163 } else {
1164 if (key > currencyNames[mid].currencyName[indexInCurrencyNames]) {
1165 first = mid + 1;
1166 }
1167 else if (key < currencyNames[mid].currencyName[indexInCurrencyNames]) {
1168 last = mid - 1;
1169 }
1170 else {
1171 // Find a match, and looking for ranges
1172 // Now do two more binary searches. First, on the left side for
1173 // the greatest L such that CurrencyNameStruct[L] < key.
1174 int32_t L = *begin;
1175 int32_t R = mid;
1176
1177#ifdef UCURR_DEBUG
1178 printf("mid = %d\n", mid);
1179#endif
1180 while (L < R) {
1181 int32_t M = (L + R) / 2;
1182#ifdef UCURR_DEBUG
1183 printf("L = %d, R = %d, M = %d\n", L, R, M);
1184#endif
1185 if (indexInCurrencyNames >= currencyNames[M].currencyNameLen) {
1186 L = M + 1;
1187 } else {
1188 if (currencyNames[M].currencyName[indexInCurrencyNames] < key) {
1189 L = M + 1;
1190 } else {
1191#ifdef UCURR_DEBUG
1192 U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
1193#endif
1194 R = M;
1195 }
1196 }
1197 }
1198#ifdef UCURR_DEBUG
1199 U_ASSERT(L == R);
1200#endif
1201 *begin = L;
1202#ifdef UCURR_DEBUG
1203 printf("begin = %d\n", *begin);
1204 U_ASSERT(currencyNames[*begin].currencyName[indexInCurrencyNames] == key);
1205#endif
374ca955 1206
729e4ab9
A
1207 // Now for the second search, finding the least R such that
1208 // key < CurrencyNameStruct[R].
1209 L = mid;
1210 R = *end;
1211 while (L < R) {
1212 int32_t M = (L + R) / 2;
1213#ifdef UCURR_DEBUG
1214 printf("L = %d, R = %d, M = %d\n", L, R, M);
1215#endif
1216 if (currencyNames[M].currencyNameLen < indexInCurrencyNames) {
1217 L = M + 1;
1218 } else {
1219 if (currencyNames[M].currencyName[indexInCurrencyNames] > key) {
1220 R = M;
1221 } else {
1222#ifdef UCURR_DEBUG
1223 U_ASSERT(currencyNames[M].currencyName[indexInCurrencyNames] == key);
1224#endif
1225 L = M + 1;
1226 }
1227 }
1228 }
1229#ifdef UCURR_DEBUG
1230 U_ASSERT(L == R);
1231#endif
1232 if (currencyNames[R].currencyName[indexInCurrencyNames] > key) {
1233 *end = R - 1;
1234 } else {
1235 *end = R;
1236 }
1237#ifdef UCURR_DEBUG
1238 printf("end = %d\n", *end);
1239#endif
1240
1241 // now, found the range. check whether there is exact match
1242 if (currencyNames[*begin].currencyNameLen == indexInCurrencyNames + 1) {
1243 return *begin; // find range and exact match.
1244 }
1245 return -1; // find range, but no exact match.
1246 }
1247 }
1248 }
1249 *begin = -1;
1250 *end = -1;
1251 return -1; // failed to find range.
1252}
1253
1254
1255// Linear search "text" in "currencyNames".
1256// @param begin, end: the begin and end index in currencyNames, within which
1257// range should the search be performed.
1258// @param textLen: the length of the text to be compared
1259// @param maxMatchLen(IN/OUT): passing in the computed max matching length
1260// pass out the new max matching length
1261// @param maxMatchIndex: the index in currencyName which has the longest
1262// match with input text.
1263static void
1264linearSearch(const CurrencyNameStruct* currencyNames,
1265 int32_t begin, int32_t end,
1266 const UChar* text, int32_t textLen,
1267 int32_t *maxMatchLen, int32_t* maxMatchIndex) {
1268 for (int32_t index = begin; index <= end; ++index) {
1269 int32_t len = currencyNames[index].currencyNameLen;
1270 if (len > *maxMatchLen && len <= textLen &&
1271 uprv_memcmp(currencyNames[index].currencyName, text, len * sizeof(UChar)) == 0) {
1272 *maxMatchIndex = index;
1273 *maxMatchLen = len;
1274#ifdef UCURR_DEBUG
1275 printf("maxMatchIndex = %d, maxMatchLen = %d\n",
1276 *maxMatchIndex, *maxMatchLen);
1277#endif
1278 }
1279 }
1280}
1281
1282#define LINEAR_SEARCH_THRESHOLD 10
1283
1284// Find longest match between "text" and currency names in "currencyNames".
1285// @param total_currency_count: total number of currency names in CurrencyNames.
1286// @param textLen: the length of the text to be compared
1287// @param maxMatchLen: passing in the computed max matching length
1288// pass out the new max matching length
1289// @param maxMatchIndex: the index in currencyName which has the longest
1290// match with input text.
1291static void
1292searchCurrencyName(const CurrencyNameStruct* currencyNames,
1293 int32_t total_currency_count,
1294 const UChar* text, int32_t textLen,
1295 int32_t* maxMatchLen, int32_t* maxMatchIndex) {
1296 *maxMatchIndex = -1;
1297 *maxMatchLen = 0;
1298 int32_t matchIndex = -1;
1299 int32_t binarySearchBegin = 0;
1300 int32_t binarySearchEnd = total_currency_count - 1;
1301 // It is a variant of binary search.
1302 // For example, given the currency names in currencyNames array are:
1303 // A AB ABC AD AZ B BB BBEX BBEXYZ BS C D E....
1304 // and the input text is BBEXST
1305 // The first round binary search search "B" in the text against
1306 // the first char in currency names, and find the first char matching range
1307 // to be "B BB BBEX BBEXYZ BS" (and the maximum matching "B").
1308 // The 2nd round binary search search the second "B" in the text against
1309 // the 2nd char in currency names, and narrow the matching range to
1310 // "BB BBEX BBEXYZ" (and the maximum matching "BB").
1311 // The 3rd round returnes the range as "BBEX BBEXYZ" (without changing
1312 // maximum matching).
1313 // The 4th round returns the same range (the maximum matching is "BBEX").
1314 // The 5th round returns no matching range.
1315 for (int32_t index = 0; index < textLen; ++index) {
1316 // matchIndex saves the one with exact match till the current point.
1317 // [binarySearchBegin, binarySearchEnd] saves the matching range.
1318 matchIndex = binarySearch(currencyNames, index,
1319 text[index],
1320 &binarySearchBegin, &binarySearchEnd);
1321 if (binarySearchBegin == -1) { // did not find the range
1322 break;
1323 }
1324 if (matchIndex != -1) {
1325 // find an exact match for text from text[0] to text[index]
1326 // in currencyNames array.
1327 *maxMatchLen = index + 1;
1328 *maxMatchIndex = matchIndex;
1329 }
1330 if (binarySearchEnd - binarySearchBegin < LINEAR_SEARCH_THRESHOLD) {
1331 // linear search if within threshold.
1332 linearSearch(currencyNames, binarySearchBegin, binarySearchEnd,
1333 text, textLen,
1334 maxMatchLen, maxMatchIndex);
1335 break;
1336 }
1337 }
1338 return;
1339}
1340
1341//========================= currency name cache =====================
1342typedef struct {
1343 char locale[ULOC_FULLNAME_CAPACITY]; //key
1344 // currency names, case insensitive
1345 CurrencyNameStruct* currencyNames; // value
1346 int32_t totalCurrencyNameCount; // currency name count
1347 // currency symbols and ISO code, case sensitive
1348 CurrencyNameStruct* currencySymbols; // value
1349 int32_t totalCurrencySymbolCount; // count
1350 // reference count.
1351 // reference count is set to 1 when an entry is put to cache.
1352 // it increases by 1 before accessing, and decreased by 1 after accessing.
1353 // The entry is deleted when ref count is zero, which means
1354 // the entry is replaced out of cache and no process is accessing it.
1355 int32_t refCount;
1356} CurrencyNameCacheEntry;
1357
1358
1359#define CURRENCY_NAME_CACHE_NUM 10
1360
1361// Reserve 10 cache entries.
1362static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
1363// Using an index to indicate which entry to be replaced when cache is full.
1364// It is a simple round-robin replacement strategy.
1365static int8_t currentCacheEntryIndex = 0;
1366
57a6839d
A
1367static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER;
1368
729e4ab9
A
1369// Cache deletion
1370static void
1371deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) {
1372 for (int32_t index = 0; index < count; ++index) {
1373 if ( (currencyNames[index].flag & NEED_TO_BE_DELETED) ) {
1374 uprv_free(currencyNames[index].currencyName);
1375 }
1376 }
1377 uprv_free(currencyNames);
1378}
1379
1380
1381static void
1382deleteCacheEntry(CurrencyNameCacheEntry* entry) {
1383 deleteCurrencyNames(entry->currencyNames, entry->totalCurrencyNameCount);
1384 deleteCurrencyNames(entry->currencySymbols, entry->totalCurrencySymbolCount);
1385 uprv_free(entry);
1386}
1387
1388
1389// Cache clean up
1390static UBool U_CALLCONV
1391currency_cache_cleanup(void) {
1392 for (int32_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1393 if (currCache[i]) {
1394 deleteCacheEntry(currCache[i]);
1395 currCache[i] = 0;
1396 }
1397 }
1398 return TRUE;
1399}
1400
1401
2ca993e8 1402U_CAPI void
729e4ab9 1403uprv_parseCurrency(const char* locale,
4388f060
A
1404 const icu::UnicodeString& text,
1405 icu::ParsePosition& pos,
729e4ab9
A
1406 int8_t type,
1407 UChar* result,
1408 UErrorCode& ec)
1409{
1410 U_NAMESPACE_USE
1411
1412 if (U_FAILURE(ec)) {
1413 return;
1414 }
1415
1416 int32_t total_currency_name_count = 0;
1417 CurrencyNameStruct* currencyNames = NULL;
1418 int32_t total_currency_symbol_count = 0;
1419 CurrencyNameStruct* currencySymbols = NULL;
1420 CurrencyNameCacheEntry* cacheEntry = NULL;
1421
57a6839d 1422 umtx_lock(&gCurrencyCacheMutex);
729e4ab9 1423 // in order to handle racing correctly,
57a6839d 1424 // not putting 'search' in a separate function.
729e4ab9
A
1425 int8_t found = -1;
1426 for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1427 if (currCache[i]!= NULL &&
1428 uprv_strcmp(locale, currCache[i]->locale) == 0) {
1429 found = i;
1430 break;
1431 }
1432 }
1433 if (found != -1) {
1434 cacheEntry = currCache[found];
1435 currencyNames = cacheEntry->currencyNames;
1436 total_currency_name_count = cacheEntry->totalCurrencyNameCount;
1437 currencySymbols = cacheEntry->currencySymbols;
1438 total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
1439 ++(cacheEntry->refCount);
1440 }
57a6839d 1441 umtx_unlock(&gCurrencyCacheMutex);
729e4ab9
A
1442 if (found == -1) {
1443 collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
1444 if (U_FAILURE(ec)) {
1445 return;
1446 }
57a6839d 1447 umtx_lock(&gCurrencyCacheMutex);
729e4ab9
A
1448 // check again.
1449 int8_t found = -1;
1450 for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
1451 if (currCache[i]!= NULL &&
1452 uprv_strcmp(locale, currCache[i]->locale) == 0) {
1453 found = i;
374ca955
A
1454 break;
1455 }
1456 }
729e4ab9
A
1457 if (found == -1) {
1458 // insert new entry to
1459 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1460 // and remove the existing entry
1461 // currentCacheEntryIndex % CURRENCY_NAME_CACHE_NUM
1462 // from cache.
1463 cacheEntry = currCache[currentCacheEntryIndex];
1464 if (cacheEntry) {
1465 --(cacheEntry->refCount);
1466 // delete if the ref count is zero
1467 if (cacheEntry->refCount == 0) {
1468 deleteCacheEntry(cacheEntry);
1469 }
1470 }
1471 cacheEntry = (CurrencyNameCacheEntry*)uprv_malloc(sizeof(CurrencyNameCacheEntry));
1472 currCache[currentCacheEntryIndex] = cacheEntry;
1473 uprv_strcpy(cacheEntry->locale, locale);
1474 cacheEntry->currencyNames = currencyNames;
1475 cacheEntry->totalCurrencyNameCount = total_currency_name_count;
1476 cacheEntry->currencySymbols = currencySymbols;
1477 cacheEntry->totalCurrencySymbolCount = total_currency_symbol_count;
1478 cacheEntry->refCount = 2; // one for cache, one for reference
1479 currentCacheEntryIndex = (currentCacheEntryIndex + 1) % CURRENCY_NAME_CACHE_NUM;
2ca993e8 1480 ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cache_cleanup);
729e4ab9
A
1481 } else {
1482 deleteCurrencyNames(currencyNames, total_currency_name_count);
1483 deleteCurrencyNames(currencySymbols, total_currency_symbol_count);
1484 cacheEntry = currCache[found];
1485 currencyNames = cacheEntry->currencyNames;
1486 total_currency_name_count = cacheEntry->totalCurrencyNameCount;
1487 currencySymbols = cacheEntry->currencySymbols;
1488 total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount;
1489 ++(cacheEntry->refCount);
374ca955 1490 }
57a6839d 1491 umtx_unlock(&gCurrencyCacheMutex);
374ca955
A
1492 }
1493
729e4ab9
A
1494 int32_t start = pos.getIndex();
1495
1496 UChar inputText[MAX_CURRENCY_NAME_LEN];
1497 UChar upperText[MAX_CURRENCY_NAME_LEN];
1498 int32_t textLen = MIN(MAX_CURRENCY_NAME_LEN, text.length() - start);
1499 text.extract(start, textLen, inputText);
1500 UErrorCode ec1 = U_ZERO_ERROR;
4388f060 1501 textLen = u_strToUpper(upperText, MAX_CURRENCY_NAME_LEN, inputText, textLen, locale, &ec1);
729e4ab9
A
1502
1503 int32_t max = 0;
1504 int32_t matchIndex = -1;
1505 // case in-sensitive comparision against currency names
1506 searchCurrencyName(currencyNames, total_currency_name_count,
1507 upperText, textLen, &max, &matchIndex);
1508
1509#ifdef UCURR_DEBUG
1510 printf("search in names, max = %d, matchIndex = %d\n", max, matchIndex);
1511#endif
1512
1513 int32_t maxInSymbol = 0;
1514 int32_t matchIndexInSymbol = -1;
1515 if (type != UCURR_LONG_NAME) { // not name only
1516 // case sensitive comparison against currency symbols and ISO code.
1517 searchCurrencyName(currencySymbols, total_currency_symbol_count,
1518 inputText, textLen,
1519 &maxInSymbol, &matchIndexInSymbol);
1520 }
1521
1522#ifdef UCURR_DEBUG
1523 printf("search in symbols, maxInSymbol = %d, matchIndexInSymbol = %d\n", maxInSymbol, matchIndexInSymbol);
57a6839d
A
1524 if(matchIndexInSymbol != -1) {
1525 printf("== ISO=%s\n", currencySymbols[matchIndexInSymbol].IsoCode);
1526 }
729e4ab9
A
1527#endif
1528
1529 if (max >= maxInSymbol && matchIndex != -1) {
1530 u_charsToUChars(currencyNames[matchIndex].IsoCode, result, 4);
1531 pos.setIndex(start + max);
1532 } else if (maxInSymbol >= max && matchIndexInSymbol != -1) {
1533 u_charsToUChars(currencySymbols[matchIndexInSymbol].IsoCode, result, 4);
1534 pos.setIndex(start + maxInSymbol);
1535 }
1536
1537 // decrease reference count
57a6839d 1538 umtx_lock(&gCurrencyCacheMutex);
729e4ab9
A
1539 --(cacheEntry->refCount);
1540 if (cacheEntry->refCount == 0) { // remove
1541 deleteCacheEntry(cacheEntry);
1542 }
57a6839d 1543 umtx_unlock(&gCurrencyCacheMutex);
374ca955
A
1544}
1545
729e4ab9 1546
374ca955
A
1547/**
1548 * Internal method. Given a currency ISO code and a locale, return
1549 * the "static" currency name. This is usually the same as the
1550 * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
1551 * format is applied to the number 2.0 (to yield the more common
1552 * plural) to return a static name.
1553 *
1554 * This is used for backward compatibility with old currency logic in
1555 * DecimalFormat and DecimalFormatSymbols.
1556 */
2ca993e8 1557U_CAPI void
374ca955 1558uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
4388f060 1559 icu::UnicodeString& result, UErrorCode& ec)
374ca955 1560{
46f4442e
A
1561 U_NAMESPACE_USE
1562
374ca955
A
1563 UBool isChoiceFormat;
1564 int32_t len;
1565 const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
1566 &isChoiceFormat, &len, &ec);
1567 if (U_SUCCESS(ec)) {
2ca993e8 1568 result.setTo(currname, len);
374ca955
A
1569 }
1570}
b75a7d8f
A
1571
1572U_CAPI int32_t U_EXPORT2
374ca955 1573ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
b331163b
A
1574 return ucurr_getDefaultFractionDigitsForUsage(currency,UCURR_USAGE_STANDARD,ec);
1575}
1576
1577U_DRAFT int32_t U_EXPORT2
1578ucurr_getDefaultFractionDigitsForUsage(const UChar* currency, const UCurrencyUsage usage, UErrorCode* ec) {
1579 int32_t fracDigits = 0;
1580 if (U_SUCCESS(*ec)) {
1581 switch (usage) {
1582 case UCURR_USAGE_STANDARD:
1583 fracDigits = (_findMetaData(currency, *ec))[0];
1584 break;
1585 case UCURR_USAGE_CASH:
1586 fracDigits = (_findMetaData(currency, *ec))[2];
1587 break;
1588 default:
1589 *ec = U_UNSUPPORTED_ERROR;
1590 }
1591 }
1592 return fracDigits;
b75a7d8f
A
1593}
1594
1595U_CAPI double U_EXPORT2
374ca955 1596ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
b331163b
A
1597 return ucurr_getRoundingIncrementForUsage(currency, UCURR_USAGE_STANDARD, ec);
1598}
1599
1600U_DRAFT double U_EXPORT2
1601ucurr_getRoundingIncrementForUsage(const UChar* currency, const UCurrencyUsage usage, UErrorCode* ec) {
1602 double result = 0.0;
1603
374ca955 1604 const int32_t *data = _findMetaData(currency, *ec);
b331163b
A
1605 if (U_SUCCESS(*ec)) {
1606 int32_t fracDigits;
1607 int32_t increment;
1608 switch (usage) {
1609 case UCURR_USAGE_STANDARD:
1610 fracDigits = data[0];
1611 increment = data[1];
1612 break;
1613 case UCURR_USAGE_CASH:
1614 fracDigits = data[2];
1615 increment = data[3];
1616 break;
1617 default:
1618 *ec = U_UNSUPPORTED_ERROR;
1619 return result;
1620 }
b75a7d8f 1621
b331163b
A
1622 // If the meta data is invalid, return 0.0
1623 if (fracDigits < 0 || fracDigits > MAX_POW10) {
374ca955 1624 *ec = U_INVALID_FORMAT_ERROR;
b331163b
A
1625 } else {
1626 // A rounding value of 0 or 1 indicates no rounding.
1627 if (increment >= 2) {
1628 // Return (increment) / 10^(fracDigits). The only actual rounding data,
1629 // as of this writing, is CHF { 2, 5 }.
1630 result = double(increment) / POW10[fracDigits];
1631 }
374ca955 1632 }
374ca955
A
1633 }
1634
b331163b 1635 return result;
b75a7d8f
A
1636}
1637
73c04bcf
A
1638U_CDECL_BEGIN
1639
1640typedef struct UCurrencyContext {
1641 uint32_t currType; /* UCurrCurrencyType */
1642 uint32_t listIdx;
1643} UCurrencyContext;
1644
1645/*
1646Please keep this list in alphabetical order.
1647You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
1648of these items.
1649ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
1650*/
1651static const struct CurrencyList {
1652 const char *currency;
1653 uint32_t currType;
1654} gCurrencyList[] = {
1655 {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
1656 {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
1657 {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
1658 {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e 1659 {"ALK", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1660 {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1661 {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1662 {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1663 {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
1664 {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
1665 {"AON", UCURR_COMMON|UCURR_DEPRECATED},
1666 {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
1667 {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9
A
1668 {"ARL", UCURR_COMMON|UCURR_DEPRECATED},
1669 {"ARM", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1670 {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
1671 {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1672 {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
1673 {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1674 {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1675 {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
1676 {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1677 {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
1678 {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1679 {"BAN", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1680 {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1681 {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1682 {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
1683 {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
1684 {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
1685 {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
46f4442e 1686 {"BGM", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf 1687 {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1688 {"BGO", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1689 {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1690 {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1691 {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1692 {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1693 {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1694 {"BOL", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1695 {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
1696 {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1697 {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
1698 {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
1699 {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
1700 {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1701 {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
1702 {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9 1703 {"BRZ", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1704 {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1705 {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1706 {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
1707 {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1708 {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
1709 {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1710 {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1711 {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1712 {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1713 {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1714 {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1715 {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
729e4ab9 1716 {"CLE", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1717 {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1718 {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1719 {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
1720 {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1721 {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1722 {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1723 {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e 1724 {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf 1725 {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9 1726 {"CUC", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1727 {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1728 {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e 1729 {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1730 {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1731 {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
1732 {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
1733 {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1734 {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1735 {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1736 {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1737 {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
1738 {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
4388f060 1739 {"EEK", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1740 {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1741 {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
1742 {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1743 {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
1744 {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
1745 {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
1746 {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1747 {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1748 {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
1749 {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1750 {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1751 {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
1752 {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1753 {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
1754 {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e
A
1755 {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
1756 {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1757 {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1758 {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1759 {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1760 {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
1761 {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
1762 {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
1763 {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
1764 {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
1765 {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1766 {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1767 {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1768 {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1769 {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
1770 {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1771 {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1772 {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1773 {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1774 {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
1775 {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9 1776 {"ILR", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1777 {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1778 {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1779 {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1780 {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1781 {"ISJ", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1782 {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1783 {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
1784 {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1785 {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1786 {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1787 {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
1788 {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1789 {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1790 {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1791 {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9
A
1792 {"KRH", UCURR_COMMON|UCURR_DEPRECATED},
1793 {"KRO", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1794 {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
1795 {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1796 {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1797 {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1798 {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1799 {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1800 {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1801 {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1802 {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1803 {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
1804 {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1805 {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
1806 {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
1807 {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
1808 {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
1809 {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1810 {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
1811 {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1812 {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1813 {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9
A
1814 {"MCF", UCURR_COMMON|UCURR_DEPRECATED},
1815 {"MDC", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1816 {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1817 {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
1818 {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
1819 {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1820 {"MKN", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1821 {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
1822 {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1823 {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
1824 {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1825 {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e 1826 {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1827 {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
1828 {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1829 {"MVP", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1830 {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1831 {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1832 {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1833 {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
1834 {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1835 {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1836 {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
1837 {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
1838 {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1839 {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1840 {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1841 {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
1842 {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
1843 {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
1844 {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1845 {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1846 {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1847 {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1848 {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1849 {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
1850 {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1851 {"PES", UCURR_COMMON|UCURR_DEPRECATED},
1852 {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1853 {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1854 {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1855 {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
1856 {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
1857 {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
1858 {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
1859 {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1860 {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
1861 {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
1862 {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e 1863 {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1864 {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1865 {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
1866 {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1867 {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
1868 {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1869 {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e
A
1870 {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
1871 {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1872 {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
1873 {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1874 {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1875 {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1876 {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
1877 {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
1878 {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1879 {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1880 {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1881 {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
51004dcb 1882 {"SSP", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1883 {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1884 {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
1885 {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
1886 {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1887 {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
1888 {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
1889 {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
1890 {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9
A
1891 {"TMM", UCURR_COMMON|UCURR_DEPRECATED},
1892 {"TMT", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1893 {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
1894 {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
1895 {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
1896 {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
1897 {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
1898 {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1899 {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1900 {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
1901 {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
1902 {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
1903 {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
1904 {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
1905 {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1906 {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1907 {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
46f4442e 1908 {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
729e4ab9 1909 {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1910 {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
1911 {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
46f4442e
A
1912 {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
1913 {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf 1914 {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
729e4ab9 1915 {"VNN", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1916 {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
1917 {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
1918 {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1919 {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1920 {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1921 {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1922 {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1923 {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1924 {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1925 {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
1926 {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1927 {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
1928 {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1929 {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1930 {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1931 {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1932 {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
1933 {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1934 {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
51004dcb 1935 {"XSU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
73c04bcf 1936 {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
51004dcb 1937 {"XUA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1938 {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1939 {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
1940 {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
1941 {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
1942 {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
1943 {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9 1944 {"YUR", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1945 {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
1946 {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
51004dcb
A
1947 {"ZMK", UCURR_COMMON|UCURR_DEPRECATED},
1948 {"ZMW", UCURR_COMMON|UCURR_NON_DEPRECATED},
73c04bcf
A
1949 {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
1950 {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
51004dcb 1951 {"ZWL", UCURR_COMMON|UCURR_DEPRECATED},
729e4ab9
A
1952 {"ZWR", UCURR_COMMON|UCURR_DEPRECATED},
1953 {"ZWD", UCURR_COMMON|UCURR_DEPRECATED},
73c04bcf
A
1954 { NULL, 0 } // Leave here to denote the end of the list.
1955};
1956
1957#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
1958 ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
1959
1960static int32_t U_CALLCONV
1961ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
1962 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1963 uint32_t currType = myContext->currType;
1964 int32_t count = 0;
1965
1966 /* Count the number of items matching the type we are looking for. */
1967 for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
1968 if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
1969 count++;
1970 }
1971 }
1972 return count;
1973}
1974
1975static const char* U_CALLCONV
1976ucurr_nextCurrencyList(UEnumeration *enumerator,
1977 int32_t* resultLength,
1978 UErrorCode * /*pErrorCode*/)
1979{
1980 UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
1981
1982 /* Find the next in the list that matches the type we are looking for. */
2ca993e8 1983 while (myContext->listIdx < UPRV_LENGTHOF(gCurrencyList)-1) {
73c04bcf
A
1984 const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
1985 if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
1986 {
1987 if (resultLength) {
1988 *resultLength = 3; /* Currency codes are only 3 chars long */
1989 }
1990 return currItem->currency;
1991 }
1992 }
1993 /* We enumerated too far. */
1994 if (resultLength) {
1995 *resultLength = 0;
1996 }
1997 return NULL;
1998}
1999
2000static void U_CALLCONV
2001ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
2002 ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
2003}
2004
2005static void U_CALLCONV
2006ucurr_closeCurrencyList(UEnumeration *enumerator) {
2007 uprv_free(enumerator->context);
2008 uprv_free(enumerator);
2009}
2010
4388f060 2011static void U_CALLCONV
57a6839d 2012ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){
4388f060
A
2013 UErrorCode localStatus = U_ZERO_ERROR;
2014
2015 // Look up the CurrencyMap element in the root bundle.
2016 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
2017 UResourceBundle *currencyMapArray = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
2018
2019 if (U_SUCCESS(localStatus)) {
2020 // process each entry in currency map
2021 for (int32_t i=0; i<ures_getSize(currencyMapArray); i++) {
2022 // get the currency resource
2023 UResourceBundle *currencyArray = ures_getByIndex(currencyMapArray, i, NULL, &localStatus);
2024 // process each currency
2025 if (U_SUCCESS(localStatus)) {
2026 for (int32_t j=0; j<ures_getSize(currencyArray); j++) {
2027 // get the currency resource
2028 UResourceBundle *currencyRes = ures_getByIndex(currencyArray, j, NULL, &localStatus);
2029 IsoCodeEntry *entry = (IsoCodeEntry*)uprv_malloc(sizeof(IsoCodeEntry));
2030 if (entry == NULL) {
2031 *status = U_MEMORY_ALLOCATION_ERROR;
2032 return;
2033 }
2034
2035 // get the ISO code
2036 int32_t isoLength = 0;
2037 UResourceBundle *idRes = ures_getByKey(currencyRes, "id", NULL, &localStatus);
2038 if (idRes == NULL) {
2039 continue;
2040 }
2041 const UChar *isoCode = ures_getString(idRes, &isoLength, &localStatus);
2042
51004dcb
A
2043 // get from date
2044 UDate fromDate = U_DATE_MIN;
4388f060 2045 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
51004dcb
A
2046
2047 if (U_SUCCESS(localStatus)) {
2048 int32_t fromLength = 0;
2049 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2050 int64_t currDate64 = (int64_t)fromArray[0] << 32;
2051 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2052 fromDate = (UDate)currDate64;
2053 }
2054 ures_close(fromRes);
2055
2056 // get to date
4388f060 2057 UDate toDate = U_DATE_MAX;
51004dcb
A
2058 localStatus = U_ZERO_ERROR;
2059 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
4388f060 2060
51004dcb 2061 if (U_SUCCESS(localStatus)) {
4388f060 2062 int32_t toLength = 0;
4388f060 2063 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
51004dcb 2064 int64_t currDate64 = (int64_t)toArray[0] << 32;
4388f060
A
2065 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2066 toDate = (UDate)currDate64;
51004dcb
A
2067 }
2068 ures_close(toRes);
4388f060 2069
4388f060
A
2070 ures_close(idRes);
2071 ures_close(currencyRes);
2072
2073 entry->isoCode = isoCode;
2074 entry->from = fromDate;
2075 entry->to = toDate;
2076
51004dcb 2077 localStatus = U_ZERO_ERROR;
57a6839d 2078 uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus);
4388f060
A
2079 }
2080 } else {
2081 *status = localStatus;
2082 }
2083 ures_close(currencyArray);
2084 }
2085 } else {
2086 *status = localStatus;
2087 }
2088
2089 ures_close(currencyMapArray);
2090}
2091
73c04bcf
A
2092static const UEnumeration gEnumCurrencyList = {
2093 NULL,
2094 NULL,
2095 ucurr_closeCurrencyList,
2096 ucurr_countCurrencyList,
2097 uenum_unextDefault,
2098 ucurr_nextCurrencyList,
2099 ucurr_resetCurrencyList
2100};
2101U_CDECL_END
2102
4388f060 2103
57a6839d
A
2104static void U_CALLCONV initIsoCodes(UErrorCode &status) {
2105 U_ASSERT(gIsoCodes == NULL);
2ca993e8 2106 ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
4388f060 2107
57a6839d
A
2108 UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
2109 if (U_FAILURE(status)) {
2110 return;
2111 }
2112 uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
2113
2114 ucurr_createCurrencyList(isoCodes, &status);
2115 if (U_FAILURE(status)) {
2116 uhash_close(isoCodes);
2117 return;
2118 }
2119 gIsoCodes = isoCodes; // Note: gIsoCodes is const. Once set up here it is never altered,
2120 // and read only access is safe without synchronization.
2121}
2122
2123static void populateCurrSymbolsEquiv(icu::Hashtable *hash, UErrorCode &status) {
2124 if (U_FAILURE(status)) {
2125 return;
2126 }
2ca993e8 2127 int32_t length = UPRV_LENGTHOF(EQUIV_CURRENCY_SYMBOLS);
57a6839d
A
2128 for (int32_t i = 0; i < length; ++i) {
2129 icu::UnicodeString lhs(EQUIV_CURRENCY_SYMBOLS[i][0], -1, US_INV);
2130 icu::UnicodeString rhs(EQUIV_CURRENCY_SYMBOLS[i][1], -1, US_INV);
2131 makeEquivalent(lhs.unescape(), rhs.unescape(), hash, status);
4388f060 2132 if (U_FAILURE(status)) {
57a6839d 2133 return;
4388f060 2134 }
57a6839d
A
2135 }
2136}
4388f060 2137
57a6839d
A
2138static void U_CALLCONV initCurrSymbolsEquiv() {
2139 U_ASSERT(gCurrSymbolsEquiv == NULL);
2140 UErrorCode status = U_ZERO_ERROR;
2ca993e8 2141 ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
57a6839d
A
2142 icu::Hashtable *temp = new icu::Hashtable(status);
2143 if (temp == NULL) {
2144 return;
4388f060 2145 }
57a6839d
A
2146 if (U_FAILURE(status)) {
2147 delete temp;
2148 return;
2149 }
2150 temp->setValueDeleter(deleteUnicode);
2151 populateCurrSymbolsEquiv(temp, status);
2152 if (U_FAILURE(status)) {
2153 delete temp;
2154 return;
2155 }
2156 gCurrSymbolsEquiv = temp;
2157}
4388f060 2158
57a6839d
A
2159U_CAPI UBool U_EXPORT2
2160ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
2161 umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
2162 if (U_FAILURE(*eErrorCode)) {
2163 return FALSE;
2164 }
4388f060 2165
57a6839d 2166 IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
4388f060
A
2167 if (result == NULL) {
2168 return FALSE;
2169 } else if (from > to) {
2170 *eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
2171 return FALSE;
2172 } else if ((from > result->to) || (to < result->from)) {
2173 return FALSE;
2174 }
4388f060
A
2175 return TRUE;
2176}
2177
57a6839d
A
2178static const icu::Hashtable* getCurrSymbolsEquiv() {
2179 umtx_initOnce(gCurrSymbolsEquivInitOnce, &initCurrSymbolsEquiv);
2180 return gCurrSymbolsEquiv;
2181}
2182
73c04bcf
A
2183U_CAPI UEnumeration * U_EXPORT2
2184ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
2185 UEnumeration *myEnum = NULL;
2186 UCurrencyContext *myContext;
2187
2188 myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
2189 if (myEnum == NULL) {
2190 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
2191 return NULL;
2192 }
2193 uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
2194 myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
2195 if (myContext == NULL) {
2196 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
2197 uprv_free(myEnum);
2198 return NULL;
2199 }
2200 myContext->currType = currType;
2201 myContext->listIdx = 0;
2202 myEnum->context = myContext;
2203 return myEnum;
2204}
2205
46f4442e
A
2206U_CAPI int32_t U_EXPORT2
2207ucurr_countCurrencies(const char* locale,
2208 UDate date,
2209 UErrorCode* ec)
2210{
729e4ab9 2211 int32_t currCount = 0;
46f4442e
A
2212
2213 if (ec != NULL && U_SUCCESS(*ec))
729e4ab9
A
2214 {
2215 // local variables
46f4442e
A
2216 UErrorCode localStatus = U_ZERO_ERROR;
2217 char id[ULOC_FULLNAME_CAPACITY];
4388f060 2218 uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
729e4ab9
A
2219 // get country or country_variant in `id'
2220 /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
2221
2222 if (U_FAILURE(*ec))
2223 {
2224 return 0;
2225 }
2226
2227 // Remove variants, which is only needed for registration.
2228 char *idDelim = strchr(id, VAR_DELIM);
2229 if (idDelim)
2230 {
2231 idDelim[0] = 0;
2232 }
2233
2234 // Look up the CurrencyMap element in the root bundle.
2235 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
2236 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
2237
2238 // Using the id derived from the local, get the currency data
2239 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
2240
2241 // process each currency to see which one is valid for the given date
2242 if (U_SUCCESS(localStatus))
2243 {
2244 for (int32_t i=0; i<ures_getSize(countryArray); i++)
2245 {
2246 // get the currency resource
2247 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
46f4442e 2248
729e4ab9
A
2249 // get the from date
2250 int32_t fromLength = 0;
2251 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
2252 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2253
2254 int64_t currDate64 = (int64_t)fromArray[0] << 32;
2255 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2256 UDate fromDate = (UDate)currDate64;
2257
2258 if (ures_getSize(currencyRes)> 2)
2259 {
2260 int32_t toLength = 0;
2261 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
2262 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
2263
2264 currDate64 = (int64_t)toArray[0] << 32;
2265 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2266 UDate toDate = (UDate)currDate64;
2267
2268 if ((fromDate <= date) && (date < toDate))
2269 {
2270 currCount++;
2271 }
2272
2273 ures_close(toRes);
2274 }
2275 else
2276 {
2277 if (fromDate <= date)
2278 {
2279 currCount++;
2280 }
2281 }
2282
2283 // close open resources
2284 ures_close(currencyRes);
2285 ures_close(fromRes);
2286
2287 } // end For loop
2288 } // end if (U_SUCCESS(localStatus))
2289
2290 ures_close(countryArray);
2291
2292 // Check for errors
2293 if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
2294 {
2295 // There is nothing to fallback to.
2296 // Report the failure/warning if possible.
2297 *ec = localStatus;
2298 }
2299
2300 if (U_SUCCESS(*ec))
2301 {
2302 // no errors
2303 return currCount;
2304 }
46f4442e
A
2305
2306 }
2307
729e4ab9
A
2308 // If we got here, either error code is invalid or
2309 // some argument passed is no good.
46f4442e
A
2310 return 0;
2311}
2312
2313U_CAPI int32_t U_EXPORT2
2314ucurr_forLocaleAndDate(const char* locale,
2315 UDate date,
2316 int32_t index,
2317 UChar* buff,
2318 int32_t buffCapacity,
2319 UErrorCode* ec)
2320{
2321 int32_t resLen = 0;
2322 int32_t currIndex = 0;
2323 const UChar* s = NULL;
2324
729e4ab9
A
2325 if (ec != NULL && U_SUCCESS(*ec))
2326 {
2327 // check the arguments passed
2328 if ((buff && buffCapacity) || !buffCapacity )
2329 {
2330 // local variables
46f4442e
A
2331 UErrorCode localStatus = U_ZERO_ERROR;
2332 char id[ULOC_FULLNAME_CAPACITY];
2333 resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus);
2334
729e4ab9
A
2335 // get country or country_variant in `id'
2336 /*uint32_t variantType =*/ idForLocale(locale, id, sizeof(id), ec);
2337 if (U_FAILURE(*ec))
2338 {
2339 return 0;
2340 }
2341
2342 // Remove variants, which is only needed for registration.
2343 char *idDelim = strchr(id, VAR_DELIM);
2344 if (idDelim)
2345 {
2346 idDelim[0] = 0;
2347 }
2348
2349 // Look up the CurrencyMap element in the root bundle.
2350 UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
2351 UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
2352
2353 // Using the id derived from the local, get the currency data
2354 UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
2355
2356 // process each currency to see which one is valid for the given date
2357 bool matchFound = false;
2358 if (U_SUCCESS(localStatus))
2359 {
2360 if ((index <= 0) || (index> ures_getSize(countryArray)))
2361 {
46f4442e
A
2362 // requested index is out of bounds
2363 ures_close(countryArray);
729e4ab9
A
2364 return 0;
2365 }
2366
2367 for (int32_t i=0; i<ures_getSize(countryArray); i++)
2368 {
2369 // get the currency resource
2370 UResourceBundle *currencyRes = ures_getByIndex(countryArray, i, NULL, &localStatus);
2371 s = ures_getStringByKey(currencyRes, "id", &resLen, &localStatus);
2372
2373 // get the from date
2374 int32_t fromLength = 0;
2375 UResourceBundle *fromRes = ures_getByKey(currencyRes, "from", NULL, &localStatus);
2376 const int32_t *fromArray = ures_getIntVector(fromRes, &fromLength, &localStatus);
2377
2378 int64_t currDate64 = (int64_t)fromArray[0] << 32;
2379 currDate64 |= ((int64_t)fromArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2380 UDate fromDate = (UDate)currDate64;
2381
2382 if (ures_getSize(currencyRes)> 2)
2383 {
2384 int32_t toLength = 0;
2385 UResourceBundle *toRes = ures_getByKey(currencyRes, "to", NULL, &localStatus);
2386 const int32_t *toArray = ures_getIntVector(toRes, &toLength, &localStatus);
2387
2388 currDate64 = (int64_t)toArray[0] << 32;
2389 currDate64 |= ((int64_t)toArray[1] & (int64_t)INT64_C(0x00000000FFFFFFFF));
2390 UDate toDate = (UDate)currDate64;
2391
2392 if ((fromDate <= date) && (date < toDate))
2393 {
2394 currIndex++;
2395 if (currIndex == index)
2396 {
2397 matchFound = true;
2398 }
2399 }
2400
2401 ures_close(toRes);
2402 }
2403 else
2404 {
2405 if (fromDate <= date)
2406 {
2407 currIndex++;
2408 if (currIndex == index)
2409 {
2410 matchFound = true;
2411 }
2412 }
2413 }
2414
2415 // close open resources
2416 ures_close(currencyRes);
2417 ures_close(fromRes);
2418
2419 // check for loop exit
2420 if (matchFound)
2421 {
2422 break;
2423 }
2424
2425 } // end For loop
2426 }
2427
2428 ures_close(countryArray);
2429
2430 // Check for errors
2431 if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR)
2432 {
2433 // There is nothing to fallback to.
2434 // Report the failure/warning if possible.
2435 *ec = localStatus;
2436 }
2437
2438 if (U_SUCCESS(*ec))
2439 {
2440 // no errors
2441 if((buffCapacity> resLen) && matchFound)
2442 {
2443 // write out the currency value
2444 u_strcpy(buff, s);
2445 }
2446 else
2447 {
2448 return 0;
2449 }
2450 }
2451
2452 // return null terminated currency string
46f4442e 2453 return u_terminateUChars(buff, buffCapacity, resLen, ec);
729e4ab9
A
2454 }
2455 else
2456 {
2457 // illegal argument encountered
46f4442e
A
2458 *ec = U_ILLEGAL_ARGUMENT_ERROR;
2459 }
2460
2461 }
2462
729e4ab9
A
2463 // If we got here, either error code is invalid or
2464 // some argument passed is no good.
46f4442e
A
2465 return resLen;
2466}
2467
729e4ab9
A
2468static const UEnumeration defaultKeywordValues = {
2469 NULL,
2470 NULL,
2471 ulist_close_keyword_values_iterator,
2472 ulist_count_keyword_values,
2473 uenum_unextDefault,
2474 ulist_next_keyword_value,
2475 ulist_reset_keyword_values_iterator
2476};
2477
2478U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
2479 // Resolve region
2ca993e8
A
2480 char prefRegion[ULOC_COUNTRY_CAPACITY];
2481 ulocimp_getRegionForSupplementalData(locale, TRUE, prefRegion, sizeof(prefRegion), status);
729e4ab9
A
2482
2483 // Read value from supplementalData
2484 UList *values = ulist_createEmptyList(status);
2485 UList *otherValues = ulist_createEmptyList(status);
2486 UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
2487 if (U_FAILURE(*status) || en == NULL) {
2488 if (en == NULL) {
2489 *status = U_MEMORY_ALLOCATION_ERROR;
2490 } else {
2491 uprv_free(en);
2492 }
2493 ulist_deleteList(values);
2494 ulist_deleteList(otherValues);
2495 return NULL;
2496 }
2497 memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
2498 en->context = values;
2499
2500 UResourceBundle *bundle = ures_openDirect(U_ICUDATA_CURR, "supplementalData", status);
2501 ures_getByKey(bundle, "CurrencyMap", bundle, status);
2502 UResourceBundle bundlekey, regbndl, curbndl, to;
2503 ures_initStackObject(&bundlekey);
2504 ures_initStackObject(&regbndl);
2505 ures_initStackObject(&curbndl);
2506 ures_initStackObject(&to);
2507
2508 while (U_SUCCESS(*status) && ures_hasNext(bundle)) {
2509 ures_getNextResource(bundle, &bundlekey, status);
2510 if (U_FAILURE(*status)) {
2511 break;
2512 }
2513 const char *region = ures_getKey(&bundlekey);
2514 UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
2515 if (!isPrefRegion && commonlyUsed) {
2516 // With commonlyUsed=true, we do not put
2517 // currencies for other regions in the
2518 // result list.
2519 continue;
2520 }
2521 ures_getByKey(bundle, region, &regbndl, status);
2522 if (U_FAILURE(*status)) {
2523 break;
2524 }
2525 while (U_SUCCESS(*status) && ures_hasNext(&regbndl)) {
2526 ures_getNextResource(&regbndl, &curbndl, status);
2527 if (ures_getType(&curbndl) != URES_TABLE) {
2528 // Currently, an empty ARRAY is mixed in.
2529 continue;
2530 }
2531 char *curID = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
2532 int32_t curIDLength = ULOC_KEYWORDS_CAPACITY;
2533 if (curID == NULL) {
2534 *status = U_MEMORY_ALLOCATION_ERROR;
2535 break;
2536 }
2537
2538#if U_CHARSET_FAMILY==U_ASCII_FAMILY
2539 ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
2540 /* optimize - use the utf-8 string */
2541#else
2542 {
2543 const UChar* defString = ures_getStringByKey(&curbndl, "id", &curIDLength, status);
2544 if(U_SUCCESS(*status)) {
2545 if(curIDLength+1 > ULOC_KEYWORDS_CAPACITY) {
2546 *status = U_BUFFER_OVERFLOW_ERROR;
2547 } else {
2548 u_UCharsToChars(defString, curID, curIDLength+1);
2549 }
2550 }
2551 }
2552#endif
2553
2554 if (U_FAILURE(*status)) {
2555 break;
2556 }
2557 UBool hasTo = FALSE;
2558 ures_getByKey(&curbndl, "to", &to, status);
2559 if (U_FAILURE(*status)) {
2560 // Do nothing here...
2561 *status = U_ZERO_ERROR;
2562 } else {
2563 hasTo = TRUE;
2564 }
2565 if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
2566 // Currently active currency for the target country
2567 ulist_addItemEndList(values, curID, TRUE, status);
2568 } else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
2569 ulist_addItemEndList(otherValues, curID, TRUE, status);
2570 } else {
2571 uprv_free(curID);
2572 }
2573 }
2574
2575 }
2576 if (U_SUCCESS(*status)) {
2577 if (commonlyUsed) {
2578 if (ulist_getListSize(values) == 0) {
2579 // This could happen if no valid region is supplied in the input
2580 // locale. In this case, we use the CLDR's default.
2581 uenum_close(en);
2582 en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
2583 }
2584 } else {
2585 // Consolidate the list
2586 char *value = NULL;
2587 ulist_resetList(otherValues);
2588 while ((value = (char *)ulist_getNext(otherValues)) != NULL) {
2589 if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
2590 char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
2591 uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
2592 ulist_addItemEndList(values, tmpValue, TRUE, status);
2593 if (U_FAILURE(*status)) {
2594 break;
2595 }
2596 }
2597 }
2598 }
2599
2600 ulist_resetList((UList *)(en->context));
2601 } else {
2602 ulist_deleteList(values);
2603 uprv_free(en);
2604 values = NULL;
2605 en = NULL;
2606 }
2607 ures_close(&to);
2608 ures_close(&curbndl);
2609 ures_close(&regbndl);
2610 ures_close(&bundlekey);
2611 ures_close(bundle);
2612
2613 ulist_deleteList(otherValues);
2614
2615 return en;
2616}
2617
4388f060
A
2618
2619U_CAPI int32_t U_EXPORT2
2620ucurr_getNumericCode(const UChar* currency) {
2621 int32_t code = 0;
2622 if (currency && u_strlen(currency) == ISO_CURRENCY_CODE_LENGTH) {
2623 UErrorCode status = U_ZERO_ERROR;
2624
2625 UResourceBundle *bundle = ures_openDirect(0, "currencyNumericCodes", &status);
2626 ures_getByKey(bundle, "codeMap", bundle, &status);
2627 if (U_SUCCESS(status)) {
2628 char alphaCode[ISO_CURRENCY_CODE_LENGTH+1];
2629 myUCharsToChars(alphaCode, currency);
2630 T_CString_toUpperCase(alphaCode);
2631 ures_getByKey(bundle, alphaCode, bundle, &status);
2632 int tmpCode = ures_getInt(bundle, &status);
2633 if (U_SUCCESS(status)) {
2634 code = tmpCode;
2635 }
2636 }
2637 ures_close(bundle);
2638 }
2639 return code;
2640}
b75a7d8f
A
2641#endif /* #if !UCONFIG_NO_FORMATTING */
2642
2643//eof