intl/icu/source/i18n/dcfmtsym.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2 *******************************************************************************
     3 * Copyright (C) 1997-2013, 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 monetarySeparator
    17 ********************************************************************************
    18 */
    20 #include "unicode/utypes.h"
    22 #if !UCONFIG_NO_FORMATTING
    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 "unicode/unum.h"
    32 #include "unicode/utf16.h"
    33 #include "ucurrimp.h"
    34 #include "cstring.h"
    35 #include "locbased.h"
    36 #include "uresimp.h"
    37 #include "ureslocs.h"
    39 // *****************************************************************************
    40 // class DecimalFormatSymbols
    41 // *****************************************************************************
    43 U_NAMESPACE_BEGIN
    45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols)
    47 static const char gNumberElements[] = "NumberElements";
    48 static const char gCurrencySpacingTag[] = "currencySpacing";
    49 static const char gBeforeCurrencyTag[] = "beforeCurrency";
    50 static const char gAfterCurrencyTag[] = "afterCurrency";
    51 static const char gCurrencyMatchTag[] = "currencyMatch";
    52 static const char gCurrencySudMatchTag[] = "surroundingMatch";
    53 static const char gCurrencyInsertBtnTag[] = "insertBetween";
    56 static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0};
    58 // -------------------------------------
    59 // Initializes this with the decimal format symbols in the default locale.
    61 DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
    62     : UObject(),
    63     locale()
    64 {
    65     initialize(locale, status, TRUE);
    66 }
    68 // -------------------------------------
    69 // Initializes this with the decimal format symbols in the desired locale.
    71 DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
    72     : UObject(),
    73     locale(loc)
    74 {
    75     initialize(locale, status);
    76 }
    78 DecimalFormatSymbols::DecimalFormatSymbols()
    79         : UObject(),
    80           locale(Locale::getRoot()),
    81           currPattern(NULL) {
    82     *validLocale = *actualLocale = 0;
    83     initialize();
    84 }
    86 DecimalFormatSymbols*
    87 DecimalFormatSymbols::createWithLastResortData(UErrorCode& status) {
    88     if (U_FAILURE(status)) { return NULL; }
    89     DecimalFormatSymbols* sym = new DecimalFormatSymbols();
    90     if (sym == NULL) {
    91         status = U_MEMORY_ALLOCATION_ERROR;
    92     }
    93     return sym;
    94 }
    96 // -------------------------------------
    98 DecimalFormatSymbols::~DecimalFormatSymbols()
    99 {
   100 }
   102 // -------------------------------------
   103 // copy constructor
   105 DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source)
   106     : UObject(source)
   107 {
   108     *this = source;
   109 }
   111 // -------------------------------------
   112 // assignment operator
   114 DecimalFormatSymbols&
   115 DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs)
   116 {
   117     if (this != &rhs) {
   118         for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) {
   119             // fastCopyFrom is safe, see docs on fSymbols
   120             fSymbols[(ENumberFormatSymbol)i].fastCopyFrom(rhs.fSymbols[(ENumberFormatSymbol)i]);
   121         }
   122         for(int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; ++i) {
   123             currencySpcBeforeSym[i].fastCopyFrom(rhs.currencySpcBeforeSym[i]);
   124             currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]);
   125         }
   126         locale = rhs.locale;
   127         uprv_strcpy(validLocale, rhs.validLocale);
   128         uprv_strcpy(actualLocale, rhs.actualLocale);
   129     }
   130     return *this;
   131 }
   133 // -------------------------------------
   135 UBool
   136 DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const
   137 {
   138     if (this == &that) {
   139         return TRUE;
   140     }
   141     for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) {
   142         if(fSymbols[(ENumberFormatSymbol)i] != that.fSymbols[(ENumberFormatSymbol)i]) {
   143             return FALSE;
   144         }
   145     }
   146     for(int32_t i = 0; i < (int32_t)UNUM_CURRENCY_SPACING_COUNT; ++i) {
   147         if(currencySpcBeforeSym[i] != that.currencySpcBeforeSym[i]) {
   148             return FALSE;
   149         }
   150         if(currencySpcAfterSym[i] != that.currencySpcAfterSym[i]) {
   151             return FALSE;
   152         }
   153     }
   154     return locale == that.locale &&
   155         uprv_strcmp(validLocale, that.validLocale) == 0 &&
   156         uprv_strcmp(actualLocale, that.actualLocale) == 0;
   157 }
   159 // -------------------------------------
   161 void
   162 DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, UBool useLastResortData)
   163 {
   164     static const char *gNumberElementKeys[kFormatSymbolCount] = {
   165         "decimal",
   166         "group",
   167         "list",
   168         "percentSign",
   169         NULL, /* Native zero digit is deprecated from CLDR - get it from the numbering system */
   170         NULL, /* Pattern digit character is deprecated from CLDR - use # by default always */
   171         "minusSign",
   172         "plusSign",
   173         NULL, /* currency symbol - We don't really try to load this directly from CLDR until we know the currency */
   174         NULL, /* intl currency symbol - We don't really try to load this directly from CLDR until we know the currency */
   175         "currencyDecimal",
   176         "exponential",
   177         "perMille",
   178         NULL, /* Escape padding character - not in CLDR */
   179         "infinity",
   180         "nan",
   181         NULL, /* Significant digit symbol - not in CLDR */
   182         "currencyGroup",
   183         NULL, /* one digit - get it from the numbering system */
   184         NULL, /* two digit - get it from the numbering system */
   185         NULL, /* three digit - get it from the numbering system */
   186         NULL, /* four digit - get it from the numbering system */
   187         NULL, /* five digit - get it from the numbering system */
   188         NULL, /* six digit - get it from the numbering system */
   189         NULL, /* seven digit - get it from the numbering system */
   190         NULL, /* eight digit - get it from the numbering system */
   191         NULL, /* nine digit - get it from the numbering system */
   192     };
   194     static const char *gLatn =  "latn";
   195     static const char *gSymbols = "symbols";
   196     const char *nsName;
   197     const UChar *sym = NULL;
   198     int32_t len = 0;
   200     *validLocale = *actualLocale = 0;
   201     currPattern = NULL;
   202     if (U_FAILURE(status))
   203         return;
   205     const char* locStr = loc.getName();
   206     LocalUResourceBundlePointer resource(ures_open(NULL, locStr, &status));
   207     LocalUResourceBundlePointer numberElementsRes(
   208         ures_getByKeyWithFallback(resource.getAlias(), gNumberElements, NULL, &status));
   210     if (U_FAILURE(status)) {
   211         if ( useLastResortData ) {
   212             status = U_USING_DEFAULT_WARNING;
   213             initialize();
   214         }
   215         return;
   216     }
   218     // First initialize all the symbols to the fallbacks for anything we can't find
   219     initialize();
   221     //
   222     // Next get the numbering system for this locale and set zero digit
   223     // and the digit string based on the numbering system for the locale
   224     //
   226     LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(loc, status));
   227     if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) {
   228         nsName = ns->getName();
   229         UnicodeString digitString(ns->getDescription());
   230         int32_t digitIndex = 0;
   231         UChar32 digit = digitString.char32At(0);
   232         fSymbols[kZeroDigitSymbol].setTo(digit);
   233         for (int32_t i = kOneDigitSymbol; i <= kNineDigitSymbol; ++i) {
   234             digitIndex += U16_LENGTH(digit);
   235             digit = digitString.char32At(digitIndex);
   236             fSymbols[i].setTo(digit);
   237         }
   238     } else {
   239         nsName = gLatn;
   240     }
   242     UBool isLatn = !uprv_strcmp(nsName,gLatn);
   244     UErrorCode nlStatus = U_ZERO_ERROR;
   245     LocalUResourceBundlePointer nonLatnSymbols;
   246     if ( !isLatn ) {
   247         nonLatnSymbols.adoptInstead(
   248             ures_getByKeyWithFallback(numberElementsRes.getAlias(), nsName, NULL, &nlStatus));
   249         ures_getByKeyWithFallback(nonLatnSymbols.getAlias(), gSymbols, nonLatnSymbols.getAlias(), &nlStatus);
   250     }
   252     LocalUResourceBundlePointer latnSymbols(
   253         ures_getByKeyWithFallback(numberElementsRes.getAlias(), gLatn, NULL, &status));
   254     ures_getByKeyWithFallback(latnSymbols.getAlias(), gSymbols, latnSymbols.getAlias(), &status);
   256     UBool kMonetaryDecimalSet = FALSE;
   257     UBool kMonetaryGroupingSet = FALSE;
   258     for(int32_t i = 0; i<kFormatSymbolCount; i++) {
   259         if ( gNumberElementKeys[i] != NULL ) {
   260             UErrorCode localStatus = U_ZERO_ERROR;
   261             if ( !isLatn ) {
   262                 sym = ures_getStringByKeyWithFallback(nonLatnSymbols.getAlias(),
   263                                                       gNumberElementKeys[i], &len, &localStatus);
   264                 // If we can't find the symbol in the numbering system specific resources,
   265                 // use the "latn" numbering system as the fallback.
   266                 if ( U_FAILURE(localStatus) ) {
   267                     localStatus = U_ZERO_ERROR;
   268                     sym = ures_getStringByKeyWithFallback(latnSymbols.getAlias(),
   269                                                           gNumberElementKeys[i], &len, &localStatus);
   270                 }
   271             } else {
   272                     sym = ures_getStringByKeyWithFallback(latnSymbols.getAlias(),
   273                                                           gNumberElementKeys[i], &len, &localStatus);
   274             }
   276             if ( U_SUCCESS(localStatus) ) {
   277                 setSymbol((ENumberFormatSymbol)i, UnicodeString(TRUE, sym, len));
   278                 if ( i == kMonetarySeparatorSymbol ) {
   279                     kMonetaryDecimalSet = TRUE;
   280                 } else if ( i == kMonetaryGroupingSeparatorSymbol ) {
   281                     kMonetaryGroupingSet = TRUE;
   282                 }
   283             }
   284         }
   285     }
   287     // If monetary decimal or grouping were not explicitly set, then set them to be the
   288     // same as their non-monetary counterparts.
   290     if ( !kMonetaryDecimalSet ) {
   291         setSymbol(kMonetarySeparatorSymbol,fSymbols[kDecimalSeparatorSymbol]);
   292     }
   293     if ( !kMonetaryGroupingSet ) {
   294         setSymbol(kMonetaryGroupingSeparatorSymbol,fSymbols[kGroupingSeparatorSymbol]);
   295     }
   297     // Obtain currency data from the currency API.  This is strictly
   298     // for backward compatibility; we don't use DecimalFormatSymbols
   299     // for currency data anymore.
   300     UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
   301     UChar curriso[4];
   302     UnicodeString tempStr;
   303     ucurr_forLocale(locStr, curriso, 4, &internalStatus);
   305     uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus);
   306     if (U_SUCCESS(internalStatus)) {
   307         fSymbols[kIntlCurrencySymbol].setTo(curriso, -1);
   308         fSymbols[kCurrencySymbol] = tempStr;
   309     }
   310     /* else use the default values. */
   312     U_LOCALE_BASED(locBased, *this);
   313     locBased.setLocaleIDs(ures_getLocaleByType(numberElementsRes.getAlias(),
   314                                                ULOC_VALID_LOCALE, &status),
   315                           ures_getLocaleByType(numberElementsRes.getAlias(),
   316                                                ULOC_ACTUAL_LOCALE, &status));
   318     //load the currency data
   319     UChar ucc[4]={0}; //Currency Codes are always 3 chars long
   320     int32_t uccLen = 4;
   321     const char* locName = loc.getName();
   322     UErrorCode localStatus = U_ZERO_ERROR;
   323     uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus);
   325     if(U_SUCCESS(localStatus) && uccLen > 0) {
   326         char cc[4]={0};
   327         u_UCharsToChars(ucc, cc, uccLen);
   328         /* An explicit currency was requested */
   329         LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &localStatus));
   330         LocalUResourceBundlePointer currency(
   331             ures_getByKeyWithFallback(currencyResource.getAlias(), "Currencies", NULL, &localStatus));
   332         ures_getByKeyWithFallback(currency.getAlias(), cc, currency.getAlias(), &localStatus);
   333         if(U_SUCCESS(localStatus) && ures_getSize(currency.getAlias())>2) { // the length is 3 if more data is present
   334             ures_getByIndex(currency.getAlias(), 2, currency.getAlias(), &localStatus);
   335             int32_t currPatternLen = 0;
   336             currPattern =
   337                 ures_getStringByIndex(currency.getAlias(), (int32_t)0, &currPatternLen, &localStatus);
   338             UnicodeString decimalSep =
   339                 ures_getUnicodeStringByIndex(currency.getAlias(), (int32_t)1, &localStatus);
   340             UnicodeString groupingSep =
   341                 ures_getUnicodeStringByIndex(currency.getAlias(), (int32_t)2, &localStatus);
   342             if(U_SUCCESS(localStatus)){
   343                 fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep;
   344                 fSymbols[kMonetarySeparatorSymbol] = decimalSep;
   345                 //pattern.setTo(TRUE, currPattern, currPatternLen);
   346                 status = localStatus;
   347             }
   348         }
   349         /* else An explicit currency was requested and is unknown or locale data is malformed. */
   350         /* ucurr_* API will get the correct value later on. */
   351     }
   352         // else ignore the error if no currency
   354     // Currency Spacing.
   355     localStatus = U_ZERO_ERROR;
   356     LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &localStatus));
   357     LocalUResourceBundlePointer currencySpcRes(
   358         ures_getByKeyWithFallback(currencyResource.getAlias(),
   359                                   gCurrencySpacingTag, NULL, &localStatus));
   361     if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
   362         const char* keywords[UNUM_CURRENCY_SPACING_COUNT] = {
   363             gCurrencyMatchTag, gCurrencySudMatchTag, gCurrencyInsertBtnTag
   364         };
   365         localStatus = U_ZERO_ERROR;
   366         LocalUResourceBundlePointer dataRes(
   367             ures_getByKeyWithFallback(currencySpcRes.getAlias(),
   368                                       gBeforeCurrencyTag, NULL, &localStatus));
   369         if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
   370             localStatus = U_ZERO_ERROR;
   371             for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) {
   372                 currencySpcBeforeSym[i] =
   373                     ures_getUnicodeStringByKey(dataRes.getAlias(), keywords[i], &localStatus);
   374             }
   375         }
   376         dataRes.adoptInstead(
   377             ures_getByKeyWithFallback(currencySpcRes.getAlias(),
   378                                       gAfterCurrencyTag, NULL, &localStatus));
   379         if (localStatus == U_USING_FALLBACK_WARNING || U_SUCCESS(localStatus)) {
   380             localStatus = U_ZERO_ERROR;
   381             for (int32_t i = 0; i < UNUM_CURRENCY_SPACING_COUNT; i++) {
   382                 currencySpcAfterSym[i] =
   383                     ures_getUnicodeStringByKey(dataRes.getAlias(), keywords[i], &localStatus);
   384             }
   385         }
   386     }
   387 }
   389 void
   390 DecimalFormatSymbols::initialize() {
   391     /*
   392      * These strings used to be in static arrays, but the HP/UX aCC compiler
   393      * cannot initialize a static array with class constructors.
   394      *  markus 2000may25
   395      */
   396     fSymbols[kDecimalSeparatorSymbol] = (UChar)0x2e;    // '.' decimal separator
   397     fSymbols[kGroupingSeparatorSymbol].remove();        //     group (thousands) separator
   398     fSymbols[kPatternSeparatorSymbol] = (UChar)0x3b;    // ';' pattern separator
   399     fSymbols[kPercentSymbol] = (UChar)0x25;             // '%' percent sign
   400     fSymbols[kZeroDigitSymbol] = (UChar)0x30;           // '0' native 0 digit
   401     fSymbols[kOneDigitSymbol] = (UChar)0x31;            // '1' native 1 digit
   402     fSymbols[kTwoDigitSymbol] = (UChar)0x32;            // '2' native 2 digit
   403     fSymbols[kThreeDigitSymbol] = (UChar)0x33;          // '3' native 3 digit
   404     fSymbols[kFourDigitSymbol] = (UChar)0x34;           // '4' native 4 digit
   405     fSymbols[kFiveDigitSymbol] = (UChar)0x35;           // '5' native 5 digit
   406     fSymbols[kSixDigitSymbol] = (UChar)0x36;            // '6' native 6 digit
   407     fSymbols[kSevenDigitSymbol] = (UChar)0x37;          // '7' native 7 digit
   408     fSymbols[kEightDigitSymbol] = (UChar)0x38;          // '8' native 8 digit
   409     fSymbols[kNineDigitSymbol] = (UChar)0x39;           // '9' native 9 digit
   410     fSymbols[kDigitSymbol] = (UChar)0x23;               // '#' pattern digit
   411     fSymbols[kPlusSignSymbol] = (UChar)0x002b;          // '+' plus sign
   412     fSymbols[kMinusSignSymbol] = (UChar)0x2d;           // '-' minus sign
   413     fSymbols[kCurrencySymbol] = (UChar)0xa4;            // 'OX' currency symbol
   414     fSymbols[kIntlCurrencySymbol].setTo(TRUE, INTL_CURRENCY_SYMBOL_STR, 2);
   415     fSymbols[kMonetarySeparatorSymbol] = (UChar)0x2e;   // '.' monetary decimal separator
   416     fSymbols[kExponentialSymbol] = (UChar)0x45;         // 'E' exponential
   417     fSymbols[kPerMillSymbol] = (UChar)0x2030;           // '%o' per mill
   418     fSymbols[kPadEscapeSymbol] = (UChar)0x2a;           // '*' pad escape symbol
   419     fSymbols[kInfinitySymbol] = (UChar)0x221e;          // 'oo' infinite
   420     fSymbols[kNaNSymbol] = (UChar)0xfffd;               // SUB NaN
   421     fSymbols[kSignificantDigitSymbol] = (UChar)0x0040;  // '@' significant digit
   422     fSymbols[kMonetaryGroupingSeparatorSymbol].remove(); // 
   423 }
   425 Locale
   426 DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
   427     U_LOCALE_BASED(locBased, *this);
   428     return locBased.getLocale(type, status);
   429 }
   431 const UnicodeString&
   432 DecimalFormatSymbols::getPatternForCurrencySpacing(UCurrencySpacing type,
   433                                                  UBool beforeCurrency,
   434                                                  UErrorCode& status) const {
   435     if (U_FAILURE(status)) {
   436       return fNoSymbol;  // always empty.
   437     }
   438     if (beforeCurrency) {
   439       return currencySpcBeforeSym[(int32_t)type];
   440     } else {
   441       return currencySpcAfterSym[(int32_t)type];
   442     }
   443 }
   445 void
   446 DecimalFormatSymbols::setPatternForCurrencySpacing(UCurrencySpacing type,
   447                                                    UBool beforeCurrency,
   448                                              const UnicodeString& pattern) {
   449   if (beforeCurrency) {
   450     currencySpcBeforeSym[(int32_t)type] = pattern;
   451   } else {
   452     currencySpcAfterSym[(int32_t)type] =  pattern;
   453   }
   454 }
   455 U_NAMESPACE_END
   457 #endif /* #if !UCONFIG_NO_FORMATTING */
   459 //eof

mercurial