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