2 *******************************************************************************
3 * Copyright (C) 1996-2009, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
6 * Modification History:
8 * Date Name Description
9 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
10 *******************************************************************************
13 #include "unicode/utypes.h"
15 #if !UCONFIG_NO_FORMATTING
17 #include "unicode/unum.h"
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"
34 U_CAPI UNumberFormat
* U_EXPORT2
35 unum_open( UNumberFormatStyle style
,
37 int32_t patternLength
,
39 UParseError
* parseErr
,
43 if(U_FAILURE(*status
))
48 UNumberFormat
*retVal
= 0;
53 retVal
= (UNumberFormat
*)NumberFormat::createInstance(*status
);
55 retVal
= (UNumberFormat
*)NumberFormat::createInstance(Locale(locale
),
61 retVal
= (UNumberFormat
*)NumberFormat::createCurrencyInstance(*status
);
63 retVal
= (UNumberFormat
*)NumberFormat::createCurrencyInstance(Locale(locale
),
69 retVal
= (UNumberFormat
*)NumberFormat::createPercentInstance(*status
);
71 retVal
= (UNumberFormat
*)NumberFormat::createPercentInstance(Locale(locale
),
77 retVal
= (UNumberFormat
*)NumberFormat::createScientificInstance(*status
);
79 retVal
= (UNumberFormat
*)NumberFormat::createScientificInstance(Locale(locale
),
83 case UNUM_PATTERN_DECIMAL
: {
85 /* UnicodeString can handle the case when patternLength = -1. */
86 const UnicodeString
pat(pattern
, patternLength
);
87 DecimalFormatSymbols
*syms
= 0;
94 syms
= new DecimalFormatSymbols(*status
);
96 syms
= new DecimalFormatSymbols(Locale(locale
), *status
);
99 *status
= U_MEMORY_ALLOCATION_ERROR
;
103 retVal
= (UNumberFormat
*)new DecimalFormat(pat
, syms
, *parseErr
, *status
);
110 case UNUM_PATTERN_RULEBASED
: {
112 /* UnicodeString can handle the case when patternLength = -1. */
113 const UnicodeString
pat(pattern
, patternLength
);
119 retVal
= (UNumberFormat
*)new RuleBasedNumberFormat(pat
, Locale(locale
), *parseErr
, *status
);
123 retVal
= (UNumberFormat
*)new RuleBasedNumberFormat(URBNF_SPELLOUT
, Locale(locale
), *status
);
127 retVal
= (UNumberFormat
*)new RuleBasedNumberFormat(URBNF_ORDINAL
, Locale(locale
), *status
);
131 retVal
= (UNumberFormat
*)new RuleBasedNumberFormat(URBNF_DURATION
, Locale(locale
), *status
);
136 *status
= U_UNSUPPORTED_ERROR
;
140 if(retVal
== 0 && U_SUCCESS(*status
)) {
141 *status
= U_MEMORY_ALLOCATION_ERROR
;
147 U_CAPI
void U_EXPORT2
148 unum_close(UNumberFormat
* fmt
)
150 delete (NumberFormat
*) fmt
;
153 U_CAPI UNumberFormat
* U_EXPORT2
154 unum_clone(const UNumberFormat
*fmt
,
157 if(U_FAILURE(*status
))
161 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
162 res
= ((const DecimalFormat
*)fmt
)->clone();
164 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
165 res
= ((const RuleBasedNumberFormat
*)fmt
)->clone();
169 *status
= U_MEMORY_ALLOCATION_ERROR
;
173 return (UNumberFormat
*) res
;
176 U_CAPI
int32_t U_EXPORT2
177 unum_format( const UNumberFormat
* fmt
,
180 int32_t resultLength
,
184 return unum_formatInt64(fmt
, number
, result
, resultLength
, pos
, status
);
187 U_CAPI
int32_t U_EXPORT2
188 unum_formatInt64(const UNumberFormat
* fmt
,
191 int32_t resultLength
,
195 if(U_FAILURE(*status
))
199 if(!(result
==NULL
&& resultLength
==0)) {
200 // NULL destination for pure preflighting: empty dummy string
201 // otherwise, alias the destination buffer
202 res
.setTo(result
, 0, resultLength
);
208 fp
.setField(pos
->field
);
210 ((const NumberFormat
*)fmt
)->format(number
, res
, fp
);
213 pos
->beginIndex
= fp
.getBeginIndex();
214 pos
->endIndex
= fp
.getEndIndex();
217 return res
.extract(result
, resultLength
, *status
);
220 U_CAPI
int32_t U_EXPORT2
221 unum_formatDouble( const UNumberFormat
* fmt
,
224 int32_t resultLength
,
225 UFieldPosition
*pos
, /* 0 if ignore */
229 if(U_FAILURE(*status
)) return -1;
232 if(!(result
==NULL
&& resultLength
==0)) {
233 // NULL destination for pure preflighting: empty dummy string
234 // otherwise, alias the destination buffer
235 res
.setTo(result
, 0, resultLength
);
241 fp
.setField(pos
->field
);
243 ((const NumberFormat
*)fmt
)->format(number
, res
, fp
);
246 pos
->beginIndex
= fp
.getBeginIndex();
247 pos
->endIndex
= fp
.getEndIndex();
250 return res
.extract(result
, resultLength
, *status
);
253 U_CAPI
int32_t U_EXPORT2
254 unum_formatDoubleCurrency(const UNumberFormat
* fmt
,
258 int32_t resultLength
,
259 UFieldPosition
* pos
, /* ignored if 0 */
260 UErrorCode
* status
) {
261 if (U_FAILURE(*status
)) return -1;
264 if (!(result
==NULL
&& resultLength
==0)) {
265 // NULL destination for pure preflighting: empty dummy string
266 // otherwise, alias the destination buffer
267 res
.setTo(result
, 0, resultLength
);
272 fp
.setField(pos
->field
);
274 CurrencyAmount
*tempCurrAmnt
= new CurrencyAmount(number
, currency
, *status
);
275 // Check for null pointer.
276 if (tempCurrAmnt
== NULL
) {
277 *status
= U_MEMORY_ALLOCATION_ERROR
;
280 Formattable
n(tempCurrAmnt
);
281 ((const NumberFormat
*)fmt
)->format(n
, res
, fp
, *status
);
284 pos
->beginIndex
= fp
.getBeginIndex();
285 pos
->endIndex
= fp
.getEndIndex();
288 return res
.extract(result
, resultLength
, *status
);
292 parseRes(Formattable
& res
,
293 const UNumberFormat
* fmt
,
296 int32_t *parsePos
/* 0 = start */,
300 if(U_FAILURE(*status
))
303 int32_t len
= (textLength
== -1 ? u_strlen(text
) : textLength
);
304 const UnicodeString
src((UChar
*)text
, len
, len
);
308 pp
.setIndex(*parsePos
);
311 ((const NumberFormat
*)fmt
)->parseCurrency(src
, res
, pp
);
313 ((const NumberFormat
*)fmt
)->parse(src
, res
, pp
);
316 if(pp
.getErrorIndex() != -1) {
317 *status
= U_PARSE_ERROR
;
319 *parsePos
= pp
.getErrorIndex();
321 } else if(parsePos
!= 0) {
322 *parsePos
= pp
.getIndex();
326 U_CAPI
int32_t U_EXPORT2
327 unum_parse( const UNumberFormat
* fmt
,
330 int32_t *parsePos
/* 0 = start */,
334 parseRes(res
, fmt
, text
, textLength
, parsePos
, FALSE
, status
);
335 return res
.getLong(*status
);
338 U_CAPI
int64_t U_EXPORT2
339 unum_parseInt64( const UNumberFormat
* fmt
,
342 int32_t *parsePos
/* 0 = start */,
346 parseRes(res
, fmt
, text
, textLength
, parsePos
, FALSE
, status
);
347 return res
.getInt64(*status
);
350 U_CAPI
double U_EXPORT2
351 unum_parseDouble( const UNumberFormat
* fmt
,
354 int32_t *parsePos
/* 0 = start */,
358 parseRes(res
, fmt
, text
, textLength
, parsePos
, FALSE
, status
);
359 return res
.getDouble(*status
);
362 U_CAPI
double U_EXPORT2
363 unum_parseDoubleCurrency(const UNumberFormat
* fmt
,
366 int32_t* parsePos
, /* 0 = start */
368 UErrorCode
* status
) {
370 parseRes(res
, fmt
, text
, textLength
, parsePos
, TRUE
, status
);
372 if (res
.getType() == Formattable::kObject
&&
373 res
.getObject()->getDynamicClassID() == CurrencyAmount::getStaticClassID()) {
374 const CurrencyAmount
* c
= (const CurrencyAmount
*) res
.getObject();
375 u_strcpy(currency
, c
->getISOCurrency());
377 return res
.getDouble(*status
);
380 U_CAPI
const char* U_EXPORT2
381 unum_getAvailable(int32_t index
)
383 return uloc_getAvailable(index
);
386 U_CAPI
int32_t U_EXPORT2
387 unum_countAvailable()
389 return uloc_countAvailable();
392 U_CAPI
int32_t U_EXPORT2
393 unum_getAttribute(const UNumberFormat
* fmt
,
394 UNumberFormatAttribute attr
)
396 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
397 const DecimalFormat
* df
= (const DecimalFormat
*) fmt
;
399 case UNUM_PARSE_INT_ONLY
:
400 return df
->isParseIntegerOnly();
402 case UNUM_GROUPING_USED
:
403 return df
->isGroupingUsed();
405 case UNUM_DECIMAL_ALWAYS_SHOWN
:
406 return df
->isDecimalSeparatorAlwaysShown();
408 case UNUM_MAX_INTEGER_DIGITS
:
409 return df
->getMaximumIntegerDigits();
411 case UNUM_MIN_INTEGER_DIGITS
:
412 return df
->getMinimumIntegerDigits();
414 case UNUM_INTEGER_DIGITS
:
415 // TBD: what should this return?
416 return df
->getMinimumIntegerDigits();
418 case UNUM_MAX_FRACTION_DIGITS
:
419 return df
->getMaximumFractionDigits();
421 case UNUM_MIN_FRACTION_DIGITS
:
422 return df
->getMinimumFractionDigits();
424 case UNUM_FRACTION_DIGITS
:
425 // TBD: what should this return?
426 return df
->getMinimumFractionDigits();
428 case UNUM_SIGNIFICANT_DIGITS_USED
:
429 return df
->areSignificantDigitsUsed();
431 case UNUM_MAX_SIGNIFICANT_DIGITS
:
432 return df
->getMaximumSignificantDigits();
434 case UNUM_MIN_SIGNIFICANT_DIGITS
:
435 return df
->getMinimumSignificantDigits();
437 case UNUM_MULTIPLIER
:
438 return df
->getMultiplier();
440 case UNUM_GROUPING_SIZE
:
441 return df
->getGroupingSize();
443 case UNUM_ROUNDING_MODE
:
444 return df
->getRoundingMode();
446 case UNUM_FORMAT_WIDTH
:
447 return df
->getFormatWidth();
449 case UNUM_PADDING_POSITION
:
450 return df
->getPadPosition();
452 case UNUM_SECONDARY_GROUPING_SIZE
:
453 return df
->getSecondaryGroupingSize();
455 case UNUM_LENIENT_PARSE
:
456 return ! df
->isParseStrict();
459 /* enums out of sync? unsupported enum? */
463 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
464 if (attr
== UNUM_LENIENT_PARSE
) {
465 #if !UCONFIG_NO_COLLATION
466 return ((const RuleBasedNumberFormat
*)fmt
)->isLenient();
474 U_CAPI
void U_EXPORT2
475 unum_setAttribute( UNumberFormat
* fmt
,
476 UNumberFormatAttribute attr
,
479 if (((NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
480 DecimalFormat
* df
= (DecimalFormat
*) fmt
;
482 case UNUM_PARSE_INT_ONLY
:
483 df
->setParseIntegerOnly(newValue
!=0);
486 case UNUM_GROUPING_USED
:
487 df
->setGroupingUsed(newValue
!=0);
490 case UNUM_DECIMAL_ALWAYS_SHOWN
:
491 df
->setDecimalSeparatorAlwaysShown(newValue
!=0);
494 case UNUM_MAX_INTEGER_DIGITS
:
495 df
->setMaximumIntegerDigits(newValue
);
498 case UNUM_MIN_INTEGER_DIGITS
:
499 df
->setMinimumIntegerDigits(newValue
);
502 case UNUM_INTEGER_DIGITS
:
503 df
->setMinimumIntegerDigits(newValue
);
504 df
->setMaximumIntegerDigits(newValue
);
507 case UNUM_MAX_FRACTION_DIGITS
:
508 df
->setMaximumFractionDigits(newValue
);
511 case UNUM_MIN_FRACTION_DIGITS
:
512 df
->setMinimumFractionDigits(newValue
);
515 case UNUM_FRACTION_DIGITS
:
516 df
->setMinimumFractionDigits(newValue
);
517 df
->setMaximumFractionDigits(newValue
);
520 case UNUM_SIGNIFICANT_DIGITS_USED
:
521 df
->setSignificantDigitsUsed(newValue
!=0);
524 case UNUM_MAX_SIGNIFICANT_DIGITS
:
525 df
->setMaximumSignificantDigits(newValue
);
528 case UNUM_MIN_SIGNIFICANT_DIGITS
:
529 df
->setMinimumSignificantDigits(newValue
);
532 case UNUM_MULTIPLIER
:
533 df
->setMultiplier(newValue
);
536 case UNUM_GROUPING_SIZE
:
537 df
->setGroupingSize(newValue
);
540 case UNUM_ROUNDING_MODE
:
541 df
->setRoundingMode((DecimalFormat::ERoundingMode
)newValue
);
544 case UNUM_FORMAT_WIDTH
:
545 df
->setFormatWidth(newValue
);
548 case UNUM_PADDING_POSITION
:
549 /** The position at which padding will take place. */
550 df
->setPadPosition((DecimalFormat::EPadPosition
)newValue
);
553 case UNUM_SECONDARY_GROUPING_SIZE
:
554 df
->setSecondaryGroupingSize(newValue
);
557 case UNUM_LENIENT_PARSE
:
558 df
->setParseStrict(newValue
== 0);
562 /* Shouldn't get here anyway */
566 U_ASSERT(((NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
567 if (attr
== UNUM_LENIENT_PARSE
) {
568 #if !UCONFIG_NO_COLLATION
569 ((RuleBasedNumberFormat
*)fmt
)->setLenient((UBool
)newValue
);
575 U_CAPI
double U_EXPORT2
576 unum_getDoubleAttribute(const UNumberFormat
* fmt
,
577 UNumberFormatAttribute attr
)
579 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID() &&
580 attr
== UNUM_ROUNDING_INCREMENT
) {
581 return ((const DecimalFormat
*)fmt
)->getRoundingIncrement();
587 U_CAPI
void U_EXPORT2
588 unum_setDoubleAttribute( UNumberFormat
* fmt
,
589 UNumberFormatAttribute attr
,
592 if (((NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID() &&
593 attr
== UNUM_ROUNDING_INCREMENT
) {
594 ((DecimalFormat
*)fmt
)->setRoundingIncrement(newValue
);
598 U_CAPI
int32_t U_EXPORT2
599 unum_getTextAttribute(const UNumberFormat
* fmt
,
600 UNumberFormatTextAttribute tag
,
602 int32_t resultLength
,
605 if(U_FAILURE(*status
))
609 if(!(result
==NULL
&& resultLength
==0)) {
610 // NULL destination for pure preflighting: empty dummy string
611 // otherwise, alias the destination buffer
612 res
.setTo(result
, 0, resultLength
);
615 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
616 const DecimalFormat
* df
= (const DecimalFormat
*) fmt
;
618 case UNUM_POSITIVE_PREFIX
:
619 df
->getPositivePrefix(res
);
622 case UNUM_POSITIVE_SUFFIX
:
623 df
->getPositiveSuffix(res
);
626 case UNUM_NEGATIVE_PREFIX
:
627 df
->getNegativePrefix(res
);
630 case UNUM_NEGATIVE_SUFFIX
:
631 df
->getNegativeSuffix(res
);
634 case UNUM_PADDING_CHARACTER
:
635 res
= df
->getPadCharacterString();
638 case UNUM_CURRENCY_CODE
:
639 res
= UnicodeString(df
->getCurrency());
643 *status
= U_UNSUPPORTED_ERROR
;
647 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
648 const RuleBasedNumberFormat
* rbnf
= (const RuleBasedNumberFormat
*)fmt
;
649 if (tag
== UNUM_DEFAULT_RULESET
) {
650 res
= rbnf
->getDefaultRuleSetName();
651 } else if (tag
== UNUM_PUBLIC_RULESETS
) {
652 int32_t count
= rbnf
->getNumberOfRuleSetNames();
653 for (int i
= 0; i
< count
; ++i
) {
654 res
+= rbnf
->getRuleSetName(i
);
655 res
+= (UChar
)0x003b; // semicolon
658 *status
= U_UNSUPPORTED_ERROR
;
663 return res
.extract(result
, resultLength
, *status
);
666 U_CAPI
void U_EXPORT2
667 unum_setTextAttribute( UNumberFormat
* fmt
,
668 UNumberFormatTextAttribute tag
,
669 const UChar
* newValue
,
670 int32_t newValueLength
,
673 if(U_FAILURE(*status
))
676 int32_t len
= (newValueLength
== -1 ? u_strlen(newValue
) : newValueLength
);
677 const UnicodeString
val((UChar
*)newValue
, len
, len
);
679 if (((NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
680 DecimalFormat
* df
= (DecimalFormat
*) fmt
;
682 case UNUM_POSITIVE_PREFIX
:
683 df
->setPositivePrefix(val
);
686 case UNUM_POSITIVE_SUFFIX
:
687 df
->setPositiveSuffix(val
);
690 case UNUM_NEGATIVE_PREFIX
:
691 df
->setNegativePrefix(val
);
694 case UNUM_NEGATIVE_SUFFIX
:
695 df
->setNegativeSuffix(val
);
698 case UNUM_PADDING_CHARACTER
:
699 df
->setPadCharacter(*newValue
);
702 case UNUM_CURRENCY_CODE
:
703 df
->setCurrency(newValue
, *status
);
707 *status
= U_UNSUPPORTED_ERROR
;
711 U_ASSERT(((NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
712 if (tag
== UNUM_DEFAULT_RULESET
) {
713 ((RuleBasedNumberFormat
*)fmt
)->setDefaultRuleSet(newValue
, *status
);
715 *status
= U_UNSUPPORTED_ERROR
;
720 U_CAPI
int32_t U_EXPORT2
721 unum_toPattern( const UNumberFormat
* fmt
,
722 UBool isPatternLocalized
,
724 int32_t resultLength
,
727 if(U_FAILURE(*status
))
731 if(!(result
==NULL
&& resultLength
==0)) {
732 // NULL destination for pure preflighting: empty dummy string
733 // otherwise, alias the destination buffer
734 pat
.setTo(result
, 0, resultLength
);
737 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
738 const DecimalFormat
* df
= (const DecimalFormat
*) fmt
;
739 if(isPatternLocalized
)
740 df
->toLocalizedPattern(pat
);
744 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
745 pat
= ((const RuleBasedNumberFormat
*)fmt
)->getRules();
747 return pat
.extract(result
, resultLength
, *status
);
750 U_CAPI
int32_t U_EXPORT2
751 unum_getSymbol(const UNumberFormat
*fmt
,
752 UNumberFormatSymbol symbol
,
757 if(status
==NULL
|| U_FAILURE(*status
)) {
761 if(fmt
==NULL
|| (uint16_t)symbol
>=UNUM_FORMAT_SYMBOL_COUNT
) {
762 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
766 if (((const NumberFormat
*)fmt
)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
767 *status
= U_UNSUPPORTED_ERROR
;
771 return ((const DecimalFormat
*)fmt
)->
772 getDecimalFormatSymbols()->
773 getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)symbol
).
774 extract(buffer
, size
, *status
);
777 U_CAPI
void U_EXPORT2
778 unum_setSymbol(UNumberFormat
*fmt
,
779 UNumberFormatSymbol symbol
,
784 if(status
==NULL
|| U_FAILURE(*status
)) {
788 if(fmt
==NULL
|| (uint16_t)symbol
>=UNUM_FORMAT_SYMBOL_COUNT
|| value
==NULL
|| length
<-1) {
789 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
793 if (((NumberFormat
*)fmt
)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
794 *status
= U_UNSUPPORTED_ERROR
;
798 DecimalFormatSymbols
symbols(*((DecimalFormat
*)fmt
)->getDecimalFormatSymbols());
799 symbols
.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)symbol
,
800 UnicodeString(value
, length
)); /* UnicodeString can handle the case when length = -1. */
801 ((DecimalFormat
*)fmt
)->setDecimalFormatSymbols(symbols
);
804 U_CAPI
void U_EXPORT2
805 unum_applyPattern( UNumberFormat
*format
,
807 const UChar
*pattern
,
808 int32_t patternLength
,
809 UParseError
*parseError
,
812 UErrorCode tStatus
= U_ZERO_ERROR
;
813 UParseError tParseError
;
815 if(parseError
== NULL
){
816 parseError
= &tParseError
;
823 int32_t len
= (patternLength
== -1 ? u_strlen(pattern
) : patternLength
);
824 const UnicodeString
pat((UChar
*)pattern
, len
, len
);
826 // Verify if the object passed is a DecimalFormat object
827 if (((NumberFormat
*)format
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
829 ((DecimalFormat
*)format
)->applyLocalizedPattern(pat
,*parseError
, *status
);
831 ((DecimalFormat
*)format
)->applyPattern(pat
,*parseError
, *status
);
834 *status
= U_UNSUPPORTED_ERROR
;
839 U_CAPI
const char* U_EXPORT2
840 unum_getLocaleByType(const UNumberFormat
*fmt
,
841 ULocDataLocaleType type
,
845 if (U_SUCCESS(*status
)) {
846 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
850 return ((const Format
*)fmt
)->getLocaleID(type
, *status
);
853 #endif /* #if !UCONFIG_NO_FORMATTING */