-// © 2016 and later: Unicode, Inc. and others.
+// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 1997-2015, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*
-* File COMPACTDECIMALFORMAT.CPP
-*
-********************************************************************************
-*/
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "charstr.h"
-#include "cstring.h"
-#include "digitlst.h"
-#include "mutex.h"
-#include "unicode/compactdecimalformat.h"
-#include "unicode/numsys.h"
-#include "unicode/plurrule.h"
-#include "unicode/ures.h"
-#include "ucln_in.h"
-#include "uhash.h"
-#include "umutex.h"
-#include "unicode/ures.h"
-#include "uresimp.h"
-
-// Maps locale name to CDFLocaleData struct.
-static UHashtable* gCompactDecimalData = NULL;
-static UMutex gCompactDecimalMetaLock = U_MUTEX_INITIALIZER;
-
-U_NAMESPACE_BEGIN
-
-static const int32_t MAX_DIGITS = 15;
-static const char gOther[] = "other";
-static const char gLatnTag[] = "latn";
-static const char gNumberElementsTag[] = "NumberElements";
-static const char gDecimalFormatTag[] = "decimalFormat";
-static const char gPatternsShort[] = "patternsShort";
-static const char gPatternsLong[] = "patternsLong";
-static const char gLatnPath[] = "NumberElements/latn";
-
-static const UChar u_0 = 0x30;
-static const UChar u_apos = 0x27;
-
-static const UChar kZero[] = {u_0};
-
-// Used to unescape single quotes.
-enum QuoteState {
- OUTSIDE,
- INSIDE_EMPTY,
- INSIDE_FULL
-};
-
-enum FallbackFlags {
- ANY = 0,
- MUST = 1,
- NOT_ROOT = 2
- // Next one will be 4 then 6 etc.
-};
-
-
-// CDFUnit represents a prefix-suffix pair for a particular variant
-// and log10 value.
-struct CDFUnit : public UMemory {
- UnicodeString prefix;
- UnicodeString suffix;
- inline CDFUnit() : prefix(), suffix() {
- prefix.setToBogus();
- }
- inline ~CDFUnit() {}
- inline UBool isSet() const {
- return !prefix.isBogus();
- }
- inline void markAsSet() {
- prefix.remove();
- }
-};
-
-// CDFLocaleStyleData contains formatting data for a particular locale
-// and style.
-class CDFLocaleStyleData : public UMemory {
- public:
- // What to divide by for each log10 value when formatting. These values
- // will be powers of 10. For English, would be:
- // 1, 1, 1, 1000, 1000, 1000, 1000000, 1000000, 1000000, 1000000000 ...
- double divisors[MAX_DIGITS];
- // Maps plural variants to CDFUnit[MAX_DIGITS] arrays.
- // To format a number x,
- // first compute log10(x). Compute displayNum = (x / divisors[log10(x)]).
- // Compute the plural variant for displayNum
- // (e.g zero, one, two, few, many, other).
- // Compute cdfUnits = unitsByVariant[pluralVariant].
- // Prefix and suffix to use at cdfUnits[log10(x)]
- UHashtable* unitsByVariant;
- // A flag for whether or not this CDFLocaleStyleData was loaded from the
- // Latin numbering system as a fallback from the locale numbering system.
- // This value is meaningless if the object is bogus or empty.
- UBool fromFallback;
- inline CDFLocaleStyleData() : unitsByVariant(NULL), fromFallback(FALSE) {
- uprv_memset(divisors, 0, sizeof(divisors));
- }
- ~CDFLocaleStyleData();
- // Init initializes this object.
- void Init(UErrorCode& status);
- inline UBool isBogus() const {
- return unitsByVariant == NULL;
- }
- void setToBogus();
- UBool isEmpty() {
- return unitsByVariant == NULL || unitsByVariant->count == 0;
- }
- private:
- CDFLocaleStyleData(const CDFLocaleStyleData&);
- CDFLocaleStyleData& operator=(const CDFLocaleStyleData&);
-};
-
-// CDFLocaleData contains formatting data for a particular locale.
-struct CDFLocaleData : public UMemory {
- CDFLocaleStyleData shortData;
- CDFLocaleStyleData longData;
- inline CDFLocaleData() : shortData(), longData() { }
- inline ~CDFLocaleData() { }
- // Init initializes this object.
- void Init(UErrorCode& status);
-};
-
-U_NAMESPACE_END
-
-U_CDECL_BEGIN
-
-static UBool U_CALLCONV cdf_cleanup(void) {
- if (gCompactDecimalData != NULL) {
- uhash_close(gCompactDecimalData);
- gCompactDecimalData = NULL;
- }
- return TRUE;
-}
-
-static void U_CALLCONV deleteCDFUnits(void* ptr) {
- delete [] (icu::CDFUnit*) ptr;
-}
-
-static void U_CALLCONV deleteCDFLocaleData(void* ptr) {
- delete (icu::CDFLocaleData*) ptr;
-}
-
-U_CDECL_END
-
-U_NAMESPACE_BEGIN
-
-static UBool divisors_equal(const double* lhs, const double* rhs);
-static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status);
-
-static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status);
-static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status);
-static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status);
-static int32_t populatePrefixSuffix(const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status);
-static double calculateDivisor(double power10, int32_t numZeros);
-static UBool onlySpaces(UnicodeString u);
-static void fixQuotes(UnicodeString& s);
-static void checkForOtherVariants(CDFLocaleStyleData* result, UErrorCode& status);
-static void fillInMissing(CDFLocaleStyleData* result);
-static int32_t computeLog10(double x, UBool inRange);
-static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status);
-static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value);
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
-
-CompactDecimalFormat::CompactDecimalFormat(
- const DecimalFormat& decimalFormat,
- const UHashtable* unitsByVariant,
- const double* divisors,
- PluralRules* pluralRules)
- : DecimalFormat(decimalFormat), _unitsByVariant(unitsByVariant), _divisors(divisors), _pluralRules(pluralRules) {
-}
-
-CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source)
- : DecimalFormat(source), _unitsByVariant(source._unitsByVariant), _divisors(source._divisors), _pluralRules(source._pluralRules->clone()) {
-}
-
-CompactDecimalFormat* U_EXPORT2
-CompactDecimalFormat::createInstance(
- const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
- LocalPointer<DecimalFormat> decfmt((DecimalFormat*) NumberFormat::makeInstance(inLocale, UNUM_DECIMAL, TRUE, status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- LocalPointer<PluralRules> pluralRules(PluralRules::forLocale(inLocale, status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- const CDFLocaleStyleData* data = getCDFLocaleStyleData(inLocale, style, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- CompactDecimalFormat* result =
- new CompactDecimalFormat(*decfmt, data->unitsByVariant, data->divisors, pluralRules.getAlias());
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- pluralRules.orphan();
- result->setMaximumSignificantDigits(3);
- result->setSignificantDigitsUsed(TRUE);
- result->setGroupingUsed(FALSE);
- return result;
-}
-
-CompactDecimalFormat&
-CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
- if (this != &rhs) {
- DecimalFormat::operator=(rhs);
- _unitsByVariant = rhs._unitsByVariant;
- _divisors = rhs._divisors;
- delete _pluralRules;
- _pluralRules = rhs._pluralRules->clone();
- }
- return *this;
-}
-
-CompactDecimalFormat::~CompactDecimalFormat() {
- delete _pluralRules;
-}
-
-
-Format*
-CompactDecimalFormat::clone(void) const {
- return new CompactDecimalFormat(*this);
-}
-
-UBool
-CompactDecimalFormat::operator==(const Format& that) const {
- if (this == &that) {
- return TRUE;
- }
- return (DecimalFormat::operator==(that) && eqHelper((const CompactDecimalFormat&) that));
-}
-
-UBool
-CompactDecimalFormat::eqHelper(const CompactDecimalFormat& that) const {
- return uhash_equals(_unitsByVariant, that._unitsByVariant) && divisors_equal(_divisors, that._divisors) && (*_pluralRules == *that._pluralRules);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- double number,
- UnicodeString& appendTo,
- FieldPosition& pos) const {
- UErrorCode status = U_ZERO_ERROR;
- return format(number, appendTo, pos, status);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- double number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- DigitList orig, rounded;
- orig.set(number);
- UBool isNegative;
- _round(orig, rounded, isNegative, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- double roundedDouble = rounded.getDouble();
- if (isNegative) {
- roundedDouble = -roundedDouble;
- }
- int32_t baseIdx = computeLog10(roundedDouble, TRUE);
- double numberToFormat = roundedDouble / _divisors[baseIdx];
- UnicodeString variant = _pluralRules->select(numberToFormat);
- if (isNegative) {
- numberToFormat = -numberToFormat;
- }
- const CDFUnit* unit = getCDFUnitFallback(_unitsByVariant, variant, baseIdx);
- appendTo += unit->prefix;
- DecimalFormat::format(numberToFormat, appendTo, pos);
- appendTo += unit->suffix;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- double /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int32_t number,
- UnicodeString& appendTo,
- FieldPosition& pos) const {
- return format((double) number, appendTo, pos);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int32_t number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return format((double) number, appendTo, pos, status);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int32_t /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int64_t number,
- UnicodeString& appendTo,
- FieldPosition& pos) const {
- return format((double) number, appendTo, pos);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int64_t number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return format((double) number, appendTo, pos, status);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int64_t /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- StringPiece /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- const DigitList& /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(const DigitList& /* number */,
- UnicodeString& appendTo,
- FieldPosition& /* pos */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-void
-CompactDecimalFormat::parse(
- const UnicodeString& /* text */,
- Formattable& /* result */,
- ParsePosition& /* parsePosition */) const {
-}
-
-void
-CompactDecimalFormat::parse(
- const UnicodeString& /* text */,
- Formattable& /* result */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
-}
-
-CurrencyAmount*
-CompactDecimalFormat::parseCurrency(
- const UnicodeString& /* text */,
- ParsePosition& /* pos */) const {
- return NULL;
-}
-
-void CDFLocaleStyleData::Init(UErrorCode& status) {
- if (unitsByVariant != NULL) {
- return;
- }
- unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_FAILURE(status)) {
- return;
- }
- uhash_setKeyDeleter(unitsByVariant, uprv_free);
- uhash_setValueDeleter(unitsByVariant, deleteCDFUnits);
-}
-
-CDFLocaleStyleData::~CDFLocaleStyleData() {
- setToBogus();
-}
-
-void CDFLocaleStyleData::setToBogus() {
- if (unitsByVariant != NULL) {
- uhash_close(unitsByVariant);
- unitsByVariant = NULL;
- }
-}
-void CDFLocaleData::Init(UErrorCode& status) {
- shortData.Init(status);
- if (U_FAILURE(status)) {
- return;
- }
- longData.Init(status);
-}
-
-// Helper method for operator=
-static UBool divisors_equal(const double* lhs, const double* rhs) {
- for (int32_t i = 0; i < MAX_DIGITS; ++i) {
- if (lhs[i] != rhs[i]) {
- return FALSE;
- }
- }
- return TRUE;
-}
-
-// getCDFLocaleStyleData returns pointer to formatting data for given locale and
-// style within the global cache. On cache miss, getCDFLocaleStyleData loads
-// the data from CLDR into the global cache before returning the pointer. If a
-// UNUM_LONG data is requested for a locale, and that locale does not have
-// UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for
-// that locale.
-static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- CDFLocaleData* result = NULL;
- const char* key = inLocale.getName();
- {
- Mutex lock(&gCompactDecimalMetaLock);
- if (gCompactDecimalData == NULL) {
- gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- uhash_setKeyDeleter(gCompactDecimalData, uprv_free);
- uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData);
- ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup);
- } else {
- result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
- }
- }
- if (result != NULL) {
- return extractDataByStyleEnum(*result, style, status);
- }
-
- result = loadCDFLocaleData(inLocale, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- {
- Mutex lock(&gCompactDecimalMetaLock);
- CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
- if (temp != NULL) {
- delete result;
- result = temp;
- } else {
- uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- }
- }
- return extractDataByStyleEnum(*result, style, status);
-}
-
-static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status) {
- switch (style) {
- case UNUM_SHORT:
- return &data.shortData;
- case UNUM_LONG:
- if (!data.longData.isBogus()) {
- return &data.longData;
- }
- return &data.shortData;
- default:
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
-}
-
-// loadCDFLocaleData loads formatting data from CLDR for a given locale. The
-// caller owns the returned pointer.
-static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- CDFLocaleData* result = new CDFLocaleData;
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- result->Init(status);
- if (U_FAILURE(status)) {
- delete result;
- return NULL;
- }
-
- load(inLocale, result, status);
-
- if (U_FAILURE(status)) {
- delete result;
- return NULL;
- }
- return result;
-}
-
-namespace {
-
-struct CmptDecDataSink : public ResourceSink {
-
- CDFLocaleData& dataBundle; // Where to save values when they are read
- UBool isLatin; // Whether or not we are traversing the Latin tree
- UBool isFallback; // Whether or not we are traversing the Latin tree as fallback
-
- enum EPatternsTableKey { PATTERNS_SHORT, PATTERNS_LONG };
- enum EFormatsTableKey { DECIMAL_FORMAT, CURRENCY_FORMAT };
-
- /*
- * NumberElements{ <-- top (numbering system table)
- * latn{ <-- patternsTable (one per numbering system)
- * patternsLong{ <-- formatsTable (one per pattern)
- * decimalFormat{ <-- powersOfTenTable (one per format)
- * 1000{ <-- pluralVariantsTable (one per power of ten)
- * one{"0 thousand"} <-- plural variant and template
- */
-
- CmptDecDataSink(CDFLocaleData& _dataBundle)
- : dataBundle(_dataBundle), isLatin(FALSE), isFallback(FALSE) {}
- virtual ~CmptDecDataSink();
-
- virtual void put(const char *key, ResourceValue &value, UBool isRoot, UErrorCode &errorCode) {
- // SPECIAL CASE: Don't consume root in the non-Latin numbering system
- if (isRoot && !isLatin) { return; }
-
- ResourceTable patternsTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i1 = 0; patternsTable.getKeyAndValue(i1, key, value); ++i1) {
-
- // Check for patternsShort or patternsLong
- EPatternsTableKey patternsTableKey;
- if (uprv_strcmp(key, gPatternsShort) == 0) {
- patternsTableKey = PATTERNS_SHORT;
- } else if (uprv_strcmp(key, gPatternsLong) == 0) {
- patternsTableKey = PATTERNS_LONG;
- } else {
- continue;
- }
-
- // Traverse into the formats table
- ResourceTable formatsTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i2 = 0; formatsTable.getKeyAndValue(i2, key, value); ++i2) {
-
- // Check for decimalFormat or currencyFormat
- EFormatsTableKey formatsTableKey;
- if (uprv_strcmp(key, gDecimalFormatTag) == 0) {
- formatsTableKey = DECIMAL_FORMAT;
- // TODO: Enable this statement when currency support is added
- // } else if (uprv_strcmp(key, gCurrencyFormat) == 0) {
- // formatsTableKey = CURRENCY_FORMAT;
- } else {
- continue;
- }
-
- // Set the current style and destination based on the two keys
- UNumberCompactStyle style;
- CDFLocaleStyleData* destination = NULL;
- if (patternsTableKey == PATTERNS_LONG
- && formatsTableKey == DECIMAL_FORMAT) {
- style = UNUM_LONG;
- destination = &dataBundle.longData;
- } else if (patternsTableKey == PATTERNS_SHORT
- && formatsTableKey == DECIMAL_FORMAT) {
- style = UNUM_SHORT;
- destination = &dataBundle.shortData;
- // TODO: Enable the following statements when currency support is added
- // } else if (patternsTableKey == PATTERNS_SHORT
- // && formatsTableKey == CURRENCY_FORMAT) {
- // style = UNUM_SHORT_CURRENCY; // or whatever the enum gets named
- // destination = &dataBundle.shortCurrencyData;
- // } else {
- // // Silently ignore this case
- // continue;
- }
-
- // SPECIAL CASE: RULES FOR WHETHER OR NOT TO CONSUME THIS TABLE:
- // 1) Don't consume longData if shortData was consumed from the non-Latin
- // locale numbering system
- // 2) Don't consume longData for the first time if this is the root bundle and
- // shortData is already populated from a more specific locale. Note that if
- // both longData and shortData are both only in root, longData will be
- // consumed since it is alphabetically before shortData in the bundle.
- if (isFallback
- && style == UNUM_LONG
- && !dataBundle.shortData.isEmpty()
- && !dataBundle.shortData.fromFallback) {
- continue;
- }
- if (isRoot
- && style == UNUM_LONG
- && dataBundle.longData.isEmpty()
- && !dataBundle.shortData.isEmpty()) {
- continue;
- }
-
- // Set the "fromFallback" flag on the data object
- destination->fromFallback = isFallback;
-
- // Traverse into the powers of ten table
- ResourceTable powersOfTenTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
-
- // The key will always be some even power of 10. e.g 10000.
- char* endPtr = NULL;
- double power10 = uprv_strtod(key, &endPtr);
- if (*endPtr != 0) {
- errorCode = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- int32_t log10Value = computeLog10(power10, FALSE);
-
- // Silently ignore divisors that are too big.
- if (log10Value >= MAX_DIGITS) continue;
-
- // Iterate over the plural variants ("one", "other", etc)
- ResourceTable pluralVariantsTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) {
- const char* pluralVariant = key;
- const UnicodeString formatStr = value.getUnicodeString(errorCode);
-
- // Copy the data into the in-memory data bundle (do not overwrite
- // existing values)
- int32_t numZeros = populatePrefixSuffix(
- pluralVariant, log10Value, formatStr,
- destination->unitsByVariant, FALSE, errorCode);
-
- // If populatePrefixSuffix returns -1, it means that this key has been
- // encountered already.
- if (numZeros < 0) {
- continue;
- }
-
- // Set the divisor, which is based on the number of zeros in the template
- // string. If the divisor from here is different from the one previously
- // stored, it means that the number of zeros in different plural variants
- // differs; throw an exception.
- // TODO: How should I check for floating-point errors here?
- // Is there a good reason why "divisor" is double and not long like Java?
- double divisor = calculateDivisor(power10, numZeros);
- if (destination->divisors[log10Value] != 0.0
- && destination->divisors[log10Value] != divisor) {
- errorCode = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- destination->divisors[log10Value] = divisor;
- }
- }
- }
- }
- }
-};
-
-// Virtual destructors must be defined out of line.
-CmptDecDataSink::~CmptDecDataSink() {}
-
-} // namespace
-
-static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) {
- LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(inLocale, status));
- if (U_FAILURE(status)) {
- return;
- }
- const char* nsName = ns->getName();
-
- LocalUResourceBundlePointer resource(ures_open(NULL, inLocale.getName(), &status));
- if (U_FAILURE(status)) {
- return;
- }
- CmptDecDataSink sink(*result);
- sink.isFallback = FALSE;
-
- // First load the number elements data if nsName is not Latin.
- if (uprv_strcmp(nsName, gLatnTag) != 0) {
- sink.isLatin = FALSE;
- CharString path;
- path.append(gNumberElementsTag, status)
- .append('/', status)
- .append(nsName, status);
- ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status);
- if (status == U_MISSING_RESOURCE_ERROR) {
- // Silently ignore and use Latin
- status = U_ZERO_ERROR;
- } else if (U_FAILURE(status)) {
- return;
- }
- sink.isFallback = TRUE;
- }
-
- // Now load Latin.
- sink.isLatin = TRUE;
- ures_getAllItemsWithFallback(resource.getAlias(), gLatnPath, sink, status);
- if (U_FAILURE(status)) return;
-
- // If longData is empty, default it to be equal to shortData
- if (result->longData.isEmpty()) {
- result->longData.setToBogus();
- }
-
- // Check for "other" variants in each of the three data classes, and resolve missing elements.
-
- if (!result->longData.isBogus()) {
- checkForOtherVariants(&result->longData, status);
- if (U_FAILURE(status)) return;
- fillInMissing(&result->longData);
- }
-
- checkForOtherVariants(&result->shortData, status);
- if (U_FAILURE(status)) return;
- fillInMissing(&result->shortData);
-
- // TODO: Enable this statement when currency support is added
- // checkForOtherVariants(&result->shortCurrencyData, status);
- // if (U_FAILURE(status)) return;
- // fillInMissing(&result->shortCurrencyData);
-}
-
-// populatePrefixSuffix Adds a specific prefix-suffix pair to result for a
-// given variant and log10 value.
-// variant is 'zero', 'one', 'two', 'few', 'many', or 'other'.
-// formatStr is the format string from which the prefix and suffix are
-// extracted. It is usually of form 'Pefix 000 suffix'.
-// populatePrefixSuffix returns the number of 0's found in formatStr
-// before the decimal point.
-// In the special case that formatStr contains only spaces for prefix
-// and suffix, populatePrefixSuffix returns log10Value + 1.
-static int32_t populatePrefixSuffix(
- const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return 0;
- }
-
- // ICU 59 HACK: Ignore negative part of format string, mimicking ICU 58 behavior.
- // TODO(sffc): Make sure this is fixed during the overhaul port in ICU 60.
- int32_t semiPos = formatStr.indexOf(';', 0);
- if (semiPos == -1) {
- semiPos = formatStr.length();
- }
- UnicodeString positivePart = formatStr.tempSubString(0, semiPos);
-
- int32_t firstIdx = positivePart.indexOf(kZero, UPRV_LENGTHOF(kZero), 0);
- // We must have 0's in format string.
- if (firstIdx == -1) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return 0;
- }
- int32_t lastIdx = positivePart.lastIndexOf(kZero, UPRV_LENGTHOF(kZero), firstIdx);
- CDFUnit* unit = createCDFUnit(variant, log10Value, result, status);
- if (U_FAILURE(status)) {
- return 0;
- }
-
- // Return -1 if we are not overwriting an existing value
- if (unit->isSet() && !overwrite) {
- return -1;
- }
- unit->markAsSet();
-
- // Everything up to first 0 is the prefix
- unit->prefix = positivePart.tempSubString(0, firstIdx);
- fixQuotes(unit->prefix);
- // Everything beyond the last 0 is the suffix
- unit->suffix = positivePart.tempSubString(lastIdx + 1);
- fixQuotes(unit->suffix);
-
- // If there is effectively no prefix or suffix, ignore the actual number of
- // 0's and act as if the number of 0's matches the size of the number.
- if (onlySpaces(unit->prefix) && onlySpaces(unit->suffix)) {
- return log10Value + 1;
- }
-
- // Calculate number of zeros before decimal point
- int32_t idx = firstIdx + 1;
- while (idx <= lastIdx && positivePart.charAt(idx) == u_0) {
- ++idx;
- }
- return (idx - firstIdx);
-}
-
-// Calculate a divisor based on the magnitude and number of zeros in the
-// template string.
-static double calculateDivisor(double power10, int32_t numZeros) {
- double divisor = power10;
- for (int32_t i = 1; i < numZeros; ++i) {
- divisor /= 10.0;
- }
- return divisor;
-}
-
-static UBool onlySpaces(UnicodeString u) {
- return u.trim().length() == 0;
-}
-
-// fixQuotes unescapes single quotes. Don''t -> Don't. Letter 'j' -> Letter j.
-// Modifies s in place.
-static void fixQuotes(UnicodeString& s) {
- QuoteState state = OUTSIDE;
- int32_t len = s.length();
- int32_t dest = 0;
- for (int32_t i = 0; i < len; ++i) {
- UChar ch = s.charAt(i);
- if (ch == u_apos) {
- if (state == INSIDE_EMPTY) {
- s.setCharAt(dest, ch);
- ++dest;
- }
- } else {
- s.setCharAt(dest, ch);
- ++dest;
- }
+#include "unicode/utypes.h"
- // Update state
- switch (state) {
- case OUTSIDE:
- state = ch == u_apos ? INSIDE_EMPTY : OUTSIDE;
- break;
- case INSIDE_EMPTY:
- case INSIDE_FULL:
- state = ch == u_apos ? OUTSIDE : INSIDE_FULL;
- break;
- default:
- break;
- }
- }
- s.truncate(dest);
-}
+#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
-// Checks to make sure that an "other" variant is present in all
-// powers of 10.
-static void checkForOtherVariants(CDFLocaleStyleData* result,
- UErrorCode& status) {
- if (result == NULL || result->unitsByVariant == NULL) {
- return;
- }
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
- const CDFUnit* otherByBase =
- (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
- if (otherByBase == NULL) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
+using namespace icu;
- // Check all other plural variants, and make sure that if
- // any of them are populated, then other is also populated
- int32_t pos = UHASH_FIRST;
- const UHashElement* element;
- while ((element = uhash_nextElement(result->unitsByVariant, &pos)) != NULL) {
- CDFUnit* variantsByBase = (CDFUnit*) element->value.pointer;
- if (variantsByBase == otherByBase) continue;
- for (int32_t log10Value = 0; log10Value < MAX_DIGITS; ++log10Value) {
- if (variantsByBase[log10Value].isSet()
- && !otherByBase[log10Value].isSet()) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- }
- }
-}
-// fillInMissing ensures that the data in result is complete.
-// result data is complete if for each variant in result, there exists
-// a prefix-suffix pair for each log10 value and there also exists
-// a divisor for each log10 value.
-//
-// First this function figures out for which log10 values, the other
-// variant already had data. These are the same log10 values defined
-// in CLDR.
-//
-// For each log10 value not defined in CLDR, it uses the divisor for
-// the last defined log10 value or 1.
-//
-// Then for each variant, it does the following. For each log10
-// value not defined in CLDR, copy the prefix-suffix pair from the
-// previous log10 value. If log10 value is defined in CLDR but is
-// missing from given variant, copy the prefix-suffix pair for that
-// log10 value from the 'other' variant.
-static void fillInMissing(CDFLocaleStyleData* result) {
- const CDFUnit* otherUnits =
- (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
- UBool definedInCLDR[MAX_DIGITS];
- double lastDivisor = 1.0;
- for (int32_t i = 0; i < MAX_DIGITS; ++i) {
- if (!otherUnits[i].isSet()) {
- result->divisors[i] = lastDivisor;
- definedInCLDR[i] = FALSE;
- } else {
- lastDivisor = result->divisors[i];
- definedInCLDR[i] = TRUE;
- }
- }
- // Iterate over each variant.
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = uhash_nextElement(result->unitsByVariant, &pos);
- for (;element != NULL; element = uhash_nextElement(result->unitsByVariant, &pos)) {
- CDFUnit* units = (CDFUnit*) element->value.pointer;
- for (int32_t i = 0; i < MAX_DIGITS; ++i) {
- if (definedInCLDR[i]) {
- if (!units[i].isSet()) {
- units[i] = otherUnits[i];
- }
- } else {
- if (i == 0) {
- units[0].markAsSet();
- } else {
- units[i] = units[i - 1];
- }
- }
- }
- }
-}
-// computeLog10 computes floor(log10(x)). If inRange is TRUE, the biggest
-// value computeLog10 will return MAX_DIGITS -1 even for
-// numbers > 10^MAX_DIGITS. If inRange is FALSE, computeLog10 will return
-// up to MAX_DIGITS.
-static int32_t computeLog10(double x, UBool inRange) {
- int32_t result = 0;
- int32_t max = inRange ? MAX_DIGITS - 1 : MAX_DIGITS;
- while (x >= 10.0) {
- x /= 10.0;
- ++result;
- if (result == max) {
- break;
- }
- }
- return result;
-}
-// createCDFUnit returns a pointer to the prefix-suffix pair for a given
-// variant and log10 value within table. If no such prefix-suffix pair is
-// stored in table, one is created within table before returning pointer.
-static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant);
- if (cdfUnit == NULL) {
- cdfUnit = new CDFUnit[MAX_DIGITS];
- if (cdfUnit == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- uhash_put(table, uprv_strdup(variant), cdfUnit, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- }
- CDFUnit* result = &cdfUnit[log10Value];
- return result;
-}
-// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given
-// variant and log10 value within table. If the given variant doesn't exist, it
-// falls back to the OTHER variant. Therefore, this method will always return
-// some non-NULL value.
-static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) {
- CharString cvariant;
- UErrorCode status = U_ZERO_ERROR;
- const CDFUnit *cdfUnit = NULL;
- cvariant.appendInvariantChars(variant, status);
- if (!U_FAILURE(status)) {
- cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data());
- }
- if (cdfUnit == NULL) {
- cdfUnit = (const CDFUnit*) uhash_get(table, gOther);
- }
- return &cdfUnit[log10Value];
-}
-U_NAMESPACE_END
-#endif
+#endif /* #if !UCONFIG_NO_FORMATTING */
-// © 2016 and later: Unicode, Inc. and others.
+// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 1997-2015, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*
-* File DECIMFMT.CPP
-*
-* Modification History:
-*
-* Date Name Description
-* 02/19/97 aliu Converted from java.
-* 03/20/97 clhuang Implemented with new APIs.
-* 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it.
-* 04/3/97 aliu Rewrote parsing and formatting completely, and
-* cleaned up and debugged. Actually works now.
-* Implemented NAN and INF handling, for both parsing
-* and formatting. Extensive testing & debugging.
-* 04/10/97 aliu Modified to compile on AIX.
-* 04/16/97 aliu Rewrote to use DigitList, which has been resurrected.
-* Changed DigitCount to int per code review.
-* 07/09/97 helena Made ParsePosition into a class.
-* 08/26/97 aliu Extensive changes to applyPattern; completely
-* rewritten from the Java.
-* 09/09/97 aliu Ported over support for exponential formats.
-* 07/20/98 stephen JDK 1.2 sync up.
-* Various instances of '0' replaced with 'NULL'
-* Check for grouping size in subFormat()
-* Brought subParse() in line with Java 1.2
-* Added method appendAffix()
-* 08/24/1998 srl Removed Mutex calls. This is not a thread safe class!
-* 02/22/99 stephen Removed character literals for EBCDIC safety
-* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
-* 06/28/99 stephen Fixed bugs in toPattern().
-* 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad,
-* fPadPosition
-********************************************************************************
-*/
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING
+#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
-#include "unicode/uniset.h"
-#include "unicode/currpinf.h"
-#include "unicode/plurrule.h"
-#include "unicode/utf16.h"
-#include "unicode/numsys.h"
-#include "unicode/localpointer.h"
-#include "unicode/ustring.h"
-#include "uresimp.h"
-#include "ucurrimp.h"
-#include "charstr.h"
-#include "patternprops.h"
-#include "cstring.h"
-#include "uassert.h"
-#include "hash.h"
-#include "decfmtst.h"
-#include "plurrule_impl.h"
-#include "decimalformatpattern.h"
-#include "fmtableimp.h"
-#include "decimfmtimpl.h"
-#include "visibledigits.h"
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
-/*
- * On certain platforms, round is a macro defined in math.h
- * This undefine is to avoid conflict between the macro and
- * the function defined below.
- */
-#ifdef round
-#undef round
-#endif
+using namespace icu;
-U_NAMESPACE_BEGIN
-#ifdef FMT_DEBUG
-#include <stdio.h>
-static void _debugout(const char *f, int l, const UnicodeString& s) {
- char buf[2000];
- s.extract((int32_t) 0, s.length(), buf, "utf-8");
- printf("%s:%d: %s\n", f,l, buf);
-}
-#define debugout(x) _debugout(__FILE__,__LINE__,x)
-#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
-static const UnicodeString dbg_null("<NULL>","");
-#define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null))
-#else
-#define debugout(x)
-#define debug(x)
-#endif
-/* For currency parsing purose,
- * Need to remember all prefix patterns and suffix patterns of
- * every currency format pattern,
- * including the pattern of default currecny style
- * and plural currency style. And the patterns are set through applyPattern.
- */
-struct AffixPatternsForCurrency : public UMemory {
- // negative prefix pattern
- UnicodeString negPrefixPatternForCurrency;
- // negative suffix pattern
- UnicodeString negSuffixPatternForCurrency;
- // positive prefix pattern
- UnicodeString posPrefixPatternForCurrency;
- // positive suffix pattern
- UnicodeString posSuffixPatternForCurrency;
- int8_t patternType;
-
- AffixPatternsForCurrency(const UnicodeString& negPrefix,
- const UnicodeString& negSuffix,
- const UnicodeString& posPrefix,
- const UnicodeString& posSuffix,
- int8_t type) {
- negPrefixPatternForCurrency = negPrefix;
- negSuffixPatternForCurrency = negSuffix;
- posPrefixPatternForCurrency = posPrefix;
- posSuffixPatternForCurrency = posSuffix;
- patternType = type;
- }
-#ifdef FMT_DEBUG
- void dump() const {
- debugout( UnicodeString("AffixPatternsForCurrency( -=\"") +
- negPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
- negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" +
- posPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
- posSuffixPatternForCurrency + (UnicodeString)"\" )");
- }
-#endif
-};
-
-/* affix for currency formatting when the currency sign in the pattern
- * equals to 3, such as the pattern contains 3 currency sign or
- * the formatter style is currency plural format style.
- */
-struct AffixesForCurrency : public UMemory {
- // negative prefix
- UnicodeString negPrefixForCurrency;
- // negative suffix
- UnicodeString negSuffixForCurrency;
- // positive prefix
- UnicodeString posPrefixForCurrency;
- // positive suffix
- UnicodeString posSuffixForCurrency;
-
- int32_t formatWidth;
-
- AffixesForCurrency(const UnicodeString& negPrefix,
- const UnicodeString& negSuffix,
- const UnicodeString& posPrefix,
- const UnicodeString& posSuffix) {
- negPrefixForCurrency = negPrefix;
- negSuffixForCurrency = negSuffix;
- posPrefixForCurrency = posPrefix;
- posSuffixForCurrency = posSuffix;
- }
-#ifdef FMT_DEBUG
- void dump() const {
- debugout( UnicodeString("AffixesForCurrency( -=\"") +
- negPrefixForCurrency + (UnicodeString)"\"/\"" +
- negSuffixForCurrency + (UnicodeString)"\" +=\"" +
- posPrefixForCurrency + (UnicodeString)"\"/\"" +
- posSuffixForCurrency + (UnicodeString)"\" )");
- }
-#endif
-};
-
-U_CDECL_BEGIN
-
-/**
- * @internal ICU 4.2
- */
-static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2);
-
-
-static UBool
-U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) {
- const AffixPatternsForCurrency* affix_1 =
- (AffixPatternsForCurrency*)val1.pointer;
- const AffixPatternsForCurrency* affix_2 =
- (AffixPatternsForCurrency*)val2.pointer;
- return affix_1->negPrefixPatternForCurrency ==
- affix_2->negPrefixPatternForCurrency &&
- affix_1->negSuffixPatternForCurrency ==
- affix_2->negSuffixPatternForCurrency &&
- affix_1->posPrefixPatternForCurrency ==
- affix_2->posPrefixPatternForCurrency &&
- affix_1->posSuffixPatternForCurrency ==
- affix_2->posSuffixPatternForCurrency &&
- affix_1->patternType == affix_2->patternType;
-}
-
-U_CDECL_END
-
-
-
-
-// *****************************************************************************
-// class DecimalFormat
-// *****************************************************************************
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
-
-// Constants for characters used in programmatic (unlocalized) patterns.
-#define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
-#define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
-#define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
-#define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
-#define kPatternPerMill ((UChar)0x2030)
-#define kPatternPercent ((UChar)0x0025) /*'%'*/
-#define kPatternDigit ((UChar)0x0023) /*'#'*/
-#define kPatternSeparator ((UChar)0x003B) /*';'*/
-#define kPatternExponent ((UChar)0x0045) /*'E'*/
-#define kPatternPlus ((UChar)0x002B) /*'+'*/
-#define kPatternMinus ((UChar)0x002D) /*'-'*/
-#define kPatternPadEscape ((UChar)0x002A) /*'*'*/
-#define kQuote ((UChar)0x0027) /*'\''*/
-/**
- * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
- * is used in patterns and substitued with either the currency symbol,
- * or if it is doubled, with the international currency symbol. If the
- * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
- * replaced with the monetary decimal separator.
- */
-#define kCurrencySign ((UChar)0x00A4)
-#define kDefaultPad ((UChar)0x0020) /* */
-
-const int32_t DecimalFormat::kDoubleIntegerDigits = 309;
-const int32_t DecimalFormat::kDoubleFractionDigits = 340;
-
-const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8;
-
-/**
- * These are the tags we expect to see in normal resource bundle files associated
- * with a locale.
- */
-const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - not used
-static const char fgNumberElements[]="NumberElements";
-static const char fgLatn[]="latn";
-static const char fgPatterns[]="patterns";
-static const char fgDecimalFormat[]="decimalFormat";
-static const char fgCurrencyFormat[]="currencyFormat";
-
-inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; }
-inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; }
-
-//------------------------------------------------------------------------------
-// Constructs a DecimalFormat instance in the default locale.
-
-DecimalFormat::DecimalFormat(UErrorCode& status) {
- init();
- UParseError parseError;
- construct(status, parseError);
-}
-
-//------------------------------------------------------------------------------
-// Constructs a DecimalFormat instance with the specified number format
-// pattern in the default locale.
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern,
- UErrorCode& status) {
- init();
- UParseError parseError;
- construct(status, parseError, &pattern);
-}
-
-//------------------------------------------------------------------------------
-// Constructs a DecimalFormat instance with the specified number format
-// pattern and the number format symbols in the default locale. The
-// created instance owns the symbols.
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern,
- DecimalFormatSymbols* symbolsToAdopt,
- UErrorCode& status) {
- init();
- UParseError parseError;
- if (symbolsToAdopt == NULL)
- status = U_ILLEGAL_ARGUMENT_ERROR;
- construct(status, parseError, &pattern, symbolsToAdopt);
-}
-
-DecimalFormat::DecimalFormat( const UnicodeString& pattern,
- DecimalFormatSymbols* symbolsToAdopt,
- UParseError& parseErr,
- UErrorCode& status) {
- init();
- if (symbolsToAdopt == NULL)
- status = U_ILLEGAL_ARGUMENT_ERROR;
- construct(status,parseErr, &pattern, symbolsToAdopt);
-}
-
-//------------------------------------------------------------------------------
-// Constructs a DecimalFormat instance with the specified number format
-// pattern and the number format symbols in the default locale. The
-// created instance owns the clone of the symbols.
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern,
- const DecimalFormatSymbols& symbols,
- UErrorCode& status) {
- init();
- UParseError parseError;
- construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
-}
-
-//------------------------------------------------------------------------------
-// Constructs a DecimalFormat instance with the specified number format
-// pattern, the number format symbols, and the number format style.
-// The created instance owns the clone of the symbols.
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern,
- DecimalFormatSymbols* symbolsToAdopt,
- UNumberFormatStyle style,
- UErrorCode& status) {
- init();
- fStyle = style;
- UParseError parseError;
- construct(status, parseError, &pattern, symbolsToAdopt);
-}
-
-//-----------------------------------------------------------------------------
-// Common DecimalFormat initialization.
-// Put all fields of an uninitialized object into a known state.
-// Common code, shared by all constructors.
-// Can not fail. Leave the object in good enough shape that the destructor
-// or assignment operator can run successfully.
-void
-DecimalFormat::init() {
- fBoolFlags.clear();
- fStyle = UNUM_DECIMAL;
- fAffixPatternsForCurrency = NULL;
- fCurrencyPluralInfo = NULL;
-#if UCONFIG_HAVE_PARSEALLINPUT
- fParseAllInput = UNUM_MAYBE;
-#endif
-
- fStaticSets = NULL;
- fImpl = NULL;
-}
-
-//------------------------------------------------------------------------------
-// Constructs a DecimalFormat instance with the specified number format
-// pattern and the number format symbols in the desired locale. The
-// created instance owns the symbols.
-
-void
-DecimalFormat::construct(UErrorCode& status,
- UParseError& parseErr,
- const UnicodeString* pattern,
- DecimalFormatSymbols* symbolsToAdopt)
-{
- LocalPointer<DecimalFormatSymbols> adoptedSymbols(symbolsToAdopt);
- if (U_FAILURE(status))
- return;
-
- if (adoptedSymbols.isNull())
- {
- adoptedSymbols.adoptInstead(
- new DecimalFormatSymbols(Locale::getDefault(), status));
- if (adoptedSymbols.isNull() && U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (U_FAILURE(status)) {
- return;
- }
- }
- fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
- if (U_FAILURE(status)) {
- return;
- }
-
- UnicodeString str;
- // Uses the default locale's number format pattern if there isn't
- // one specified.
- if (pattern == NULL)
- {
- UErrorCode nsStatus = U_ZERO_ERROR;
- LocalPointer<NumberingSystem> ns(
- NumberingSystem::createInstance(nsStatus));
- if (U_FAILURE(nsStatus)) {
- status = nsStatus;
- return;
- }
-
- int32_t len = 0;
- UResourceBundle *top = ures_open(NULL, Locale::getDefault().getName(), &status);
-
- UResourceBundle *resource = ures_getByKeyWithFallback(top, fgNumberElements, NULL, &status);
- resource = ures_getByKeyWithFallback(resource, ns->getName(), resource, &status);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
- const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status);
- if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(fgLatn,ns->getName())) {
- status = U_ZERO_ERROR;
- resource = ures_getByKeyWithFallback(top, fgNumberElements, resource, &status);
- resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
- resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status);
- }
- str.setTo(TRUE, resStr, len);
- pattern = &str;
- ures_close(resource);
- ures_close(top);
- }
-
- fImpl = new DecimalFormatImpl(this, *pattern, adoptedSymbols.getAlias(), parseErr, status);
- if (fImpl) {
- adoptedSymbols.orphan();
- } else if (U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (U_FAILURE(status)) {
- return;
- }
-
- if (U_FAILURE(status))
- {
- return;
- }
-
- const UnicodeString* patternUsed;
- UnicodeString currencyPluralPatternForOther;
- // apply pattern
- if (fStyle == UNUM_CURRENCY_PLURAL) {
- fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status);
- if (U_FAILURE(status)) {
- return;
- }
-
- // the pattern used in format is not fixed until formatting,
- // in which, the number is known and
- // will be used to pick the right pattern based on plural count.
- // Here, set the pattern as the pattern of plural count == "other".
- // For most locale, the patterns are probably the same for all
- // plural count. If not, the right pattern need to be re-applied
- // during format.
- fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther);
- // TODO(refactor): Revisit, we are setting the pattern twice.
- fImpl->applyPatternFavorCurrencyPrecision(
- currencyPluralPatternForOther, status);
- patternUsed = ¤cyPluralPatternForOther;
-
- } else {
- patternUsed = pattern;
- }
-
- if (patternUsed->indexOf(kCurrencySign) != -1) {
- // initialize for currency, not only for plural format,
- // but also for mix parsing
- handleCurrencySignInPattern(status);
- }
-}
-
-void
-DecimalFormat::handleCurrencySignInPattern(UErrorCode& status) {
- // initialize for currency, not only for plural format,
- // but also for mix parsing
- if (U_FAILURE(status)) {
- return;
- }
- if (fCurrencyPluralInfo == NULL) {
- fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status);
- if (U_FAILURE(status)) {
- return;
- }
- }
- // need it for mix parsing
- if (fAffixPatternsForCurrency == NULL) {
- setupCurrencyAffixPatterns(status);
- }
-}
-
-static void
-applyPatternWithNoSideEffects(
- const UnicodeString& pattern,
- UParseError& parseError,
- UnicodeString &negPrefix,
- UnicodeString &negSuffix,
- UnicodeString &posPrefix,
- UnicodeString &posSuffix,
- UErrorCode& status) {
- if (U_FAILURE(status))
- {
- return;
- }
- DecimalFormatPatternParser patternParser;
- DecimalFormatPattern out;
- patternParser.applyPatternWithoutExpandAffix(
- pattern,
- out,
- parseError,
- status);
- if (U_FAILURE(status)) {
- return;
- }
- negPrefix = out.fNegPrefixPattern;
- negSuffix = out.fNegSuffixPattern;
- posPrefix = out.fPosPrefixPattern;
- posSuffix = out.fPosSuffixPattern;
-}
-
-void
-DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- UParseError parseErr;
- fAffixPatternsForCurrency = initHashForAffixPattern(status);
- if (U_FAILURE(status)) {
- return;
- }
-
- NumberingSystem *ns = NumberingSystem::createInstance(fImpl->fSymbols->getLocale(),status);
- if (U_FAILURE(status)) {
- return;
- }
-
- // Save the default currency patterns of this locale.
- // Here, chose onlyApplyPatternWithoutExpandAffix without
- // expanding the affix patterns into affixes.
- UnicodeString currencyPattern;
- UErrorCode error = U_ZERO_ERROR;
-
- UResourceBundle *resource = ures_open(NULL, fImpl->fSymbols->getLocale().getName(), &error);
- UResourceBundle *numElements = ures_getByKeyWithFallback(resource, fgNumberElements, NULL, &error);
- resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &error);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
- int32_t patLen = 0;
- const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
- if ( error == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),fgLatn)) {
- error = U_ZERO_ERROR;
- resource = ures_getByKeyWithFallback(numElements, fgLatn, resource, &error);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
- patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
- }
- ures_close(numElements);
- ures_close(resource);
- delete ns;
-
- if (U_SUCCESS(error)) {
- UnicodeString negPrefix;
- UnicodeString negSuffix;
- UnicodeString posPrefix;
- UnicodeString posSuffix;
- applyPatternWithNoSideEffects(UnicodeString(patResStr, patLen),
- parseErr,
- negPrefix, negSuffix, posPrefix, posSuffix, status);
- AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
- negPrefix,
- negSuffix,
- posPrefix,
- posSuffix,
- UCURR_SYMBOL_NAME);
- fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status);
- }
-
- // save the unique currency plural patterns of this locale.
- Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern;
- const UHashElement* element = NULL;
- int32_t pos = UHASH_FIRST;
- Hashtable pluralPatternSet;
- while ((element = pluralPtn->nextElement(pos)) != NULL) {
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- if (pluralPatternSet.geti(*value) != 1) {
- UnicodeString negPrefix;
- UnicodeString negSuffix;
- UnicodeString posPrefix;
- UnicodeString posSuffix;
- pluralPatternSet.puti(*value, 1, status);
- applyPatternWithNoSideEffects(
- *value, parseErr,
- negPrefix, negSuffix, posPrefix, posSuffix, status);
- AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
- negPrefix,
- negSuffix,
- posPrefix,
- posSuffix,
- UCURR_LONG_NAME);
- fAffixPatternsForCurrency->put(*key, affixPtn, status);
- }
- }
-}
-
-
-//------------------------------------------------------------------------------
-
-DecimalFormat::~DecimalFormat()
-{
- deleteHashForAffixPattern();
- delete fCurrencyPluralInfo;
- delete fImpl;
-}
-
-//------------------------------------------------------------------------------
-// copy constructor
-
-DecimalFormat::DecimalFormat(const DecimalFormat &source) :
- NumberFormat(source) {
- init();
- *this = source;
-}
-
-//------------------------------------------------------------------------------
-// assignment operator
-
-template <class T>
-static void _clone_ptr(T** pdest, const T* source) {
- delete *pdest;
- if (source == NULL) {
- *pdest = NULL;
- } else {
- *pdest = static_cast<T*>(source->clone());
- }
-}
-
-DecimalFormat&
-DecimalFormat::operator=(const DecimalFormat& rhs)
-{
- if(this != &rhs) {
- UErrorCode status = U_ZERO_ERROR;
- NumberFormat::operator=(rhs);
- if (fImpl == NULL) {
- fImpl = new DecimalFormatImpl(this, *rhs.fImpl, status);
- } else {
- fImpl->assign(*rhs.fImpl, status);
- }
- fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
- fStyle = rhs.fStyle;
- _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo);
- deleteHashForAffixPattern();
- if (rhs.fAffixPatternsForCurrency) {
- UErrorCode status = U_ZERO_ERROR;
- fAffixPatternsForCurrency = initHashForAffixPattern(status);
- copyHashForAffixPattern(rhs.fAffixPatternsForCurrency,
- fAffixPatternsForCurrency, status);
- }
- }
-
- return *this;
-}
-
-//------------------------------------------------------------------------------
-
-UBool
-DecimalFormat::operator==(const Format& that) const
-{
- if (this == &that)
- return TRUE;
-
- // NumberFormat::operator== guarantees this cast is safe
- const DecimalFormat* other = (DecimalFormat*)&that;
-
- return (
- NumberFormat::operator==(that) &&
- fBoolFlags.getAll() == other->fBoolFlags.getAll() &&
- *fImpl == *other->fImpl);
-
-}
-
-//------------------------------------------------------------------------------
-
-Format*
-DecimalFormat::clone() const
-{
- return new DecimalFormat(*this);
-}
-
-
-FixedDecimal
-DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- if (U_FAILURE(status)) {
- return FixedDecimal();
- }
- return FixedDecimal(digits.getMantissa());
-}
-
-VisibleDigitsWithExponent &
-DecimalFormat::initVisibleDigitsWithExponent(
- double number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- return fImpl->initVisibleDigitsWithExponent(number, digits, status);
-}
-
-FixedDecimal
-DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- if (U_FAILURE(status)) {
- return FixedDecimal();
- }
- return FixedDecimal(digits.getMantissa());
-}
-
-VisibleDigitsWithExponent &
-DecimalFormat::initVisibleDigitsWithExponent(
- const Formattable &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return digits;
- }
- if (!number.isNumeric()) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return digits;
- }
-
- DigitList *dl = number.getDigitList();
- if (dl != NULL) {
- DigitList dlCopy(*dl);
- return fImpl->initVisibleDigitsWithExponent(
- dlCopy, digits, status);
- }
-
- Formattable::Type type = number.getType();
- if (type == Formattable::kDouble || type == Formattable::kLong) {
- return fImpl->initVisibleDigitsWithExponent(
- number.getDouble(status), digits, status);
- }
- return fImpl->initVisibleDigitsWithExponent(
- number.getInt64(), digits, status);
-}
-
-
-// Create a fixed decimal from a DigitList.
-// The digit list may be modified.
-// Internal function only.
-FixedDecimal
-DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- if (U_FAILURE(status)) {
- return FixedDecimal();
- }
- return FixedDecimal(digits.getMantissa());
-}
-
-VisibleDigitsWithExponent &
-DecimalFormat::initVisibleDigitsWithExponent(
- DigitList &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- return fImpl->initVisibleDigitsWithExponent(
- number, digits, status);
-}
-
-
-//------------------------------------------------------------------------------
-
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR;
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, posIter, status);
-}
-
-
-//------------------------------------------------------------------------------
-
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR; /* ignored */
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, posIter, status);
-}
-
-//------------------------------------------------------------------------------
-
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR; /* ignored */
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
-
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, posIter, status);
-}
-
-//------------------------------------------------------------------------------
-
-
-UnicodeString&
-DecimalFormat::format(StringPiece number,
- UnicodeString &toAppendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const
-{
- return fImpl->format(number, toAppendTo, posIter, status);
-}
-
-
-UnicodeString&
-DecimalFormat::format(const DigitList &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, posIter, status);
-}
-
-
-UnicodeString&
-DecimalFormat::format(const DigitList &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, pos, status);
-}
-
-UnicodeString&
-DecimalFormat::format(const VisibleDigitsWithExponent &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, posIter, status);
-}
-
-
-UnicodeString&
-DecimalFormat::format(const VisibleDigitsWithExponent &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, pos, status);
-}
-
-DigitList&
-DecimalFormat::_round(const DigitList& number, DigitList& adjustedNum, UBool& isNegative, UErrorCode& status) const {
- adjustedNum = number;
- fImpl->round(adjustedNum, status);
- isNegative = !adjustedNum.isPositive();
- return adjustedNum;
-}
-
-void
-DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- ParsePosition& parsePosition) const {
- parse(text, result, parsePosition, NULL);
-}
-
-CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text,
- ParsePosition& pos) const {
- Formattable parseResult;
- int32_t start = pos.getIndex();
- UChar curbuf[4] = {};
- parse(text, parseResult, pos, curbuf);
- if (pos.getIndex() != start) {
- UErrorCode ec = U_ZERO_ERROR;
- LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec), ec);
- if (U_FAILURE(ec)) {
- pos.setIndex(start); // indicate failure
- } else {
- return currAmt.orphan();
- }
- }
- return NULL;
-}
-
-/**
- * Parses the given text as a number, optionally providing a currency amount.
- * @param text the string to parse
- * @param result output parameter for the numeric result.
- * @param parsePosition input-output position; on input, the
- * position within text to match; must have 0 <= pos.getIndex() <
- * text.length(); on output, the position after the last matched
- * character. If the parse fails, the position in unchanged upon
- * output.
- * @param currency if non-NULL, it should point to a 4-UChar buffer.
- * In this case the text is parsed as a currency format, and the
- * ISO 4217 code for the parsed currency is put into the buffer.
- * Otherwise the text is parsed as a non-currency format.
- */
-void DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- ParsePosition& parsePosition,
- UChar* currency) const {
- int32_t startIdx, backup;
- int32_t i = startIdx = backup = parsePosition.getIndex();
-
- // clear any old contents in the result. In particular, clears any DigitList
- // that it may be holding.
- result.setLong(0);
- if (currency != NULL) {
- for (int32_t ci=0; ci<4; ci++) {
- currency[ci] = 0;
- }
- }
-
- // Handle NaN as a special case:
- int32_t formatWidth = fImpl->getOldFormatWidth();
-
- // Skip padding characters, if around prefix
- if (formatWidth > 0 && (
- fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix ||
- fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix)) {
- i = skipPadding(text, i);
- }
-
- if (isLenient()) {
- // skip any leading whitespace
- i = backup = skipUWhiteSpace(text, i);
- }
-
- // If the text is composed of the representation of NaN, returns NaN.length
- const UnicodeString *nan = &fImpl->getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
- int32_t nanLen = (text.compare(i, nan->length(), *nan)
- ? 0 : nan->length());
- if (nanLen) {
- i += nanLen;
- if (formatWidth > 0 && (fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix || fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix)) {
- i = skipPadding(text, i);
- }
- parsePosition.setIndex(i);
- result.setDouble(uprv_getNaN());
- return;
- }
-
- // NaN parse failed; start over
- i = backup;
- parsePosition.setIndex(i);
-
- // status is used to record whether a number is infinite.
- UBool status[fgStatusLength];
-
- DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
- if (digits == NULL) {
- return; // no way to report error from here.
- }
-
- if (fImpl->fMonetary) {
- if (!parseForCurrency(text, parsePosition, *digits,
- status, currency)) {
- return;
- }
- } else {
- if (!subparse(text,
- &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(),
- FALSE, UCURR_SYMBOL_NAME,
- parsePosition, *digits, status, currency)) {
- debug("!subparse(...) - rewind");
- parsePosition.setIndex(startIdx);
- return;
- }
- }
-
- // Handle infinity
- if (status[fgStatusInfinite]) {
- double inf = uprv_getInfinity();
- result.setDouble(digits->isPositive() ? inf : -inf);
- // TODO: set the dl to infinity, and let it fall into the code below.
- }
-
- else {
-
- if (!fImpl->fMultiplier.isZero()) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->div(fImpl->fMultiplier, ec);
- }
-
- if (fImpl->fScale != 0) {
- DigitList ten;
- ten.set((int32_t)10);
- if (fImpl->fScale > 0) {
- for (int32_t i = fImpl->fScale; i > 0; i--) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->div(ten,ec);
- }
- } else {
- for (int32_t i = fImpl->fScale; i < 0; i++) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->mult(ten,ec);
- }
- }
- }
-
- // Negative zero special case:
- // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
- // if not parsing integerOnly, leave as -0, which a double can represent.
- if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) {
- digits->setPositive(TRUE);
- }
- result.adoptDigitList(digits);
- }
-}
-
-
-
-UBool
-DecimalFormat::parseForCurrency(const UnicodeString& text,
- ParsePosition& parsePosition,
- DigitList& digits,
- UBool* status,
- UChar* currency) const {
- UnicodeString positivePrefix;
- UnicodeString positiveSuffix;
- UnicodeString negativePrefix;
- UnicodeString negativeSuffix;
- fImpl->fPositivePrefixPattern.toString(positivePrefix);
- fImpl->fPositiveSuffixPattern.toString(positiveSuffix);
- fImpl->fNegativePrefixPattern.toString(negativePrefix);
- fImpl->fNegativeSuffixPattern.toString(negativeSuffix);
-
- int origPos = parsePosition.getIndex();
- int maxPosIndex = origPos;
- int maxErrorPos = -1;
- // First, parse against current pattern.
- // Since current pattern could be set by applyPattern(),
- // it could be an arbitrary pattern, and it may not be the one
- // defined in current locale.
- UBool tmpStatus[fgStatusLength];
- ParsePosition tmpPos(origPos);
- DigitList tmpDigitList;
- UBool found;
- if (fStyle == UNUM_CURRENCY_PLURAL) {
- found = subparse(text,
- &negativePrefix, &negativeSuffix,
- &positivePrefix, &positiveSuffix,
- TRUE, UCURR_LONG_NAME,
- tmpPos, tmpDigitList, tmpStatus, currency);
- } else {
- found = subparse(text,
- &negativePrefix, &negativeSuffix,
- &positivePrefix, &positiveSuffix,
- TRUE, UCURR_SYMBOL_NAME,
- tmpPos, tmpDigitList, tmpStatus, currency);
- }
- if (found) {
- if (tmpPos.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus[i];
- }
- digits = tmpDigitList;
- }
- } else {
- maxErrorPos = tmpPos.getErrorIndex();
- }
- // Then, parse against affix patterns.
- // Those are currency patterns and currency plural patterns.
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer;
- UBool tmpStatus[fgStatusLength];
- ParsePosition tmpPos(origPos);
- DigitList tmpDigitList;
-
-#ifdef FMT_DEBUG
- debug("trying affix for currency..");
- affixPtn->dump();
-#endif
-
- UBool result = subparse(text,
- &affixPtn->negPrefixPatternForCurrency,
- &affixPtn->negSuffixPatternForCurrency,
- &affixPtn->posPrefixPatternForCurrency,
- &affixPtn->posSuffixPatternForCurrency,
- TRUE, affixPtn->patternType,
- tmpPos, tmpDigitList, tmpStatus, currency);
- if (result) {
- found = true;
- if (tmpPos.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus[i];
- }
- digits = tmpDigitList;
- }
- } else {
- maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
- tmpPos.getErrorIndex() : maxErrorPos;
- }
- }
- // Finally, parse against simple affix to find the match.
- // For example, in TestMonster suite,
- // if the to-be-parsed text is "-\u00A40,00".
- // complexAffixCompare will not find match,
- // since there is no ISO code matches "\u00A4",
- // and the parse stops at "\u00A4".
- // We will just use simple affix comparison (look for exact match)
- // to pass it.
- //
- // TODO: We should parse against simple affix first when
- // output currency is not requested. After the complex currency
- // parsing implementation was introduced, the default currency
- // instance parsing slowed down because of the new code flow.
- // I filed #10312 - Yoshito
- UBool tmpStatus_2[fgStatusLength];
- ParsePosition tmpPos_2(origPos);
- DigitList tmpDigitList_2;
-
- // Disable complex currency parsing and try it again.
- UBool result = subparse(text,
- &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(),
- FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME,
- tmpPos_2, tmpDigitList_2, tmpStatus_2,
- currency);
- if (result) {
- if (tmpPos_2.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos_2.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus_2[i];
- }
- digits = tmpDigitList_2;
- }
- found = true;
- } else {
- maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ?
- tmpPos_2.getErrorIndex() : maxErrorPos;
- }
-
- if (!found) {
- //parsePosition.setIndex(origPos);
- parsePosition.setErrorIndex(maxErrorPos);
- } else {
- parsePosition.setIndex(maxPosIndex);
- parsePosition.setErrorIndex(-1);
- }
- return found;
-}
-
-
-/**
- * Parse the given text into a number. The text is parsed beginning at
- * parsePosition, until an unparseable character is seen.
- * @param text the string to parse.
- * @param negPrefix negative prefix.
- * @param negSuffix negative suffix.
- * @param posPrefix positive prefix.
- * @param posSuffix positive suffix.
- * @param complexCurrencyParsing whether it is complex currency parsing or not.
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param parsePosition The position at which to being parsing. Upon
- * return, the first unparsed character.
- * @param digits the DigitList to set to the parsed value.
- * @param status output param containing boolean status flags indicating
- * whether the value was infinite and whether it was positive.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or NULL for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- */
-UBool DecimalFormat::subparse(const UnicodeString& text,
- const UnicodeString* negPrefix,
- const UnicodeString* negSuffix,
- const UnicodeString* posPrefix,
- const UnicodeString* posSuffix,
- UBool complexCurrencyParsing,
- int8_t type,
- ParsePosition& parsePosition,
- DigitList& digits, UBool* status,
- UChar* currency) const
-{
- // The parsing process builds up the number as char string, in the neutral format that
- // will be acceptable to the decNumber library, then at the end passes that string
- // off for conversion to a decNumber.
- UErrorCode err = U_ZERO_ERROR;
- CharString parsedNum;
- digits.setToZero();
-
- int32_t position = parsePosition.getIndex();
- int32_t oldStart = position;
- int32_t textLength = text.length(); // One less pointer to follow
- UBool strictParse = !isLenient();
- UChar32 zero = fImpl->getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- const UnicodeString *groupingString = &fImpl->getConstSymbol(
- !fImpl->fMonetary ?
- DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
- UChar32 groupingChar = groupingString->char32At(0);
- int32_t groupingStringLength = groupingString->length();
- int32_t groupingCharLength = U16_LENGTH(groupingChar);
- UBool groupingUsed = isGroupingUsed();
-#ifdef FMT_DEBUG
- UChar dbgbuf[300];
- UnicodeString s(dbgbuf,0,300);;
- s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " );
-#define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); }
- DBGAPPD(negPrefix);
- DBGAPPD(negSuffix);
- DBGAPPD(posPrefix);
- DBGAPPD(posSuffix);
- debugout(s);
-#endif
-
- UBool fastParseOk = false; /* TRUE iff fast parse is OK */
- // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
- if((fImpl->isParseFastpath()) && !fImpl->fMonetary &&
- text.length()>0 &&
- text.length()<32 &&
- (posPrefix==NULL||posPrefix->isEmpty()) &&
- (posSuffix==NULL||posSuffix->isEmpty()) &&
- // (negPrefix==NULL||negPrefix->isEmpty()) &&
- // (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
- TRUE) { // optimized path
- int j=position;
- int l=text.length();
- int digitCount=0;
- UChar32 ch = text.char32At(j);
- const UnicodeString *decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- UChar32 decimalChar = 0;
- UBool intOnly = FALSE;
- UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0;
-
- int32_t decimalCount = decimalString->countChar32(0,3);
- if(isParseIntegerOnly()) {
- decimalChar = 0; // not allowed
- intOnly = TRUE; // Don't look for decimals.
- } else if(decimalCount==1) {
- decimalChar = decimalString->char32At(0); // Look for this decimal
- } else if(decimalCount==0) {
- decimalChar=0; // NO decimal set
- } else {
- j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation.
- }
-
-#ifdef FMT_DEBUG
- printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n",
- decimalChar, groupingChar, ch,
- (intOnly)?'y':'n',
- (strictParse)?'y':'n');
-#endif
- if(ch==0x002D) { // '-'
- j=l+1;//=break - negative number.
-
- /*
- parsedNum.append('-',err);
- j+=U16_LENGTH(ch);
- if(j<l) ch = text.char32At(j);
- */
- } else {
- parsedNum.append('+',err);
- }
- while(j<l) {
- int32_t digit = ch - zero;
- if(digit >=0 && digit <= 9) {
- parsedNum.append((char)(digit + '0'), err);
- if((digitCount>0) || digit!=0 || j==(l-1)) {
- digitCount++;
- }
- } else if(ch == 0) { // break out
- digitCount=-1;
- break;
- } else if(ch == decimalChar) {
- parsedNum.append((char)('.'), err);
- decimalChar=0; // no more decimals.
- // fastParseHadDecimal=TRUE;
- } else if(ch == lookForGroup) {
- // ignore grouping char. No decimals, so it has to be an ignorable grouping sep
- } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) {
- // parsing integer only and can fall through
- } else {
- digitCount=-1; // fail - fall through to slow parse
- break;
- }
- j+=U16_LENGTH(ch);
- ch = text.char32At(j); // for next
- }
- if(
- ((j==l)||intOnly) // end OR only parsing integer
- && (digitCount>0)) { // and have at least one digit
- fastParseOk=true; // Fast parse OK!
-
-#ifdef SKIP_OPT
- debug("SKIP_OPT");
- /* for testing, try it the slow way. also */
- fastParseOk=false;
- parsedNum.clear();
-#else
- parsePosition.setIndex(position=j);
- status[fgStatusInfinite]=false;
-#endif
- } else {
- // was not OK. reset, retry
-#ifdef FMT_DEBUG
- printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount);
-#endif
- parsedNum.clear();
- }
- } else {
-#ifdef FMT_DEBUG
- printf("Could not fastpath parse. ");
- printf("text.length()=%d ", text.length());
- printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
-
- printf("\n");
-#endif
- }
-
- UnicodeString formatPattern;
- toPattern(formatPattern);
-
- if(!fastParseOk
-#if UCONFIG_HAVE_PARSEALLINPUT
- && fParseAllInput!=UNUM_YES
-#endif
- )
- {
- int32_t formatWidth = fImpl->getOldFormatWidth();
- // Match padding before prefix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) {
- position = skipPadding(text, position);
- }
-
- // Match positive and negative prefixes; prefer longest match.
- int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency);
- int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency);
- if (posMatch >= 0 && negMatch >= 0) {
- if (posMatch > negMatch) {
- negMatch = -1;
- } else if (negMatch > posMatch) {
- posMatch = -1;
- }
- }
- if (posMatch >= 0) {
- position += posMatch;
- parsedNum.append('+', err);
- } else if (negMatch >= 0) {
- position += negMatch;
- parsedNum.append('-', err);
- } else if (strictParse){
- parsePosition.setErrorIndex(position);
- return FALSE;
- } else {
- // Temporary set positive. This might be changed after checking suffix
- parsedNum.append('+', err);
- }
-
- // Match padding before prefix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) {
- position = skipPadding(text, position);
- }
-
- if (! strictParse) {
- position = skipUWhiteSpace(text, position);
- }
-
- // process digits or Inf, find decimal position
- const UnicodeString *inf = &fImpl->getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
- int32_t infLen = (text.compare(position, inf->length(), *inf)
- ? 0 : inf->length());
- position += infLen; // infLen is non-zero when it does equal to infinity
- status[fgStatusInfinite] = infLen != 0;
-
- if (infLen != 0) {
- parsedNum.append("Infinity", err);
- } else {
- // We now have a string of digits, possibly with grouping symbols,
- // and decimal points. We want to process these into a DigitList.
- // We don't want to put a bunch of leading zeros into the DigitList
- // though, so we keep track of the location of the decimal point,
- // put only significant digits into the DigitList, and adjust the
- // exponent as needed.
-
-
- UBool strictFail = FALSE; // did we exit with a strict parse failure?
- int32_t lastGroup = -1; // after which digit index did we last see a grouping separator?
- int32_t currGroup = -1; // for temporary storage the digit index of the current grouping separator
- int32_t gs2 = fImpl->fEffGrouping.fGrouping2 == 0 ? fImpl->fEffGrouping.fGrouping : fImpl->fEffGrouping.fGrouping2;
-
- const UnicodeString *decimalString;
- if (fImpl->fMonetary) {
- decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
- } else {
- decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- }
- UChar32 decimalChar = decimalString->char32At(0);
- int32_t decimalStringLength = decimalString->length();
- int32_t decimalCharLength = U16_LENGTH(decimalChar);
-
- UBool sawDecimal = FALSE;
- UChar32 sawDecimalChar = 0xFFFF;
- UBool sawGrouping = FALSE;
- UChar32 sawGroupingChar = 0xFFFF;
- UBool sawDigit = FALSE;
- int32_t backup = -1;
- int32_t digit;
-
- // equivalent grouping and decimal support
- const UnicodeSet *decimalSet = NULL;
- const UnicodeSet *groupingSet = NULL;
-
- if (decimalCharLength == decimalStringLength) {
- decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse);
- }
-
- if (groupingCharLength == groupingStringLength) {
- if (strictParse) {
- groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
- } else {
- groupingSet = fStaticSets->fDefaultGroupingSeparators;
- }
- }
-
- // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized.
- // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet
- // If a character matches decimalSet, don't consider it to be a member of the groupingSet.
-
- // We have to track digitCount ourselves, because digits.fCount will
- // pin when the maximum allowable digits is reached.
- int32_t digitCount = 0;
- int32_t integerDigitCount = 0;
-
- for (; position < textLength; )
- {
- UChar32 ch = text.char32At(position);
-
- /* We recognize all digit ranges, not only the Latin digit range
- * '0'..'9'. We do so by using the Character.digit() method,
- * which converts a valid Unicode digit to the range 0..9.
- *
- * The character 'ch' may be a digit. If so, place its value
- * from 0 to 9 in 'digit'. First try using the locale digit,
- * which may or MAY NOT be a standard Unicode digit range. If
- * this fails, try using the standard Unicode digit ranges by
- * calling Character.digit(). If this also fails, digit will
- * have a value outside the range 0..9.
- */
- digit = ch - zero;
- if (digit < 0 || digit > 9)
- {
- digit = u_charDigitValue(ch);
- }
-
- // As a last resort, look through the localized digits if the zero digit
- // is not a "standard" Unicode digit.
- if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) {
- digit = 0;
- if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kZeroDigitSymbol)).char32At(0) == ch ) {
- break;
- }
- for (digit = 1 ; digit < 10 ; digit++ ) {
- if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) {
- break;
- }
- }
- }
-
- if (digit >= 0 && digit <= 9)
- {
- if (strictParse && backup != -1) {
- // comma followed by digit, so group before comma is a
- // secondary group. If there was a group separator
- // before that, the group must == the secondary group
- // length, else it can be <= the the secondary group
- // length.
- if ((lastGroup != -1 && currGroup - lastGroup != gs2) ||
- (lastGroup == -1 && digitCount - 1 > gs2)) {
- strictFail = TRUE;
- break;
- }
-
- lastGroup = currGroup;
- }
-
- // Cancel out backup setting (see grouping handler below)
- currGroup = -1;
- backup = -1;
- sawDigit = TRUE;
-
- // Note: this will append leading zeros
- parsedNum.append((char)(digit + '0'), err);
-
- // count any digit that's not a leading zero
- if (digit > 0 || digitCount > 0 || sawDecimal) {
- digitCount += 1;
-
- // count any integer digit that's not a leading zero
- if (! sawDecimal) {
- integerDigitCount += 1;
- }
- }
-
- position += U16_LENGTH(ch);
- }
- else if (groupingStringLength > 0 &&
- matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet,
- decimalChar, decimalSet,
- ch) && groupingUsed)
- {
- if (sawDecimal) {
- break;
- }
-
- if (strictParse) {
- if ((!sawDigit || backup != -1)) {
- // leading group, or two group separators in a row
- strictFail = TRUE;
- break;
- }
- }
-
- // Ignore grouping characters, if we are using them, but require
- // that they be followed by a digit. Otherwise we backup and
- // reprocess them.
- currGroup = digitCount;
- backup = position;
- position += groupingStringLength;
- sawGrouping=TRUE;
- // Once we see a grouping character, we only accept that grouping character from then on.
- sawGroupingChar=ch;
- }
- else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch))
- {
- if (strictParse) {
- if (backup != -1 ||
- (lastGroup != -1 && digitCount - lastGroup != fImpl->fEffGrouping.fGrouping)) {
- strictFail = TRUE;
- break;
- }
- }
-
- // If we're only parsing integers, or if we ALREADY saw the
- // decimal, then don't parse this one.
- if (isParseIntegerOnly() || sawDecimal) {
- break;
- }
-
- parsedNum.append('.', err);
- position += decimalStringLength;
- sawDecimal = TRUE;
- // Once we see a decimal character, we only accept that decimal character from then on.
- sawDecimalChar=ch;
- // decimalSet is considered to consist of (ch,ch)
- }
- else {
-
- if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
- isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
- const UnicodeString *tmp;
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
- // TODO: CASE
- if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
- {
- // Parse sign, if present
- int32_t pos = position + tmp->length();
- char exponentSign = '+';
-
- if (pos < textLength)
- {
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- pos += tmp->length();
- }
- else {
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- exponentSign = '-';
- pos += tmp->length();
- }
- }
- }
-
- UBool sawExponentDigit = FALSE;
- while (pos < textLength) {
- ch = text.char32At(pos);
- digit = ch - zero;
-
- if (digit < 0 || digit > 9) {
- digit = u_charDigitValue(ch);
- }
- if (0 <= digit && digit <= 9) {
- if (!sawExponentDigit) {
- parsedNum.append('E', err);
- parsedNum.append(exponentSign, err);
- sawExponentDigit = TRUE;
- }
- pos += U16_LENGTH(ch);
- parsedNum.append((char)(digit + '0'), err);
- } else {
- break;
- }
- }
-
- if (sawExponentDigit) {
- position = pos; // Advance past the exponent
- }
-
- break; // Whether we fail or succeed, we exit this loop
- } else {
- break;
- }
- } else { // not parsing exponent
- break;
- }
- }
- }
-
- // if we didn't see a decimal and it is required, check to see if the pattern had one
- if(!sawDecimal && isDecimalPatternMatchRequired())
- {
- if(formatPattern.indexOf(kPatternDecimalSeparator) != -1)
- {
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("decimal point match required fail!");
- return FALSE;
- }
- }
-
- if (backup != -1)
- {
- position = backup;
- }
-
- if (strictParse && !sawDecimal) {
- if (lastGroup != -1 && digitCount - lastGroup != fImpl->fEffGrouping.fGrouping) {
- strictFail = TRUE;
- }
- }
-
- if (strictFail) {
- // only set with strictParse and a grouping separator error
-
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("strictFail!");
- return FALSE;
- }
-
- // If there was no decimal point we have an integer
-
- // If none of the text string was recognized. For example, parse
- // "x" with pattern "#0.00" (return index and error index both 0)
- // parse "$" with pattern "$#0.00". (return index 0 and error index
- // 1).
- if (!sawDigit && digitCount == 0) {
-#ifdef FMT_DEBUG
- debug("none of text rec");
- printf("position=%d\n",position);
-#endif
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(oldStart);
- return FALSE;
- }
- }
-
- // Match padding before suffix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) {
- position = skipPadding(text, position);
- }
-
- int32_t posSuffixMatch = -1, negSuffixMatch = -1;
-
- // Match positive and negative suffixes; prefer longest match.
- if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
- posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency);
- }
- if (negMatch >= 0) {
- negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency);
- }
- if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
- if (posSuffixMatch > negSuffixMatch) {
- negSuffixMatch = -1;
- } else if (negSuffixMatch > posSuffixMatch) {
- posSuffixMatch = -1;
- }
- }
-
- // Fail if neither or both
- if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
- parsePosition.setErrorIndex(position);
- debug("neither or both");
- return FALSE;
- }
-
- position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0));
-
- // Match padding before suffix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) {
- position = skipPadding(text, position);
- }
-
- parsePosition.setIndex(position);
-
- parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
-#ifdef FMT_DEBUG
-printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err));
-#endif
- } /* end SLOW parse */
- if(parsePosition.getIndex() == oldStart)
- {
-#ifdef FMT_DEBUG
- printf(" PP didnt move, err\n");
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-#if UCONFIG_HAVE_PARSEALLINPUT
- else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength)
- {
-#ifdef FMT_DEBUG
- printf(" PP didnt consume all (UNUM_YES), err\n");
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-#endif
- // uint32_t bits = (fastParseOk?kFastpathOk:0) |
- // (fastParseHadDecimal?0:kNoDecimal);
- //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
- digits.set(parsedNum.toStringPiece(),
- err,
- 0//bits
- );
-
- if (U_FAILURE(err)) {
-#ifdef FMT_DEBUG
- printf(" err setting %s\n", u_errorName(err));
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-
- // check if we missed a required decimal point
- if(fastParseOk && isDecimalPatternMatchRequired())
- {
- if(formatPattern.indexOf(kPatternDecimalSeparator) != -1)
- {
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("decimal point match required fail!");
- return FALSE;
- }
- }
-
-
- return TRUE;
-}
-
-/**
- * Starting at position, advance past a run of pad characters, if any.
- * Return the index of the first character after position that is not a pad
- * character. Result is >= position.
- */
-int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const {
- int32_t padLen = U16_LENGTH(fImpl->fAffixes.fPadChar);
- while (position < text.length() &&
- text.char32At(position) == fImpl->fAffixes.fPadChar) {
- position += padLen;
- }
- return position;
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * Runs of white space in the affix, match runs of white space in
- * the input. Pattern white space and input white space are
- * determined differently; see code.
- * @param text input text
- * @param pos offset into input at which to begin matching
- * @param isNegative
- * @param isPrefix
- * @param affixPat affix pattern used for currency affix comparison.
- * @param complexCurrencyParsing whether it is currency parsing or not
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or null for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareAffix(const UnicodeString& text,
- int32_t pos,
- UBool isNegative,
- UBool isPrefix,
- const UnicodeString* affixPat,
- UBool complexCurrencyParsing,
- int8_t type,
- UChar* currency) const
-{
- const UnicodeString *patternToCompare;
- if (currency != NULL ||
- (fImpl->fMonetary && complexCurrencyParsing)) {
-
- if (affixPat != NULL) {
- return compareComplexAffix(*affixPat, text, pos, type, currency);
- }
- }
-
- if (isNegative) {
- if (isPrefix) {
- patternToCompare = &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString();
- }
- else {
- patternToCompare = &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString();
- }
- }
- else {
- if (isPrefix) {
- patternToCompare = &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString();
- }
- else {
- patternToCompare = &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString();
- }
- }
- return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
-}
-
-UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const {
- if (lhs == rhs) {
- return TRUE;
- }
- U_ASSERT(fStaticSets != NULL); // should already be loaded
- const UnicodeSet *minusSigns = fStaticSets->fMinusSigns;
- const UnicodeSet *plusSigns = fStaticSets->fPlusSigns;
- return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) ||
- (plusSigns->contains(lhs) && plusSigns->contains(rhs));
-}
-
-// check for LRM 0x200E, RLM 0x200F, ALM 0x061C
-#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
-
-#define TRIM_BUFLEN 32
-UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) {
- UChar trimBuf[TRIM_BUFLEN];
- int32_t affixLen = affix.length();
- int32_t affixPos, trimLen = 0;
-
- for (affixPos = 0; affixPos < affixLen; affixPos++) {
- UChar c = affix.charAt(affixPos);
- if (!IS_BIDI_MARK(c)) {
- if (trimLen < TRIM_BUFLEN) {
- trimBuf[trimLen++] = c;
- } else {
- trimLen = 0;
- break;
- }
- }
- }
- return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix);
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * Runs of white space in the affix, match runs of white space in
- * the input. Pattern white space and input white space are
- * determined differently; see code.
- * @param affix pattern string, taken as a literal
- * @param input input text
- * @param pos offset into input at which to begin matching
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
- const UnicodeString& input,
- int32_t pos,
- UBool lenient) const {
- int32_t start = pos;
- UnicodeString trimmedAffix;
- // For more efficiency we should keep lazily-created trimmed affixes around in
- // instance variables instead of trimming each time they are used (the next step)
- trimMarksFromAffix(affix, trimmedAffix);
- UChar32 affixChar = trimmedAffix.char32At(0);
- int32_t affixLength = trimmedAffix.length();
- int32_t inputLength = input.length();
- int32_t affixCharLength = U16_LENGTH(affixChar);
- UnicodeSet *affixSet;
- UErrorCode status = U_ZERO_ERROR;
-
- U_ASSERT(fStaticSets != NULL); // should already be loaded
-
- if (U_FAILURE(status)) {
- return -1;
- }
- if (!lenient) {
- affixSet = fStaticSets->fStrictDashEquivalents;
-
- // If the trimmedAffix is exactly one character long and that character
- // is in the dash set and the very next input character is also
- // in the dash set, return a match.
- if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- UChar32 ic = input.char32At(pos);
- if (affixSet->contains(ic)) {
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos); // skip any trailing bidi marks
- return pos - start;
- }
- }
-
- for (int32_t i = 0; i < affixLength; ) {
- UChar32 c = trimmedAffix.char32At(i);
- int32_t len = U16_LENGTH(c);
- if (PatternProps::isWhiteSpace(c)) {
- // We may have a pattern like: \u200F \u0020
- // and input text like: \u200F \u0020
- // Note that U+200F and U+0020 are Pattern_White_Space but only
- // U+0020 is UWhiteSpace. So we have to first do a direct
- // match of the run of Pattern_White_Space in the pattern,
- // then match any extra characters.
- UBool literalMatch = FALSE;
- while (pos < inputLength) {
- UChar32 ic = input.char32At(pos);
- if (ic == c) {
- literalMatch = TRUE;
- i += len;
- pos += len;
- if (i == affixLength) {
- break;
- }
- c = trimmedAffix.char32At(i);
- len = U16_LENGTH(c);
- if (!PatternProps::isWhiteSpace(c)) {
- break;
- }
- } else if (IS_BIDI_MARK(ic)) {
- pos ++; // just skip over this input text
- } else {
- break;
- }
- }
-
- // Advance over run in pattern
- i = skipPatternWhiteSpace(trimmedAffix, i);
-
- // Advance over run in input text
- // Must see at least one white space char in input,
- // unless we've already matched some characters literally.
- int32_t s = pos;
- pos = skipUWhiteSpace(input, pos);
- if (pos == s && !literalMatch) {
- return -1;
- }
-
- // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
- // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
- // is also in the trimmedAffix.
- i = skipUWhiteSpace(trimmedAffix, i);
- } else {
- UBool match = FALSE;
- while (pos < inputLength) {
- UChar32 ic = input.char32At(pos);
- if (!match && ic == c) {
- i += len;
- pos += len;
- match = TRUE;
- } else if (IS_BIDI_MARK(ic)) {
- pos++; // just skip over this input text
- } else {
- break;
- }
- }
- if (!match) {
- return -1;
- }
- }
- }
- } else {
- UBool match = FALSE;
-
- affixSet = fStaticSets->fDashEquivalents;
-
- if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- pos = skipUWhiteSpaceAndMarks(input, pos);
- UChar32 ic = input.char32At(pos);
-
- if (affixSet->contains(ic)) {
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos);
- return pos - start;
- }
- }
-
- for (int32_t i = 0; i < affixLength; )
- {
- //i = skipRuleWhiteSpace(trimmedAffix, i);
- i = skipUWhiteSpace(trimmedAffix, i);
- pos = skipUWhiteSpaceAndMarks(input, pos);
-
- if (i >= affixLength || pos >= inputLength) {
- break;
- }
-
- UChar32 c = trimmedAffix.char32At(i);
- UChar32 ic = input.char32At(pos);
-
- if (!equalWithSignCompatibility(ic, c)) {
- return -1;
- }
-
- match = TRUE;
- i += U16_LENGTH(c);
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos);
- }
-
- if (affixLength > 0 && ! match) {
- return -1;
- }
- }
- return pos - start;
-}
-
-/**
- * Skip over a run of zero or more Pattern_White_Space characters at
- * pos in text.
- */
-int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) {
- const UChar* s = text.getBuffer();
- return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
-}
-
-/**
- * Skip over a run of zero or more isUWhiteSpace() characters at pos
- * in text.
- */
-int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
- while (pos < text.length()) {
- UChar32 c = text.char32At(pos);
- if (!u_isUWhiteSpace(c)) {
- break;
- }
- pos += U16_LENGTH(c);
- }
- return pos;
-}
-
-/**
- * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos
- * in text.
- */
-int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) {
- while (pos < text.length()) {
- UChar32 c = text.char32At(pos);
- if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM
- break;
- }
- pos += U16_LENGTH(c);
- }
- return pos;
-}
-
-/**
- * Skip over a run of zero or more bidi marks at pos in text.
- */
-int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) {
- while (pos < text.length()) {
- UChar c = text.charAt(pos);
- if (!IS_BIDI_MARK(c)) {
- break;
- }
- pos++;
- }
- return pos;
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * @param affixPat pattern string
- * @param input input text
- * @param pos offset into input at which to begin matching
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or null for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
- const UnicodeString& text,
- int32_t pos,
- int8_t type,
- UChar* currency) const
-{
- int32_t start = pos;
- U_ASSERT(currency != NULL || fImpl->fMonetary);
-
- for (int32_t i=0;
- i<affixPat.length() && pos >= 0; ) {
- UChar32 c = affixPat.char32At(i);
- i += U16_LENGTH(c);
-
- if (c == kQuote) {
- U_ASSERT(i <= affixPat.length());
- c = affixPat.char32At(i);
- i += U16_LENGTH(c);
-
- const UnicodeString* affix = NULL;
-
- switch (c) {
- case kCurrencySign: {
- // since the currency names in choice format is saved
- // the same way as other currency names,
- // do not need to do currency choice parsing here.
- // the general currency parsing parse against all names,
- // including names in choice format.
- UBool intl = i<affixPat.length() &&
- affixPat.char32At(i) == kCurrencySign;
- if (intl) {
- ++i;
- }
- UBool plural = i<affixPat.length() &&
- affixPat.char32At(i) == kCurrencySign;
- if (plural) {
- ++i;
- intl = FALSE;
- }
- // Parse generic currency -- anything for which we
- // have a display name, or any 3-letter ISO code.
- // Try to parse display name for our locale; first
- // determine our locale.
- const char* loc = fCurrencyPluralInfo->getLocale().getName();
- ParsePosition ppos(pos);
- int32_t currMatchLen = 0;
- UChar curr[4];
- UErrorCode ec = U_ZERO_ERROR;
- // Delegate parse of display name => ISO code to Currency
- uprv_parseCurrency(loc, text, ppos, type, &currMatchLen, curr, ec);
-
- // If parse succeeds, populate currency[0]
- if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
- if (currency) {
- u_strcpy(currency, curr);
- } else {
- // The formatter is currency-style but the client has not requested
- // the value of the parsed currency. In this case, if that value does
- // not match the formatter's current value, then the parse fails.
- UChar effectiveCurr[4];
- getEffectiveCurrency(effectiveCurr, ec);
- if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) {
- pos = -1;
- continue;
- }
- }
- pos = ppos.getIndex();
- } else if (!isLenient()){
- pos = -1;
- }
- continue;
- }
- case kPatternPercent:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
- break;
- case kPatternPerMill:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
- break;
- case kPatternPlus:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- break;
- case kPatternMinus:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- break;
- default:
- // fall through to affix!=0 test, which will fail
- break;
- }
-
- if (affix != NULL) {
- pos = match(text, pos, *affix);
- continue;
- }
- }
-
- pos = match(text, pos, c);
- if (PatternProps::isWhiteSpace(c)) {
- i = skipPatternWhiteSpace(affixPat, i);
- }
- }
- return pos - start;
-}
-
-/**
- * Match a single character at text[pos] and return the index of the
- * next character upon success. Return -1 on failure. If
- * ch is a Pattern_White_Space then match a run of white space in text.
- */
-int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) {
- if (PatternProps::isWhiteSpace(ch)) {
- // Advance over run of white space in input text
- // Must see at least one white space char in input
- int32_t s = pos;
- pos = skipPatternWhiteSpace(text, pos);
- if (pos == s) {
- return -1;
- }
- return pos;
- }
- return (pos >= 0 && text.char32At(pos) == ch) ?
- (pos + U16_LENGTH(ch)) : -1;
-}
-
-/**
- * Match a string at text[pos] and return the index of the next
- * character upon success. Return -1 on failure. Match a run of
- * white space in str with a run of white space in text.
- */
-int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) {
- for (int32_t i=0; i<str.length() && pos >= 0; ) {
- UChar32 ch = str.char32At(i);
- i += U16_LENGTH(ch);
- if (PatternProps::isWhiteSpace(ch)) {
- i = skipPatternWhiteSpace(str, i);
- }
- pos = match(text, pos, ch);
- }
- return pos;
-}
-
-UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol,
- UnicodeSet *sset, UChar32 schar)
-{
- if (sset != NULL) {
- return sset->contains(schar);
- }
-
- return text.compare(position, length, symbol) == 0;
-}
-
-UBool DecimalFormat::matchDecimal(UChar32 symbolChar,
- UBool sawDecimal, UChar32 sawDecimalChar,
- const UnicodeSet *sset, UChar32 schar) {
- if(sawDecimal) {
- return schar==sawDecimalChar;
- } else if(schar==symbolChar) {
- return TRUE;
- } else if(sset!=NULL) {
- return sset->contains(schar);
- } else {
- return FALSE;
- }
-}
-
-UBool DecimalFormat::matchGrouping(UChar32 groupingChar,
- UBool sawGrouping, UChar32 sawGroupingChar,
- const UnicodeSet *sset,
- UChar32 /*decimalChar*/, const UnicodeSet *decimalSet,
- UChar32 schar) {
- if(sawGrouping) {
- return schar==sawGroupingChar; // previously found
- } else if(schar==groupingChar) {
- return TRUE; // char from symbols
- } else if(sset!=NULL) {
- return sset->contains(schar) && // in groupingSet but...
- ((decimalSet==NULL) || !decimalSet->contains(schar)); // Exclude decimalSet from groupingSet
- } else {
- return FALSE;
- }
-}
-
-
-
-//------------------------------------------------------------------------------
-// Gets the pointer to the localized decimal format symbols
-
-const DecimalFormatSymbols*
-DecimalFormat::getDecimalFormatSymbols() const
-{
- return &fImpl->getDecimalFormatSymbols();
-}
-
-//------------------------------------------------------------------------------
-// De-owning the current localized symbols and adopt the new symbols.
-
-void
-DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
-{
- if (symbolsToAdopt == NULL) {
- return; // do not allow caller to set fSymbols to NULL
- }
- fImpl->adoptDecimalFormatSymbols(symbolsToAdopt);
-}
-//------------------------------------------------------------------------------
-// Setting the symbols is equlivalent to adopting a newly created localized
-// symbols.
-
-void
-DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
-{
- adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
-}
-
-
-const CurrencyPluralInfo*
-DecimalFormat::getCurrencyPluralInfo(void) const
-{
- return fCurrencyPluralInfo;
-}
-
-
-void
-DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt)
-{
- if (toAdopt != NULL) {
- delete fCurrencyPluralInfo;
- fCurrencyPluralInfo = toAdopt;
- // re-set currency affix patterns and currency affixes.
- if (fImpl->fMonetary) {
- UErrorCode status = U_ZERO_ERROR;
- if (fAffixPatternsForCurrency) {
- deleteHashForAffixPattern();
- }
- setupCurrencyAffixPatterns(status);
- }
- }
-}
-
-void
-DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info)
-{
- adoptCurrencyPluralInfo(info.clone());
-}
-
-
-//------------------------------------------------------------------------------
-// Gets the positive prefix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getPositivePrefix(UnicodeString& result) const
-{
- return fImpl->getPositivePrefix(result);
-}
-
-//------------------------------------------------------------------------------
-// Sets the positive prefix of the number pattern.
-
-void
-DecimalFormat::setPositivePrefix(const UnicodeString& newValue)
-{
- fImpl->setPositivePrefix(newValue);
-}
-
-//------------------------------------------------------------------------------
-// Gets the negative prefix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getNegativePrefix(UnicodeString& result) const
-{
- return fImpl->getNegativePrefix(result);
-}
-
-//------------------------------------------------------------------------------
-// Gets the negative prefix of the number pattern.
-
-void
-DecimalFormat::setNegativePrefix(const UnicodeString& newValue)
-{
- fImpl->setNegativePrefix(newValue);
-}
-
-//------------------------------------------------------------------------------
-// Gets the positive suffix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getPositiveSuffix(UnicodeString& result) const
-{
- return fImpl->getPositiveSuffix(result);
-}
-
-//------------------------------------------------------------------------------
-// Sets the positive suffix of the number pattern.
-
-void
-DecimalFormat::setPositiveSuffix(const UnicodeString& newValue)
-{
- fImpl->setPositiveSuffix(newValue);
-}
-
-//------------------------------------------------------------------------------
-// Gets the negative suffix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getNegativeSuffix(UnicodeString& result) const
-{
- return fImpl->getNegativeSuffix(result);
-}
-
-//------------------------------------------------------------------------------
-// Sets the negative suffix of the number pattern.
-
-void
-DecimalFormat::setNegativeSuffix(const UnicodeString& newValue)
-{
- fImpl->setNegativeSuffix(newValue);
-}
-
-//------------------------------------------------------------------------------
-// Gets the multiplier of the number pattern.
-// Multipliers are stored as decimal numbers (DigitLists) because that
-// is the most convenient for muliplying or dividing the numbers to be formatted.
-// A NULL multiplier implies one, and the scaling operations are skipped.
-
-int32_t
-DecimalFormat::getMultiplier() const
-{
- return fImpl->getMultiplier();
-}
-
-//------------------------------------------------------------------------------
-// Sets the multiplier of the number pattern.
-void
-DecimalFormat::setMultiplier(int32_t newValue)
-{
- fImpl->setMultiplier(newValue);
-}
-
-/**
- * Get the rounding increment.
- * @return A positive rounding increment, or 0.0 if rounding
- * is not in effect.
- * @see #setRoundingIncrement
- * @see #getRoundingMode
- * @see #setRoundingMode
- */
-double DecimalFormat::getRoundingIncrement() const {
- return fImpl->getRoundingIncrement();
-}
-
-/**
- * Set the rounding increment. This method also controls whether
- * rounding is enabled.
- * @param newValue A positive rounding increment, or 0.0 to disable rounding.
- * Negative increments are equivalent to 0.0.
- * @see #getRoundingIncrement
- * @see #getRoundingMode
- * @see #setRoundingMode
- */
-void DecimalFormat::setRoundingIncrement(double newValue) {
- fImpl->setRoundingIncrement(newValue);
-}
-
-/**
- * Get the rounding mode.
- * @return A rounding mode
- * @see #setRoundingIncrement
- * @see #getRoundingIncrement
- * @see #setRoundingMode
- */
-DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const {
- return fImpl->getRoundingMode();
-}
-
-/**
- * Set the rounding mode. This has no effect unless the rounding
- * increment is greater than zero.
- * @param roundingMode A rounding mode
- * @see #setRoundingIncrement
- * @see #getRoundingIncrement
- * @see #getRoundingMode
- */
-void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
- fImpl->setRoundingMode(roundingMode);
-}
-
-/**
- * Get the width to which the output of <code>format()</code> is padded.
- * @return the format width, or zero if no padding is in effect
- * @see #setFormatWidth
- * @see #getPadCharacter
- * @see #setPadCharacter
- * @see #getPadPosition
- * @see #setPadPosition
- */
-int32_t DecimalFormat::getFormatWidth() const {
- return fImpl->getFormatWidth();
-}
-
-/**
- * Set the width to which the output of <code>format()</code> is padded.
- * This method also controls whether padding is enabled.
- * @param width the width to which to pad the result of
- * <code>format()</code>, or zero to disable padding. A negative
- * width is equivalent to 0.
- * @see #getFormatWidth
- * @see #getPadCharacter
- * @see #setPadCharacter
- * @see #getPadPosition
- * @see #setPadPosition
- */
-void DecimalFormat::setFormatWidth(int32_t width) {
- int32_t formatWidth = (width > 0) ? width : 0;
- fImpl->setFormatWidth(formatWidth);
-}
-
-UnicodeString DecimalFormat::getPadCharacterString() const {
- return UnicodeString(fImpl->getPadCharacter());
-}
-
-void DecimalFormat::setPadCharacter(const UnicodeString &padChar) {
- UChar32 pad;
- if (padChar.length() > 0) {
- pad = padChar.char32At(0);
- }
- else {
- pad = kDefaultPad;
- }
- fImpl->setPadCharacter(pad);
-}
-
-static DecimalFormat::EPadPosition fromPadPosition(DigitAffixesAndPadding::EPadPosition padPos) {
- switch (padPos) {
- case DigitAffixesAndPadding::kPadBeforePrefix:
- return DecimalFormat::kPadBeforePrefix;
- case DigitAffixesAndPadding::kPadAfterPrefix:
- return DecimalFormat::kPadAfterPrefix;
- case DigitAffixesAndPadding::kPadBeforeSuffix:
- return DecimalFormat::kPadBeforeSuffix;
- case DigitAffixesAndPadding::kPadAfterSuffix:
- return DecimalFormat::kPadAfterSuffix;
- default:
- U_ASSERT(FALSE);
- break;
- }
- return DecimalFormat::kPadBeforePrefix;
-}
-
-/**
- * Get the position at which padding will take place. This is the location
- * at which padding will be inserted if the result of <code>format()</code>
- * is shorter than the format width.
- * @return the pad position, one of <code>kPadBeforePrefix</code>,
- * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or
- * <code>kPadAfterSuffix</code>.
- * @see #setFormatWidth
- * @see #getFormatWidth
- * @see #setPadCharacter
- * @see #getPadCharacter
- * @see #setPadPosition
- * @see #kPadBeforePrefix
- * @see #kPadAfterPrefix
- * @see #kPadBeforeSuffix
- * @see #kPadAfterSuffix
- */
-DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const {
- return fromPadPosition(fImpl->getPadPosition());
-}
-
-static DigitAffixesAndPadding::EPadPosition toPadPosition(DecimalFormat::EPadPosition padPos) {
- switch (padPos) {
- case DecimalFormat::kPadBeforePrefix:
- return DigitAffixesAndPadding::kPadBeforePrefix;
- case DecimalFormat::kPadAfterPrefix:
- return DigitAffixesAndPadding::kPadAfterPrefix;
- case DecimalFormat::kPadBeforeSuffix:
- return DigitAffixesAndPadding::kPadBeforeSuffix;
- case DecimalFormat::kPadAfterSuffix:
- return DigitAffixesAndPadding::kPadAfterSuffix;
- default:
- U_ASSERT(FALSE);
- break;
- }
- return DigitAffixesAndPadding::kPadBeforePrefix;
-}
-
-/**
- * <strong><font face=helvetica color=red>NEW</font></strong>
- * Set the position at which padding will take place. This is the location
- * at which padding will be inserted if the result of <code>format()</code>
- * is shorter than the format width. This has no effect unless padding is
- * enabled.
- * @param padPos the pad position, one of <code>kPadBeforePrefix</code>,
- * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or
- * <code>kPadAfterSuffix</code>.
- * @see #setFormatWidth
- * @see #getFormatWidth
- * @see #setPadCharacter
- * @see #getPadCharacter
- * @see #getPadPosition
- * @see #kPadBeforePrefix
- * @see #kPadAfterPrefix
- * @see #kPadBeforeSuffix
- * @see #kPadAfterSuffix
- */
-void DecimalFormat::setPadPosition(EPadPosition padPos) {
- fImpl->setPadPosition(toPadPosition(padPos));
-}
-
-/**
- * Return whether or not scientific notation is used.
- * @return TRUE if this object formats and parses scientific notation
- * @see #setScientificNotation
- * @see #getMinimumExponentDigits
- * @see #setMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-UBool DecimalFormat::isScientificNotation() const {
- return fImpl->isScientificNotation();
-}
-
-/**
- * Set whether or not scientific notation is used.
- * @param useScientific TRUE if this object formats and parses scientific
- * notation
- * @see #isScientificNotation
- * @see #getMinimumExponentDigits
- * @see #setMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-void DecimalFormat::setScientificNotation(UBool useScientific) {
- fImpl->setScientificNotation(useScientific);
-}
-
-/**
- * Return the minimum exponent digits that will be shown.
- * @return the minimum exponent digits that will be shown
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #setMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-int8_t DecimalFormat::getMinimumExponentDigits() const {
- return fImpl->getMinimumExponentDigits();
-}
-
-/**
- * Set the minimum exponent digits that will be shown. This has no
- * effect unless scientific notation is in use.
- * @param minExpDig a value >= 1 indicating the fewest exponent digits
- * that will be shown. Values less than 1 will be treated as 1.
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #getMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
- int32_t minExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1);
- fImpl->setMinimumExponentDigits(minExponentDigits);
-}
-
-/**
- * Return whether the exponent sign is always shown.
- * @return TRUE if the exponent is always prefixed with either the
- * localized minus sign or the localized plus sign, false if only negative
- * exponents are prefixed with the localized minus sign.
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #setMinimumExponentDigits
- * @see #getMinimumExponentDigits
- * @see #setExponentSignAlwaysShown
- */
-UBool DecimalFormat::isExponentSignAlwaysShown() const {
- return fImpl->isExponentSignAlwaysShown();
-}
-
-/**
- * Set whether the exponent sign is always shown. This has no effect
- * unless scientific notation is in use.
- * @param expSignAlways TRUE if the exponent is always prefixed with either
- * the localized minus sign or the localized plus sign, false if only
- * negative exponents are prefixed with the localized minus sign.
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #setMinimumExponentDigits
- * @see #getMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- */
-void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
- fImpl->setExponentSignAlwaysShown(expSignAlways);
-}
-
-//------------------------------------------------------------------------------
-// Gets the grouping size of the number pattern. For example, thousand or 10
-// thousand groupings.
-
-int32_t
-DecimalFormat::getGroupingSize() const
-{
- return fImpl->getGroupingSize();
-}
-
-//------------------------------------------------------------------------------
-// Gets the grouping size of the number pattern.
-
-void
-DecimalFormat::setGroupingSize(int32_t newValue)
-{
- fImpl->setGroupingSize(newValue);
-}
-
-//------------------------------------------------------------------------------
-
-int32_t
-DecimalFormat::getSecondaryGroupingSize() const
-{
- return fImpl->getSecondaryGroupingSize();
-}
-
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::setSecondaryGroupingSize(int32_t newValue)
-{
- fImpl->setSecondaryGroupingSize(newValue);
-}
-
-//------------------------------------------------------------------------------
-
-int32_t
-DecimalFormat::getMinimumGroupingDigits() const
-{
- return fImpl->getMinimumGroupingDigits();
-}
-
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::setMinimumGroupingDigits(int32_t newValue)
-{
- fImpl->setMinimumGroupingDigits(newValue);
-}
-
-//------------------------------------------------------------------------------
-// Checks if to show the decimal separator.
-
-UBool
-DecimalFormat::isDecimalSeparatorAlwaysShown() const
-{
- return fImpl->isDecimalSeparatorAlwaysShown();
-}
-
-//------------------------------------------------------------------------------
-// Sets to always show the decimal separator.
-
-void
-DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
-{
- fImpl->setDecimalSeparatorAlwaysShown(newValue);
-}
-
-//------------------------------------------------------------------------------
-// Checks if decimal point pattern match is required
-UBool
-DecimalFormat::isDecimalPatternMatchRequired(void) const
-{
- return static_cast<UBool>(fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED));
-}
-
-//------------------------------------------------------------------------------
-// Checks if decimal point pattern match is required
-
-void
-DecimalFormat::setDecimalPatternMatchRequired(UBool newValue)
-{
- fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue);
-}
-
-
-//------------------------------------------------------------------------------
-// Emits the pattern of this DecimalFormat instance.
-
-UnicodeString&
-DecimalFormat::toPattern(UnicodeString& result) const
-{
- return fImpl->toPattern(result);
-}
-
-//------------------------------------------------------------------------------
-// Emits the localized pattern this DecimalFormat instance.
-
-UnicodeString&
-DecimalFormat::toLocalizedPattern(UnicodeString& result) const
-{
- // toLocalizedPattern is deprecated, so we just make it the same as
- // toPattern.
- return fImpl->toPattern(result);
-}
-
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
- }
- fImpl->applyPattern(pattern, status);
-}
-
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::applyPattern(const UnicodeString& pattern,
- UParseError& parseError,
- UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
- }
- fImpl->applyPattern(pattern, parseError, status);
-}
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
- }
- fImpl->applyLocalizedPattern(pattern, status);
-}
-
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern,
- UParseError& parseError,
- UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
- }
- fImpl->applyLocalizedPattern(pattern, parseError, status);
-}
-
-//------------------------------------------------------------------------------
-
-/**
- * Sets the maximum number of digits allowed in the integer portion of a
- * number.
- * @see NumberFormat#setMaximumIntegerDigits
- */
-void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
- newValue = _min(newValue, gDefaultMaxIntegerDigits);
- NumberFormat::setMaximumIntegerDigits(newValue);
- fImpl->updatePrecision();
-}
-
-/**
- * Sets the minimum number of digits allowed in the integer portion of a
- * number. This override limits the integer digit count to 309.
- * @see NumberFormat#setMinimumIntegerDigits
- */
-void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
- newValue = _min(newValue, kDoubleIntegerDigits);
- NumberFormat::setMinimumIntegerDigits(newValue);
- fImpl->updatePrecision();
-}
-
-/**
- * Sets the maximum number of digits allowed in the fraction portion of a
- * number. This override limits the fraction digit count to 340.
- * @see NumberFormat#setMaximumFractionDigits
- */
-void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
- newValue = _min(newValue, kDoubleFractionDigits);
- NumberFormat::setMaximumFractionDigits(newValue);
- fImpl->updatePrecision();
-}
-
-/**
- * Sets the minimum number of digits allowed in the fraction portion of a
- * number. This override limits the fraction digit count to 340.
- * @see NumberFormat#setMinimumFractionDigits
- */
-void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
- newValue = _min(newValue, kDoubleFractionDigits);
- NumberFormat::setMinimumFractionDigits(newValue);
- fImpl->updatePrecision();
-}
-
-int32_t DecimalFormat::getMinimumSignificantDigits() const {
- return fImpl->getMinimumSignificantDigits();
-}
-
-int32_t DecimalFormat::getMaximumSignificantDigits() const {
- return fImpl->getMaximumSignificantDigits();
-}
-
-void DecimalFormat::setMinimumSignificantDigits(int32_t min) {
- if (min < 1) {
- min = 1;
- }
- // pin max sig dig to >= min
- int32_t max = _max(fImpl->fMaxSigDigits, min);
- fImpl->setMinMaxSignificantDigits(min, max);
-}
-
-void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
- if (max < 1) {
- max = 1;
- }
- // pin min sig dig to 1..max
- U_ASSERT(fImpl->fMinSigDigits >= 1);
- int32_t min = _min(fImpl->fMinSigDigits, max);
- fImpl->setMinMaxSignificantDigits(min, max);
-}
-
-UBool DecimalFormat::areSignificantDigitsUsed() const {
- return fImpl->areSignificantDigitsUsed();
-}
-
-void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
- fImpl->setSignificantDigitsUsed(useSignificantDigits);
-}
-
-void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
- // set the currency before compute affixes to get the right currency names
- NumberFormat::setCurrency(theCurrency, ec);
- fImpl->updateCurrency(ec);
-}
-
-void DecimalFormat::setCurrencyUsage(UCurrencyUsage newContext, UErrorCode* ec){
- fImpl->setCurrencyUsage(newContext, *ec);
-}
-
-UCurrencyUsage DecimalFormat::getCurrencyUsage() const {
- return fImpl->getCurrencyUsage();
-}
-
-// Deprecated variant with no UErrorCode parameter
-void DecimalFormat::setCurrency(const UChar* theCurrency) {
- UErrorCode ec = U_ZERO_ERROR;
- setCurrency(theCurrency, ec);
-}
-
-void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
- if (fImpl->fSymbols == NULL) {
- ec = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- ec = U_ZERO_ERROR;
- const UChar* c = getCurrency();
- if (*c == 0) {
- const UnicodeString &intl =
- fImpl->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
- c = intl.getBuffer(); // ok for intl to go out of scope
- }
- u_strncpy(result, c, 3);
- result[3] = 0;
-}
-
-Hashtable*
-DecimalFormat::initHashForAffixPattern(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- if ( U_FAILURE(status) ) {
- delete hTable;
- return NULL;
- }
- hTable->setValueComparator(decimfmtAffixPatternValueComparator);
- return hTable;
-}
-
-void
-DecimalFormat::deleteHashForAffixPattern()
-{
- if ( fAffixPatternsForCurrency == NULL ) {
- return;
- }
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
- delete value;
- }
- delete fAffixPatternsForCurrency;
- fAffixPatternsForCurrency = NULL;
-}
-
-
-void
-DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
- Hashtable* target,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
- AffixPatternsForCurrency* copy = new AffixPatternsForCurrency(
- value->negPrefixPatternForCurrency,
- value->negSuffixPatternForCurrency,
- value->posPrefixPatternForCurrency,
- value->posSuffixPatternForCurrency,
- value->patternType);
- target->put(UnicodeString(*key), copy, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- }
- }
-}
-
-void
-DecimalFormat::setGroupingUsed(UBool newValue) {
- NumberFormat::setGroupingUsed(newValue);
- fImpl->updateGrouping();
-}
-
-void
-DecimalFormat::setParseIntegerOnly(UBool newValue) {
- NumberFormat::setParseIntegerOnly(newValue);
-}
-
-void
-DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) {
- NumberFormat::setContext(value, status);
-}
-
-DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
- int32_t newValue,
- UErrorCode &status) {
- if(U_FAILURE(status)) return *this;
-
- switch(attr) {
- case UNUM_LENIENT_PARSE:
- setLenient(newValue!=0);
- break;
-
- case UNUM_PARSE_INT_ONLY:
- setParseIntegerOnly(newValue!=0);
- break;
-
- case UNUM_GROUPING_USED:
- setGroupingUsed(newValue!=0);
- break;
-
- case UNUM_DECIMAL_ALWAYS_SHOWN:
- setDecimalSeparatorAlwaysShown(newValue!=0);
- break;
-
- case UNUM_MAX_INTEGER_DIGITS:
- setMaximumIntegerDigits(newValue);
- break;
-
- case UNUM_MIN_INTEGER_DIGITS:
- setMinimumIntegerDigits(newValue);
- break;
-
- case UNUM_INTEGER_DIGITS:
- setMinimumIntegerDigits(newValue);
- setMaximumIntegerDigits(newValue);
- break;
-
- case UNUM_MAX_FRACTION_DIGITS:
- setMaximumFractionDigits(newValue);
- break;
-
- case UNUM_MIN_FRACTION_DIGITS:
- setMinimumFractionDigits(newValue);
- break;
-
- case UNUM_FRACTION_DIGITS:
- setMinimumFractionDigits(newValue);
- setMaximumFractionDigits(newValue);
- break;
-
- case UNUM_SIGNIFICANT_DIGITS_USED:
- setSignificantDigitsUsed(newValue!=0);
- break;
-
- case UNUM_MAX_SIGNIFICANT_DIGITS:
- setMaximumSignificantDigits(newValue);
- break;
-
- case UNUM_MIN_SIGNIFICANT_DIGITS:
- setMinimumSignificantDigits(newValue);
- break;
-
- case UNUM_MULTIPLIER:
- setMultiplier(newValue);
- break;
-
- case UNUM_GROUPING_SIZE:
- setGroupingSize(newValue);
- break;
-
- case UNUM_ROUNDING_MODE:
- setRoundingMode((DecimalFormat::ERoundingMode)newValue);
- break;
-
- case UNUM_FORMAT_WIDTH:
- setFormatWidth(newValue);
- break;
-
- case UNUM_PADDING_POSITION:
- /** The position at which padding will take place. */
- setPadPosition((DecimalFormat::EPadPosition)newValue);
- break;
-
- case UNUM_SECONDARY_GROUPING_SIZE:
- setSecondaryGroupingSize(newValue);
- break;
-
-#if UCONFIG_HAVE_PARSEALLINPUT
- case UNUM_PARSE_ALL_INPUT:
- setParseAllInput((UNumberFormatAttributeValue)newValue);
- break;
-#endif
-
- /* These are stored in fBoolFlags */
- case UNUM_PARSE_NO_EXPONENT:
- case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
- case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
- if(!fBoolFlags.isValidValue(newValue)) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- } else {
- if (attr == UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS) {
- fImpl->setFailIfMoreThanMaxDigits((UBool) newValue);
- }
- fBoolFlags.set(attr, newValue);
- }
- break;
-
- case UNUM_SCALE:
- fImpl->setScale(newValue);
- break;
-
- case UNUM_CURRENCY_USAGE:
- setCurrencyUsage((UCurrencyUsage)newValue, &status);
- break;
-
- case UNUM_MINIMUM_GROUPING_DIGITS:
- setMinimumGroupingDigits(newValue);
- break;
-
- default:
- status = U_UNSUPPORTED_ERROR;
- break;
- }
- return *this;
-}
-
-int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
- UErrorCode &status ) const {
- if(U_FAILURE(status)) return -1;
- switch(attr) {
- case UNUM_LENIENT_PARSE:
- return isLenient();
-
- case UNUM_PARSE_INT_ONLY:
- return isParseIntegerOnly();
-
- case UNUM_GROUPING_USED:
- return isGroupingUsed();
-
- case UNUM_DECIMAL_ALWAYS_SHOWN:
- return isDecimalSeparatorAlwaysShown();
-
- case UNUM_MAX_INTEGER_DIGITS:
- return getMaximumIntegerDigits();
-
- case UNUM_MIN_INTEGER_DIGITS:
- return getMinimumIntegerDigits();
-
- case UNUM_INTEGER_DIGITS:
- // TBD: what should this return?
- return getMinimumIntegerDigits();
-
- case UNUM_MAX_FRACTION_DIGITS:
- return getMaximumFractionDigits();
-
- case UNUM_MIN_FRACTION_DIGITS:
- return getMinimumFractionDigits();
-
- case UNUM_FRACTION_DIGITS:
- // TBD: what should this return?
- return getMinimumFractionDigits();
-
- case UNUM_SIGNIFICANT_DIGITS_USED:
- return areSignificantDigitsUsed();
-
- case UNUM_MAX_SIGNIFICANT_DIGITS:
- return getMaximumSignificantDigits();
-
- case UNUM_MIN_SIGNIFICANT_DIGITS:
- return getMinimumSignificantDigits();
-
- case UNUM_MULTIPLIER:
- return getMultiplier();
-
- case UNUM_GROUPING_SIZE:
- return getGroupingSize();
-
- case UNUM_ROUNDING_MODE:
- return getRoundingMode();
-
- case UNUM_FORMAT_WIDTH:
- return getFormatWidth();
-
- case UNUM_PADDING_POSITION:
- return getPadPosition();
-
- case UNUM_SECONDARY_GROUPING_SIZE:
- return getSecondaryGroupingSize();
-
- /* These are stored in fBoolFlags */
- case UNUM_PARSE_NO_EXPONENT:
- case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
- case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
- return fBoolFlags.get(attr);
-
- case UNUM_SCALE:
- return fImpl->fScale;
-
- case UNUM_CURRENCY_USAGE:
- return fImpl->getCurrencyUsage();
-
- case UNUM_MINIMUM_GROUPING_DIGITS:
- return getMinimumGroupingDigits();
-
- default:
- status = U_UNSUPPORTED_ERROR;
- break;
- }
-
- return -1; /* undefined */
-}
-
-#if UCONFIG_HAVE_PARSEALLINPUT
-void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
- fParseAllInput = value;
-}
-#endif
-
-U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
-
-//eof