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