2 *******************************************************************************
3 * Copyright (C) 1996-2012, 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"
27 #include "unicode/localpointer.h"
36 U_CAPI UNumberFormat
* U_EXPORT2
37 unum_open( UNumberFormatStyle style
,
39 int32_t patternLength
,
41 UParseError
* parseErr
,
43 if(U_FAILURE(*status
)) {
47 NumberFormat
*retVal
= NULL
;
54 retVal
= NumberFormat::createInstance(Locale(locale
), style
, *status
);
57 case UNUM_PATTERN_DECIMAL
: {
59 /* UnicodeString can handle the case when patternLength = -1. */
60 const UnicodeString
pat(pattern
, patternLength
);
66 DecimalFormatSymbols
*syms
= new DecimalFormatSymbols(Locale(locale
), *status
);
68 *status
= U_MEMORY_ALLOCATION_ERROR
;
71 if (U_FAILURE(*status
)) {
76 retVal
= new DecimalFormat(pat
, syms
, *parseErr
, *status
);
83 case UNUM_PATTERN_RULEBASED
: {
85 /* UnicodeString can handle the case when patternLength = -1. */
86 const UnicodeString
pat(pattern
, patternLength
);
92 retVal
= new RuleBasedNumberFormat(pat
, Locale(locale
), *parseErr
, *status
);
96 retVal
= new RuleBasedNumberFormat(URBNF_SPELLOUT
, Locale(locale
), *status
);
100 retVal
= new RuleBasedNumberFormat(URBNF_ORDINAL
, Locale(locale
), *status
);
104 retVal
= new RuleBasedNumberFormat(URBNF_DURATION
, Locale(locale
), *status
);
107 case UNUM_NUMBERING_SYSTEM
:
108 retVal
= new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM
, Locale(locale
), *status
);
113 *status
= U_UNSUPPORTED_ERROR
;
117 if(retVal
== NULL
&& U_SUCCESS(*status
)) {
118 *status
= U_MEMORY_ALLOCATION_ERROR
;
121 return reinterpret_cast<UNumberFormat
*>(retVal
);
124 U_CAPI
void U_EXPORT2
125 unum_close(UNumberFormat
* fmt
)
127 delete (NumberFormat
*) fmt
;
130 U_CAPI UNumberFormat
* U_EXPORT2
131 unum_clone(const UNumberFormat
*fmt
,
134 if(U_FAILURE(*status
))
138 const NumberFormat
* nf
= reinterpret_cast<const NumberFormat
*>(fmt
);
139 const DecimalFormat
* df
= dynamic_cast<const DecimalFormat
*>(nf
);
143 const RuleBasedNumberFormat
* rbnf
= dynamic_cast<const RuleBasedNumberFormat
*>(nf
);
144 U_ASSERT(rbnf
!= NULL
);
149 *status
= U_MEMORY_ALLOCATION_ERROR
;
153 return (UNumberFormat
*) res
;
156 U_CAPI
int32_t U_EXPORT2
157 unum_format( const UNumberFormat
* fmt
,
160 int32_t resultLength
,
164 return unum_formatInt64(fmt
, number
, result
, resultLength
, pos
, status
);
167 U_CAPI
int32_t U_EXPORT2
168 unum_formatInt64(const UNumberFormat
* fmt
,
171 int32_t resultLength
,
175 if(U_FAILURE(*status
))
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
);
188 fp
.setField(pos
->field
);
190 ((const NumberFormat
*)fmt
)->format(number
, res
, fp
, *status
);
193 pos
->beginIndex
= fp
.getBeginIndex();
194 pos
->endIndex
= fp
.getEndIndex();
197 return res
.extract(result
, resultLength
, *status
);
200 U_CAPI
int32_t U_EXPORT2
201 unum_formatDouble( const UNumberFormat
* fmt
,
204 int32_t resultLength
,
205 UFieldPosition
*pos
, /* 0 if ignore */
209 if(U_FAILURE(*status
)) return -1;
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
);
221 fp
.setField(pos
->field
);
223 ((const NumberFormat
*)fmt
)->format(number
, res
, fp
, *status
);
226 pos
->beginIndex
= fp
.getBeginIndex();
227 pos
->endIndex
= fp
.getEndIndex();
230 return res
.extract(result
, resultLength
, *status
);
234 U_CAPI
int32_t U_EXPORT2
235 unum_formatDecimal(const UNumberFormat
* fmt
,
239 int32_t resultLength
,
240 UFieldPosition
*pos
, /* 0 if ignore */
241 UErrorCode
* status
) {
243 if(U_FAILURE(*status
)) {
246 if ((result
== NULL
&& resultLength
!= 0) || resultLength
< 0) {
247 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
253 fp
.setField(pos
->field
);
257 length
= uprv_strlen(number
);
259 StringPiece
numSP(number
, length
);
260 Formattable
numFmtbl(numSP
, *status
);
262 UnicodeString resultStr
;
263 if (resultLength
> 0) {
264 // Alias the destination buffer.
265 resultStr
.setTo(result
, 0, resultLength
);
267 ((const NumberFormat
*)fmt
)->format(numFmtbl
, resultStr
, fp
, *status
);
269 pos
->beginIndex
= fp
.getBeginIndex();
270 pos
->endIndex
= fp
.getEndIndex();
272 return resultStr
.extract(result
, resultLength
, *status
);
278 U_CAPI
int32_t U_EXPORT2
279 unum_formatDoubleCurrency(const UNumberFormat
* fmt
,
283 int32_t resultLength
,
284 UFieldPosition
* pos
, /* ignored if 0 */
285 UErrorCode
* status
) {
286 if (U_FAILURE(*status
)) return -1;
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
);
297 fp
.setField(pos
->field
);
299 CurrencyAmount
*tempCurrAmnt
= new CurrencyAmount(number
, currency
, *status
);
300 // Check for null pointer.
301 if (tempCurrAmnt
== NULL
) {
302 *status
= U_MEMORY_ALLOCATION_ERROR
;
305 Formattable
n(tempCurrAmnt
);
306 ((const NumberFormat
*)fmt
)->format(n
, res
, fp
, *status
);
309 pos
->beginIndex
= fp
.getBeginIndex();
310 pos
->endIndex
= fp
.getEndIndex();
313 return res
.extract(result
, resultLength
, *status
);
317 parseRes(Formattable
& res
,
318 const UNumberFormat
* fmt
,
321 int32_t *parsePos
/* 0 = start */,
324 if(U_FAILURE(*status
))
327 const UnicodeString
src((UBool
)(textLength
== -1), text
, textLength
);
331 pp
.setIndex(*parsePos
);
333 ((const NumberFormat
*)fmt
)->parse(src
, res
, pp
);
335 if(pp
.getErrorIndex() != -1) {
336 *status
= U_PARSE_ERROR
;
338 *parsePos
= pp
.getErrorIndex();
340 } else if(parsePos
!= 0) {
341 *parsePos
= pp
.getIndex();
345 U_CAPI
int32_t U_EXPORT2
346 unum_parse( const UNumberFormat
* fmt
,
349 int32_t *parsePos
/* 0 = start */,
353 parseRes(res
, fmt
, text
, textLength
, parsePos
, status
);
354 return res
.getLong(*status
);
357 U_CAPI
int64_t U_EXPORT2
358 unum_parseInt64( const UNumberFormat
* fmt
,
361 int32_t *parsePos
/* 0 = start */,
365 parseRes(res
, fmt
, text
, textLength
, parsePos
, status
);
366 return res
.getInt64(*status
);
369 U_CAPI
double U_EXPORT2
370 unum_parseDouble( const UNumberFormat
* fmt
,
373 int32_t *parsePos
/* 0 = start */,
377 parseRes(res
, fmt
, text
, textLength
, parsePos
, status
);
378 return res
.getDouble(*status
);
381 U_CAPI
int32_t U_EXPORT2
382 unum_parseDecimal(const UNumberFormat
* fmt
,
385 int32_t *parsePos
/* 0 = start */,
387 int32_t outBufLength
,
390 if (U_FAILURE(*status
)) {
393 if ((outBuf
== NULL
&& outBufLength
!= 0) || outBufLength
< 0) {
394 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
398 parseRes(res
, fmt
, text
, textLength
, parsePos
, status
);
399 StringPiece sp
= res
.getDecimalNumber(*status
);
400 if (U_FAILURE(*status
)) {
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
;
408 U_ASSERT(outBufLength
> 0);
409 uprv_strcpy(outBuf
, sp
.data());
414 U_CAPI
double U_EXPORT2
415 unum_parseDoubleCurrency(const UNumberFormat
* fmt
,
418 int32_t* parsePos
, /* 0 = start */
420 UErrorCode
* status
) {
421 double doubleVal
= 0.0;
423 if (U_FAILURE(*status
)) {
426 const UnicodeString
src((UBool
)(textLength
== -1), text
, textLength
);
428 if (parsePos
!= NULL
) {
429 pp
.setIndex(*parsePos
);
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();
438 if (parsePos
!= NULL
) {
439 *parsePos
= pp
.getIndex();
441 if (pp
.getIndex() > 0) {
442 *status
= U_ZERO_ERROR
;
443 u_strcpy(currency
, currAmt
->getISOCurrency());
444 doubleVal
= currAmt
->getNumber().getDouble(*status
);
450 U_CAPI
const char* U_EXPORT2
451 unum_getAvailable(int32_t index
)
453 return uloc_getAvailable(index
);
456 U_CAPI
int32_t U_EXPORT2
457 unum_countAvailable()
459 return uloc_countAvailable();
462 U_CAPI
int32_t U_EXPORT2
463 unum_getAttribute(const UNumberFormat
* fmt
,
464 UNumberFormatAttribute attr
)
466 const NumberFormat
* nf
= reinterpret_cast<const NumberFormat
*>(fmt
);
467 if ( attr
== UNUM_LENIENT_PARSE
) {
468 // Supported for all subclasses
469 return nf
->isLenient();
472 // The remaining attributea are only supported for DecimalFormat
473 const DecimalFormat
* df
= dynamic_cast<const DecimalFormat
*>(nf
);
475 UErrorCode ignoredStatus
= U_ZERO_ERROR
;
476 return df
->getAttribute( attr
, ignoredStatus
);
482 U_CAPI
void U_EXPORT2
483 unum_setAttribute( UNumberFormat
* fmt
,
484 UNumberFormatAttribute attr
,
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);
493 // The remaining attributea are only supported for DecimalFormat
494 DecimalFormat
* df
= dynamic_cast<DecimalFormat
*>(nf
);
496 UErrorCode ignoredStatus
= U_ZERO_ERROR
;
497 df
->setAttribute(attr
, newValue
, ignoredStatus
);
501 U_CAPI
double U_EXPORT2
502 unum_getDoubleAttribute(const UNumberFormat
* fmt
,
503 UNumberFormatAttribute attr
)
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();
514 U_CAPI
void U_EXPORT2
515 unum_setDoubleAttribute( UNumberFormat
* fmt
,
516 UNumberFormatAttribute attr
,
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
);
526 U_CAPI
int32_t U_EXPORT2
527 unum_getTextAttribute(const UNumberFormat
* fmt
,
528 UNumberFormatTextAttribute tag
,
530 int32_t resultLength
,
533 if(U_FAILURE(*status
))
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
);
543 const NumberFormat
* nf
= reinterpret_cast<const NumberFormat
*>(fmt
);
544 const DecimalFormat
* df
= dynamic_cast<const DecimalFormat
*>(nf
);
547 case UNUM_POSITIVE_PREFIX
:
548 df
->getPositivePrefix(res
);
551 case UNUM_POSITIVE_SUFFIX
:
552 df
->getPositiveSuffix(res
);
555 case UNUM_NEGATIVE_PREFIX
:
556 df
->getNegativePrefix(res
);
559 case UNUM_NEGATIVE_SUFFIX
:
560 df
->getNegativeSuffix(res
);
563 case UNUM_PADDING_CHARACTER
:
564 res
= df
->getPadCharacterString();
567 case UNUM_CURRENCY_CODE
:
568 res
= UnicodeString(df
->getCurrency());
572 *status
= U_UNSUPPORTED_ERROR
;
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
587 *status
= U_UNSUPPORTED_ERROR
;
592 return res
.extract(result
, resultLength
, *status
);
595 U_CAPI
void U_EXPORT2
596 unum_setTextAttribute( UNumberFormat
* fmt
,
597 UNumberFormatTextAttribute tag
,
598 const UChar
* newValue
,
599 int32_t newValueLength
,
602 if(U_FAILURE(*status
))
605 UnicodeString
val(newValue
, newValueLength
);
606 NumberFormat
* nf
= reinterpret_cast<NumberFormat
*>(fmt
);
607 DecimalFormat
* df
= dynamic_cast<DecimalFormat
*>(nf
);
610 case UNUM_POSITIVE_PREFIX
:
611 df
->setPositivePrefix(val
);
614 case UNUM_POSITIVE_SUFFIX
:
615 df
->setPositiveSuffix(val
);
618 case UNUM_NEGATIVE_PREFIX
:
619 df
->setNegativePrefix(val
);
622 case UNUM_NEGATIVE_SUFFIX
:
623 df
->setNegativeSuffix(val
);
626 case UNUM_PADDING_CHARACTER
:
627 df
->setPadCharacter(val
);
630 case UNUM_CURRENCY_CODE
:
631 df
->setCurrency(val
.getTerminatedBuffer(), *status
);
635 *status
= U_UNSUPPORTED_ERROR
;
639 RuleBasedNumberFormat
* rbnf
= dynamic_cast<RuleBasedNumberFormat
*>(nf
);
640 U_ASSERT(rbnf
!= NULL
);
641 if (tag
== UNUM_DEFAULT_RULESET
) {
642 rbnf
->setDefaultRuleSet(val
, *status
);
644 *status
= U_UNSUPPORTED_ERROR
;
649 U_CAPI
int32_t U_EXPORT2
650 unum_toPattern( const UNumberFormat
* fmt
,
651 UBool isPatternLocalized
,
653 int32_t resultLength
,
656 if(U_FAILURE(*status
))
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
);
666 const NumberFormat
* nf
= reinterpret_cast<const NumberFormat
*>(fmt
);
667 const DecimalFormat
* df
= dynamic_cast<const DecimalFormat
*>(nf
);
669 if(isPatternLocalized
)
670 df
->toLocalizedPattern(pat
);
674 const RuleBasedNumberFormat
* rbnf
= dynamic_cast<const RuleBasedNumberFormat
*>(nf
);
675 U_ASSERT(rbnf
!= NULL
);
676 pat
= rbnf
->getRules();
678 return pat
.extract(result
, resultLength
, *status
);
681 U_CAPI
int32_t U_EXPORT2
682 unum_getSymbol(const UNumberFormat
*fmt
,
683 UNumberFormatSymbol symbol
,
688 if(status
==NULL
|| U_FAILURE(*status
)) {
691 if(fmt
==NULL
|| symbol
< 0 || symbol
>=UNUM_FORMAT_SYMBOL_COUNT
) {
692 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
695 const NumberFormat
*nf
= reinterpret_cast<const NumberFormat
*>(fmt
);
696 const DecimalFormat
*dcf
= dynamic_cast<const DecimalFormat
*>(nf
);
698 *status
= U_UNSUPPORTED_ERROR
;
703 getDecimalFormatSymbols()->
704 getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)symbol
).
705 extract(buffer
, size
, *status
);
708 U_CAPI
void U_EXPORT2
709 unum_setSymbol(UNumberFormat
*fmt
,
710 UNumberFormatSymbol symbol
,
715 if(status
==NULL
|| U_FAILURE(*status
)) {
718 if(fmt
==NULL
|| symbol
< 0 || symbol
>=UNUM_FORMAT_SYMBOL_COUNT
|| value
==NULL
|| length
<-1) {
719 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
722 NumberFormat
*nf
= reinterpret_cast<NumberFormat
*>(fmt
);
723 DecimalFormat
*dcf
= dynamic_cast<DecimalFormat
*>(nf
);
725 *status
= U_UNSUPPORTED_ERROR
;
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
);
735 U_CAPI
void U_EXPORT2
736 unum_applyPattern( UNumberFormat
*fmt
,
738 const UChar
*pattern
,
739 int32_t patternLength
,
740 UParseError
*parseError
,
743 UErrorCode tStatus
= U_ZERO_ERROR
;
744 UParseError tParseError
;
746 if(parseError
== NULL
){
747 parseError
= &tParseError
;
754 int32_t len
= (patternLength
== -1 ? u_strlen(pattern
) : patternLength
);
755 const UnicodeString
pat((UChar
*)pattern
, len
, len
);
757 // Verify if the object passed is a DecimalFormat object
758 NumberFormat
* nf
= reinterpret_cast<NumberFormat
*>(fmt
);
759 DecimalFormat
* df
= dynamic_cast<DecimalFormat
*>(nf
);
762 df
->applyLocalizedPattern(pat
,*parseError
, *status
);
764 df
->applyPattern(pat
,*parseError
, *status
);
767 *status
= U_UNSUPPORTED_ERROR
;
772 U_CAPI
const char* U_EXPORT2
773 unum_getLocaleByType(const UNumberFormat
*fmt
,
774 ULocDataLocaleType type
,
778 if (U_SUCCESS(*status
)) {
779 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
783 return ((const Format
*)fmt
)->getLocaleID(type
, *status
);
786 #endif /* #if !UCONFIG_NO_FORMATTING */