Home | History | Annotate | Download | only in i18n
      1 // Copyright (C) 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 
    251 U_CAPI int32_t U_EXPORT2
    252 unum_formatDecimal(const    UNumberFormat*  fmt,
    253             const char *    number,
    254             int32_t         length,
    255             UChar*          result,
    256             int32_t         resultLength,
    257             UFieldPosition  *pos, /* 0 if ignore */
    258             UErrorCode*     status) {
    259 
    260     if(U_FAILURE(*status)) {
    261         return -1;
    262     }
    263     if ((result == NULL && resultLength != 0) || resultLength < 0) {
    264         *status = U_ILLEGAL_ARGUMENT_ERROR;
    265         return -1;
    266     }
    267 
    268     FieldPosition fp;
    269     if(pos != 0) {
    270         fp.setField(pos->field);
    271     }
    272 
    273     if (length < 0) {
    274         length = uprv_strlen(number);
    275     }
    276     StringPiece numSP(number, length);
    277     Formattable numFmtbl(numSP, *status);
    278 
    279     UnicodeString resultStr;
    280     if (resultLength > 0) {
    281         // Alias the destination buffer.
    282         resultStr.setTo(result, 0, resultLength);
    283     }
    284     ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
    285     if(pos != 0) {
    286         pos->beginIndex = fp.getBeginIndex();
    287         pos->endIndex = fp.getEndIndex();
    288     }
    289     return resultStr.extract(result, resultLength, *status);
    290 }
    291 
    292 
    293 
    294 
    295 U_CAPI int32_t U_EXPORT2
    296 unum_formatDoubleCurrency(const UNumberFormat* fmt,
    297                           double number,
    298                           UChar* currency,
    299                           UChar* result,
    300                           int32_t resultLength,
    301                           UFieldPosition* pos, /* ignored if 0 */
    302                           UErrorCode* status) {
    303     if (U_FAILURE(*status)) return -1;
    304 
    305     UnicodeString res;
    306     if (!(result==NULL && resultLength==0)) {
    307         // NULL destination for pure preflighting: empty dummy string
    308         // otherwise, alias the destination buffer
    309         res.setTo(result, 0, resultLength);
    310     }
    311 
    312     FieldPosition fp;
    313     if (pos != 0) {
    314         fp.setField(pos->field);
    315     }
    316     CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
    317     // Check for null pointer.
    318     if (tempCurrAmnt == NULL) {
    319         *status = U_MEMORY_ALLOCATION_ERROR;
    320         return -1;
    321     }
    322     Formattable n(tempCurrAmnt);
    323     ((const NumberFormat*)fmt)->format(n, res, fp, *status);
    324 
    325     if (pos != 0) {
    326         pos->beginIndex = fp.getBeginIndex();
    327         pos->endIndex = fp.getEndIndex();
    328     }
    329 
    330     return res.extract(result, resultLength, *status);
    331 }
    332 
    333 static void
    334 parseRes(Formattable& res,
    335          const   UNumberFormat*  fmt,
    336          const   UChar*          text,
    337          int32_t         textLength,
    338          int32_t         *parsePos /* 0 = start */,
    339          UErrorCode      *status)
    340 {
    341     if(U_FAILURE(*status))
    342         return;
    343 
    344     const UnicodeString src((UBool)(textLength == -1), text, textLength);
    345     ParsePosition pp;
    346 
    347     if(parsePos != 0)
    348         pp.setIndex(*parsePos);
    349 
    350     ((const NumberFormat*)fmt)->parse(src, res, pp);
    351 
    352     if(pp.getErrorIndex() != -1) {
    353         *status = U_PARSE_ERROR;
    354         if(parsePos != 0) {
    355             *parsePos = pp.getErrorIndex();
    356         }
    357     } else if(parsePos != 0) {
    358         *parsePos = pp.getIndex();
    359     }
    360 }
    361 
    362 U_CAPI int32_t U_EXPORT2
    363 unum_parse(    const   UNumberFormat*  fmt,
    364         const   UChar*          text,
    365         int32_t         textLength,
    366         int32_t         *parsePos /* 0 = start */,
    367         UErrorCode      *status)
    368 {
    369     Formattable res;
    370     parseRes(res, fmt, text, textLength, parsePos, status);
    371     return res.getLong(*status);
    372 }
    373 
    374 U_CAPI int64_t U_EXPORT2
    375 unum_parseInt64(    const   UNumberFormat*  fmt,
    376         const   UChar*          text,
    377         int32_t         textLength,
    378         int32_t         *parsePos /* 0 = start */,
    379         UErrorCode      *status)
    380 {
    381     Formattable res;
    382     parseRes(res, fmt, text, textLength, parsePos, status);
    383     return res.getInt64(*status);
    384 }
    385 
    386 U_CAPI double U_EXPORT2
    387 unum_parseDouble(    const   UNumberFormat*  fmt,
    388             const   UChar*          text,
    389             int32_t         textLength,
    390             int32_t         *parsePos /* 0 = start */,
    391             UErrorCode      *status)
    392 {
    393     Formattable res;
    394     parseRes(res, fmt, text, textLength, parsePos, status);
    395     return res.getDouble(*status);
    396 }
    397 
    398 U_CAPI int32_t U_EXPORT2
    399 unum_parseDecimal(const UNumberFormat*  fmt,
    400             const UChar*    text,
    401             int32_t         textLength,
    402             int32_t         *parsePos /* 0 = start */,
    403             char            *outBuf,
    404             int32_t         outBufLength,
    405             UErrorCode      *status)
    406 {
    407     if (U_FAILURE(*status)) {
    408         return -1;
    409     }
    410     if ((outBuf == NULL && outBufLength != 0) || outBufLength < 0) {
    411         *status = U_ILLEGAL_ARGUMENT_ERROR;
    412         return -1;
    413     }
    414     Formattable res;
    415     parseRes(res, fmt, text, textLength, parsePos, status);
    416     StringPiece sp = res.getDecimalNumber(*status);
    417     if (U_FAILURE(*status)) {
    418        return -1;
    419     } else if (sp.size() > outBufLength) {
    420         *status = U_BUFFER_OVERFLOW_ERROR;
    421     } else if (sp.size() == outBufLength) {
    422         uprv_strncpy(outBuf, sp.data(), sp.size());
    423         *status = U_STRING_NOT_TERMINATED_WARNING;
    424     } else {
    425         U_ASSERT(outBufLength > 0);
    426         uprv_strcpy(outBuf, sp.data());
    427     }
    428     return sp.size();
    429 }
    430 
    431 U_CAPI double U_EXPORT2
    432 unum_parseDoubleCurrency(const UNumberFormat* fmt,
    433                          const UChar* text,
    434                          int32_t textLength,
    435                          int32_t* parsePos, /* 0 = start */
    436                          UChar* currency,
    437                          UErrorCode* status) {
    438     double doubleVal = 0.0;
    439     currency[0] = 0;
    440     if (U_FAILURE(*status)) {
    441         return doubleVal;
    442     }
    443     const UnicodeString src((UBool)(textLength == -1), text, textLength);
    444     ParsePosition pp;
    445     if (parsePos != NULL) {
    446         pp.setIndex(*parsePos);
    447     }
    448     *status = U_PARSE_ERROR; // assume failure, reset if succeed
    449     LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
    450     if (pp.getErrorIndex() != -1) {
    451         if (parsePos != NULL) {
    452             *parsePos = pp.getErrorIndex();
    453         }
    454     } else {
    455         if (parsePos != NULL) {
    456             *parsePos = pp.getIndex();
    457         }
    458         if (pp.getIndex() > 0) {
    459             *status = U_ZERO_ERROR;
    460             u_strcpy(currency, currAmt->getISOCurrency());
    461             doubleVal = currAmt->getNumber().getDouble(*status);
    462         }
    463     }
    464     return doubleVal;
    465 }
    466 
    467 U_CAPI const char* U_EXPORT2
    468 unum_getAvailable(int32_t index)
    469 {
    470     return uloc_getAvailable(index);
    471 }
    472 
    473 U_CAPI int32_t U_EXPORT2
    474 unum_countAvailable()
    475 {
    476     return uloc_countAvailable();
    477 }
    478 
    479 U_CAPI int32_t U_EXPORT2
    480 unum_getAttribute(const UNumberFormat*          fmt,
    481           UNumberFormatAttribute  attr)
    482 {
    483   const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    484   if ( attr == UNUM_LENIENT_PARSE ) {
    485     // Supported for all subclasses
    486     return nf->isLenient();
    487   }
    488 
    489   // The remaining attributea are only supported for DecimalFormat
    490   const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    491   if (df != NULL) {
    492     UErrorCode ignoredStatus = U_ZERO_ERROR;
    493     return df->getAttribute( attr, ignoredStatus );
    494   }
    495 
    496   return -1;
    497 }
    498 
    499 U_CAPI void U_EXPORT2
    500 unum_setAttribute(    UNumberFormat*          fmt,
    501             UNumberFormatAttribute  attr,
    502             int32_t                 newValue)
    503 {
    504   NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    505   if ( attr == UNUM_LENIENT_PARSE ) {
    506     // Supported for all subclasses
    507     // keep this here as the class may not be a DecimalFormat
    508     return nf->setLenient(newValue != 0);
    509   }
    510   // The remaining attributea are only supported for DecimalFormat
    511   DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    512   if (df != NULL) {
    513     UErrorCode ignoredStatus = U_ZERO_ERROR;
    514     df->setAttribute(attr, newValue, ignoredStatus);
    515   }
    516 }
    517 
    518 U_CAPI double U_EXPORT2
    519 unum_getDoubleAttribute(const UNumberFormat*          fmt,
    520           UNumberFormatAttribute  attr)
    521 {
    522     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    523     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    524     if (df != NULL &&  attr == UNUM_ROUNDING_INCREMENT) {
    525         return df->getRoundingIncrement();
    526     } else {
    527         return -1.0;
    528     }
    529 }
    530 
    531 U_CAPI void U_EXPORT2
    532 unum_setDoubleAttribute(    UNumberFormat*          fmt,
    533             UNumberFormatAttribute  attr,
    534             double                 newValue)
    535 {
    536     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    537     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    538     if (df != NULL && attr == UNUM_ROUNDING_INCREMENT) {
    539         df->setRoundingIncrement(newValue);
    540     }
    541 }
    542 
    543 U_CAPI int32_t U_EXPORT2
    544 unum_getTextAttribute(const UNumberFormat*  fmt,
    545             UNumberFormatTextAttribute      tag,
    546             UChar*                          result,
    547             int32_t                         resultLength,
    548             UErrorCode*                     status)
    549 {
    550     if(U_FAILURE(*status))
    551         return -1;
    552 
    553     UnicodeString res;
    554     if(!(result==NULL && resultLength==0)) {
    555         // NULL destination for pure preflighting: empty dummy string
    556         // otherwise, alias the destination buffer
    557         res.setTo(result, 0, resultLength);
    558     }
    559 
    560     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    561     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    562     if (df != NULL) {
    563         switch(tag) {
    564         case UNUM_POSITIVE_PREFIX:
    565             df->getPositivePrefix(res);
    566             break;
    567 
    568         case UNUM_POSITIVE_SUFFIX:
    569             df->getPositiveSuffix(res);
    570             break;
    571 
    572         case UNUM_NEGATIVE_PREFIX:
    573             df->getNegativePrefix(res);
    574             break;
    575 
    576         case UNUM_NEGATIVE_SUFFIX:
    577             df->getNegativeSuffix(res);
    578             break;
    579 
    580         case UNUM_PADDING_CHARACTER:
    581             res = df->getPadCharacterString();
    582             break;
    583 
    584         case UNUM_CURRENCY_CODE:
    585             res = UnicodeString(df->getCurrency());
    586             break;
    587 
    588         default:
    589             *status = U_UNSUPPORTED_ERROR;
    590             return -1;
    591         }
    592     } else {
    593         const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
    594         U_ASSERT(rbnf != NULL);
    595         if (tag == UNUM_DEFAULT_RULESET) {
    596             res = rbnf->getDefaultRuleSetName();
    597         } else if (tag == UNUM_PUBLIC_RULESETS) {
    598             int32_t count = rbnf->getNumberOfRuleSetNames();
    599             for (int i = 0; i < count; ++i) {
    600                 res += rbnf->getRuleSetName(i);
    601                 res += (UChar)0x003b; // semicolon
    602             }
    603         } else {
    604             *status = U_UNSUPPORTED_ERROR;
    605             return -1;
    606         }
    607     }
    608 
    609     return res.extract(result, resultLength, *status);
    610 }
    611 
    612 U_CAPI void U_EXPORT2
    613 unum_setTextAttribute(    UNumberFormat*                    fmt,
    614             UNumberFormatTextAttribute      tag,
    615             const    UChar*                            newValue,
    616             int32_t                            newValueLength,
    617             UErrorCode                        *status)
    618 {
    619     if(U_FAILURE(*status))
    620         return;
    621 
    622     UnicodeString val(newValue, newValueLength);
    623     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    624     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    625     if (df != NULL) {
    626       switch(tag) {
    627       case UNUM_POSITIVE_PREFIX:
    628         df->setPositivePrefix(val);
    629         break;
    630 
    631       case UNUM_POSITIVE_SUFFIX:
    632         df->setPositiveSuffix(val);
    633         break;
    634 
    635       case UNUM_NEGATIVE_PREFIX:
    636         df->setNegativePrefix(val);
    637         break;
    638 
    639       case UNUM_NEGATIVE_SUFFIX:
    640         df->setNegativeSuffix(val);
    641         break;
    642 
    643       case UNUM_PADDING_CHARACTER:
    644         df->setPadCharacter(val);
    645         break;
    646 
    647       case UNUM_CURRENCY_CODE:
    648         df->setCurrency(val.getTerminatedBuffer(), *status);
    649         break;
    650 
    651       default:
    652         *status = U_UNSUPPORTED_ERROR;
    653         break;
    654       }
    655     } else {
    656       RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
    657       U_ASSERT(rbnf != NULL);
    658       if (tag == UNUM_DEFAULT_RULESET) {
    659         rbnf->setDefaultRuleSet(val, *status);
    660       } else {
    661         *status = U_UNSUPPORTED_ERROR;
    662       }
    663     }
    664 }
    665 
    666 U_CAPI int32_t U_EXPORT2
    667 unum_toPattern(    const    UNumberFormat*          fmt,
    668         UBool                  isPatternLocalized,
    669         UChar*                  result,
    670         int32_t                 resultLength,
    671         UErrorCode*             status)
    672 {
    673     if(U_FAILURE(*status))
    674         return -1;
    675 
    676     UnicodeString pat;
    677     if(!(result==NULL && resultLength==0)) {
    678         // NULL destination for pure preflighting: empty dummy string
    679         // otherwise, alias the destination buffer
    680         pat.setTo(result, 0, resultLength);
    681     }
    682 
    683     const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    684     const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    685     if (df != NULL) {
    686       if(isPatternLocalized)
    687         df->toLocalizedPattern(pat);
    688       else
    689         df->toPattern(pat);
    690     } else {
    691       const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
    692       U_ASSERT(rbnf != NULL);
    693       pat = rbnf->getRules();
    694     }
    695     return pat.extract(result, resultLength, *status);
    696 }
    697 
    698 U_CAPI int32_t U_EXPORT2
    699 unum_getSymbol(const UNumberFormat *fmt,
    700                UNumberFormatSymbol symbol,
    701                UChar *buffer,
    702                int32_t size,
    703                UErrorCode *status)
    704 {
    705     if(status==NULL || U_FAILURE(*status)) {
    706         return 0;
    707     }
    708     if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
    709         *status=U_ILLEGAL_ARGUMENT_ERROR;
    710         return 0;
    711     }
    712     const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
    713     const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
    714     if (dcf == NULL) {
    715       *status = U_UNSUPPORTED_ERROR;
    716       return 0;
    717     }
    718 
    719     return dcf->
    720       getDecimalFormatSymbols()->
    721         getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
    722           extract(buffer, size, *status);
    723 }
    724 
    725 U_CAPI void U_EXPORT2
    726 unum_setSymbol(UNumberFormat *fmt,
    727                UNumberFormatSymbol symbol,
    728                const UChar *value,
    729                int32_t length,
    730                UErrorCode *status)
    731 {
    732     if(status==NULL || U_FAILURE(*status)) {
    733         return;
    734     }
    735     if(fmt==NULL || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
    736         *status=U_ILLEGAL_ARGUMENT_ERROR;
    737         return;
    738     }
    739     NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
    740     DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
    741     if (dcf == NULL) {
    742       *status = U_UNSUPPORTED_ERROR;
    743       return;
    744     }
    745 
    746     DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
    747     symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
    748         UnicodeString(value, length));  /* UnicodeString can handle the case when length = -1. */
    749     dcf->setDecimalFormatSymbols(symbols);
    750 }
    751 
    752 U_CAPI void U_EXPORT2
    753 unum_applyPattern(  UNumberFormat  *fmt,
    754                     UBool          localized,
    755                     const UChar    *pattern,
    756                     int32_t        patternLength,
    757                     UParseError    *parseError,
    758                     UErrorCode*    status)
    759 {
    760     UErrorCode tStatus = U_ZERO_ERROR;
    761     UParseError tParseError;
    762 
    763     if(parseError == NULL){
    764         parseError = &tParseError;
    765     }
    766 
    767     if(status==NULL){
    768         status = &tStatus;
    769     }
    770 
    771     int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
    772     const UnicodeString pat((UChar*)pattern, len, len);
    773 
    774     // Verify if the object passed is a DecimalFormat object
    775     NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    776     DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    777     if (df != NULL) {
    778       if(localized) {
    779         df->applyLocalizedPattern(pat,*parseError, *status);
    780       } else {
    781         df->applyPattern(pat,*parseError, *status);
    782       }
    783     } else {
    784       *status = U_UNSUPPORTED_ERROR;
    785       return;
    786     }
    787 }
    788 
    789 U_CAPI const char* U_EXPORT2
    790 unum_getLocaleByType(const UNumberFormat *fmt,
    791                      ULocDataLocaleType type,
    792                      UErrorCode* status)
    793 {
    794     if (fmt == NULL) {
    795         if (U_SUCCESS(*status)) {
    796             *status = U_ILLEGAL_ARGUMENT_ERROR;
    797         }
    798         return NULL;
    799     }
    800     return ((const Format*)fmt)->getLocaleID(type, *status);
    801 }
    802 
    803 U_CAPI void U_EXPORT2
    804 unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
    805 {
    806     if (U_FAILURE(*status)) {
    807         return;
    808     }
    809     ((NumberFormat*)fmt)->setContext(value, *status);
    810     return;
    811 }
    812 
    813 U_CAPI UDisplayContext U_EXPORT2
    814 unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
    815 {
    816     if (U_FAILURE(*status)) {
    817         return (UDisplayContext)0;
    818     }
    819     return ((const NumberFormat*)fmt)->getContext(type, *status);
    820 }
    821 
    822 U_INTERNAL UFormattable * U_EXPORT2
    823 unum_parseToUFormattable(const UNumberFormat* fmt,
    824                          UFormattable *result,
    825                          const UChar* text,
    826                          int32_t textLength,
    827                          int32_t* parsePos, /* 0 = start */
    828                          UErrorCode* status) {
    829   UFormattable *newFormattable = NULL;
    830   if (U_FAILURE(*status)) return result;
    831   if (fmt == NULL || (text==NULL && textLength!=0)) {
    832     *status = U_ILLEGAL_ARGUMENT_ERROR;
    833     return result;
    834   }
    835   if (result == NULL) { // allocate if not allocated.
    836     newFormattable = result = ufmt_open(status);
    837   }
    838   parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
    839   if (U_FAILURE(*status) && newFormattable != NULL) {
    840     ufmt_close(newFormattable);
    841     result = NULL; // deallocate if there was a parse error
    842   }
    843   return result;
    844 }
    845 
    846 U_INTERNAL int32_t U_EXPORT2
    847 unum_formatUFormattable(const UNumberFormat* fmt,
    848                         const UFormattable *number,
    849                         UChar *result,
    850                         int32_t resultLength,
    851                         UFieldPosition *pos, /* ignored if 0 */
    852                         UErrorCode *status) {
    853     if (U_FAILURE(*status)) {
    854       return 0;
    855     }
    856     if (fmt == NULL || number==NULL ||
    857         (result==NULL ? resultLength!=0 : resultLength<0)) {
    858       *status = U_ILLEGAL_ARGUMENT_ERROR;
    859       return 0;
    860     }
    861     UnicodeString res(result, 0, resultLength);
    862 
    863     FieldPosition fp;
    864 
    865     if(pos != 0)
    866         fp.setField(pos->field);
    867 
    868     ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
    869 
    870     if(pos != 0) {
    871         pos->beginIndex = fp.getBeginIndex();
    872         pos->endIndex = fp.getEndIndex();
    873     }
    874 
    875     return res.extract(result, resultLength, *status);
    876 }
    877 
    878 #endif /* #if !UCONFIG_NO_FORMATTING */
    879