X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b75a7d8f3b4adbae880cab104ce2c6a50eee4db2..1a147d096ae81f4c8262f7bfc56bd19fc2dee932:/icuSources/i18n/unum.cpp diff --git a/icuSources/i18n/unum.cpp b/icuSources/i18n/unum.cpp index e39ac880..c2bd5488 100644 --- a/icuSources/i18n/unum.cpp +++ b/icuSources/i18n/unum.cpp @@ -1,6 +1,8 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* -* Copyright (C) 1996-2003, International Business Machines +* Copyright (C) 1996-2015, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* * Modification History: @@ -20,75 +22,19 @@ #include "unicode/numfmt.h" #include "unicode/decimfmt.h" #include "unicode/rbnf.h" +#include "unicode/compactdecimalformat.h" #include "unicode/ustring.h" #include "unicode/fmtable.h" #include "unicode/dcfmtsym.h" +#include "unicode/curramt.h" +#include "unicode/localpointer.h" +#include "unicode/udisplaycontext.h" +#include "uassert.h" #include "cpputils.h" -U_NAMESPACE_USE -/* -U_CAPI UNumberFormat* -unum_open( UNumberFormatStyle style, - const char* locale, - UErrorCode* status) -{ - if(U_FAILURE(*status)) - return 0; - UNumberFormat *retVal = 0; - - switch(style) { - case UNUM_DECIMAL: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale), - *status); - break; - - case UNUM_CURRENCY: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale), - *status); - break; - - case UNUM_PERCENT: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale), - *status); - break; - - case UNUM_SPELLOUT: - // Todo: TBD: Add spellout support - //retVal = (UNumberFormat*)new NumberSpelloutFormat(); - //break; - *status = U_UNSUPPORTED_ERROR; - return 0; - - default: - *status = U_UNSUPPORTED_ERROR; - return 0; - } +#include "cstring.h" - if(retVal == 0) { - *status = U_MEMORY_ALLOCATION_ERROR; - return 0; - } - return retVal; -} - -U_CAPI UNumberFormat* -unum_openPattern( const UChar* pattern, - int32_t patternLength, - const char* locale, - UErrorCode* status) -{ - UParseError parseError; - return unum_openPatternWithError( pattern,patternLength,locale,&parseError,status); -}*/ +U_NAMESPACE_USE U_CAPI UNumberFormat* U_EXPORT2 @@ -97,155 +43,180 @@ unum_open( UNumberFormatStyle style, int32_t patternLength, const char* locale, UParseError* parseErr, - UErrorCode* status) -{ + UErrorCode* status) { + if(U_FAILURE(*status)) { + return NULL; + } - if(U_FAILURE(*status)) - { - return 0; - } - if(style!=UNUM_IGNORE){ - UNumberFormat *retVal = 0; - - switch(style) { - case UNUM_DECIMAL: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale), - *status); + NumberFormat *retVal = NULL; + + switch(style) { + case UNUM_DECIMAL: + case UNUM_CURRENCY: + case UNUM_PERCENT: + case UNUM_SCIENTIFIC: + case UNUM_CURRENCY_ISO: + case UNUM_CURRENCY_PLURAL: + case UNUM_CURRENCY_ACCOUNTING: + case UNUM_CASH_CURRENCY: + case UNUM_CURRENCY_STANDARD: + retVal = NumberFormat::createInstance(Locale(locale), style, *status); break; - case UNUM_CURRENCY: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale), - *status); + case UNUM_PATTERN_DECIMAL: { + UParseError tErr; + /* UnicodeString can handle the case when patternLength = -1. */ + const UnicodeString pat(pattern, patternLength); + + if(parseErr==NULL){ + parseErr = &tErr; + } + + DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status); + if(syms == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + if (U_FAILURE(*status)) { + delete syms; + return NULL; + } + + retVal = new DecimalFormat(pat, syms, *parseErr, *status); + if(retVal == NULL) { + delete syms; + } + } break; + +#if U_HAVE_RBNF + case UNUM_PATTERN_RULEBASED: { + UParseError tErr; + /* UnicodeString can handle the case when patternLength = -1. */ + const UnicodeString pat(pattern, patternLength); + + if(parseErr==NULL){ + parseErr = &tErr; + } + + retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status); + } break; + + case UNUM_SPELLOUT: + retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status); break; - case UNUM_PERCENT: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale), - *status); + case UNUM_ORDINAL: + retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status); break; - case UNUM_SCIENTIFIC: - if(locale == 0) - retVal = (UNumberFormat*)NumberFormat::createScientificInstance(*status); - else - retVal = (UNumberFormat*)NumberFormat::createScientificInstance(Locale(locale), - *status); + case UNUM_DURATION: + retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status); break; - case UNUM_SPELLOUT: -#if U_HAVE_RBNF - return (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status); -#else - // fall through + case UNUM_NUMBERING_SYSTEM: + retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status); + break; #endif - default: - *status = U_UNSUPPORTED_ERROR; - return 0; - } - if(retVal == 0) { - *status = U_MEMORY_ALLOCATION_ERROR; - return 0; - } + case UNUM_DECIMAL_COMPACT_SHORT: + retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status); + break; - return retVal; - }else{ - /* we don't support RBNF patterns yet */ - UParseError tErr; - int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength); - const UnicodeString pat((UChar*)pattern, len, len); - DecimalFormatSymbols *syms = 0; - - if(parseErr==NULL){ - parseErr = &tErr; - } - - if(locale == 0) - syms = new DecimalFormatSymbols(*status); - else - syms = new DecimalFormatSymbols(Locale(locale), - *status); - - if(syms == 0) { - *status = U_MEMORY_ALLOCATION_ERROR; - return 0; - } + case UNUM_DECIMAL_COMPACT_LONG: + retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status); + break; + + default: + *status = U_UNSUPPORTED_ERROR; + return NULL; + } - DecimalFormat *fmt = 0; - fmt = new DecimalFormat(pat, syms, *parseErr, *status); - if(fmt == 0) { + if(retVal == NULL && U_SUCCESS(*status)) { *status = U_MEMORY_ALLOCATION_ERROR; - delete syms; - return 0; - } + } - return (UNumberFormat*) fmt; - } + return reinterpret_cast(retVal); } U_CAPI void U_EXPORT2 unum_close(UNumberFormat* fmt) { - - delete (NumberFormat*) fmt; + delete (NumberFormat*) fmt; } U_CAPI UNumberFormat* U_EXPORT2 unum_clone(const UNumberFormat *fmt, UErrorCode *status) { - - if(U_FAILURE(*status)) return 0; - - Format *res = ((DecimalFormat*)fmt)->clone(); - - if(res == 0) { - *status = U_MEMORY_ALLOCATION_ERROR; - return 0; - } + if(U_FAILURE(*status)) + return 0; + + Format *res = 0; + const NumberFormat* nf = reinterpret_cast(fmt); + const DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + res = df->clone(); + } else { + const RuleBasedNumberFormat* rbnf = dynamic_cast(nf); + U_ASSERT(rbnf != NULL); + res = rbnf->clone(); + } - return (UNumberFormat*) res; + if(res == 0) { + *status = U_MEMORY_ALLOCATION_ERROR; + return 0; + } + + return (UNumberFormat*) res; } U_CAPI int32_t U_EXPORT2 unum_format( const UNumberFormat* fmt, - int32_t number, + int32_t number, UChar* result, - int32_t resultLength, + int32_t resultLength, UFieldPosition *pos, - UErrorCode* status) + UErrorCode* status) { - - if(U_FAILURE(*status)) return -1; + return unum_formatInt64(fmt, number, result, resultLength, pos, status); +} - UnicodeString res; - if(!(result==NULL && resultLength==0)) { - // NULL destination for pure preflighting: empty dummy string - // otherwise, alias the destination buffer - res.setTo(result, 0, resultLength); - } +U_CAPI int32_t U_EXPORT2 +unum_formatInt64(const UNumberFormat* fmt, + int64_t number, + UChar* result, + int32_t resultLength, + UFieldPosition *pos, + UErrorCode* status) +{ + if(U_FAILURE(*status)) + return -1; + + UnicodeString res; + if(!(result==NULL && resultLength==0)) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + FieldPosition fp; + + if(pos != 0) + fp.setField(pos->field); + + const CompactDecimalFormat* cdf = dynamic_cast((const NumberFormat*)fmt); + if (cdf != NULL) { + cdf->format(number, res, fp); // CompactDecimalFormat does not override the version with UErrorCode& !! + } else { + ((const NumberFormat*)fmt)->format(number, res, fp, *status); + } - FieldPosition fp; - - if(pos != 0) - fp.setField(pos->field); - - ((NumberFormat*)fmt)->format(number, res, fp); - - if(pos != 0) { - pos->beginIndex = fp.getBeginIndex(); - pos->endIndex = fp.getEndIndex(); - } - - return res.extract(result, resultLength, *status); + if(pos != 0) { + pos->beginIndex = fp.getBeginIndex(); + pos->endIndex = fp.getEndIndex(); + } + + return res.extract(result, resultLength, *status); } U_CAPI int32_t U_EXPORT2 @@ -271,7 +242,12 @@ unum_formatDouble( const UNumberFormat* fmt, if(pos != 0) fp.setField(pos->field); - ((NumberFormat*)fmt)->format(number, res, fp); + const CompactDecimalFormat* cdf = dynamic_cast((const NumberFormat*)fmt); + if (cdf != NULL) { + cdf->format(number, res, fp); // CompactDecimalFormat does not override the version with UErrorCode& !! + } else { + ((const NumberFormat*)fmt)->format(number, res, fp, *status); + } if(pos != 0) { pos->beginIndex = fp.getBeginIndex(); @@ -282,38 +258,166 @@ unum_formatDouble( const UNumberFormat* fmt, } U_CAPI int32_t U_EXPORT2 -unum_parse( const UNumberFormat* fmt, - const UChar* text, - int32_t textLength, - int32_t *parsePos /* 0 = start */, - UErrorCode *status) +unum_formatDoubleForFields(const UNumberFormat* format, + double number, + UChar* result, + int32_t resultLength, + UFieldPositionIterator* fpositer, + UErrorCode* status) { - - if(U_FAILURE(*status)) return 0; + if (U_FAILURE(*status)) + return -1; - int32_t len = (textLength == -1 ? u_strlen(text) : textLength); - const UnicodeString src((UChar*)text, len, len); - ParsePosition pp; - Formattable res; + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } - if(parsePos != 0) - pp.setIndex(*parsePos); + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status); - ((NumberFormat*)fmt)->parse(src, res, pp); + return res.extract(result, resultLength, *status); +} + +U_CAPI int32_t U_EXPORT2 +unum_formatDecimal(const UNumberFormat* fmt, + const char * number, + int32_t length, + UChar* result, + int32_t resultLength, + UFieldPosition *pos, /* 0 if ignore */ + UErrorCode* status) { - if(parsePos != 0) { - if(pp.getErrorIndex() == -1) - *parsePos = pp.getIndex(); - else { - *parsePos = pp.getErrorIndex(); - *status = U_PARSE_ERROR; + if(U_FAILURE(*status)) { + return -1; } - } + if ((result == NULL && resultLength != 0) || resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + FieldPosition fp; + if(pos != 0) { + fp.setField(pos->field); + } + + if (length < 0) { + length = static_cast(uprv_strlen(number)); + } + StringPiece numSP(number, length); + Formattable numFmtbl(numSP, *status); - /* return the actual type of the result, cast to a long */ - return (res.getType() == Formattable::kLong) - ? res.getLong() - : (int32_t) res.getDouble(); + UnicodeString resultStr; + if (resultLength > 0) { + // Alias the destination buffer. + resultStr.setTo(result, 0, resultLength); + } + ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status); + if(pos != 0) { + pos->beginIndex = fp.getBeginIndex(); + pos->endIndex = fp.getEndIndex(); + } + return resultStr.extract(result, resultLength, *status); +} + + + + +U_CAPI int32_t U_EXPORT2 +unum_formatDoubleCurrency(const UNumberFormat* fmt, + double number, + UChar* currency, + UChar* result, + int32_t resultLength, + UFieldPosition* pos, /* ignored if 0 */ + UErrorCode* status) { + if (U_FAILURE(*status)) return -1; + + UnicodeString res; + if (!(result==NULL && resultLength==0)) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + FieldPosition fp; + if (pos != 0) { + fp.setField(pos->field); + } + CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status); + // Check for null pointer. + if (tempCurrAmnt == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return -1; + } + Formattable n(tempCurrAmnt); + ((const NumberFormat*)fmt)->format(n, res, fp, *status); + + if (pos != 0) { + pos->beginIndex = fp.getBeginIndex(); + pos->endIndex = fp.getEndIndex(); + } + + return res.extract(result, resultLength, *status); +} + +static void +parseRes(Formattable& res, + const UNumberFormat* fmt, + const UChar* text, + int32_t textLength, + int32_t *parsePos /* 0 = start */, + UErrorCode *status) +{ + if(U_FAILURE(*status)) + return; + + const UnicodeString src((UBool)(textLength == -1), text, textLength); + ParsePosition pp; + + if(parsePos != 0) + pp.setIndex(*parsePos); + + ((const NumberFormat*)fmt)->parse(src, res, pp); + + if(pp.getErrorIndex() != -1) { + *status = U_PARSE_ERROR; + if(parsePos != 0) { + *parsePos = pp.getErrorIndex(); + } + } else if(parsePos != 0) { + *parsePos = pp.getIndex(); + } +} + +U_CAPI int32_t U_EXPORT2 +unum_parse( const UNumberFormat* fmt, + const UChar* text, + int32_t textLength, + int32_t *parsePos /* 0 = start */, + UErrorCode *status) +{ + Formattable res; + parseRes(res, fmt, text, textLength, parsePos, status); + return res.getLong(*status); +} + +U_CAPI int64_t U_EXPORT2 +unum_parseInt64( const UNumberFormat* fmt, + const UChar* text, + int32_t textLength, + int32_t *parsePos /* 0 = start */, + UErrorCode *status) +{ + Formattable res; + parseRes(res, fmt, text, textLength, parsePos, status); + return res.getInt64(*status); } U_CAPI double U_EXPORT2 @@ -323,104 +427,133 @@ unum_parseDouble( const UNumberFormat* fmt, int32_t *parsePos /* 0 = start */, UErrorCode *status) { - - if(U_FAILURE(*status)) - return 0; - - int32_t len = (textLength < 0 ? u_strlen(text) : textLength); - const UnicodeString src((UChar*)text, len, len); - ParsePosition pp; - Formattable res; - - if(parsePos != 0) - pp.setIndex(*parsePos); + Formattable res; + parseRes(res, fmt, text, textLength, parsePos, status); + return res.getDouble(*status); +} - ((NumberFormat*)fmt)->parse(src, res, pp); +U_CAPI int32_t U_EXPORT2 +unum_parseDecimal(const UNumberFormat* fmt, + const UChar* text, + int32_t textLength, + int32_t *parsePos /* 0 = start */, + char *outBuf, + int32_t outBufLength, + UErrorCode *status) +{ + if (U_FAILURE(*status)) { + return -1; + } + if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + Formattable res; + parseRes(res, fmt, text, textLength, parsePos, status); + StringPiece sp = res.getDecimalNumber(*status); + if (U_FAILURE(*status)) { + return -1; + } else if (sp.size() > outBufLength) { + *status = U_BUFFER_OVERFLOW_ERROR; + } else if (sp.size() == outBufLength) { + uprv_strncpy(outBuf, sp.data(), sp.size()); + *status = U_STRING_NOT_TERMINATED_WARNING; + } else { + U_ASSERT(outBufLength > 0); + uprv_strcpy(outBuf, sp.data()); + } + return sp.size(); +} - if(parsePos != 0) { - if(pp.getErrorIndex() == -1) - *parsePos = pp.getIndex(); - else { - *parsePos = pp.getErrorIndex(); - *status = U_PARSE_ERROR; +U_CAPI double U_EXPORT2 +unum_parseDoubleCurrency(const UNumberFormat* fmt, + const UChar* text, + int32_t textLength, + int32_t* parsePos, /* 0 = start */ + UChar* currency, + UErrorCode* status) { + double doubleVal = 0.0; + currency[0] = 0; + if (U_FAILURE(*status)) { + return doubleVal; } - } - - /* return the actual type of the result, cast to a double */ - return (res.getType() == Formattable::kDouble) - ? res.getDouble() - : (double) res.getLong(); + const UnicodeString src((UBool)(textLength == -1), text, textLength); + ParsePosition pp; + if (parsePos != NULL) { + pp.setIndex(*parsePos); + } + *status = U_PARSE_ERROR; // assume failure, reset if succeed + LocalPointer currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp)); + if (pp.getErrorIndex() != -1) { + if (parsePos != NULL) { + *parsePos = pp.getErrorIndex(); + } + } else { + if (parsePos != NULL) { + *parsePos = pp.getIndex(); + } + if (pp.getIndex() > 0) { + *status = U_ZERO_ERROR; + u_strcpy(currency, currAmt->getISOCurrency()); + doubleVal = currAmt->getNumber().getDouble(*status); + } + } + return doubleVal; } U_CAPI const char* U_EXPORT2 unum_getAvailable(int32_t index) { - - return uloc_getAvailable(index); + return uloc_getAvailable(index); } U_CAPI int32_t U_EXPORT2 unum_countAvailable() { - - return uloc_countAvailable(); + return uloc_countAvailable(); } U_CAPI int32_t U_EXPORT2 unum_getAttribute(const UNumberFormat* fmt, UNumberFormatAttribute attr) { - - switch(attr) { - case UNUM_PARSE_INT_ONLY: - return ((NumberFormat*)fmt)->isParseIntegerOnly(); - - case UNUM_GROUPING_USED: - return ((NumberFormat*)fmt)->isGroupingUsed(); - - case UNUM_DECIMAL_ALWAYS_SHOWN: - return ((DecimalFormat*)fmt)->isDecimalSeparatorAlwaysShown(); - - case UNUM_MAX_INTEGER_DIGITS: - return ((NumberFormat*)fmt)->getMaximumIntegerDigits(); - - case UNUM_MIN_INTEGER_DIGITS: - return ((NumberFormat*)fmt)->getMinimumIntegerDigits(); - - case UNUM_INTEGER_DIGITS: - // TBD: what should this return? - return ((NumberFormat*)fmt)->getMinimumIntegerDigits(); - - case UNUM_MAX_FRACTION_DIGITS: - return ((NumberFormat*)fmt)->getMaximumFractionDigits(); - - case UNUM_MIN_FRACTION_DIGITS: - return ((NumberFormat*)fmt)->getMinimumFractionDigits(); - - case UNUM_FRACTION_DIGITS: - // TBD: what should this return? - return ((NumberFormat*)fmt)->getMinimumFractionDigits(); - - case UNUM_MULTIPLIER: - return ((DecimalFormat*)fmt)->getMultiplier(); - - case UNUM_GROUPING_SIZE: - return ((DecimalFormat*)fmt)->getGroupingSize(); - - case UNUM_ROUNDING_MODE: - return ((DecimalFormat*)fmt)->getRoundingMode(); - - case UNUM_FORMAT_WIDTH: - return ((DecimalFormat*)fmt)->getFormatWidth(); + const NumberFormat* nf = reinterpret_cast(fmt); + if (attr == UNUM_LENIENT_PARSE) { + // Supported for all subclasses + return nf->isLenient(); + } + else if (attr == UNUM_MAX_INTEGER_DIGITS) { + return nf->getMaximumIntegerDigits(); + } + else if (attr == UNUM_MIN_INTEGER_DIGITS) { + return nf->getMinimumIntegerDigits(); + } + else if (attr == UNUM_INTEGER_DIGITS) { + // TODO: what should this return? + return nf->getMinimumIntegerDigits(); + } + else if (attr == UNUM_MAX_FRACTION_DIGITS) { + return nf->getMaximumFractionDigits(); + } + else if (attr == UNUM_MIN_FRACTION_DIGITS) { + return nf->getMinimumFractionDigits(); + } + else if (attr == UNUM_FRACTION_DIGITS) { + // TODO: what should this return? + return nf->getMinimumFractionDigits(); + } + else if (attr == UNUM_ROUNDING_MODE) { + return nf->getRoundingMode(); + } - /** The position at which padding will take place. */ - case UNUM_PADDING_POSITION: - return ((DecimalFormat*)fmt)->getPadPosition(); + // The remaining attributes are only supported for DecimalFormat + const DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + UErrorCode ignoredStatus = U_ZERO_ERROR; + return df->getAttribute(attr, ignoredStatus); + } - default: - break; - } - return -1; + return -1; } U_CAPI void U_EXPORT2 @@ -428,87 +561,55 @@ unum_setAttribute( UNumberFormat* fmt, UNumberFormatAttribute attr, int32_t newValue) { - - switch(attr) { - case UNUM_PARSE_INT_ONLY: - ((NumberFormat*)fmt)->setParseIntegerOnly((UBool)newValue); - break; - - case UNUM_GROUPING_USED: - ((NumberFormat*)fmt)->setGroupingUsed((UBool)newValue); - break; - - case UNUM_DECIMAL_ALWAYS_SHOWN: - ((DecimalFormat*)fmt)->setDecimalSeparatorAlwaysShown((UBool)newValue); - break; - - case UNUM_MAX_INTEGER_DIGITS: - ((NumberFormat*)fmt)->setMaximumIntegerDigits(newValue); - break; - - case UNUM_MIN_INTEGER_DIGITS: - ((NumberFormat*)fmt)->setMinimumIntegerDigits(newValue); - break; - - case UNUM_INTEGER_DIGITS: - ((NumberFormat*)fmt)->setMinimumIntegerDigits(newValue); - ((NumberFormat*)fmt)->setMaximumIntegerDigits(newValue); - break; - - case UNUM_MAX_FRACTION_DIGITS: - ((NumberFormat*)fmt)->setMaximumFractionDigits(newValue); - break; - - case UNUM_MIN_FRACTION_DIGITS: - ((NumberFormat*)fmt)->setMinimumFractionDigits(newValue); - break; - - case UNUM_FRACTION_DIGITS: - ((NumberFormat*)fmt)->setMinimumFractionDigits(newValue); - ((NumberFormat*)fmt)->setMaximumFractionDigits(newValue); - break; - - case UNUM_MULTIPLIER: - ((DecimalFormat*)fmt)->setMultiplier(newValue); - break; - - case UNUM_GROUPING_SIZE: - ((DecimalFormat*)fmt)->setGroupingSize(newValue); - break; - - case UNUM_ROUNDING_MODE: - ((DecimalFormat*)fmt)->setRoundingMode((DecimalFormat::ERoundingMode)newValue); - break; - - case UNUM_FORMAT_WIDTH: - ((DecimalFormat*)fmt)->setFormatWidth(newValue); - break; - - /** The position at which padding will take place. */ - case UNUM_PADDING_POSITION: - ((DecimalFormat*)fmt)->setPadPosition((DecimalFormat::EPadPosition)newValue); - break; - - case UNUM_SECONDARY_GROUPING_SIZE: - ((DecimalFormat*)fmt)->setSecondaryGroupingSize(newValue); - break; - - default: - /* Shouldn't get here anyway */ - break; - } + NumberFormat* nf = reinterpret_cast(fmt); + if (attr == UNUM_LENIENT_PARSE) { + // Supported for all subclasses + // keep this here as the class may not be a DecimalFormat + return nf->setLenient(newValue != 0); + } + else if (attr == UNUM_MAX_INTEGER_DIGITS) { + return nf->setMaximumIntegerDigits(newValue); + } + else if (attr == UNUM_MIN_INTEGER_DIGITS) { + return nf->setMinimumIntegerDigits(newValue); + } + else if (attr == UNUM_INTEGER_DIGITS) { + nf->setMinimumIntegerDigits(newValue); + return nf->setMaximumIntegerDigits(newValue); + } + else if (attr == UNUM_MAX_FRACTION_DIGITS) { + return nf->setMaximumFractionDigits(newValue); + } + else if (attr == UNUM_MIN_FRACTION_DIGITS) { + return nf->setMinimumFractionDigits(newValue); + } + else if (attr == UNUM_FRACTION_DIGITS) { + nf->setMinimumFractionDigits(newValue); + return nf->setMaximumFractionDigits(newValue); + } + else if (attr == UNUM_ROUNDING_MODE) { + return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue); + } + + // The remaining attributes are only supported for DecimalFormat + DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + UErrorCode ignoredStatus = U_ZERO_ERROR; + df->setAttribute(attr, newValue, ignoredStatus); + } } U_CAPI double U_EXPORT2 unum_getDoubleAttribute(const UNumberFormat* fmt, UNumberFormatAttribute attr) { - - if (attr == UNUM_ROUNDING_INCREMENT) { - return ((DecimalFormat*)fmt)->getRoundingIncrement(); - } else { - return -1.0; - } + const NumberFormat* nf = reinterpret_cast(fmt); + const DecimalFormat* df = dynamic_cast(nf); + if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) { + return df->getRoundingIncrement(); + } else { + return -1.0; + } } U_CAPI void U_EXPORT2 @@ -516,10 +617,11 @@ unum_setDoubleAttribute( UNumberFormat* fmt, UNumberFormatAttribute attr, double newValue) { - - if (attr == UNUM_ROUNDING_INCREMENT) { - ((DecimalFormat*)fmt)->setRoundingIncrement(newValue); - } + NumberFormat* nf = reinterpret_cast(fmt); + DecimalFormat* df = dynamic_cast(nf); + if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) { + df->setRoundingIncrement(newValue); + } } U_CAPI int32_t U_EXPORT2 @@ -529,48 +631,66 @@ unum_getTextAttribute(const UNumberFormat* fmt, int32_t resultLength, UErrorCode* status) { - - if(U_FAILURE(*status)) - return -1; - - UnicodeString res; - if(!(result==NULL && resultLength==0)) { - // NULL destination for pure preflighting: empty dummy string - // otherwise, alias the destination buffer - res.setTo(result, 0, resultLength); - } - - switch(tag) { - case UNUM_POSITIVE_PREFIX: - ((DecimalFormat*)fmt)->getPositivePrefix(res); - break; - - case UNUM_POSITIVE_SUFFIX: - ((DecimalFormat*)fmt)->getPositiveSuffix(res); - break; - - case UNUM_NEGATIVE_PREFIX: - ((DecimalFormat*)fmt)->getNegativePrefix(res); - break; - - case UNUM_NEGATIVE_SUFFIX: - ((DecimalFormat*)fmt)->getNegativeSuffix(res); - break; - - case UNUM_PADDING_CHARACTER: - res = ((DecimalFormat*)fmt)->getPadCharacterString(); - break; - - case UNUM_CURRENCY_CODE: - res = UnicodeString(((DecimalFormat*)fmt)->getCurrency()); - break; + if(U_FAILURE(*status)) + return -1; + + UnicodeString res; + if(!(result==NULL && resultLength==0)) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } - default: - *status = U_UNSUPPORTED_ERROR; - return -1; - } + const NumberFormat* nf = reinterpret_cast(fmt); + const DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + switch(tag) { + case UNUM_POSITIVE_PREFIX: + df->getPositivePrefix(res); + break; + + case UNUM_POSITIVE_SUFFIX: + df->getPositiveSuffix(res); + break; + + case UNUM_NEGATIVE_PREFIX: + df->getNegativePrefix(res); + break; + + case UNUM_NEGATIVE_SUFFIX: + df->getNegativeSuffix(res); + break; + + case UNUM_PADDING_CHARACTER: + res = df->getPadCharacterString(); + break; + + case UNUM_CURRENCY_CODE: + res = UnicodeString(df->getCurrency()); + break; + + default: + *status = U_UNSUPPORTED_ERROR; + return -1; + } + } else { + const RuleBasedNumberFormat* rbnf = dynamic_cast(nf); + U_ASSERT(rbnf != NULL); + if (tag == UNUM_DEFAULT_RULESET) { + res = rbnf->getDefaultRuleSetName(); + } else if (tag == UNUM_PUBLIC_RULESETS) { + int32_t count = rbnf->getNumberOfRuleSetNames(); + for (int i = 0; i < count; ++i) { + res += rbnf->getRuleSetName(i); + res += (UChar)0x003b; // semicolon + } + } else { + *status = U_UNSUPPORTED_ERROR; + return -1; + } + } - return res.extract(result, resultLength, *status); + return res.extract(result, resultLength, *status); } U_CAPI void U_EXPORT2 @@ -580,41 +700,51 @@ unum_setTextAttribute( UNumberFormat* fmt, int32_t newValueLength, UErrorCode *status) { - - if(U_FAILURE(*status)) return; - - int32_t len = (newValueLength == -1 ? u_strlen(newValue) : newValueLength); - const UnicodeString val((UChar*)newValue, len, len); - - switch(tag) { - case UNUM_POSITIVE_PREFIX: - ((DecimalFormat*)fmt)->setPositivePrefix(val); - break; - - case UNUM_POSITIVE_SUFFIX: - ((DecimalFormat*)fmt)->setPositiveSuffix(val); - break; - - case UNUM_NEGATIVE_PREFIX: - ((DecimalFormat*)fmt)->setNegativePrefix(val); - break; - - case UNUM_NEGATIVE_SUFFIX: - ((DecimalFormat*)fmt)->setNegativeSuffix(val); - break; - - case UNUM_PADDING_CHARACTER: - ((DecimalFormat*)fmt)->setPadCharacter(*newValue); - break; - - case UNUM_CURRENCY_CODE: - ((DecimalFormat*)fmt)->setCurrency(newValue); - break; - - default: - *status = U_UNSUPPORTED_ERROR; - break; - } + if(U_FAILURE(*status)) + return; + + UnicodeString val(newValue, newValueLength); + NumberFormat* nf = reinterpret_cast(fmt); + DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + switch(tag) { + case UNUM_POSITIVE_PREFIX: + df->setPositivePrefix(val); + break; + + case UNUM_POSITIVE_SUFFIX: + df->setPositiveSuffix(val); + break; + + case UNUM_NEGATIVE_PREFIX: + df->setNegativePrefix(val); + break; + + case UNUM_NEGATIVE_SUFFIX: + df->setNegativeSuffix(val); + break; + + case UNUM_PADDING_CHARACTER: + df->setPadCharacter(val); + break; + + case UNUM_CURRENCY_CODE: + df->setCurrency(val.getTerminatedBuffer(), *status); + break; + + default: + *status = U_UNSUPPORTED_ERROR; + break; + } + } else { + RuleBasedNumberFormat* rbnf = dynamic_cast(nf); + U_ASSERT(rbnf != NULL); + if (tag == UNUM_DEFAULT_RULESET) { + rbnf->setDefaultRuleSet(val, *status); + } else { + *status = U_UNSUPPORTED_ERROR; + } + } } U_CAPI int32_t U_EXPORT2 @@ -624,42 +754,53 @@ unum_toPattern( const UNumberFormat* fmt, int32_t resultLength, UErrorCode* status) { - - if(U_FAILURE(*status)) return -1; - - UnicodeString pat; - if(!(result==NULL && resultLength==0)) { - // NULL destination for pure preflighting: empty dummy string - // otherwise, alias the destination buffer - pat.setTo(result, 0, resultLength); - } - - if(isPatternLocalized) - ((DecimalFormat*)fmt)->toLocalizedPattern(pat); - else - ((DecimalFormat*)fmt)->toPattern(pat); + if(U_FAILURE(*status)) + return -1; + + UnicodeString pat; + if(!(result==NULL && resultLength==0)) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + pat.setTo(result, 0, resultLength); + } - return pat.extract(result, resultLength, *status); + const NumberFormat* nf = reinterpret_cast(fmt); + const DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + if(isPatternLocalized) + df->toLocalizedPattern(pat); + else + df->toPattern(pat); + } else { + const RuleBasedNumberFormat* rbnf = dynamic_cast(nf); + U_ASSERT(rbnf != NULL); + pat = rbnf->getRules(); + } + return pat.extract(result, resultLength, *status); } U_CAPI int32_t U_EXPORT2 -unum_getSymbol(UNumberFormat *fmt, +unum_getSymbol(const UNumberFormat *fmt, UNumberFormatSymbol symbol, UChar *buffer, int32_t size, - UErrorCode *status) { - - if(status==NULL || U_FAILURE(*status)) { - return 0; - } - - if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT) { - *status=U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } + UErrorCode *status) +{ + if(status==NULL || U_FAILURE(*status)) { + return 0; + } + if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) { + *status=U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + const NumberFormat *nf = reinterpret_cast(fmt); + const DecimalFormat *dcf = dynamic_cast(nf); + if (dcf == NULL) { + *status = U_UNSUPPORTED_ERROR; + return 0; + } - return - ((const DecimalFormat *)fmt)-> + return dcf-> getDecimalFormatSymbols()-> getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol). extract(buffer, size, *status); @@ -670,70 +811,152 @@ unum_setSymbol(UNumberFormat *fmt, UNumberFormatSymbol symbol, const UChar *value, int32_t length, - UErrorCode *status) { - - if(status==NULL || U_FAILURE(*status)) { - return; - } - - if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) { - *status=U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - DecimalFormatSymbols symbols(*((DecimalFormat *)fmt)->getDecimalFormatSymbols()); - symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol, - length>=0 ? UnicodeString(value, length) : UnicodeString(value)); - ((DecimalFormat *)fmt)->setDecimalFormatSymbols(symbols); -} - -/* -U_CAPI void -unum_applyPattern( UNumberFormat *format, - UBool localized, - const UChar *pattern, - int32_t patternLength - ) + UErrorCode *status) { - UErrorCode status = U_ZERO_ERROR; - UParseError parseError; - unum_applyPatternWithError(format,localized,pattern,patternLength,&parseError,&status); + if(status==NULL || U_FAILURE(*status)) { + return; + } + if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) { + *status=U_ILLEGAL_ARGUMENT_ERROR; + return; + } + NumberFormat *nf = reinterpret_cast(fmt); + DecimalFormat *dcf = dynamic_cast(nf); + if (dcf == NULL) { + *status = U_UNSUPPORTED_ERROR; + return; + } + + DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols()); + symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol, + UnicodeString(value, length)); /* UnicodeString can handle the case when length = -1. */ + dcf->setDecimalFormatSymbols(symbols); } -*/ U_CAPI void U_EXPORT2 -unum_applyPattern( UNumberFormat *format, +unum_applyPattern( UNumberFormat *fmt, UBool localized, const UChar *pattern, int32_t patternLength, UParseError *parseError, UErrorCode* status) { - - UErrorCode tStatus = U_ZERO_ERROR; - UParseError tParseError; - - if(parseError == NULL){ - parseError = &tParseError; + UErrorCode tStatus = U_ZERO_ERROR; + UParseError tParseError; + + if(parseError == NULL){ + parseError = &tParseError; + } + + if(status==NULL){ + status = &tStatus; + } + + int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength); + const UnicodeString pat((UChar*)pattern, len, len); + + // Verify if the object passed is a DecimalFormat object + NumberFormat* nf = reinterpret_cast(fmt); + DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { + if(localized) { + df->applyLocalizedPattern(pat,*parseError, *status); + } else { + df->applyPattern(pat,*parseError, *status); + } + } else { + *status = U_UNSUPPORTED_ERROR; + return; + } +} + +U_CAPI const char* U_EXPORT2 +unum_getLocaleByType(const UNumberFormat *fmt, + ULocDataLocaleType type, + UErrorCode* status) +{ + if (fmt == NULL) { + if (U_SUCCESS(*status)) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } + return NULL; + } + return ((const Format*)fmt)->getLocaleID(type, *status); +} + +U_CAPI void U_EXPORT2 +unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status) +{ + if (U_FAILURE(*status)) { + return; + } + ((NumberFormat*)fmt)->setContext(value, *status); + return; +} + +U_CAPI UDisplayContext U_EXPORT2 +unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status) +{ + if (U_FAILURE(*status)) { + return (UDisplayContext)0; + } + return ((const NumberFormat*)fmt)->getContext(type, *status); +} + +U_INTERNAL UFormattable * U_EXPORT2 +unum_parseToUFormattable(const UNumberFormat* fmt, + UFormattable *result, + const UChar* text, + int32_t textLength, + int32_t* parsePos, /* 0 = start */ + UErrorCode* status) { + UFormattable *newFormattable = NULL; + if (U_FAILURE(*status)) return result; + if (fmt == NULL || (text==NULL && textLength!=0)) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return result; } - - if(status==NULL){ - status = &tStatus; + if (result == NULL) { // allocate if not allocated. + newFormattable = result = ufmt_open(status); } + parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status); + if (U_FAILURE(*status) && newFormattable != NULL) { + ufmt_close(newFormattable); + result = NULL; // deallocate if there was a parse error + } + return result; +} - int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength); - const UnicodeString pat((UChar*)pattern, len, len); - - // Verify if the object passed is a DecimalFormat object - if(((NumberFormat*)format)->getDynamicClassID()!= DecimalFormat::getStaticClassID()){ +U_INTERNAL int32_t U_EXPORT2 +unum_formatUFormattable(const UNumberFormat* fmt, + const UFormattable *number, + UChar *result, + int32_t resultLength, + UFieldPosition *pos, /* ignored if 0 */ + UErrorCode *status) { + if (U_FAILURE(*status)) { + return 0; + } + if (fmt == NULL || number==NULL || + (result==NULL ? resultLength!=0 : resultLength<0)) { *status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - if(localized) - ((DecimalFormat*)format)->applyLocalizedPattern(pat,*parseError, *status); - else - ((DecimalFormat*)format)->applyPattern(pat,*parseError, *status); + return 0; + } + UnicodeString res(result, 0, resultLength); + + FieldPosition fp; + + if(pos != 0) + fp.setField(pos->field); + + ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status); + + if(pos != 0) { + pos->beginIndex = fp.getBeginIndex(); + pos->endIndex = fp.getEndIndex(); + } + + return res.extract(result, resultLength, *status); } #endif /* #if !UCONFIG_NO_FORMATTING */