Home | History | Annotate | Download | only in i18n
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *   Copyright (C) 1996-2015, International Business Machines
      6 *   Corporation and others.  All Rights Reserved.
      7 *******************************************************************************
      8 * Modification History:
      9 *
     10 *   Date        Name        Description
     11 *   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
     12 *******************************************************************************
     13 */
     14 
     15 #include "unicode/utypes.h"
     16 
     17 #if !UCONFIG_NO_FORMATTING
     18 
     19 #include "unicode/unum.h"
     20 
     21 #include "unicode/uloc.h"
     22 #include "unicode/numfmt.h"
     23 #include "unicode/decimfmt.h"
     24 #include "unicode/rbnf.h"
     25 #include "unicode/compactdecimalformat.h"
     26 #include "unicode/ustring.h"
     27 #include "unicode/fmtable.h"
     28 #include "unicode/dcfmtsym.h"
     29 #include "unicode/curramt.h"
     30 #include "unicode/localpointer.h"
     31 #include "unicode/udisplaycontext.h"
     32 #include "uassert.h"
     33 #include "cpputils.h"
     34 #include "cstring.h"
     35 
     36 
     37 U_NAMESPACE_USE
     38 
     39 
     40 U_CAPI UNumberFormat* U_EXPORT2
     41 unum_open(  UNumberFormatStyle    style,
     42             const    UChar*    pattern,
     43             int32_t            patternLength,
     44             const    char*     locale,
     45             UParseError*       parseErr,
     46             UErrorCode*        status) {
     47     if(U_FAILURE(*status)) {
     48         return NULL;
     49     }
     50 
     51     NumberFormat *retVal = NULL;
     52 
     53     switch(style) {
     54     case UNUM_DECIMAL:
     55     case UNUM_CURRENCY:
     56     case UNUM_PERCENT:
     57     case UNUM_SCIENTIFIC:
     58     case UNUM_CURRENCY_ISO:
     59     case UNUM_CURRENCY_PLURAL:
     60     case UNUM_CURRENCY_ACCOUNTING:
     61     case UNUM_CASH_CURRENCY:
     62     case UNUM_CURRENCY_STANDARD:
     63         retVal = NumberFormat::createInstance(Locale(locale), style, *status);
     64         break;
     65 
     66     case UNUM_PATTERN_DECIMAL: {
     67         UParseError tErr;
     68         /* UnicodeString can handle the case when patternLength = -1. */
     69         const UnicodeString pat(pattern, patternLength);
     70 
     71         if(parseErr==NULL){
     72             parseErr = &tErr;
     73         }
     74 
     75         DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
     76         if(syms == NULL) {
     77             *status = U_MEMORY_ALLOCATION_ERROR;
     78             return NULL;
     79         }
     80         if (U_FAILURE(*status)) {
     81             delete syms;
     82             return NULL;
     83         }
     84 
     85         retVal = new DecimalFormat(pat, syms, *parseErr, *status);
     86         if(retVal == NULL) {
     87             delete syms;
     88         }
     89     } break;
     90 
     91 #if U_HAVE_RBNF
     92     case UNUM_PATTERN_RULEBASED: {
     93         UParseError tErr;
     94         /* UnicodeString can handle the case when patternLength = -1. */
     95         const UnicodeString pat(pattern, patternLength);
     96 
     97         if(parseErr==NULL){
     98             parseErr = &tErr;
     99         }
    100 
    101         retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
    102     } break;
    103 
    104     case UNUM_SPELLOUT:
    105         retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
    106         break;
    107 
    108     case UNUM_ORDINAL:
    109         retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
    110         break;
    111 
    112     case UNUM_DURATION:
    113         retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
    114         break;
    115 
    116     case UNUM_NUMBERING_SYSTEM:
    117         retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
    118         break;
    119 #endif
    120 
    121     case UNUM_DECIMAL_COMPACT_SHORT:
    122         retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
    123         break;
    124 
    125     case UNUM_DECIMAL_COMPACT_LONG:
    126         retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
    127         break;
    128 
    129     default:
    130         *status = U_UNSUPPORTED_ERROR;
    131         return NULL;
    132     }
    133 
    134     if(retVal == NULL && U_SUCCESS(*status)) {
    135         *status = U_MEMORY_ALLOCATION_ERROR;
    136     }
    137 
    138     return reinterpret_cast<UNumberFormat *>(retVal);
    139 }
    140 
    141 U_CAPI void U_EXPORT2
    142 unum_close(UNumberFormat* fmt)
    143 {
    144     delete (NumberFormat*) fmt;
    145 }
    146 
    147 U_CAPI UNumberFormat* U_EXPORT2
    148 unum_clone(const UNumberFormat *fmt,
    149        UErrorCode *status)
    150 {
    151     if(U_FAILURE(*status))
    152         return 0;
    153 
    154     Format *res = 0;
    155     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    156     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    157     if (df != NULL) {
    158         res = df->clone();
    159     } else {
    160         const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
    161         U_ASSERT(rbnf != NULL);
    162         res = rbnf->clone();
    163     }
    164 
    165     if(res == 0) {
    166         *status = U_MEMORY_ALLOCATION_ERROR;
    167         return 0;
    168     }
    169 
    170     return (UNumberFormat*) res;
    171 }
    172 
    173 U_CAPI int32_t U_EXPORT2
    174 unum_format(    const    UNumberFormat*    fmt,
    175         int32_t           number,
    176         UChar*            result,
    177         int32_t           resultLength,
    178         UFieldPosition    *pos,
    179         UErrorCode*       status)
    180 {
    181         return unum_formatInt64(fmt, number, result, resultLength, pos, status);
    182 }
    183 
    184 U_CAPI int32_t U_EXPORT2
    185 unum_formatInt64(const UNumberFormat* fmt,
    186         int64_t         number,
    187         UChar*          result,
    188         int32_t         resultLength,
    189         UFieldPosition *pos,
    190         UErrorCode*     status)
    191 {
    192     if(U_FAILURE(*status))
    193         return -1;
    194 
    195     UnicodeString res;
    196     if(!(result==NULL && resultLength==0)) {
    197         // NULL destination for pure preflighting: empty dummy string
    198         // otherwise, alias the destination buffer
    199         res.setTo(result, 0, resultLength);
    200     }
    201 
    202     FieldPosition fp;
    203 
    204     if(pos != 0)
    205         fp.setField(pos->field);
    206 
    207     ((const NumberFormat*)fmt)->format(number, res, fp, *status);
    208 
    209     if(pos != 0) {
    210         pos->beginIndex = fp.getBeginIndex();
    211         pos->endIndex = fp.getEndIndex();
    212     }
    213 
    214     return res.extract(result, resultLength, *status);
    215 }
    216 
    217 U_CAPI int32_t U_EXPORT2
    218 unum_formatDouble(    const    UNumberFormat*  fmt,
    219             double          number,
    220             UChar*          result,
    221             int32_t         resultLength,
    222             UFieldPosition  *pos, /* 0 if ignore */
    223             UErrorCode*     status)
    224 {
    225 
    226   if(U_FAILURE(*status)) return -1;
    227 
    228   UnicodeString res;
    229   if(!(result==NULL && resultLength==0)) {
    230     // NULL destination for pure preflighting: empty dummy string
    231     // otherwise, alias the destination buffer
    232     res.setTo(result, 0, resultLength);
    233   }
    234 
    235   FieldPosition fp;
    236 
    237   if(pos != 0)
    238     fp.setField(pos->field);
    239 
    240   ((const NumberFormat*)fmt)->format(number, res, fp, *status);
    241 
    242   if(pos != 0) {
    243     pos->beginIndex = fp.getBeginIndex();
    244     pos->endIndex = fp.getEndIndex();
    245   }
    246 
    247   return res.extract(result, resultLength, *status);
    248 }
    249 
    250 U_CAPI int32_t U_EXPORT2
    251 unum_formatDoubleForFields(const UNumberFormat* format,
    252                            double number,
    253                            UChar* result,
    254                            int32_t resultLength,
    255                            UFieldPositionIterator* fpositer,
    256                            UErrorCode* status)
    257 {
    258     if (U_FAILURE(*status))
    259         return -1;
    260 
    261     if (result == NULL ? resultLength != 0 : resultLength < 0) {
    262         *status = U_ILLEGAL_ARGUMENT_ERROR;
    263         return -1;
    264     }
    265 
    266     UnicodeString res;
    267     if (result != NULL) {
    268         // NULL destination for pure preflighting: empty dummy string
    269         // otherwise, alias the destination buffer
    270         res.setTo(result, 0, resultLength);
    271     }
    272 
    273     ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
    274 
    275     return res.extract(result, resultLength, *status);
    276 }
    277 
    278 U_CAPI int32_t U_EXPORT2
    279 unum_formatDecimal(const    UNumberFormat*  fmt,
    280             const char *    number,
    281             int32_t         length,
    282             UChar*          result,
    283             int32_t         resultLength,
    284             UFieldPosition  *pos, /* 0 if ignore */
    285             UErrorCode*     status) {
    286 
    287     if(U_FAILURE(*status)) {
    288         return -1;
    289     }
    290     if ((result == NULL && resultLength != 0) || resultLength < 0) {
    291         *status = U_ILLEGAL_ARGUMENT_ERROR;
    292         return -1;
    293     }
    294 
    295     FieldPosition fp;
    296     if(pos != 0) {
    297         fp.setField(pos->field);
    298     }
    299 
    300     if (length < 0) {
    301         length = static_cast<int32_t>(uprv_strlen(number));
    302     }
    303     StringPiece numSP(number, length);
    304     Formattable numFmtbl(numSP, *status);
    305 
    306     UnicodeString resultStr;
    307     if (resultLength > 0) {
    308         // Alias the destination buffer.
    309         resultStr.setTo(result, 0, resultLength);
    310     }
    311     ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
    312     if(pos != 0) {
    313         pos->beginIndex = fp.getBeginIndex();
    314         pos->endIndex = fp.getEndIndex();
    315     }
    316     return resultStr.extract(result, resultLength, *status);
    317 }
    318 
    319 
    320 
    321 
    322 U_CAPI int32_t U_EXPORT2
    323 unum_formatDoubleCurrency(const UNumberFormat* fmt,
    324                           double number,
    325                           UChar* currency,
    326                           UChar* result,
    327                           int32_t resultLength,
    328                           UFieldPosition* pos, /* ignored if 0 */
    329                           UErrorCode* status) {
    330     if (U_FAILURE(*status)) return -1;
    331 
    332     UnicodeString res;
    333     if (!(result==NULL && resultLength==0)) {
    334         // NULL destination for pure preflighting: empty dummy string
    335         // otherwise, alias the destination buffer
    336         res.setTo(result, 0, resultLength);
    337     }
    338 
    339     FieldPosition fp;
    340     if (pos != 0) {
    341         fp.setField(pos->field);
    342     }
    343     CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
    344     // Check for null pointer.
    345     if (tempCurrAmnt == NULL) {
    346         *status = U_MEMORY_ALLOCATION_ERROR;
    347         return -1;
    348     }
    349     Formattable n(tempCurrAmnt);
    350     ((const NumberFormat*)fmt)->format(n, res, fp, *status);
    351 
    352     if (pos != 0) {
    353         pos->beginIndex = fp.getBeginIndex();
    354         pos->endIndex = fp.getEndIndex();
    355     }
    356 
    357     return res.extract(result, resultLength, *status);
    358 }
    359 
    360 static void
    361 parseRes(Formattable& res,
    362          const   UNumberFormat*  fmt,
    363          const   UChar*          text,
    364          int32_t         textLength,
    365          int32_t         *parsePos /* 0 = start */,
    366          UErrorCode      *status)
    367 {
    368     if(U_FAILURE(*status))
    369         return;
    370 
    371     const UnicodeString src((UBool)(textLength == -1), text, textLength);
    372     ParsePosition pp;
    373 
    374     if(parsePos != 0)
    375         pp.setIndex(*parsePos);
    376 
    377     ((const NumberFormat*)fmt)->parse(src, res, pp);
    378 
    379     if(pp.getErrorIndex() != -1) {
    380         *status = U_PARSE_ERROR;
    381         if(parsePos != 0) {
    382             *parsePos = pp.getErrorIndex();
    383         }
    384     } else if(parsePos != 0) {
    385         *parsePos = pp.getIndex();
    386     }
    387 }
    388 
    389 U_CAPI int32_t U_EXPORT2
    390 unum_parse(    const   UNumberFormat*  fmt,
    391         const   UChar*          text,
    392         int32_t         textLength,
    393         int32_t         *parsePos /* 0 = start */,
    394         UErrorCode      *status)
    395 {
    396     Formattable res;
    397     parseRes(res, fmt, text, textLength, parsePos, status);
    398     return res.getLong(*status);
    399 }
    400 
    401 U_CAPI int64_t U_EXPORT2
    402 unum_parseInt64(    const   UNumberFormat*  fmt,
    403         const   UChar*          text,
    404         int32_t         textLength,
    405         int32_t         *parsePos /* 0 = start */,
    406         UErrorCode      *status)
    407 {
    408     Formattable res;
    409     parseRes(res, fmt, text, textLength, parsePos, status);
    410     return res.getInt64(*status);
    411 }
    412 
    413 U_CAPI double U_EXPORT2
    414 unum_parseDouble(    const   UNumberFormat*  fmt,
    415             const   UChar*          text,
    416             int32_t         textLength,
    417             int32_t         *parsePos /* 0 = start */,
    418             UErrorCode      *status)
    419 {
    420     Formattable res;
    421     parseRes(res, fmt, text, textLength, parsePos, status);
    422     return res.getDouble(*status);
    423 }
    424 
    425 U_CAPI int32_t U_EXPORT2
    426 unum_parseDecimal(const UNumberFormat*  fmt,
    427             const UChar*    text,
    428             int32_t         textLength,
    429             int32_t         *parsePos /* 0 = start */,
    430             char            *outBuf,
    431             int32_t         outBufLength,
    432             UErrorCode      *status)
    433 {
    434     if (U_FAILURE(*status)) {
    435         return -1;
    436     }
    437     if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
    438         *status = U_ILLEGAL_ARGUMENT_ERROR;
    439         return -1;
    440     }
    441     Formattable res;
    442     parseRes(res, fmt, text, textLength, parsePos, status);
    443     StringPiece sp = res.getDecimalNumber(*status);
    444     if (U_FAILURE(*status)) {
    445        return -1;
    446     } else if (sp.size() > outBufLength) {
    447         *status = U_BUFFER_OVERFLOW_ERROR;
    448     } else if (sp.size() == outBufLength) {
    449         uprv_strncpy(outBuf, sp.data(), sp.size());
    450         *status = U_STRING_NOT_TERMINATED_WARNING;
    451     } else {
    452         U_ASSERT(outBufLength > 0);
    453         uprv_strcpy(outBuf, sp.data());
    454     }
    455     return sp.size();
    456 }
    457 
    458 U_CAPI double U_EXPORT2
    459 unum_parseDoubleCurrency(const UNumberFormat* fmt,
    460                          const UChar* text,
    461                          int32_t textLength,
    462                          int32_t* parsePos, /* 0 = start */
    463                          UChar* currency,
    464                          UErrorCode* status) {
    465     double doubleVal = 0.0;
    466     currency[0] = 0;
    467     if (U_FAILURE(*status)) {
    468         return doubleVal;
    469     }
    470     const UnicodeString src((UBool)(textLength == -1), text, textLength);
    471     ParsePosition pp;
    472     if (parsePos != NULL) {
    473         pp.setIndex(*parsePos);
    474     }
    475     *status = U_PARSE_ERROR; // assume failure, reset if succeed
    476     LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
    477     if (pp.getErrorIndex() != -1) {
    478         if (parsePos != NULL) {
    479             *parsePos = pp.getErrorIndex();
    480         }
    481     } else {
    482         if (parsePos != NULL) {
    483             *parsePos = pp.getIndex();
    484         }
    485         if (pp.getIndex() > 0) {
    486             *status = U_ZERO_ERROR;
    487             u_strcpy(currency, currAmt->getISOCurrency());
    488             doubleVal = currAmt->getNumber().getDouble(*status);
    489         }
    490     }
    491     return doubleVal;
    492 }
    493 
    494 U_CAPI const char* U_EXPORT2
    495 unum_getAvailable(int32_t index)
    496 {
    497     return uloc_getAvailable(index);
    498 }
    499 
    500 U_CAPI int32_t U_EXPORT2
    501 unum_countAvailable()
    502 {
    503     return uloc_countAvailable();
    504 }
    505 
    506 U_CAPI int32_t U_EXPORT2
    507 unum_getAttribute(const UNumberFormat*          fmt,
    508           UNumberFormatAttribute  attr)
    509 {
    510     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    511     if (attr == UNUM_LENIENT_PARSE) {
    512         // Supported for all subclasses
    513         return nf->isLenient();
    514     }
    515     else if (attr == UNUM_MAX_INTEGER_DIGITS) {
    516         return nf->getMaximumIntegerDigits();
    517     }
    518     else if (attr == UNUM_MIN_INTEGER_DIGITS) {
    519         return nf->getMinimumIntegerDigits();
    520     }
    521     else if (attr == UNUM_INTEGER_DIGITS) {
    522         // TODO: what should this return?
    523         return nf->getMinimumIntegerDigits();
    524     }
    525     else if (attr == UNUM_MAX_FRACTION_DIGITS) {
    526         return nf->getMaximumFractionDigits();
    527     }
    528     else if (attr == UNUM_MIN_FRACTION_DIGITS) {
    529         return nf->getMinimumFractionDigits();
    530     }
    531     else if (attr == UNUM_FRACTION_DIGITS) {
    532         // TODO: what should this return?
    533         return nf->getMinimumFractionDigits();
    534     }
    535     else if (attr == UNUM_ROUNDING_MODE) {
    536         return nf->getRoundingMode();
    537     }
    538 
    539     // The remaining attributes are only supported for DecimalFormat
    540     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    541     if (df != NULL) {
    542         UErrorCode ignoredStatus = U_ZERO_ERROR;
    543         return df->getAttribute(attr, ignoredStatus);
    544     }
    545 
    546     return -1;
    547 }
    548 
    549 U_CAPI void U_EXPORT2
    550 unum_setAttribute(    UNumberFormat*          fmt,
    551             UNumberFormatAttribute  attr,
    552             int32_t                 newValue)
    553 {
    554     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    555     if (attr == UNUM_LENIENT_PARSE) {
    556         // Supported for all subclasses
    557         // keep this here as the class may not be a DecimalFormat
    558         return nf->setLenient(newValue != 0);
    559     }
    560     else if (attr == UNUM_MAX_INTEGER_DIGITS) {
    561         return nf->setMaximumIntegerDigits(newValue);
    562     }
    563     else if (attr == UNUM_MIN_INTEGER_DIGITS) {
    564         return nf->setMinimumIntegerDigits(newValue);
    565     }
    566     else if (attr == UNUM_INTEGER_DIGITS) {
    567         nf->setMinimumIntegerDigits(newValue);
    568         return nf->setMaximumIntegerDigits(newValue);
    569     }
    570     else if (attr == UNUM_MAX_FRACTION_DIGITS) {
    571         return nf->setMaximumFractionDigits(newValue);
    572     }
    573     else if (attr == UNUM_MIN_FRACTION_DIGITS) {
    574         return nf->setMinimumFractionDigits(newValue);
    575     }
    576     else if (attr == UNUM_FRACTION_DIGITS) {
    577         nf->setMinimumFractionDigits(newValue);
    578         return nf->setMaximumFractionDigits(newValue);
    579     }
    580     else if (attr == UNUM_ROUNDING_MODE) {
    581         return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
    582     }
    583 
    584     // The remaining attributes are only supported for DecimalFormat
    585     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    586     if (df != NULL) {
    587         UErrorCode ignoredStatus = U_ZERO_ERROR;
    588         df->setAttribute(attr, newValue, ignoredStatus);
    589     }
    590 }
    591 
    592 U_CAPI double U_EXPORT2
    593 unum_getDoubleAttribute(const UNumberFormat*          fmt,
    594           UNumberFormatAttribute  attr)
    595 {
    596     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    597     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    598     if (df != NULL &&  attr == UNUM_ROUNDING_INCREMENT) {
    599         return df->getRoundingIncrement();
    600     } else {
    601         return -1.0;
    602     }
    603 }
    604 
    605 U_CAPI void U_EXPORT2
    606 unum_setDoubleAttribute(    UNumberFormat*          fmt,
    607             UNumberFormatAttribute  attr,
    608             double                 newValue)
    609 {
    610     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    611     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    612     if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
    613         df->setRoundingIncrement(newValue);
    614     }
    615 }
    616 
    617 U_CAPI int32_t U_EXPORT2
    618 unum_getTextAttribute(const UNumberFormat*  fmt,
    619             UNumberFormatTextAttribute      tag,
    620             UChar*                          result,
    621             int32_t                         resultLength,
    622             UErrorCode*                     status)
    623 {
    624     if(U_FAILURE(*status))
    625         return -1;
    626 
    627     UnicodeString res;
    628     if(!(result==NULL && resultLength==0)) {
    629         // NULL destination for pure preflighting: empty dummy string
    630         // otherwise, alias the destination buffer
    631         res.setTo(result, 0, resultLength);
    632     }
    633 
    634     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    635     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    636     if (df != NULL) {
    637         switch(tag) {
    638         case UNUM_POSITIVE_PREFIX:
    639             df->getPositivePrefix(res);
    640             break;
    641 
    642         case UNUM_POSITIVE_SUFFIX:
    643             df->getPositiveSuffix(res);
    644             break;
    645 
    646         case UNUM_NEGATIVE_PREFIX:
    647             df->getNegativePrefix(res);
    648             break;
    649 
    650         case UNUM_NEGATIVE_SUFFIX:
    651             df->getNegativeSuffix(res);
    652             break;
    653 
    654         case UNUM_PADDING_CHARACTER:
    655             res = df->getPadCharacterString();
    656             break;
    657 
    658         case UNUM_CURRENCY_CODE:
    659             res = UnicodeString(df->getCurrency());
    660             break;
    661 
    662         default:
    663             *status = U_UNSUPPORTED_ERROR;
    664             return -1;
    665         }
    666     } else {
    667         const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
    668         U_ASSERT(rbnf != NULL);
    669         if (tag == UNUM_DEFAULT_RULESET) {
    670             res = rbnf->getDefaultRuleSetName();
    671         } else if (tag == UNUM_PUBLIC_RULESETS) {
    672             int32_t count = rbnf->getNumberOfRuleSetNames();
    673             for (int i = 0; i < count; ++i) {
    674                 res += rbnf->getRuleSetName(i);
    675                 res += (UChar)0x003b; // semicolon
    676             }
    677         } else {
    678             *status = U_UNSUPPORTED_ERROR;
    679             return -1;
    680         }
    681     }
    682 
    683     return res.extract(result, resultLength, *status);
    684 }
    685 
    686 U_CAPI void U_EXPORT2
    687 unum_setTextAttribute(    UNumberFormat*                    fmt,
    688             UNumberFormatTextAttribute      tag,
    689             const    UChar*                            newValue,
    690             int32_t                            newValueLength,
    691             UErrorCode                        *status)
    692 {
    693     if(U_FAILURE(*status))
    694         return;
    695 
    696     UnicodeString val(newValue, newValueLength);
    697     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    698     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    699     if (df != NULL) {
    700       switch(tag) {
    701       case UNUM_POSITIVE_PREFIX:
    702         df->setPositivePrefix(val);
    703         break;
    704 
    705       case UNUM_POSITIVE_SUFFIX:
    706         df->setPositiveSuffix(val);
    707         break;
    708 
    709       case UNUM_NEGATIVE_PREFIX:
    710         df->setNegativePrefix(val);
    711         break;
    712 
    713       case UNUM_NEGATIVE_SUFFIX:
    714         df->setNegativeSuffix(val);
    715         break;
    716 
    717       case UNUM_PADDING_CHARACTER:
    718         df->setPadCharacter(val);
    719         break;
    720 
    721       case UNUM_CURRENCY_CODE:
    722         df->setCurrency(val.getTerminatedBuffer(), *status);
    723         break;
    724 
    725       default:
    726         *status = U_UNSUPPORTED_ERROR;
    727         break;
    728       }
    729     } else {
    730       RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
    731       U_ASSERT(rbnf != NULL);
    732       if (tag == UNUM_DEFAULT_RULESET) {
    733         rbnf->setDefaultRuleSet(val, *status);
    734       } else {
    735         *status = U_UNSUPPORTED_ERROR;
    736       }
    737     }
    738 }
    739 
    740 U_CAPI int32_t U_EXPORT2
    741 unum_toPattern(    const    UNumberFormat*          fmt,
    742         UBool                  isPatternLocalized,
    743         UChar*                  result,
    744         int32_t                 resultLength,
    745         UErrorCode*             status)
    746 {
    747     if(U_FAILURE(*status))
    748         return -1;
    749 
    750     UnicodeString pat;
    751     if(!(result==NULL && resultLength==0)) {
    752         // NULL destination for pure preflighting: empty dummy string
    753         // otherwise, alias the destination buffer
    754         pat.setTo(result, 0, resultLength);
    755     }
    756 
    757     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    758     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    759     if (df != NULL) {
    760       if(isPatternLocalized)
    761         df->toLocalizedPattern(pat);
    762       else
    763         df->toPattern(pat);
    764     } else {
    765       const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
    766       U_ASSERT(rbnf != NULL);
    767       pat = rbnf->getRules();
    768     }
    769     return pat.extract(result, resultLength, *status);
    770 }
    771 
    772 U_CAPI int32_t U_EXPORT2
    773 unum_getSymbol(const UNumberFormat *fmt,
    774                UNumberFormatSymbol symbol,
    775                UChar *buffer,
    776                int32_t size,
    777                UErrorCode *status)
    778 {
    779     if(status==NULL || U_FAILURE(*status)) {
    780         return 0;
    781     }
    782     if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
    783         *status=U_ILLEGAL_ARGUMENT_ERROR;
    784         return 0;
    785     }
    786     const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
    787     const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
    788     if (dcf == NULL) {
    789       *status = U_UNSUPPORTED_ERROR;
    790       return 0;
    791     }
    792 
    793     return dcf->
    794       getDecimalFormatSymbols()->
    795         getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
    796           extract(buffer, size, *status);
    797 }
    798 
    799 U_CAPI void U_EXPORT2
    800 unum_setSymbol(UNumberFormat *fmt,
    801                UNumberFormatSymbol symbol,
    802                const UChar *value,
    803                int32_t length,
    804                UErrorCode *status)
    805 {
    806     if(status==NULL || U_FAILURE(*status)) {
    807         return;
    808     }
    809     if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
    810         *status=U_ILLEGAL_ARGUMENT_ERROR;
    811         return;
    812     }
    813     NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
    814     DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
    815     if (dcf == NULL) {
    816       *status = U_UNSUPPORTED_ERROR;
    817       return;
    818     }
    819 
    820     DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
    821     symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
    822         UnicodeString(value, length));  /* UnicodeString can handle the case when length = -1. */
    823     dcf->setDecimalFormatSymbols(symbols);
    824 }
    825 
    826 U_CAPI void U_EXPORT2
    827 unum_applyPattern(  UNumberFormat  *fmt,
    828                     UBool          localized,
    829                     const UChar    *pattern,
    830                     int32_t        patternLength,
    831                     UParseError    *parseError,
    832                     UErrorCode*    status)
    833 {
    834     UErrorCode tStatus = U_ZERO_ERROR;
    835     UParseError tParseError;
    836 
    837     if(parseError == NULL){
    838         parseError = &tParseError;
    839     }
    840 
    841     if(status==NULL){
    842         status = &tStatus;
    843     }
    844 
    845     int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
    846     const UnicodeString pat((UChar*)pattern, len, len);
    847 
    848     // Verify if the object passed is a DecimalFormat object
    849     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    850     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    851     if (df != NULL) {
    852       if(localized) {
    853         df->applyLocalizedPattern(pat,*parseError, *status);
    854       } else {
    855         df->applyPattern(pat,*parseError, *status);
    856       }
    857     } else {
    858       *status = U_UNSUPPORTED_ERROR;
    859       return;
    860     }
    861 }
    862 
    863 U_CAPI const char* U_EXPORT2
    864 unum_getLocaleByType(const UNumberFormat *fmt,
    865                      ULocDataLocaleType type,
    866                      UErrorCode* status)
    867 {
    868     if (fmt == NULL) {
    869         if (U_SUCCESS(*status)) {
    870             *status = U_ILLEGAL_ARGUMENT_ERROR;
    871         }
    872         return NULL;
    873     }
    874     return ((const Format*)fmt)->getLocaleID(type, *status);
    875 }
    876 
    877 U_CAPI void U_EXPORT2
    878 unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
    879 {
    880     if (U_FAILURE(*status)) {
    881         return;
    882     }
    883     ((NumberFormat*)fmt)->setContext(value, *status);
    884     return;
    885 }
    886 
    887 U_CAPI UDisplayContext U_EXPORT2
    888 unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
    889 {
    890     if (U_FAILURE(*status)) {
    891         return (UDisplayContext)0;
    892     }
    893     return ((const NumberFormat*)fmt)->getContext(type, *status);
    894 }
    895 
    896 U_INTERNAL UFormattable * U_EXPORT2
    897 unum_parseToUFormattable(const UNumberFormat* fmt,
    898                          UFormattable *result,
    899                          const UChar* text,
    900                          int32_t textLength,
    901                          int32_t* parsePos, /* 0 = start */
    902                          UErrorCode* status) {
    903   UFormattable *newFormattable = NULL;
    904   if (U_FAILURE(*status)) return result;
    905   if (fmt == NULL || (text==NULL && textLength!=0)) {
    906     *status = U_ILLEGAL_ARGUMENT_ERROR;
    907     return result;
    908   }
    909   if (result == NULL) { // allocate if not allocated.
    910     newFormattable = result = ufmt_open(status);
    911   }
    912   parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
    913   if (U_FAILURE(*status) && newFormattable != NULL) {
    914     ufmt_close(newFormattable);
    915     result = NULL; // deallocate if there was a parse error
    916   }
    917   return result;
    918 }
    919 
    920 U_INTERNAL int32_t U_EXPORT2
    921 unum_formatUFormattable(const UNumberFormat* fmt,
    922                         const UFormattable *number,
    923                         UChar *result,
    924                         int32_t resultLength,
    925                         UFieldPosition *pos, /* ignored if 0 */
    926                         UErrorCode *status) {
    927     if (U_FAILURE(*status)) {
    928       return 0;
    929     }
    930     if (fmt == NULL || number==NULL ||
    931         (result==NULL ? resultLength!=0 : resultLength<0)) {
    932       *status = U_ILLEGAL_ARGUMENT_ERROR;
    933       return 0;
    934     }
    935     UnicodeString res(result, 0, resultLength);
    936 
    937     FieldPosition fp;
    938 
    939     if(pos != 0)
    940         fp.setField(pos->field);
    941 
    942     ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
    943 
    944     if(pos != 0) {
    945         pos->beginIndex = fp.getBeginIndex();
    946         pos->endIndex = fp.getEndIndex();
    947     }
    948 
    949     return res.extract(result, resultLength, *status);
    950 }
    951 
    952 #endif /* #if !UCONFIG_NO_FORMATTING */
    953