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