diff --git a/icu4c/source/common/messagepattern.cpp b/icu4c/source/common/messagepattern.cpp index 6e94fcba2b8..0f09f277279 100644 --- a/icu4c/source/common/messagepattern.cpp +++ b/icu4c/source/common/messagepattern.cpp @@ -81,7 +81,7 @@ static const UChar kOther[]={ // "other" // MessagePatternList ------------------------------------------------------ *** template -class MessagePatternList { +class MessagePatternList : public UMemory { public: MessagePatternList() {} void copyFrom(const MessagePatternList &other, diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index f92196abd74..a5bec86a1fe 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -303,7 +303,7 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, - NumberFormat::EStyles style, + UNumberFormatStyle style, UErrorCode& status) { init(); fStyle = style; @@ -338,7 +338,7 @@ DecimalFormat::init() { fPad = 0; fFormatWidth = 0; fPadPosition = kPadBeforePrefix; - fStyle = NumberFormat::kNumberStyle; + fStyle = UNUM_DECIMAL; fCurrencySignCount = 0; fAffixPatternsForCurrency = NULL; fAffixesForCurrency = NULL; @@ -418,7 +418,7 @@ DecimalFormat::construct(UErrorCode& status, const UnicodeString* patternUsed; UnicodeString currencyPluralPatternForOther; // apply pattern - if (fStyle == NumberFormat::kPluralCurrencyStyle) { + if (fStyle == UNUM_CURRENCY_PLURAL) { fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status); if (U_FAILURE(status)) { return; @@ -1686,7 +1686,7 @@ DecimalFormat::parseForCurrency(const UnicodeString& text, ParsePosition tmpPos(origPos); DigitList tmpDigitList; UBool found; - if (fStyle == NumberFormat::kPluralCurrencyStyle) { + if (fStyle == UNUM_CURRENCY_PLURAL) { found = subparse(text, fNegPrefixPattern, fNegSuffixPattern, fPosPrefixPattern, fPosSuffixPattern, @@ -3208,7 +3208,7 @@ int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number, if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) { UnicodeString pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number); AffixesForCurrency* oneSet; - if (fStyle == NumberFormat::kPluralCurrencyStyle) { + if (fStyle == UNUM_CURRENCY_PLURAL) { oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount); } else { oneSet = (AffixesForCurrency*)fAffixesForCurrency->get(pluralCount); @@ -3393,7 +3393,7 @@ DecimalFormat::appendAffixPattern(UnicodeString& appendTo, UnicodeString& DecimalFormat::toPattern(UnicodeString& result, UBool localized) const { - if (fStyle == NumberFormat::kPluralCurrencyStyle) { + if (fStyle == UNUM_CURRENCY_PLURAL) { // the prefix or suffix pattern might not be defined yet, // so they can not be synthesized, // instead, get them directly. diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index dcd24a7406b..416b60f6a32 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2010, International Business Machines Corporation and * +* Copyright (C) 1997-2011, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -35,6 +35,7 @@ #include "unicode/curramt.h" #include "unicode/numsys.h" #include "unicode/rbnf.h" +#include "charstr.h" #include "winnmfmt.h" #include "uresimp.h" #include "uhash.h" @@ -44,6 +45,7 @@ #include "cstring.h" #include "putilimp.h" #include "umutex.h" +#include "mutex.h" #include "digitlst.h" #include @@ -94,14 +96,19 @@ static const UChar gSlash = 0x2f; static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1; static const int32_t gMinIntegerDigits = 127; -static const UChar * const gLastResortNumberPatterns[] = -{ - gLastResortDecimalPat, - gLastResortCurrencyPat, - gLastResortPercentPat, - gLastResortScientificPat, - gLastResortIsoCurrencyPat, - gLastResortPluralCurrencyPat, +static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] = { + NULL, // UNUM_PATTERN_DECIMAL + gLastResortDecimalPat, // UNUM_DECIMAL + gLastResortCurrencyPat, // UNUM_CURRENCY + gLastResortPercentPat, // UNUM_PERCENT + gLastResortScientificPat, // UNUM_SCIENTIFIC + NULL, // UNUM_SPELLOUT + NULL, // UNUM_ORDINAL + NULL, // UNUM_DURATION + NULL, // UNUM_NUMBERING_SYSTEM + NULL, // UNUM_PATTERN_RULEBASED + gLastResortIsoCurrencyPat, // UNUM_CURRENCY_ISO + gLastResortPluralCurrencyPat // UNUM_CURRENCY_PLURAL }; // Keys used for accessing resource bundles @@ -109,7 +116,24 @@ static const UChar * const gLastResortNumberPatterns[] = static const char *gNumberElements = "NumberElements"; static const char *gLatn = "latn"; static const char *gPatterns = "patterns"; -static const char *gFormatKeys[] = { "decimalFormat", "currencyFormat", "percentFormat", "scientificFormat" }; +static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = { + NULL, // UNUM_PATTERN_DECIMAL + "decimalFormat", // UNUM_DECIMAL + "currencyFormat", // UNUM_CURRENCY + "percentFormat", // UNUM_PERCENT + "scientificFormat", // UNUM_SCIENTIFIC + NULL, // UNUM_SPELLOUT + NULL, // UNUM_ORDINAL + NULL, // UNUM_DURATION + NULL, // UNUM_NUMBERING_SYSTEM + NULL, // UNUM_PATTERN_RULEBASED + // For UNUM_CURRENCY_ISO and UNUM_CURRENCY_PLURAL, + // the pattern is the same as the pattern of UNUM_CURRENCY + // except for replacing the single currency sign with + // double currency sign or triple currency sign. + "currencyFormat", // UNUM_CURRENCY_ISO + "currencyFormat" // UNUM_CURRENCY_PLURAL +}; // Static hashtable cache of NumberingSystem objects used by NumberFormat static UHashtable * NumberingSystem_cache = NULL; @@ -630,7 +654,7 @@ NumberFormat::setParseIntegerOnly(UBool value) NumberFormat* U_EXPORT2 NumberFormat::createInstance(UErrorCode& status) { - return createInstance(Locale::getDefault(), kNumberStyle, status); + return createInstance(Locale::getDefault(), UNUM_DECIMAL, status); } // ------------------------------------- @@ -639,7 +663,7 @@ NumberFormat::createInstance(UErrorCode& status) NumberFormat* U_EXPORT2 NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status) { - return createInstance(inLocale, kNumberStyle, status); + return createInstance(inLocale, UNUM_DECIMAL, status); } // ------------------------------------- @@ -657,7 +681,7 @@ NumberFormat::createCurrencyInstance(UErrorCode& status) NumberFormat* U_EXPORT2 NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status) { - return createInstance(inLocale, kCurrencyStyle, status); + return createInstance(inLocale, UNUM_CURRENCY, status); } // ------------------------------------- @@ -666,7 +690,7 @@ NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status) NumberFormat* U_EXPORT2 NumberFormat::createPercentInstance(UErrorCode& status) { - return createInstance(Locale::getDefault(), kPercentStyle, status); + return createInstance(Locale::getDefault(), UNUM_PERCENT, status); } // ------------------------------------- @@ -675,7 +699,7 @@ NumberFormat::createPercentInstance(UErrorCode& status) NumberFormat* U_EXPORT2 NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status) { - return createInstance(inLocale, kPercentStyle, status); + return createInstance(inLocale, UNUM_PERCENT, status); } // ------------------------------------- @@ -684,7 +708,7 @@ NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status) NumberFormat* U_EXPORT2 NumberFormat::createScientificInstance(UErrorCode& status) { - return createInstance(Locale::getDefault(), kScientificStyle, status); + return createInstance(Locale::getDefault(), UNUM_SCIENTIFIC, status); } // ------------------------------------- @@ -693,7 +717,7 @@ NumberFormat::createScientificInstance(UErrorCode& status) NumberFormat* U_EXPORT2 NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status) { - return createInstance(inLocale, kScientificStyle, status); + return createInstance(inLocale, UNUM_SCIENTIFIC, status); } // ------------------------------------- @@ -717,8 +741,7 @@ NumberFormat::getAvailableLocales(int32_t& count) class ICUNumberFormatFactory : public ICUResourceBundleFactory { protected: virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const { - // !!! kind is not an EStyles, need to determine how to handle this - return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status); + return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status); } }; @@ -751,7 +774,7 @@ public: lkey.canonicalLocale(loc); int32_t kind = lkey.kind(); - UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1)); + UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)kind); if (result == NULL) { result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status); } @@ -803,7 +826,7 @@ public: int32_t kind = lkey.kind(); Locale loc; lkey.currentLocale(loc); - return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status); + return NumberFormat::makeInstance(loc, (UNumberFormatStyle)kind, status); } virtual UBool isDefault() const { @@ -884,7 +907,7 @@ NumberFormat::getAvailableLocales(void) // ------------------------------------- NumberFormat* U_EXPORT2 -NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status) +NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) { #if !UCONFIG_NO_SERVICE UBool haveService; @@ -1043,35 +1066,51 @@ void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { // Creates the NumberFormat instance of the specified style (number, currency, // or percent) for the desired locale. +UBool +NumberFormat::isStyleSupported(UNumberFormatStyle style) { + return gLastResortNumberPatterns[style] != NULL; +} + NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, - EStyles style, + UNumberFormatStyle style, UErrorCode& status) { if (U_FAILURE(status)) return NULL; - if (style < 0 || style >= kStyleCount) { + if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } + // Some styles are not supported. This is a result of merging + // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle. + // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations: + // this one and unum_open(). + // The UNUM_PATTERN_ styles are not supported here + // because this method does not take a pattern string. + if (!isStyleSupported(style)) { + status = U_UNSUPPORTED_ERROR; + return NULL; + } + #ifdef U_WINDOWS char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat - if (count > 0 && uprv_strcmp(buffer, "host") == 0) { + if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { - case kNumberStyle: + case UNUM_DECIMAL: curr = FALSE; // fall-through - case kCurrencyStyle: - case kIsoCurrencyStyle: // do not support plural formatting here - case kPluralCurrencyStyle: + case UNUM_CURRENCY: + case UNUM_CURRENCY_ISO: // do not support plural formatting here + case UNUM_CURRENCY_PLURAL: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { @@ -1087,55 +1126,47 @@ NumberFormat::makeInstance(const Locale& desiredLocale, } #endif - NumberFormat* f = NULL; - DecimalFormatSymbols* symbolsToAdopt = NULL; + LocalPointer symbolsToAdopt; UnicodeString pattern; - UResourceBundle *resource = ures_open(NULL, desiredLocale.getName(), &status); - NumberingSystem *ns = NULL; - UBool deleteSymbols = TRUE; - UHashtable * cache = NULL; - int32_t hashKey; - UBool getCache = FALSE; - UBool deleteNS = FALSE; - + LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status)); if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. - symbolsToAdopt = new DecimalFormatSymbols(status); + symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status)); + if (symbolsToAdopt.isNull()) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // Loads the decimal symbols of the desired locale. - symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status); - - int32_t patLen = 0; - - /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE, - * the pattern is the same as the pattern of CURRENCYSTYLE - * but by replacing the single currency sign with - * double currency sign or triple currency sign. - */ - int styleInNumberPattern = ((style == kIsoCurrencyStyle || - style == kPluralCurrencyStyle) ? - kCurrencyStyle : style); + symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status)); + if (symbolsToAdopt.isNull()) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + UResourceBundle *resource = ownedResource.orphan(); resource = ures_getByKeyWithFallback(resource, gNumberElements, resource, &status); // TODO : Get patterns on a per numbering system basis, for right now assumes "latn" for patterns resource = ures_getByKeyWithFallback(resource, gLatn, resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); + ownedResource.adoptInstead(resource); - const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[styleInNumberPattern], &patLen, &status); + int32_t patLen = 0; + const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } - if (U_FAILURE(status) || symbolsToAdopt == NULL) { - goto cleanup; + if (U_FAILURE(status)) { + return NULL; } - if(style==kCurrencyStyle || style == kIsoCurrencyStyle){ + if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); @@ -1143,75 +1174,60 @@ NumberFormat::makeInstance(const Locale& desiredLocale, } // Use numbering system cache hashtable - UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache); - if (getCache) { - umtx_lock(&nscacheMutex); - cache = NumberingSystem_cache; - umtx_unlock(&nscacheMutex); - } + UHashtable *cache; + UMTX_CHECK(&nscacheMutex, NumberingSystem_cache, cache); // Check cache we got, create if non-existant - status = U_ZERO_ERROR; if (cache == NULL) { cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); - if (cache == NULL || U_FAILURE(status)) { + if (U_FAILURE(status)) { // cache not created - out of memory + status = U_ZERO_ERROR; // work without the cache cache = NULL; - } - else { + } else { // cache created uhash_setValueDeleter(cache, deleteNumberingSystem); // set final NumberingSystem_cache value - UHashtable* h = NULL; - - UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache); - if (getCache) { - umtx_lock(&nscacheMutex); - h = NumberingSystem_cache; - umtx_unlock(&nscacheMutex); - } - if (h == NULL) { - umtx_lock(&nscacheMutex); - NumberingSystem_cache = h = cache; - cache = NULL; + Mutex lock(&nscacheMutex); + if (NumberingSystem_cache == NULL) { + NumberingSystem_cache = cache; ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); - umtx_unlock(&nscacheMutex); + } else { + uhash_close(cache); + cache = NumberingSystem_cache; } - - if(cache != NULL) { - uhash_close(cache); - } - cache = h; } } // Get cached numbering system + LocalPointer ownedNs; + NumberingSystem *ns = NULL; if (cache != NULL) { - hashKey = desiredLocale.hashCode(); + // TODO: Bad hash key usage, see ticket #8504. + int32_t hashKey = desiredLocale.hashCode(); - umtx_lock(&nscacheMutex); + Mutex lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(cache, hashKey, (void*)ns, &status); } - umtx_unlock(&nscacheMutex); - } - else { - ns = NumberingSystem::createInstance(desiredLocale,status); - deleteNS = TRUE; + } else { + ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); + ns = ownedNs.getAlias(); } // check results of getting a numbering system - if ((ns == NULL) || (U_FAILURE(status))) { - goto cleanup; + if (U_FAILURE(status)) { + return NULL; } + NumberFormat *f; if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; @@ -1223,13 +1239,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale, int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { - char nsLocID[ULOC_FULLNAME_CAPACITY]; + CharString nsLocID; - nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV); + nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); - nsLoc = Locale::createFromName(nsLocID); + nsLoc = Locale::createFromName(nsLocID.data()); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { @@ -1241,54 +1257,35 @@ NumberFormat::makeInstance(const Locale& desiredLocale, } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); - - if (U_FAILURE(status) || r == NULL) { - goto cleanup; + if (r == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; } r->setDefaultRuleSet(nsRuleSetName,status); - f = (NumberFormat *) r; - + f = r; } else { // replace single currency sign in the pattern with double currency sign - // if the style is kIsoCurrencyStyle - if (style == kIsoCurrencyStyle) { + // if the style is UNUM_CURRENCY_ISO + if (style == UNUM_CURRENCY_ISO) { pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign); } - f = new DecimalFormat(pattern, symbolsToAdopt, style, status); - if (U_FAILURE(status) || f == NULL) { - goto cleanup; + // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. + DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); + f = new DecimalFormat(pattern, syms, style, status); + if (f == NULL) { + delete syms; + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; } - deleteSymbols = FALSE; - } - - f->setLocaleIDs(ures_getLocaleByType(resource, ULOC_VALID_LOCALE, &status), - ures_getLocaleByType(resource, ULOC_ACTUAL_LOCALE, &status)); - -cleanup: - ures_close(resource); - - if (deleteNS && ns) { - delete ns; } + f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), + ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); if (U_FAILURE(status)) { - /* If f exists, then it will delete the symbols */ - if (f==NULL) { - delete symbolsToAdopt; - } - else { - delete f; - } + delete f; return NULL; } - if (f == NULL || symbolsToAdopt == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - f = NULL; - } - if (deleteSymbols && symbolsToAdopt != NULL) { - delete symbolsToAdopt; - } return f; } diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index 229d8f806c5..94525aab470 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -732,14 +732,14 @@ public: * @param pattern a non-localized pattern string * @param symbolsToAdopt the set of symbols to be used. The caller should not * delete this object after making this call. - * @param style style of decimal format, kNumberStyle etc. + * @param style style of decimal format * @param status Output param set to success/failure code. If the * pattern is invalid this will be set to a failure code. * @internal ICU 4.2 */ DecimalFormat( const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, - NumberFormat::EStyles style, + UNumberFormatStyle style, UErrorCode& status); /** diff --git a/icu4c/source/i18n/unicode/numfmt.h b/icu4c/source/i18n/unicode/numfmt.h index 63914ca4f1a..1d39c183e71 100644 --- a/icu4c/source/i18n/unicode/numfmt.h +++ b/icu4c/source/i18n/unicode/numfmt.h @@ -1,6 +1,6 @@ /* ******************************************************************************** -* Copyright (C) 1997-2010, International Business Machines Corporation and others. +* Copyright (C) 1997-2011, International Business Machines Corporation and others. * All Rights Reserved. ******************************************************************************** * @@ -37,6 +37,8 @@ #include "unicode/locid.h" #include "unicode/stringpiece.h" +class NumberFormatTest; + U_NAMESPACE_BEGIN #if !UCONFIG_NO_SERVICE @@ -162,30 +164,6 @@ class StringEnumeration; */ class U_I18N_API NumberFormat : public Format { public: - - /** - * Constants for various number format styles. - * kNumberStyle specifies a normal number style of format. - * kCurrencyStyle specifies a currency format using currency symbol name, - * such as in "$1.00". - * kPercentStyle specifies a style of format to display percent. - * kScientificStyle specifies a style of format to display scientific number. - * kISOCurrencyStyle specifies a currency format using ISO currency code, - * such as in "USD1.00". - * kPluralCurrencyStyle specifies a currency format using currency plural - * names, such as in "1.00 US dollar" and "3.00 US dollars". - * @draft ICU 4.2 - */ - enum EStyles { - kNumberStyle, - kCurrencyStyle, - kPercentStyle, - kScientificStyle, - kIsoCurrencyStyle, - kPluralCurrencyStyle, - kStyleCount // ALWAYS LAST ENUM: number of styles - }; - /** * Alignment Field constants used to construct a FieldPosition object. * Signifies that the position of the integer part or fraction part of @@ -645,12 +623,14 @@ public: /** * Creates the specified decimal format style of the desired locale. * @param desiredLocale the given locale. - * @param choice the given style. - * @param success Output param filled with success/failure status. + * @param style the given style. + * @param errorCode Output param filled with success/failure status. * @return A new NumberFormat instance. - * @draft ICU 4.2 + * @draft ICU 4.8 */ - static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success); + static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, + UNumberFormatStyle style, + UErrorCode& errorCode); /** @@ -921,14 +901,18 @@ protected: private: + static UBool isStyleSupported(UNumberFormatStyle style); + /** * Creates the specified decimal format style of the desired locale. * @param desiredLocale the given locale. - * @param choice the given style. - * @param success Output param filled with success/failure status. + * @param style the given style. + * @param errorCode Output param filled with success/failure status. * @return A new NumberFormat instance. */ - static NumberFormat* makeInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success); + static NumberFormat* makeInstance(const Locale& desiredLocale, + UNumberFormatStyle style, + UErrorCode& errorCode); UBool fGroupingUsed; int32_t fMaxIntegerDigits; @@ -940,8 +924,9 @@ private: // ISO currency code UChar fCurrency[4]; - friend class ICUNumberFormatFactory; // access to makeInstance, EStyles + friend class ICUNumberFormatFactory; // access to makeInstance friend class ICUNumberFormatService; + friend class ::NumberFormatTest; // access to isStyleSupported() }; #if !UCONFIG_NO_SERVICE diff --git a/icu4c/source/i18n/unicode/unum.h b/icu4c/source/i18n/unicode/unum.h index c4f431246d8..7d1f0f27e91 100644 --- a/icu4c/source/i18n/unicode/unum.h +++ b/icu4c/source/i18n/unicode/unum.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2010, International Business Machines Corporation and others. +* Copyright (C) 1997-2011, International Business Machines Corporation and others. * All Rights Reserved. * Modification History: * @@ -134,19 +134,34 @@ typedef void* UNumberFormat; */ typedef enum UNumberFormatStyle { /** - * Decimal format defined by pattern + * Decimal format defined by a pattern string. * @stable ICU 3.0 */ UNUM_PATTERN_DECIMAL=0, - /** Decimal format */ + /** + * Decimal format ("normal" style). + * @stable ICU 2.0 + */ UNUM_DECIMAL=1, - /** Currency format */ + /** + * Currency format with a currency symbol, e.g., "$1.00". + * @stable ICU 2.0 + */ UNUM_CURRENCY, - /** Percent format */ + /** + * Percent format + * @stable ICU 2.0 + */ UNUM_PERCENT, - /** Scientific format */ + /** + * Scientific format + * @stable ICU 2.1 + */ UNUM_SCIENTIFIC, - /** Spellout rule-based format */ + /** + * Spellout rule-based format + * @stable ICU 2.0 + */ UNUM_SPELLOUT, /** * Ordinal rule-based format @@ -159,18 +174,40 @@ typedef enum UNumberFormatStyle { */ UNUM_DURATION, /** - * Numbering system rule-based format + * Numbering system rule-based format * @stable ICU 4.2 */ UNUM_NUMBERING_SYSTEM, /** - * Rule-based format defined by pattern + * Rule-based format defined by a pattern string. * @stable ICU 3.0 */ UNUM_PATTERN_RULEBASED, - /** Default format */ + /** + * Currency format with an ISO currency code, e.g., "USD1.00". + * @draft ICU 4.8 + */ + UNUM_CURRENCY_ISO, + /** + * Currency format with a pluralized currency name, + * e.g., "1.00 US dollar" and "3.00 US dollars". + * @draft ICU 4.8 + */ + UNUM_CURRENCY_PLURAL, + /** + * One more than the highest number format style constant. + * @draft ICU 4.8 + */ + UNUM_FORMAT_STYLE_COUNT, + /** + * Default format + * @stable ICU 2.0 + */ UNUM_DEFAULT = UNUM_DECIMAL, - /** (Alias for UNUM_PATTERN_DECIMAL) */ + /** + * Alias for UNUM_PATTERN_DECIMAL + * @stable ICU 3.0 + */ UNUM_IGNORE = UNUM_PATTERN_DECIMAL } UNumberFormatStyle; diff --git a/icu4c/source/i18n/unum.cpp b/icu4c/source/i18n/unum.cpp index c7a5cf197c0..f584ea379d0 100644 --- a/icu4c/source/i18n/unum.cpp +++ b/icu4c/source/i18n/unum.cpp @@ -38,78 +38,45 @@ unum_open( UNumberFormatStyle style, int32_t patternLength, const char* locale, UParseError* parseErr, - UErrorCode* status) -{ - - if(U_FAILURE(*status)) - { - return 0; + UErrorCode* status) { + if(U_FAILURE(*status)) { + return NULL; } - UNumberFormat *retVal = 0; + NumberFormat *retVal = NULL; switch(style) { case UNUM_DECIMAL: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale), - *status); - break; - case UNUM_CURRENCY: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale), - *status); - break; - case UNUM_PERCENT: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale), - *status); - break; - case UNUM_SCIENTIFIC: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createScientificInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createScientificInstance(Locale(locale), - *status); + retVal = NumberFormat::createInstance(Locale(locale), style, *status); break; case UNUM_PATTERN_DECIMAL: { UParseError tErr; /* UnicodeString can handle the case when patternLength = -1. */ const UnicodeString pat(pattern, patternLength); - DecimalFormatSymbols *syms = 0; if(parseErr==NULL){ parseErr = &tErr; } - if(locale == 0) - syms = new DecimalFormatSymbols(*status); - else - syms = new DecimalFormatSymbols(Locale(locale), *status); - - if(syms == 0) { + DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status); + if(syms == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; - return 0; + return NULL; } if (U_FAILURE(*status)) { delete syms; - return 0; + return NULL; } - retVal = (UNumberFormat*)new DecimalFormat(pat, syms, *parseErr, *status); - if(retVal == 0) { + retVal = new DecimalFormat(pat, syms, *parseErr, *status); + if(retVal == NULL) { delete syms; } - } break; + } break; #if U_HAVE_RBNF case UNUM_PATTERN_RULEBASED: { @@ -121,36 +88,36 @@ unum_open( UNumberFormatStyle style, parseErr = &tErr; } - retVal = (UNumberFormat*)new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status); + retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status); } break; case UNUM_SPELLOUT: - retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status); + retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status); break; case UNUM_ORDINAL: - retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status); + retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status); break; case UNUM_DURATION: - retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status); + retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status); break; case UNUM_NUMBERING_SYSTEM: - retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status); + retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status); break; #endif default: *status = U_UNSUPPORTED_ERROR; - return 0; + return NULL; } - if(retVal == 0 && U_SUCCESS(*status)) { + if(retVal == NULL && U_SUCCESS(*status)) { *status = U_MEMORY_ALLOCATION_ERROR; } - return retVal; + return reinterpret_cast(retVal); } U_CAPI void U_EXPORT2 diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index d60ab00bc5c..d8536445b8d 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -15,6 +15,7 @@ #include "numfmtst.h" #include "unicode/dcfmtsym.h" #include "unicode/decimfmt.h" +#include "unicode/localpointer.h" #include "unicode/ucurr.h" #include "unicode/ustring.h" #include "unicode/measfmt.h" @@ -37,6 +38,7 @@ //#define NUMFMTST_DEBUG 1 +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof(array[0])) static const UChar EUR[] = {69,85,82,0}; // "EUR" static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD" @@ -2371,13 +2373,21 @@ void NumberFormatTest::TestHost() #ifdef U_WINDOWS Win32NumberTest::testLocales(this); #endif - for (NumberFormat::EStyles k = NumberFormat::kNumberStyle; - k < NumberFormat::kStyleCount; k = (NumberFormat::EStyles)(k+1)) { + Locale loc("en_US@compat=host"); + for (UNumberFormatStyle k = UNUM_DECIMAL; + k < UNUM_FORMAT_STYLE_COUNT; k = (UNumberFormatStyle)(k+1)) { UErrorCode status = U_ZERO_ERROR; - Locale loc("en_US@compat=host"); - NumberFormat *full = NumberFormat::createInstance(loc, status); - if (full == NULL || U_FAILURE(status)) { - dataerrln("FAIL: Can't create number instance for host - %s", u_errorName(status)); + LocalPointer full(NumberFormat::createInstance(loc, k, status)); + if (!NumberFormat::isStyleSupported(k)) { + if (status != U_UNSUPPORTED_ERROR) { + errln("FAIL: expected style %d to be unsupported - %s", + k, u_errorName(status)); + } + continue; + } + if (full.isNull() || U_FAILURE(status)) { + dataerrln("FAIL: Can't create number instance of style %d for host - %s", + k, u_errorName(status)); return; } UnicodeString result1; @@ -2393,7 +2403,6 @@ void NumberFormatTest::TestHost() errln("FAIL: Can't parse for host"); return; } - delete full; } } @@ -2932,7 +2941,7 @@ NumberFormatTest::TestDecimalFormatCurrencyParse() { void NumberFormatTest::TestCurrencyIsoPluralFormat() { - const char* DATA[][6] = { + static const char* DATA[][6] = { // the data are: // locale, // currency amount to be formatted, @@ -2958,17 +2967,15 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() { // test choice format {"es_AR", "1", "INR", "\\u20B9\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"}, }; + static const UNumberFormatStyle currencyStyles[] = { + UNUM_CURRENCY, + UNUM_CURRENCY_ISO, + UNUM_CURRENCY_PLURAL + }; - for (uint32_t i=0; iformat(numberToBeFormat, strBuf); - int resultDataIndex = k; - if ( k == NumberFormat::kCurrencyStyle ) { - resultDataIndex = k+2; - } + int resultDataIndex = 3 + kIndex; // DATA[i][resultDataIndex] is the currency format result // using 'k' currency style. UnicodeString formatResult = ctou(DATA[i][resultDataIndex]); @@ -3034,7 +3038,7 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() { void NumberFormatTest::TestCurrencyParsing() { - const char* DATA[][6] = { + static const char* DATA[][6] = { // the data are: // locale, // currency amount to be formatted, @@ -3057,6 +3061,11 @@ NumberFormatTest::TestCurrencyParsing() { {"zh_TW", "1", "CNY", "\\uFFE51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"}, {"ru_RU", "1", "RUB", "1,00\\u00A0\\u0440\\u0443\\u0431.", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"}, }; + static const UNumberFormatStyle currencyStyles[] = { + UNUM_CURRENCY, + UNUM_CURRENCY_ISO, + UNUM_CURRENCY_PLURAL + }; #ifdef NUMFMTST_CACHE_DEBUG int deadloop = 0; @@ -3064,15 +3073,8 @@ for (;;) { printf("loop: %d\n", deadloop++); #endif for (uint32_t i=0; iformat(numberToBeFormat, strBuf); - int resultDataIndex = k; - if ( k == NumberFormat::kCurrencyStyle ) { - resultDataIndex = k+2; - } + int resultDataIndex = 3 + kIndex; // DATA[i][resultDataIndex] is the currency format result // using 'k' currency style. UnicodeString formatResult = ctou(DATA[i][resultDataIndex]); @@ -5778,7 +5777,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { for (uint32_t i=0; iparse(formatted, parseResult, status); @@ -5799,7 +5798,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { for (uint32_t i=0; iparse(formatted, parseResult, status); @@ -5919,7 +5918,7 @@ void NumberFormatTest::TestFieldPositionIterator() { void NumberFormatTest::TestFormatAttributes() { Locale locale("en_US"); UErrorCode status = U_ZERO_ERROR; - DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, NumberFormat::kCurrencyStyle, status); + DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_CURRENCY, status); if (failure(status, "NumberFormat::createInstance", TRUE)) return; double val = 12345.67; @@ -5952,7 +5951,7 @@ void NumberFormatTest::TestFormatAttributes() { } delete decFmt; - decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, NumberFormat::kScientificStyle, status); + decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_SCIENTIFIC, status); val = -0.0000123; { int32_t expected[] = { @@ -6078,8 +6077,7 @@ void NumberFormatTest::TestDecimal() { { UErrorCode status = U_ZERO_ERROR; - NumberFormat *fmtr = NumberFormat::createInstance( - Locale::getUS(), NumberFormat::kNumberStyle, status); + NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status); if (U_FAILURE(status) || fmtr == NULL) { dataerrln("Unable to create NumberFormat"); } else { @@ -6097,8 +6095,7 @@ void NumberFormatTest::TestDecimal() { // Check formatting a DigitList. DigitList is internal, but this is // a critical interface that must work. UErrorCode status = U_ZERO_ERROR; - NumberFormat *fmtr = NumberFormat::createInstance( - Locale::getUS(), NumberFormat::kNumberStyle, status); + NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status); if (U_FAILURE(status) || fmtr == NULL) { dataerrln("Unable to create NumberFormat"); } else { @@ -6129,8 +6126,7 @@ void NumberFormatTest::TestDecimal() { { // Check a parse with a formatter with a multiplier. UErrorCode status = U_ZERO_ERROR; - NumberFormat *fmtr = NumberFormat::createInstance( - Locale::getUS(), NumberFormat::kPercentStyle, status); + NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_PERCENT, status); if (U_FAILURE(status) || fmtr == NULL) { dataerrln("Unable to create NumberFormat"); } else { @@ -6147,8 +6143,7 @@ void NumberFormatTest::TestDecimal() { { // Check that a parse returns a decimal number with full accuracy UErrorCode status = U_ZERO_ERROR; - NumberFormat *fmtr = NumberFormat::createInstance( - Locale::getUS(), NumberFormat::kNumberStyle, status); + NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status); if (U_FAILURE(status) || fmtr == NULL) { dataerrln("Unable to create NumberFormat"); } else {