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