958 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			958 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
| // © 2016 and later: Unicode, Inc. and others.
 | |
| // License & terms of use: http://www.unicode.org/copyright.html
 | |
| /*
 | |
| *******************************************************************************
 | |
| *   Copyright (C) 1996-2015, International Business Machines
 | |
| *   Corporation and others.  All Rights Reserved.
 | |
| *******************************************************************************
 | |
| * Modification History:
 | |
| *
 | |
| *   Date        Name        Description
 | |
| *   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
 | |
| *******************************************************************************
 | |
| */
 | |
| 
 | |
| #include "unicode/utypes.h"
 | |
| 
 | |
| #if !UCONFIG_NO_FORMATTING
 | |
| 
 | |
| #include "unicode/unum.h"
 | |
| 
 | |
| #include "unicode/uloc.h"
 | |
| #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"
 | |
| #include "cstring.h"
 | |
| 
 | |
| 
 | |
| U_NAMESPACE_USE
 | |
| 
 | |
| 
 | |
| U_CAPI UNumberFormat* U_EXPORT2
 | |
| unum_open(  UNumberFormatStyle    style,  
 | |
|             const    UChar*    pattern,
 | |
|             int32_t            patternLength,
 | |
|             const    char*     locale,
 | |
|             UParseError*       parseErr,
 | |
|             UErrorCode*        status) {
 | |
|     if(U_FAILURE(*status)) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     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_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_ORDINAL:
 | |
|         retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
 | |
|         break;
 | |
| 
 | |
|     case UNUM_DURATION:
 | |
|         retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
 | |
|         break;
 | |
| 
 | |
|     case UNUM_NUMBERING_SYSTEM:
 | |
|         retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
 | |
|         break;
 | |
| #endif
 | |
| 
 | |
|     case UNUM_DECIMAL_COMPACT_SHORT:
 | |
|         retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
 | |
|         break;
 | |
| 
 | |
|     case UNUM_DECIMAL_COMPACT_LONG:
 | |
|         retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         *status = U_UNSUPPORTED_ERROR;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if(retVal == NULL && U_SUCCESS(*status)) {
 | |
|         *status = U_MEMORY_ALLOCATION_ERROR;
 | |
|     }
 | |
| 
 | |
|     if (U_FAILURE(*status) && retVal != NULL) {
 | |
|         delete retVal;
 | |
|         retVal = NULL;
 | |
|     }
 | |
| 
 | |
|     return reinterpret_cast<UNumberFormat *>(retVal);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| unum_close(UNumberFormat* fmt)
 | |
| {
 | |
|     delete (NumberFormat*) fmt;
 | |
| }
 | |
| 
 | |
| U_CAPI UNumberFormat* U_EXPORT2
 | |
| unum_clone(const UNumberFormat *fmt,
 | |
|        UErrorCode *status)
 | |
| {
 | |
|     if(U_FAILURE(*status))
 | |
|         return 0;
 | |
|     
 | |
|     Format *res = 0;
 | |
|     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
 | |
|     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
 | |
|     if (df != NULL) {
 | |
|         res = df->clone();
 | |
|     } else {
 | |
|         const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
 | |
|         U_ASSERT(rbnf != NULL);
 | |
|         res = rbnf->clone();
 | |
|     }
 | |
| 
 | |
|     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,
 | |
|         UChar*            result,
 | |
|         int32_t           resultLength,
 | |
|         UFieldPosition    *pos,
 | |
|         UErrorCode*       status)
 | |
| {
 | |
|         return unum_formatInt64(fmt, number, result, resultLength, pos, status);
 | |
| }
 | |
| 
 | |
| 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 NumberFormat*)fmt)->format(number, res, fp, *status);
 | |
| 
 | |
|     if(pos != 0) {
 | |
|         pos->beginIndex = fp.getBeginIndex();
 | |
|         pos->endIndex = fp.getEndIndex();
 | |
|     }
 | |
|     
 | |
|     return res.extract(result, resultLength, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| unum_formatDouble(    const    UNumberFormat*  fmt,
 | |
|             double          number,
 | |
|             UChar*          result,
 | |
|             int32_t         resultLength,
 | |
|             UFieldPosition  *pos, /* 0 if ignore */
 | |
|             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 NumberFormat*)fmt)->format(number, res, fp, *status);
 | |
|   
 | |
|   if(pos != 0) {
 | |
|     pos->beginIndex = fp.getBeginIndex();
 | |
|     pos->endIndex = fp.getEndIndex();
 | |
|   }
 | |
|   
 | |
