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