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