|   return res.extract(result, resultLength, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| unum_formatDoubleForFields(const UNumberFormat* format,
 | |
|                            double number,
 | |
|                            UChar* result,
 | |
|                            int32_t resultLength,
 | |
|                            UFieldPositionIterator* fpositer,
 | |
|                            UErrorCode* status)
 | |
| {
 | |
|     if (U_FAILURE(*status))
 | |
|         return -1;
 | |
| 
 | |
|     if (result == NULL ? resultLength != 0 : resultLength < 0) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     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);
 | |
| 
 | |
|     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(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<int32_t>(uprv_strlen(number));
 | |
|     }
 | |
|     StringPiece numSP(number, length);
 | |
|     Formattable numFmtbl(numSP, *status);
 | |
| 
 | |
|     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
 | |
| unum_parseDouble(    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.getDouble(*status);
 | |
| }
 | |
| 
 | |
| 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();
 | |
| }
 | |
| 
 | |
| 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;
 | |
|     }
 | |
|     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<CurrencyAmount> 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);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| unum_countAvailable()
 | |
| {
 | |
|     return uloc_countAvailable();
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| unum_getAttribute(const UNumberFormat*          fmt,
 | |
|           UNumberFormatAttribute  attr)
 | |
| {
 | |
|     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(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 remaining attributes are only supported for DecimalFormat
 | |
|     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
 | |
|     if (df != NULL) {
 | |
|         UErrorCode ignoredStatus = U_ZERO_ERROR;
 | |
|         return df->getAttribute(attr, ignoredStatus);
 | |
|     }
 | |
| 
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| unum_setAttribute(    UNumberFormat*          fmt,
 | |
|             UNumberFormatAttribute  attr,
 | |
|             int32_t                 newValue)
 | |
| {
 | |
|     NumberFormat* nf = reinterpret_cast<NumberFormat*>(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<DecimalFormat*>(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)
 | |
| {
 | |
|     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
 | |
|     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
 | |
|     if (df != NULL &&  attr == UNUM_ROUNDING_INCREMENT) {
 | |
|         return df->getRoundingIncrement();
 | |
|     } else {
 | |
|         return -1.0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| unum_setDoubleAttribute(    UNumberFormat*          fmt,
 | |
|             UNumberFormatAttribute  attr,
 | |
|             double                 newValue)
 | |
| {
 | |
|     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
 | |
|     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
 | |
|     if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {   
 | |
|         df->setRoundingIncrement(newValue);
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| unum_getTextAttribute(const UNumberFormat*  fmt,
 | |
|             UNumberFormatTextAttribute      tag,
 | |
|             UChar*                          result,
 | |
|             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);
 | |
|     }
 | |
| 
 | |
|     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
 | |
|     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(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<const RuleBasedNumberFormat*>(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);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| unum_setTextAttribute(    UNumberFormat*                    fmt,
 | |
|             UNumberFormatTextAttribute      tag,
 | |
|             const    UChar*                            newValue,
 | |
|             int32_t                            newValueLength,
 | |
|             UErrorCode                        *status)
 | |
| {
 | |
|     if(U_FAILURE(*status))
 | |
|         return;
 | |
| 
 | |
|     UnicodeString val(newValue, newValueLength);
 | |
|     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
 | |
|     DecimalFormat* df = dynamic_cast<DecimalFormat*>(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<RuleBasedNumberFormat*>(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
 | |
| unum_toPattern(    const    UNumberFormat*          fmt,
 | |
|         UBool                  isPatternLocalized,
 | |
|         UChar*                  result,
 | |
|         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);
 | |
|     }
 | |
| 
 | |
|     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
 | |
|     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
 | |
|     if (df != NULL) {
 | |
|       if(isPatternLocalized)
 | |
|         df->toLocalizedPattern(pat);
 | |
|       else
 | |
|         df->toPattern(pat);
 | |
|     } else {
 | |
|       const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
 | |
|       U_ASSERT(rbnf != NULL);
 | |
|       pat = rbnf->getRules();
 | |
|     }
 | |
|     return pat.extract(result, resultLength, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| 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 || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
 | |
|         *status=U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return 0;
 | |
|     }
 | |
|     const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
 | |
|     const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
 | |
|     if (dcf == NULL) {
 | |
|       *status = U_UNSUPPORTED_ERROR;
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     return dcf->
 | |
|       getDecimalFormatSymbols()->
 | |
|         getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
 | |
|           extract(buffer, size, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| unum_setSymbol(UNumberFormat *fmt,
 | |
|                UNumberFormatSymbol symbol,
 | |
|                const UChar *value,
 | |
|                int32_t length,
 | |
|                UErrorCode *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<NumberFormat *>(fmt);
 | |
|     DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(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  *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;
 | |
|     }
 | |
|     
 | |
|     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<NumberFormat*>(fmt);
 | |
|     DecimalFormat* df = dynamic_cast<DecimalFormat*>(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_CAPI 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 (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;
 | |
| }
 | |
| 
 | |
| U_CAPI 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 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 */
 |