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