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