OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * Copyright (C) 1997-2010, International Business Machines Corporation and * |
| 4 * others. All Rights Reserved. * |
| 5 ******************************************************************************* |
| 6 * |
| 7 * File DCFMTSYM.CPP |
| 8 * |
| 9 * Modification History: |
| 10 * |
| 11 * Date Name Description |
| 12 * 02/19/97 aliu Converted from java. |
| 13 * 03/18/97 clhuang Implemented with C++ APIs. |
| 14 * 03/27/97 helena Updated to pass the simple test after code review. |
| 15 * 08/26/97 aliu Added currency/intl currency symbol support. |
| 16 * 07/20/98 stephen Slightly modified initialization of monetarySeparato
r |
| 17 ******************************************************************************** |
| 18 */ |
| 19 |
| 20 #include "unicode/utypes.h" |
| 21 |
| 22 #if !UCONFIG_NO_FORMATTING |
| 23 |
| 24 #include "unicode/dcfmtsym.h" |
| 25 #include "unicode/ures.h" |
| 26 #include "unicode/decimfmt.h" |
| 27 #include "unicode/ucurr.h" |
| 28 #include "unicode/choicfmt.h" |
| 29 #include "unicode/unistr.h" |
| 30 #include "unicode/numsys.h" |
| 31 #include "ucurrimp.h" |
| 32 #include "cstring.h" |
| 33 #include "locbased.h" |
| 34 #include "uresimp.h" |
| 35 #include "ureslocs.h" |
| 36 |
| 37 // ***************************************************************************** |
| 38 // class DecimalFormatSymbols |
| 39 // ***************************************************************************** |
| 40 |
| 41 U_NAMESPACE_BEGIN |
| 42 |
| 43 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols) |
| 44 |
| 45 static const char gNumberElements[] = "NumberElements"; |
| 46 static const char gCurrencySpacingTag[] = "currencySpacing"; |
| 47 static const char gBeforeCurrencyTag[] = "beforeCurrency"; |
| 48 static const char gAfterCurrencyTag[] = "afterCurrency"; |
| 49 static const char gCurrencyMatchTag[] = "currencyMatch"; |
| 50 static const char gCurrencySudMatchTag[] = "surroundingMatch"; |
| 51 static const char gCurrencyInsertBtnTag[] = "insertBetween"; |
| 52 |
| 53 |
| 54 static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0}; |
| 55 |
| 56 // ------------------------------------- |
| 57 // Initializes this with the decimal format symbols in the default locale. |
| 58 |
| 59 DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status) |
| 60 : UObject(), |
| 61 locale() |
| 62 { |
| 63 initialize(locale, status, TRUE); |
| 64 } |
| 65 |
| 66 // ------------------------------------- |
| 67 // Initializes this with the decimal format symbols in the desired locale. |
| 68 |
| 69 DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status
) |
| 70 : UObject(), |
| 71 locale(loc) |
| 72 { |
| 73 initialize(locale, status); |
| 74 } |
| 75 |
| 76 // ------------------------------------- |
| 77 |
| 78 DecimalFormatSymbols::~DecimalFormatSymbols() |
| 79 { |
| 80 } |
| 81 |
| 82 // ------------------------------------- |
| 83 // copy constructor |
| 84 |
| 85 DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source) |
| 86 : UObject(source) |
| 87 { |
| 88 *this = source; |
| 89 } |
| 90 |
| 91 // ------------------------------------- |
| 92 // assignment operator |
| 93 |
| 94 DecimalFormatSymbols& |
| 95 DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs) |
| 96 { |
| 97 if (this != &rhs) { |
| 98 for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) { |
| 99 // fastCopyFrom is safe, see docs on fSymbols |
| 100 fSymbols[(ENumberFormatSymbol)i].fastCopyFrom(rhs.fSymbols[(ENumberF
ormatSymbol)i]); |
| 101 } |
| 102 for(int32_t i = 0; i < (int32_t)kCurrencySpacingCount; ++i) { |
| 103 currencySpcBeforeSym[i].fastCopyFrom(rhs.currencySpcBeforeSym[i]); |
| 104 currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]); |
| 105 } |
| 106 locale = rhs.locale; |
| 107 uprv_strcpy(validLocale, rhs.validLocale); |
| 108 uprv_strcpy(actualLocale, rhs.actualLocale); |
| 109 } |
| 110 return *this; |
| 111 } |
| 112 |
| 113 // ------------------------------------- |
| 114 |
| 115 UBool |
| 116 DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const |
| 117 { |
| 118 if (this == &that) { |
| 119 return TRUE; |
| 120 } |
| 121 for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) { |
| 122 if(fSymbols[(ENumberFormatSymbol)i] != that.fSymbols[(ENumberFormatSymbo
l)i]) { |
| 123 return FALSE; |
| 124 } |
| 125 } |
| 126 for(int32_t i = 0; i < (int32_t)kCurrencySpacingCount; ++i) { |
| 127 if(currencySpcBeforeSym[i] != that.currencySpcBeforeSym[i]) { |
| 128 return FALSE; |
| 129 } |
| 130 if(currencySpcAfterSym[i] != that.currencySpcAfterSym[i]) { |
| 131 return FALSE; |
| 132 } |
| 133 } |
| 134 return locale == that.locale && |
| 135 uprv_strcmp(validLocale, that.validLocale) == 0 && |
| 136 uprv_strcmp(actualLocale, that.actualLocale) == 0; |
| 137 } |
| 138 |
| 139 // ------------------------------------- |
| 140 |
| 141 void |
| 142 DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UBool us
eLastResortData) |
| 143 { |
| 144 static const char *gNumberElementKeys[kFormatSymbolCount] = { |
| 145 "decimal", |
| 146 "group", |
| 147 "list", |
| 148 "percentSign", |
| 149 NULL, /* Native zero digit is deprecated from CLDR - get it from the num
bering system */ |
| 150 NULL, /* Pattern digit character is deprecated from CLDR - use # by defa
ult always */ |
| 151 "minusSign", |
| 152 "plusSign", |
| 153 NULL, /* currency symbol - We don't really try to load this directly fro
m CLDR until we know the currency */ |
| 154 NULL, /* intl currency symbol - We don't really try to load this directl
y from CLDR until we know the currency */ |
| 155 "currencyDecimal", |
| 156 "exponential", |
| 157 "perMille", |
| 158 NULL, /* Escape padding character - not in CLDR */ |
| 159 "infinity", |
| 160 "nan", |
| 161 NULL, /* Significant digit symbol - not in CLDR */ |
| 162 "currencyGroup", |
| 163 NULL, /* one digit - get it from the numbering system */ |
| 164 NULL, /* two digit - get it from the numbering system */ |
| 165 NULL, /* three digit - get it from the numbering system */ |
| 166 NULL, /* four digit - get it from the numbering system */ |
| 167 NULL, /* five digit - get it from the numbering system */ |
| 168 NULL, /* six digit - get it from the numbering system */ |
| 169 NULL, /* seven digit - get it from the numbering system */ |
| 170 NULL, /* eight digit - get it from the numbering system */ |
| 171 NULL, /* nine digit - get it from the numbering system */ |
| 172 }; |
| 173 |
| 174 static const char *gLatn = "latn"; |
| 175 static const char *gSymbols = "symbols"; |
| 176 const char *nsName; |
| 177 const UChar *sym = NULL; |
| 178 int32_t len = 0; |
| 179 |
| 180 *validLocale = *actualLocale = 0; |
| 181 currPattern = NULL; |
| 182 if (U_FAILURE(status)) |
| 183 return; |
| 184 |
| 185 const char* locStr = loc.getName(); |
| 186 UResourceBundle *resource = ures_open((char *)0, locStr, &status); |
| 187 UResourceBundle *numberElementsRes = ures_getByKeyWithFallback(resource, gNu
mberElements, NULL, &status); |
| 188 |
| 189 if (U_FAILURE(status)) { |
| 190 if ( useLastResortData ) { |
| 191 status = U_USING_FALLBACK_WARNING; |
| 192 initialize(); |
| 193 } |
| 194 return; |
| 195 } else { |
| 196 |
| 197 // First initialize all the symbols to the fallbacks for anything we can
't find |
| 198 initialize(); |
| 199 |
| 200 // |
| 201 // Next get the numbering system for this locale and set zero digit |
| 202 // and the digit string based on the numbering system for the locale |
| 203 // |
| 204 |
| 205 NumberingSystem* ns = NumberingSystem::createInstance(loc,status); |
| 206 if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) { |
| 207 nsName = ns->getName(); |
| 208 UnicodeString *DigitString = new UnicodeString(ns->getDescription())
; |
| 209 setSymbol(kZeroDigitSymbol,DigitString->charAt(0),FALSE); |
| 210 setSymbol(kOneDigitSymbol,DigitString->charAt(1),FALSE); |
| 211 setSymbol(kTwoDigitSymbol,DigitString->charAt(2),FALSE); |
| 212 setSymbol(kThreeDigitSymbol,DigitString->charAt(3),FALSE); |
| 213 setSymbol(kFourDigitSymbol,DigitString->charAt(4),FALSE); |
| 214 setSymbol(kFiveDigitSymbol,DigitString->charAt(5),FALSE); |
| 215 setSymbol(kSixDigitSymbol,DigitString->charAt(6),FALSE); |
| 216 setSymbol(kSevenDigitSymbol,DigitString->charAt(7),FALSE); |
| 217 setSymbol(kEightDigitSymbol,DigitString->charAt(8),FALSE); |
| 218 setSymbol(kNineDigitSymbol,DigitString->charAt(9),FALSE); |
| 219 delete DigitString; |
| 220 } else { |
| 221 nsName = gLatn; |
| 222 } |
| 223 |
| 224 UBool isLatn = !uprv_strcmp(nsName,gLatn); |
| 225 |
| 226 UErrorCode nlStatus = U_ZERO_ERROR; |
| 227 UResourceBundle *nonLatnSymbols = NULL; |
| 228 if ( !isLatn ) { |
| 229 nonLatnSymbols = ures_getByKeyWithFallback(numberElementsRes, nsName
, NULL, &nlStatus); |
| 230 nonLatnSymbols = ures_getByKeyWithFallback(nonLatnSymbols, gSymbols,
nonLatnSymbols, &nlStatus); |
| 231 } |
| 232 |
| 233 UResourceBundle *latnSymbols = ures_getByKeyWithFallback(numberElementsR
es, gLatn, NULL, &status); |
| 234 latnSymbols = ures_getByKeyWithFallback(latnSymbols, gSymbols, latnSymbo
ls, &status); |
| 235 |
| 236 UBool kMonetaryDecimalSet = FALSE; |
| 237 UBool kMonetaryGroupingSet = FALSE; |
| 238 for(int32_t i = 0; i<kFormatSymbolCount; i++) { |
| 239 if ( gNumberElementKeys[i] != NULL ) { |
| 240 UErrorCode localStatus = U_ZERO_ERROR; |
| 241 if ( !isLatn ) { |
| 242 sym = ures_getStringByKeyWithFallback(nonLatnSymbols,gNumber
ElementKeys[i],&len,&localStatus); |
| 243 // If we can't find the symbol in the numbering system speci
fic resources, |
| 244 // use the "latn" numbering system as the fallback. |
| 245 if ( U_FAILURE(localStatus) ) { |
| 246 localStatus = U_ZERO_ERROR; |
| 247 sym = ures_getStringByKeyWithFallback(latnSymbols,gNumbe
rElementKeys[i],&len,&localStatus); |
| 248 } |
| 249 } else { |
| 250 sym = ures_getStringByKeyWithFallback(latnSymbols,gNumbe
rElementKeys[i],&len,&localStatus); |
| 251 } |
| 252 |
| 253 if ( U_SUCCESS(localStatus) ) { |
| 254 setSymbol((ENumberFormatSymbol)i,sym); |
| 255 if ( i == kMonetarySeparatorSymbol ) { |
| 256 kMonetaryDecimalSet = TRUE; |
| 257 } else if ( i == kMonetaryGroupingSeparatorSymbol ) { |
| 258 kMonetaryGroupingSet = TRUE; |
| 259 } |
| 260 } |
| 261 } |
| 262 } |
| 263 |
| 264 ures_close(latnSymbols); |
| 265 if ( !isLatn ) { |
| 266 ures_close(nonLatnSymbols); |
| 267 } |
| 268 |
| 269 // If monetary decimal or grouping were not explicitly set, then set the
m to be the |
| 270 // same as their non-monetary counterparts. |
| 271 |
| 272 if ( !kMonetaryDecimalSet ) { |
| 273 setSymbol(kMonetarySeparatorSymbol,fSymbols[kDecimalSeparatorSymbol]
); |
| 274 } |
| 275 if ( !kMonetaryGroupingSet ) { |
| 276 setSymbol(kMonetaryGroupingSeparatorSymbol,fSymbols[kGroupingSeparat
orSymbol]); |
| 277 } |
| 278 |
| 279 if (ns) { |
| 280 delete ns; |
| 281 } |
| 282 |
| 283 // Obtain currency data from the currency API. This is strictly |
| 284 // for backward compatibility; we don't use DecimalFormatSymbols |
| 285 // for currency data anymore. |
| 286 UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures ou
t |
| 287 UChar curriso[4]; |
| 288 UnicodeString tempStr; |
| 289 ucurr_forLocale(locStr, curriso, 4, &internalStatus); |
| 290 |
| 291 // Reuse numberElements[0] as a temporary buffer |
| 292 uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus); |
| 293 if (U_SUCCESS(internalStatus)) { |
| 294 fSymbols[kIntlCurrencySymbol] = curriso; |
| 295 fSymbols[kCurrencySymbol] = tempStr; |
| 296 } |
| 297 /* else use the default values. */ |
| 298 |
| 299 U_LOCALE_BASED(locBased, *this); |
| 300 locBased.setLocaleIDs(ures_getLocaleByType(numberElementsRes, |
| 301 ULOC_VALID_LOCALE, &status), |
| 302 ures_getLocaleByType(numberElementsRes, |
| 303 ULOC_ACTUAL_LOCALE, &status)); |
| 304 |
| 305 //load the currency data |
| 306 UChar ucc[4]={0}; //Currency Codes are always 3 chars long |
| 307 int32_t uccLen = 4; |
| 308 const char* locName = loc.getName(); |
| 309 UErrorCode localStatus = U_ZERO_ERROR; |
| 310 uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus); |
| 311 |
| 312 if(U_SUCCESS(localStatus) && uccLen > 0) { |
| 313 char cc[4]={0}; |
| 314 u_UCharsToChars(ucc, cc, uccLen); |
| 315 /* An explicit currency was requested */ |
| 316 UResourceBundle *currencyResource = ures_open(U_ICUDATA_CURR, locStr
, &localStatus); |
| 317 UResourceBundle *currency = ures_getByKeyWithFallback(currencyResour
ce, "Currencies", NULL, &localStatus); |
| 318 currency = ures_getByKeyWithFallback(currency, cc, currency, &localS
tatus); |
| 319 if(U_SUCCESS(localStatus) && ures_getSize(currency)>2) { // the leng
th is 3 if more data is present |
| 320 currency = ures_getByIndex(currency, 2, currency, &localStatus); |
| 321 int32_t currPatternLen = 0; |
| 322 currPattern = ures_getStringByIndex(currency, (int32_t)0, &currP
atternLen, &localStatus); |
| 323 UnicodeString decimalSep = ures_getStringByIndex(currency, (int3
2_t)1, NULL, &localStatus); |
| 324 UnicodeString groupingSep = ures_getStringByIndex(currency, (int
32_t)2, NULL, &localStatus); |
| 325 if(U_SUCCESS(localStatus)){ |
| 326 fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep; |
| 327 fSymbols[kMonetarySeparatorSymbol] = decimalSep; |
| 328 //pattern.setTo(TRUE, currPattern, currPatternLen); |
| 329 status = localStatus; |
| 330 } |
| 331 } |
| 332 ures_close(currency); |
| 333 ures_close(currencyResource); |
| 334 /* else An explicit currency was requested and is unknown or locale
data is malformed. */ |
| 335 /* ucurr_* API will get the correct value later on. */ |
| 336 } |
| 337 // else ignore the error if no currency |
| 338 |
| 339 // Currency Spacing. |
| 340 localStatus = U_ZERO_ERROR; |
| 341 UResourceBundle *currencyResource = ures_open(U_ICUDATA_CURR, locStr, &l
ocalStatus); |
| 342 UResourceBundle *currencySpcRes = ures_getByKeyWithFallback(currencyReso
urce, |
| 343 gCurrencySpacingTag, NULL, &localStat
us); |
| 344 |
| 345 if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) { |
| 346 const char* keywords[kCurrencySpacingCount] = { |
| 347 gCurrencyMatchTag, gCurrencySudMatchTag, gCurrencyInsertBtnTag |
| 348 }; |
| 349 localStatus = U_ZERO_ERROR; |
| 350 UResourceBundle *dataRes = ures_getByKeyWithFallback(currencySpcRes, |
| 351 gBeforeCurrencyTag, NULL, &localStatus); |
| 352 if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus
)) { |
| 353 localStatus = U_ZERO_ERROR; |
| 354 for (int32_t i = 0; i < kCurrencySpacingCount; i++) { |
| 355 currencySpcBeforeSym[i] = ures_getStringByKey(dataRes, keyword
s[i], |
| 356 NULL, &localStatus); |
| 357 } |
| 358 ures_close(dataRes); |
| 359 } |
| 360 dataRes = ures_getByKeyWithFallback(currencySpcRes, |
| 361 gAfterCurrencyTag, NULL, &localStatus); |
| 362 if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus
)) { |
| 363 localStatus = U_ZERO_ERROR; |
| 364 for (int32_t i = 0; i < kCurrencySpacingCount; i++) { |
| 365 currencySpcAfterSym[i] = ures_getStringByKey(dataRes, keywords
[i], |
| 366 NULL, &localStat
us); |
| 367 } |
| 368 ures_close(dataRes); |
| 369 } |
| 370 ures_close(currencySpcRes); |
| 371 ures_close(currencyResource); |
| 372 } |
| 373 } |
| 374 ures_close(resource); |
| 375 ures_close(numberElementsRes); |
| 376 |
| 377 } |
| 378 |
| 379 void |
| 380 DecimalFormatSymbols::initialize() { |
| 381 /* |
| 382 * These strings used to be in static arrays, but the HP/UX aCC compiler |
| 383 * cannot initialize a static array with class constructors. |
| 384 * markus 2000may25 |
| 385 */ |
| 386 fSymbols[kDecimalSeparatorSymbol] = (UChar)0x2e; // '.' decimal separator |
| 387 fSymbols[kGroupingSeparatorSymbol].remove(); // group (thousands)
separator |
| 388 fSymbols[kPatternSeparatorSymbol] = (UChar)0x3b; // ';' pattern separator |
| 389 fSymbols[kPercentSymbol] = (UChar)0x25; // '%' percent sign |
| 390 fSymbols[kZeroDigitSymbol] = (UChar)0x30; // '0' native 0 digit |
| 391 fSymbols[kOneDigitSymbol] = (UChar)0x31; // '1' native 1 digit |
| 392 fSymbols[kTwoDigitSymbol] = (UChar)0x32; // '2' native 2 digit |
| 393 fSymbols[kThreeDigitSymbol] = (UChar)0x33; // '3' native 3 digit |
| 394 fSymbols[kFourDigitSymbol] = (UChar)0x34; // '4' native 4 digit |
| 395 fSymbols[kFiveDigitSymbol] = (UChar)0x35; // '5' native 5 digit |
| 396 fSymbols[kSixDigitSymbol] = (UChar)0x36; // '6' native 6 digit |
| 397 fSymbols[kSevenDigitSymbol] = (UChar)0x37; // '7' native 7 digit |
| 398 fSymbols[kEightDigitSymbol] = (UChar)0x38; // '8' native 8 digit |
| 399 fSymbols[kNineDigitSymbol] = (UChar)0x39; // '9' native 9 digit |
| 400 fSymbols[kDigitSymbol] = (UChar)0x23; // '#' pattern digit |
| 401 fSymbols[kPlusSignSymbol] = (UChar)0x002b; // '+' plus sign |
| 402 fSymbols[kMinusSignSymbol] = (UChar)0x2d; // '-' minus sign |
| 403 fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol |
| 404 fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR; |
| 405 fSymbols[kMonetarySeparatorSymbol] = (UChar)0x2e; // '.' monetary decimal
separator |
| 406 fSymbols[kExponentialSymbol] = (UChar)0x45; // 'E' exponential |
| 407 fSymbols[kPerMillSymbol] = (UChar)0x2030; // '%o' per mill |
| 408 fSymbols[kPadEscapeSymbol] = (UChar)0x2a; // '*' pad escape symbol |
| 409 fSymbols[kInfinitySymbol] = (UChar)0x221e; // 'oo' infinite |
| 410 fSymbols[kNaNSymbol] = (UChar)0xfffd; // SUB NaN |
| 411 fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit |
| 412 fSymbols[kMonetaryGroupingSeparatorSymbol].remove(); // |
| 413 } |
| 414 |
| 415 Locale |
| 416 DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) con
st { |
| 417 U_LOCALE_BASED(locBased, *this); |
| 418 return locBased.getLocale(type, status); |
| 419 } |
| 420 |
| 421 const UnicodeString& |
| 422 DecimalFormatSymbols::getPatternForCurrencySpacing(ECurrencySpacing type, |
| 423 UBool beforeCurrency, |
| 424 UErrorCode& status) const { |
| 425 if (U_FAILURE(status)) { |
| 426 return fNoSymbol; // always empty. |
| 427 } |
| 428 if (beforeCurrency) { |
| 429 return currencySpcBeforeSym[(int32_t)type]; |
| 430 } else { |
| 431 return currencySpcAfterSym[(int32_t)type]; |
| 432 } |
| 433 } |
| 434 |
| 435 void |
| 436 DecimalFormatSymbols::setPatternForCurrencySpacing(ECurrencySpacing type, |
| 437 UBool beforeCurrency, |
| 438 const UnicodeString& pattern) { |
| 439 if (beforeCurrency) { |
| 440 currencySpcBeforeSym[(int32_t)type] = pattern; |
| 441 } else { |
| 442 currencySpcAfterSym[(int32_t)type] = pattern; |
| 443 } |
| 444 } |
| 445 U_NAMESPACE_END |
| 446 |
| 447 #endif /* #if !UCONFIG_NO_FORMATTING */ |
| 448 |
| 449 //eof |
OLD | NEW |