2 *******************************************************************************
3 * Copyright (C) 1996-2004, 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_DRAFT
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
);
275 Formattable
n(new CurrencyAmount(number
, currency
, *status
));
276 ((const NumberFormat
*)fmt
)->format(n
, res
, fp
, *status
);
279 pos
->beginIndex
= fp
.getBeginIndex();
280 pos
->endIndex
= fp
.getEndIndex();
283 return res
.extract(result
, resultLength
, *status
);
287 parseRes(Formattable
& res
,
288 const UNumberFormat
* fmt
,
291 int32_t *parsePos
/* 0 = start */,
295 if(U_FAILURE(*status
))
298 int32_t len
= (textLength
== -1 ? u_strlen(text
) : textLength
);
299 const UnicodeString
src((UChar
*)text
, len
, len
);
303 pp
.setIndex(*parsePos
);
306 ((const NumberFormat
*)fmt
)->parseCurrency(src
, res
, pp
);
308 ((const NumberFormat
*)fmt
)->parse(src
, res
, pp
);
312 if(pp
.getErrorIndex() == -1)
313 *parsePos
= pp
.getIndex();
315 *parsePos
= pp
.getErrorIndex();
316 *status
= U_PARSE_ERROR
;
321 U_CAPI
int32_t U_EXPORT2
322 unum_parse( const UNumberFormat
* fmt
,
325 int32_t *parsePos
/* 0 = start */,
329 parseRes(res
, fmt
, text
, textLength
, parsePos
, FALSE
, status
);
330 return res
.getLong(*status
);
333 U_CAPI
int64_t U_EXPORT2
334 unum_parseInt64( const UNumberFormat
* fmt
,
337 int32_t *parsePos
/* 0 = start */,
341 parseRes(res
, fmt
, text
, textLength
, parsePos
, FALSE
, status
);
342 return res
.getInt64(*status
);
345 U_CAPI
double U_EXPORT2
346 unum_parseDouble( const UNumberFormat
* fmt
,
349 int32_t *parsePos
/* 0 = start */,
353 parseRes(res
, fmt
, text
, textLength
, parsePos
, FALSE
, status
);
354 return res
.getDouble(*status
);
357 U_DRAFT
double U_EXPORT2
358 unum_parseDoubleCurrency(const UNumberFormat
* fmt
,
361 int32_t* parsePos
, /* 0 = start */
363 UErrorCode
* status
) {
365 parseRes(res
, fmt
, text
, textLength
, parsePos
, TRUE
, status
);
367 if (res
.getType() == Formattable::kObject
&&
368 res
.getObject()->getDynamicClassID() == CurrencyAmount::getStaticClassID()) {
369 const CurrencyAmount
* c
= (const CurrencyAmount
*) res
.getObject();
370 u_strcpy(currency
, c
->getISOCurrency());
372 return res
.getDouble(*status
);
375 U_CAPI
const char* U_EXPORT2
376 unum_getAvailable(int32_t index
)
378 return uloc_getAvailable(index
);
381 U_CAPI
int32_t U_EXPORT2
382 unum_countAvailable()
384 return uloc_countAvailable();
387 U_CAPI
int32_t U_EXPORT2
388 unum_getAttribute(const UNumberFormat
* fmt
,
389 UNumberFormatAttribute attr
)
391 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
392 const DecimalFormat
* df
= (const DecimalFormat
*) fmt
;
394 case UNUM_PARSE_INT_ONLY
:
395 return df
->isParseIntegerOnly();
397 case UNUM_GROUPING_USED
:
398 return df
->isGroupingUsed();
400 case UNUM_DECIMAL_ALWAYS_SHOWN
:
401 return df
->isDecimalSeparatorAlwaysShown();
403 case UNUM_MAX_INTEGER_DIGITS
:
404 return df
->getMaximumIntegerDigits();
406 case UNUM_MIN_INTEGER_DIGITS
:
407 return df
->getMinimumIntegerDigits();
409 case UNUM_INTEGER_DIGITS
:
410 // TBD: what should this return?
411 return df
->getMinimumIntegerDigits();
413 case UNUM_MAX_FRACTION_DIGITS
:
414 return df
->getMaximumFractionDigits();
416 case UNUM_MIN_FRACTION_DIGITS
:
417 return df
->getMinimumFractionDigits();
419 case UNUM_FRACTION_DIGITS
:
420 // TBD: what should this return?
421 return df
->getMinimumFractionDigits();
423 case UNUM_SIGNIFICANT_DIGITS_USED
:
424 return df
->areSignificantDigitsUsed();
426 case UNUM_MAX_SIGNIFICANT_DIGITS
:
427 return df
->getMaximumSignificantDigits();
429 case UNUM_MIN_SIGNIFICANT_DIGITS
:
430 return df
->getMinimumSignificantDigits();
432 case UNUM_MULTIPLIER
:
433 return df
->getMultiplier();
435 case UNUM_GROUPING_SIZE
:
436 return df
->getGroupingSize();
438 case UNUM_ROUNDING_MODE
:
439 return df
->getRoundingMode();
441 case UNUM_FORMAT_WIDTH
:
442 return df
->getFormatWidth();
444 case UNUM_PADDING_POSITION
:
445 return df
->getPadPosition();
447 case UNUM_SECONDARY_GROUPING_SIZE
:
448 return df
->getSecondaryGroupingSize();
451 /* enums out of sync? unsupported enum? */
455 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
456 if (attr
== UNUM_LENIENT_PARSE
) {
457 #if !UCONFIG_NO_COLLATION
458 return ((const RuleBasedNumberFormat
*)fmt
)->isLenient();
466 U_CAPI
void U_EXPORT2
467 unum_setAttribute( UNumberFormat
* fmt
,
468 UNumberFormatAttribute attr
,
471 if (((NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
472 DecimalFormat
* df
= (DecimalFormat
*) fmt
;
474 case UNUM_PARSE_INT_ONLY
:
475 df
->setParseIntegerOnly(newValue
!=0);
478 case UNUM_GROUPING_USED
:
479 df
->setGroupingUsed(newValue
!=0);
482 case UNUM_DECIMAL_ALWAYS_SHOWN
:
483 df
->setDecimalSeparatorAlwaysShown(newValue
!=0);
486 case UNUM_MAX_INTEGER_DIGITS
:
487 df
->setMaximumIntegerDigits(newValue
);
490 case UNUM_MIN_INTEGER_DIGITS
:
491 df
->setMinimumIntegerDigits(newValue
);
494 case UNUM_INTEGER_DIGITS
:
495 df
->setMinimumIntegerDigits(newValue
);
496 df
->setMaximumIntegerDigits(newValue
);
499 case UNUM_MAX_FRACTION_DIGITS
:
500 df
->setMaximumFractionDigits(newValue
);
503 case UNUM_MIN_FRACTION_DIGITS
:
504 df
->setMinimumFractionDigits(newValue
);
507 case UNUM_FRACTION_DIGITS
:
508 df
->setMinimumFractionDigits(newValue
);
509 df
->setMaximumFractionDigits(newValue
);
512 case UNUM_SIGNIFICANT_DIGITS_USED
:
513 df
->setSignificantDigitsUsed(newValue
!=0);
516 case UNUM_MAX_SIGNIFICANT_DIGITS
:
517 df
->setMaximumSignificantDigits(newValue
);
520 case UNUM_MIN_SIGNIFICANT_DIGITS
:
521 df
->setMinimumSignificantDigits(newValue
);
524 case UNUM_MULTIPLIER
:
525 df
->setMultiplier(newValue
);
528 case UNUM_GROUPING_SIZE
:
529 df
->setGroupingSize(newValue
);
532 case UNUM_ROUNDING_MODE
:
533 df
->setRoundingMode((DecimalFormat::ERoundingMode
)newValue
);
536 case UNUM_FORMAT_WIDTH
:
537 df
->setFormatWidth(newValue
);
540 case UNUM_PADDING_POSITION
:
541 /** The position at which padding will take place. */
542 df
->setPadPosition((DecimalFormat::EPadPosition
)newValue
);
545 case UNUM_SECONDARY_GROUPING_SIZE
:
546 df
->setSecondaryGroupingSize(newValue
);
550 /* Shouldn't get here anyway */
554 U_ASSERT(((NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
555 if (attr
== UNUM_LENIENT_PARSE
) {
556 #if !UCONFIG_NO_COLLATION
557 ((RuleBasedNumberFormat
*)fmt
)->setLenient((UBool
)newValue
);
563 U_CAPI
double U_EXPORT2
564 unum_getDoubleAttribute(const UNumberFormat
* fmt
,
565 UNumberFormatAttribute attr
)
567 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID() &&
568 attr
== UNUM_ROUNDING_INCREMENT
) {
569 return ((const DecimalFormat
*)fmt
)->getRoundingIncrement();
575 U_CAPI
void U_EXPORT2
576 unum_setDoubleAttribute( UNumberFormat
* fmt
,
577 UNumberFormatAttribute attr
,
580 if (((NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID() &&
581 attr
== UNUM_ROUNDING_INCREMENT
) {
582 ((DecimalFormat
*)fmt
)->setRoundingIncrement(newValue
);
586 U_CAPI
int32_t U_EXPORT2
587 unum_getTextAttribute(const UNumberFormat
* fmt
,
588 UNumberFormatTextAttribute tag
,
590 int32_t resultLength
,
593 if(U_FAILURE(*status
))
597 if(!(result
==NULL
&& resultLength
==0)) {
598 // NULL destination for pure preflighting: empty dummy string
599 // otherwise, alias the destination buffer
600 res
.setTo(result
, 0, resultLength
);
603 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
604 const DecimalFormat
* df
= (const DecimalFormat
*) fmt
;
606 case UNUM_POSITIVE_PREFIX
:
607 df
->getPositivePrefix(res
);
610 case UNUM_POSITIVE_SUFFIX
:
611 df
->getPositiveSuffix(res
);
614 case UNUM_NEGATIVE_PREFIX
:
615 df
->getNegativePrefix(res
);
618 case UNUM_NEGATIVE_SUFFIX
:
619 df
->getNegativeSuffix(res
);
622 case UNUM_PADDING_CHARACTER
:
623 res
= df
->getPadCharacterString();
626 case UNUM_CURRENCY_CODE
:
627 res
= UnicodeString(df
->getCurrency());
631 *status
= U_UNSUPPORTED_ERROR
;
635 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
636 const RuleBasedNumberFormat
* rbnf
= (const RuleBasedNumberFormat
*)fmt
;
637 if (tag
== UNUM_DEFAULT_RULESET
) {
638 res
= rbnf
->getDefaultRuleSetName();
639 } else if (tag
== UNUM_PUBLIC_RULESETS
) {
640 int32_t count
= rbnf
->getNumberOfRuleSetNames();
641 for (int i
= 0; i
< count
; ++i
) {
642 res
+= rbnf
->getRuleSetName(i
);
643 res
+= (UChar
)0x003b; // semicolon
646 *status
= U_UNSUPPORTED_ERROR
;
651 return res
.extract(result
, resultLength
, *status
);
654 U_CAPI
void U_EXPORT2
655 unum_setTextAttribute( UNumberFormat
* fmt
,
656 UNumberFormatTextAttribute tag
,
657 const UChar
* newValue
,
658 int32_t newValueLength
,
661 if(U_FAILURE(*status
))
664 int32_t len
= (newValueLength
== -1 ? u_strlen(newValue
) : newValueLength
);
665 const UnicodeString
val((UChar
*)newValue
, len
, len
);
667 if (((NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
668 DecimalFormat
* df
= (DecimalFormat
*) fmt
;
670 case UNUM_POSITIVE_PREFIX
:
671 df
->setPositivePrefix(val
);
674 case UNUM_POSITIVE_SUFFIX
:
675 df
->setPositiveSuffix(val
);
678 case UNUM_NEGATIVE_PREFIX
:
679 df
->setNegativePrefix(val
);
682 case UNUM_NEGATIVE_SUFFIX
:
683 df
->setNegativeSuffix(val
);
686 case UNUM_PADDING_CHARACTER
:
687 df
->setPadCharacter(*newValue
);
690 case UNUM_CURRENCY_CODE
:
691 df
->setCurrency(newValue
, *status
);
695 *status
= U_UNSUPPORTED_ERROR
;
699 U_ASSERT(((NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
700 if (tag
== UNUM_DEFAULT_RULESET
) {
701 ((RuleBasedNumberFormat
*)fmt
)->setDefaultRuleSet(newValue
, *status
);
703 *status
= U_UNSUPPORTED_ERROR
;
708 U_CAPI
int32_t U_EXPORT2
709 unum_toPattern( const UNumberFormat
* fmt
,
710 UBool isPatternLocalized
,
712 int32_t resultLength
,
715 if(U_FAILURE(*status
))
719 if(!(result
==NULL
&& resultLength
==0)) {
720 // NULL destination for pure preflighting: empty dummy string
721 // otherwise, alias the destination buffer
722 pat
.setTo(result
, 0, resultLength
);
725 if (((const NumberFormat
*)fmt
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
726 const DecimalFormat
* df
= (const DecimalFormat
*) fmt
;
727 if(isPatternLocalized
)
728 df
->toLocalizedPattern(pat
);
732 U_ASSERT(((const NumberFormat
*)fmt
)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
733 pat
= ((const RuleBasedNumberFormat
*)fmt
)->getRules();
735 return pat
.extract(result
, resultLength
, *status
);
738 U_CAPI
int32_t U_EXPORT2
739 unum_getSymbol(const UNumberFormat
*fmt
,
740 UNumberFormatSymbol symbol
,
745 if(status
==NULL
|| U_FAILURE(*status
)) {
749 if(fmt
==NULL
|| (uint16_t)symbol
>=UNUM_FORMAT_SYMBOL_COUNT
) {
750 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
754 if (((const NumberFormat
*)fmt
)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
755 *status
= U_UNSUPPORTED_ERROR
;
759 return ((const DecimalFormat
*)fmt
)->
760 getDecimalFormatSymbols()->
761 getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)symbol
).
762 extract(buffer
, size
, *status
);
765 U_CAPI
void U_EXPORT2
766 unum_setSymbol(UNumberFormat
*fmt
,
767 UNumberFormatSymbol symbol
,
772 if(status
==NULL
|| U_FAILURE(*status
)) {
776 if(fmt
==NULL
|| (uint16_t)symbol
>=UNUM_FORMAT_SYMBOL_COUNT
|| value
==NULL
|| length
<-1) {
777 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
781 if (((NumberFormat
*)fmt
)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
782 *status
= U_UNSUPPORTED_ERROR
;
786 DecimalFormatSymbols
symbols(*((DecimalFormat
*)fmt
)->getDecimalFormatSymbols());
787 symbols
.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)symbol
,
788 UnicodeString(value
, length
)); /* UnicodeString can handle the case when length = -1. */
789 ((DecimalFormat
*)fmt
)->setDecimalFormatSymbols(symbols
);
792 U_CAPI
void U_EXPORT2
793 unum_applyPattern( UNumberFormat
*format
,
795 const UChar
*pattern
,
796 int32_t patternLength
,
797 UParseError
*parseError
,
800 UErrorCode tStatus
= U_ZERO_ERROR
;
801 UParseError tParseError
;
803 if(parseError
== NULL
){
804 parseError
= &tParseError
;
811 int32_t len
= (patternLength
== -1 ? u_strlen(pattern
) : patternLength
);
812 const UnicodeString
pat((UChar
*)pattern
, len
, len
);
814 // Verify if the object passed is a DecimalFormat object
815 if (((NumberFormat
*)format
)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
817 ((DecimalFormat
*)format
)->applyLocalizedPattern(pat
,*parseError
, *status
);
819 ((DecimalFormat
*)format
)->applyPattern(pat
,*parseError
, *status
);
822 *status
= U_UNSUPPORTED_ERROR
;
827 U_CAPI
const char* U_EXPORT2
828 unum_getLocaleByType(const UNumberFormat
*fmt
,
829 ULocDataLocaleType type
,
833 if (U_SUCCESS(*status
)) {
834 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
838 return ((const Format
*)fmt
)->getLocaleID(type
, *status
);
841 #endif /* #if !UCONFIG_NO_FORMATTING */