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