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