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