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