2 *******************************************************************************
3 * Copyright (C) 1997-2014, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 *******************************************************************************
8 #include "unicode/utypes.h"
9 #include "utypeinfo.h" // for 'typeid' to work
11 #include "unicode/rbnf.h"
15 #include "unicode/normlzr.h"
16 #include "unicode/tblcoll.h"
17 #include "unicode/uchar.h"
18 #include "unicode/ucol.h"
19 #include "unicode/uloc.h"
20 #include "unicode/unum.h"
21 #include "unicode/ures.h"
22 #include "unicode/ustring.h"
23 #include "unicode/utf16.h"
24 #include "unicode/udata.h"
25 #include "unicode/udisplaycontext.h"
26 #include "unicode/brkiter.h"
31 #include "patternprops.h"
41 #define U_ICUDATA_RBNF U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "rbnf"
43 static const UChar gPercentPercent
[] =
48 // All urbnf objects are created through openRules, so we init all of the
49 // Unicode string constants required by rbnf, nfrs, or nfr here.
50 static const UChar gLenientParse
[] =
52 0x25, 0x25, 0x6C, 0x65, 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x70, 0x61, 0x72, 0x73, 0x65, 0x3A, 0
53 }; /* "%%lenient-parse:" */
54 static const UChar gSemiColon
= 0x003B;
55 static const UChar gSemiPercent
[] =
60 #define kSomeNumberOfBitsDiv2 22
61 #define kHalfMaxDouble (double)(1 << kSomeNumberOfBitsDiv2)
62 #define kMaxDouble (kHalfMaxDouble * kHalfMaxDouble)
66 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat
)
69 This is a utility class. It does not use ICU's RTTI.
70 If ICU's RTTI is needed again, you can uncomment the RTTI code and derive from UObject.
71 Please make sure that intltest passes on Windows in Release mode,
72 since the string pooling per compilation unit will mess up how RTTI works.
73 The RTTI code was also removed due to lack of code coverage.
75 class LocalizationInfo
: public UMemory
{
77 virtual ~LocalizationInfo();
81 LocalizationInfo() : refcount(0) {}
83 LocalizationInfo
* ref(void) {
88 LocalizationInfo
* unref(void) {
89 if (refcount
&& --refcount
== 0) {
95 virtual UBool
operator==(const LocalizationInfo
* rhs
) const;
96 inline UBool
operator!=(const LocalizationInfo
* rhs
) const { return !operator==(rhs
); }
98 virtual int32_t getNumberOfRuleSets(void) const = 0;
99 virtual const UChar
* getRuleSetName(int32_t index
) const = 0;
100 virtual int32_t getNumberOfDisplayLocales(void) const = 0;
101 virtual const UChar
* getLocaleName(int32_t index
) const = 0;
102 virtual const UChar
* getDisplayName(int32_t localeIndex
, int32_t ruleIndex
) const = 0;
104 virtual int32_t indexForLocale(const UChar
* locale
) const;
105 virtual int32_t indexForRuleSet(const UChar
* ruleset
) const;
107 // virtual UClassID getDynamicClassID() const = 0;
108 // static UClassID getStaticClassID(void);
111 LocalizationInfo::~LocalizationInfo() {}
113 //UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(LocalizationInfo)
115 // if both strings are NULL, this returns TRUE
117 streq(const UChar
* lhs
, const UChar
* rhs
) {
122 return u_strcmp(lhs
, rhs
) == 0;
128 LocalizationInfo::operator==(const LocalizationInfo
* rhs
) const {
134 int32_t rsc
= getNumberOfRuleSets();
135 if (rsc
== rhs
->getNumberOfRuleSets()) {
136 for (int i
= 0; i
< rsc
; ++i
) {
137 if (!streq(getRuleSetName(i
), rhs
->getRuleSetName(i
))) {
141 int32_t dlc
= getNumberOfDisplayLocales();
142 if (dlc
== rhs
->getNumberOfDisplayLocales()) {
143 for (int i
= 0; i
< dlc
; ++i
) {
144 const UChar
* locale
= getLocaleName(i
);
145 int32_t ix
= rhs
->indexForLocale(locale
);
146 // if no locale, ix is -1, getLocaleName returns null, so streq returns false
147 if (!streq(locale
, rhs
->getLocaleName(ix
))) {
150 for (int j
= 0; j
< rsc
; ++j
) {
151 if (!streq(getDisplayName(i
, j
), rhs
->getDisplayName(ix
, j
))) {
164 LocalizationInfo::indexForLocale(const UChar
* locale
) const {
165 for (int i
= 0; i
< getNumberOfDisplayLocales(); ++i
) {
166 if (streq(locale
, getLocaleName(i
))) {
174 LocalizationInfo::indexForRuleSet(const UChar
* ruleset
) const {
176 for (int i
= 0; i
< getNumberOfRuleSets(); ++i
) {
177 if (streq(ruleset
, getRuleSetName(i
))) {
186 typedef void (*Fn_Deleter
)(void*);
194 VArray() : buf(NULL
), cap(0), size(0), deleter(NULL
) {}
196 VArray(Fn_Deleter del
) : buf(NULL
), cap(0), size(0), deleter(del
) {}
200 for (int i
= 0; i
< size
; ++i
) {
211 void add(void* elem
, UErrorCode
& status
) {
212 if (U_SUCCESS(status
)) {
216 } else if (cap
< 256) {
222 buf
= (void**)uprv_malloc(cap
* sizeof(void*));
224 buf
= (void**)uprv_realloc(buf
, cap
* sizeof(void*));
227 // if we couldn't realloc, we leak the memory we've already allocated, but we're in deep trouble anyway
228 status
= U_MEMORY_ALLOCATION_ERROR
;
231 void* start
= &buf
[size
];
232 size_t count
= (cap
- size
) * sizeof(void*);
233 uprv_memset(start
, 0, count
); // fill with nulls, just because
239 void** release(void) {
250 class StringLocalizationInfo
: public LocalizationInfo
{
256 friend class LocDataParser
;
258 StringLocalizationInfo(UChar
* i
, UChar
*** d
, int32_t numRS
, int32_t numLocs
)
259 : info(i
), data(d
), numRuleSets(numRS
), numLocales(numLocs
)
264 static StringLocalizationInfo
* create(const UnicodeString
& info
, UParseError
& perror
, UErrorCode
& status
);
266 virtual ~StringLocalizationInfo();
267 virtual int32_t getNumberOfRuleSets(void) const { return numRuleSets
; }
268 virtual const UChar
* getRuleSetName(int32_t index
) const;
269 virtual int32_t getNumberOfDisplayLocales(void) const { return numLocales
; }
270 virtual const UChar
* getLocaleName(int32_t index
) const;
271 virtual const UChar
* getDisplayName(int32_t localeIndex
, int32_t ruleIndex
) const;
273 // virtual UClassID getDynamicClassID() const;
274 // static UClassID getStaticClassID(void);
277 void init(UErrorCode
& status
) const;
282 OPEN_ANGLE
= 0x003c, /* '<' */
283 CLOSE_ANGLE
= 0x003e, /* '>' */
291 * Utility for parsing a localization string and returning a StringLocalizationInfo*.
293 class LocDataParser
{
302 LocDataParser(UParseError
& parseError
, UErrorCode
& status
)
303 : data(NULL
), e(NULL
), p(NULL
), ch(0xffff), pe(parseError
), ec(status
) {}
307 * On a successful parse, return a StringLocalizationInfo*, otherwise delete locData, set perror and status,
308 * and return NULL. The StringLocalizationInfo will adopt locData if it is created.
310 StringLocalizationInfo
* parse(UChar
* data
, int32_t len
);
314 void inc(void) { ++p
; ch
= 0xffff; }
315 UBool
checkInc(UChar c
) { if (p
< e
&& (ch
== c
|| *p
== c
)) { inc(); return TRUE
; } return FALSE
; }
316 UBool
check(UChar c
) { return p
< e
&& (ch
== c
|| *p
== c
); }
317 void skipWhitespace(void) { while (p
< e
&& PatternProps::isWhiteSpace(ch
!= 0xffff ? ch
: *p
)) inc();}
318 UBool
inList(UChar c
, const UChar
* list
) const {
319 if (*list
== SPACE
&& PatternProps::isWhiteSpace(c
)) return TRUE
;
320 while (*list
&& *list
!= c
) ++list
; return *list
== c
;
322 void parseError(const char* msg
);
324 StringLocalizationInfo
* doParse(void);
326 UChar
** nextArray(int32_t& requiredLength
);
327 UChar
* nextString(void);
331 #define ERROR(msg) parseError(msg); return NULL;
332 #define EXPLANATION_ARG explanationArg
334 #define ERROR(msg) parseError(NULL); return NULL;
335 #define EXPLANATION_ARG
339 static const UChar DQUOTE_STOPLIST
[] = {
343 static const UChar SQUOTE_STOPLIST
[] = {
347 static const UChar NOQUOTE_STOPLIST
[] = {
348 SPACE
, COMMA
, CLOSE_ANGLE
, OPEN_ANGLE
, TICK
, QUOTE
, 0
356 StringLocalizationInfo
*
357 LocDataParser::parse(UChar
* _data
, int32_t len
) {
359 if (_data
) uprv_free(_data
);
365 pe
.postContext
[0] = 0;
366 pe
.preContext
[0] = 0;
369 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
374 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
388 StringLocalizationInfo
*
389 LocDataParser::doParse(void) {
391 if (!checkInc(OPEN_ANGLE
)) {
392 ERROR("Missing open angle");
394 VArray
array(DeleteFn
);
395 UBool mightHaveNext
= TRUE
;
396 int32_t requiredLength
= -1;
397 while (mightHaveNext
) {
398 mightHaveNext
= FALSE
;
399 UChar
** elem
= nextArray(requiredLength
);
401 UBool haveComma
= check(COMMA
);
406 mightHaveNext
= TRUE
;
408 } else if (haveComma
) {
409 ERROR("Unexpected character");
414 if (!checkInc(CLOSE_ANGLE
)) {
415 if (check(OPEN_ANGLE
)) {
416 ERROR("Missing comma in outer array");
418 ERROR("Missing close angle bracket in outer array");
424 ERROR("Extra text after close of localization data");
429 int32_t numLocs
= array
.length() - 2; // subtract first, NULL
430 UChar
*** result
= (UChar
***)array
.release();
432 return new StringLocalizationInfo(data
, result
, requiredLength
-2, numLocs
); // subtract first, NULL
436 ERROR("Unknown error");
440 LocDataParser::nextArray(int32_t& requiredLength
) {
446 if (!checkInc(OPEN_ANGLE
)) {
447 ERROR("Missing open angle");
451 UBool mightHaveNext
= TRUE
;
452 while (mightHaveNext
) {
453 mightHaveNext
= FALSE
;
454 UChar
* elem
= nextString();
456 UBool haveComma
= check(COMMA
);
461 mightHaveNext
= TRUE
;
463 } else if (haveComma
) {
464 ERROR("Unexpected comma");
468 if (!checkInc(CLOSE_ANGLE
)) {
469 if (check(OPEN_ANGLE
)) {
470 ERROR("Missing close angle bracket in inner array");
472 ERROR("Missing comma in inner array");
478 if (requiredLength
== -1) {
479 requiredLength
= array
.length() + 1;
480 } else if (array
.length() != requiredLength
) {
481 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
482 ERROR("Array not of required length");
485 return (UChar
**)array
.release();
487 ERROR("Unknown Error");
491 LocDataParser::nextString() {
492 UChar
* result
= NULL
;
496 const UChar
* terminators
;
498 UBool haveQuote
= c
== QUOTE
|| c
== TICK
;
501 terminators
= c
== QUOTE
? DQUOTE_STOPLIST
: SQUOTE_STOPLIST
;
503 terminators
= NOQUOTE_STOPLIST
;
506 while (p
< e
&& !inList(*p
, terminators
)) ++p
;
508 ERROR("Unexpected end of data");
514 *p
= 0x0; // terminate by writing to data
515 result
= start
; // just point into data
519 ERROR("Missing matching quote");
520 } else if (p
== start
) {
521 ERROR("Empty string");
524 } else if (x
== OPEN_ANGLE
|| x
== TICK
|| x
== QUOTE
) {
525 ERROR("Unexpected character in string");
529 // ok for there to be no next string
533 void LocDataParser::parseError(const char* EXPLANATION_ARG
)
539 const UChar
* start
= p
- U_PARSE_CONTEXT_LEN
- 1;
543 for (UChar
* x
= p
; --x
>= start
;) {
549 const UChar
* limit
= p
+ U_PARSE_CONTEXT_LEN
- 1;
553 u_strncpy(pe
.preContext
, start
, (int32_t)(p
-start
));
554 pe
.preContext
[p
-start
] = 0;
555 u_strncpy(pe
.postContext
, p
, (int32_t)(limit
-p
));
556 pe
.postContext
[limit
-p
] = 0;
557 pe
.offset
= (int32_t)(p
- data
);
560 fprintf(stderr
, "%s at or near character %ld: ", EXPLANATION_ARG
, p
-data
);
563 msg
.append(start
, p
- start
);
564 msg
.append((UChar
)0x002f); /* SOLIDUS/SLASH */
565 msg
.append(p
, limit
-p
);
566 msg
.append(UNICODE_STRING_SIMPLE("'"));
569 int32_t len
= msg
.extract(0, msg
.length(), buf
, 128);
575 fprintf(stderr
, "%s\n", buf
);
589 //UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringLocalizationInfo)
591 StringLocalizationInfo
*
592 StringLocalizationInfo::create(const UnicodeString
& info
, UParseError
& perror
, UErrorCode
& status
) {
593 if (U_FAILURE(status
)) {
597 int32_t len
= info
.length();
599 return NULL
; // no error;
602 UChar
* p
= (UChar
*)uprv_malloc(len
* sizeof(UChar
));
604 status
= U_MEMORY_ALLOCATION_ERROR
;
607 info
.extract(p
, len
, status
);
608 if (!U_FAILURE(status
)) {
609 status
= U_ZERO_ERROR
; // clear warning about non-termination
612 LocDataParser
parser(perror
, status
);
613 return parser
.parse(p
, len
);
616 StringLocalizationInfo::~StringLocalizationInfo() {
617 for (UChar
*** p
= (UChar
***)data
; *p
; ++p
) {
618 // remaining data is simply pointer into our unicode string data.
619 if (*p
) uprv_free(*p
);
621 if (data
) uprv_free(data
);
622 if (info
) uprv_free(info
);
627 StringLocalizationInfo::getRuleSetName(int32_t index
) const {
628 if (index
>= 0 && index
< getNumberOfRuleSets()) {
629 return data
[0][index
];
635 StringLocalizationInfo::getLocaleName(int32_t index
) const {
636 if (index
>= 0 && index
< getNumberOfDisplayLocales()) {
637 return data
[index
+1][0];
643 StringLocalizationInfo::getDisplayName(int32_t localeIndex
, int32_t ruleIndex
) const {
644 if (localeIndex
>= 0 && localeIndex
< getNumberOfDisplayLocales() &&
645 ruleIndex
>= 0 && ruleIndex
< getNumberOfRuleSets()) {
646 return data
[localeIndex
+1][ruleIndex
+1];
653 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
654 const UnicodeString
& locs
,
655 const Locale
& alocale
, UParseError
& perror
, UErrorCode
& status
)
657 , ruleSetDescriptions(NULL
)
659 , defaultRuleSet(NULL
)
662 , decimalFormatSymbols(NULL
)
664 , lenientParseRules(NULL
)
665 , localizations(NULL
)
666 , capitalizationInfoSet(FALSE
)
667 , capitalizationForUIListMenu(FALSE
)
668 , capitalizationForStandAlone(FALSE
)
669 , capitalizationBrkIter(NULL
)
671 LocalizationInfo
* locinfo
= StringLocalizationInfo::create(locs
, perror
, status
);
672 init(description
, locinfo
, perror
, status
);
675 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
676 const UnicodeString
& locs
,
677 UParseError
& perror
, UErrorCode
& status
)
679 , ruleSetDescriptions(NULL
)
681 , defaultRuleSet(NULL
)
682 , locale(Locale::getDefault())
684 , decimalFormatSymbols(NULL
)
686 , lenientParseRules(NULL
)
687 , localizations(NULL
)
688 , capitalizationInfoSet(FALSE
)
689 , capitalizationForUIListMenu(FALSE
)
690 , capitalizationForStandAlone(FALSE
)
691 , capitalizationBrkIter(NULL
)
693 LocalizationInfo
* locinfo
= StringLocalizationInfo::create(locs
, perror
, status
);
694 init(description
, locinfo
, perror
, status
);
697 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
698 LocalizationInfo
* info
,
699 const Locale
& alocale
, UParseError
& perror
, UErrorCode
& status
)
701 , ruleSetDescriptions(NULL
)
703 , defaultRuleSet(NULL
)
706 , decimalFormatSymbols(NULL
)
708 , lenientParseRules(NULL
)
709 , localizations(NULL
)
710 , capitalizationInfoSet(FALSE
)
711 , capitalizationForUIListMenu(FALSE
)
712 , capitalizationForStandAlone(FALSE
)
713 , capitalizationBrkIter(NULL
)
715 init(description
, info
, perror
, status
);
718 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
722 , ruleSetDescriptions(NULL
)
724 , defaultRuleSet(NULL
)
725 , locale(Locale::getDefault())
727 , decimalFormatSymbols(NULL
)
729 , lenientParseRules(NULL
)
730 , localizations(NULL
)
731 , capitalizationInfoSet(FALSE
)
732 , capitalizationForUIListMenu(FALSE
)
733 , capitalizationForStandAlone(FALSE
)
734 , capitalizationBrkIter(NULL
)
736 init(description
, NULL
, perror
, status
);
739 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
740 const Locale
& aLocale
,
744 , ruleSetDescriptions(NULL
)
746 , defaultRuleSet(NULL
)
749 , decimalFormatSymbols(NULL
)
751 , lenientParseRules(NULL
)
752 , localizations(NULL
)
753 , capitalizationInfoSet(FALSE
)
754 , capitalizationForUIListMenu(FALSE
)
755 , capitalizationForStandAlone(FALSE
)
756 , capitalizationBrkIter(NULL
)
758 init(description
, NULL
, perror
, status
);
761 RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag
, const Locale
& alocale
, UErrorCode
& status
)
763 , ruleSetDescriptions(NULL
)
765 , defaultRuleSet(NULL
)
768 , decimalFormatSymbols(NULL
)
770 , lenientParseRules(NULL
)
771 , localizations(NULL
)
772 , capitalizationInfoSet(FALSE
)
773 , capitalizationForUIListMenu(FALSE
)
774 , capitalizationForStandAlone(FALSE
)
775 , capitalizationBrkIter(NULL
)
777 if (U_FAILURE(status
)) {
781 const char* rules_tag
= "RBNFRules";
782 const char* fmt_tag
= "";
784 case URBNF_SPELLOUT
: fmt_tag
= "SpelloutRules"; break;
785 case URBNF_ORDINAL
: fmt_tag
= "OrdinalRules"; break;
786 case URBNF_DURATION
: fmt_tag
= "DurationRules"; break;
787 case URBNF_NUMBERING_SYSTEM
: fmt_tag
= "NumberingSystemRules"; break;
788 default: status
= U_ILLEGAL_ARGUMENT_ERROR
; return;
791 // TODO: read localization info from resource
792 LocalizationInfo
* locinfo
= NULL
;
794 UResourceBundle
* nfrb
= ures_open(U_ICUDATA_RBNF
, locale
.getName(), &status
);
795 if (U_SUCCESS(status
)) {
796 setLocaleIDs(ures_getLocaleByType(nfrb
, ULOC_VALID_LOCALE
, &status
),
797 ures_getLocaleByType(nfrb
, ULOC_ACTUAL_LOCALE
, &status
));
799 UResourceBundle
* rbnfRules
= ures_getByKeyWithFallback(nfrb
, rules_tag
, NULL
, &status
);
800 if (U_FAILURE(status
)) {
803 UResourceBundle
* ruleSets
= ures_getByKeyWithFallback(rbnfRules
, fmt_tag
, NULL
, &status
);
804 if (U_FAILURE(status
)) {
805 ures_close(rbnfRules
);
811 while (ures_hasNext(ruleSets
)) {
812 desc
.append(ures_getNextUnicodeString(ruleSets
,NULL
,&status
));
816 init (desc
, locinfo
, perror
, status
);
818 ures_close(ruleSets
);
819 ures_close(rbnfRules
);
824 RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat
& rhs
)
827 , ruleSetDescriptions(NULL
)
829 , defaultRuleSet(NULL
)
832 , decimalFormatSymbols(NULL
)
834 , lenientParseRules(NULL
)
835 , localizations(NULL
)
836 , capitalizationInfoSet(FALSE
)
837 , capitalizationForUIListMenu(FALSE
)
838 , capitalizationForStandAlone(FALSE
)
839 , capitalizationBrkIter(NULL
)
841 this->operator=(rhs
);
846 RuleBasedNumberFormat
&
847 RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat
& rhs
)
852 NumberFormat::operator=(rhs
);
853 UErrorCode status
= U_ZERO_ERROR
;
856 lenient
= rhs
.lenient
;
859 init(rhs
.originalDescription
, rhs
.localizations
? rhs
.localizations
->ref() : NULL
, perror
, status
);
860 setDecimalFormatSymbols(*rhs
.getDecimalFormatSymbols());
861 setDefaultRuleSet(rhs
.getDefaultRuleSetName(), status
);
863 capitalizationInfoSet
= rhs
.capitalizationInfoSet
;
864 capitalizationForUIListMenu
= rhs
.capitalizationForUIListMenu
;
865 capitalizationForStandAlone
= rhs
.capitalizationForStandAlone
;
866 #if !UCONFIG_NO_BREAK_ITERATION
867 capitalizationBrkIter
= (rhs
.capitalizationBrkIter
!=NULL
)? rhs
.capitalizationBrkIter
->clone(): NULL
;
873 RuleBasedNumberFormat::~RuleBasedNumberFormat()
879 RuleBasedNumberFormat::clone(void) const
881 return new RuleBasedNumberFormat(*this);
885 RuleBasedNumberFormat::operator==(const Format
& other
) const
887 if (this == &other
) {
891 if (typeid(*this) == typeid(other
)) {
892 const RuleBasedNumberFormat
& rhs
= (const RuleBasedNumberFormat
&)other
;
893 // test for capitalization info equality is adequately handled
894 // by the NumberFormat test for fCapitalizationContext equality;
895 // the info here is just derived from that.
896 if (locale
== rhs
.locale
&&
897 lenient
== rhs
.lenient
&&
898 (localizations
== NULL
899 ? rhs
.localizations
== NULL
900 : (rhs
.localizations
== NULL
902 : *localizations
== rhs
.localizations
))) {
904 NFRuleSet
** p
= ruleSets
;
905 NFRuleSet
** q
= rhs
.ruleSets
;
908 } else if (q
== NULL
) {
911 while (*p
&& *q
&& (**p
== **q
)) {
915 return *q
== NULL
&& *p
== NULL
;
923 RuleBasedNumberFormat::getRules() const
925 UnicodeString result
;
926 if (ruleSets
!= NULL
) {
927 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
928 (*p
)->appendRules(result
);
935 RuleBasedNumberFormat::getRuleSetName(int32_t index
) const
938 UnicodeString
string(TRUE
, localizations
->getRuleSetName(index
), (int32_t)-1);
940 } else if (ruleSets
) {
941 UnicodeString result
;
942 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
944 if (rs
->isPublic()) {
957 RuleBasedNumberFormat::getNumberOfRuleSetNames() const
961 result
= localizations
->getNumberOfRuleSets();
962 } else if (ruleSets
) {
963 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
964 if ((**p
).isPublic()) {
973 RuleBasedNumberFormat::getNumberOfRuleSetDisplayNameLocales(void) const {
975 return localizations
->getNumberOfDisplayLocales();
981 RuleBasedNumberFormat::getRuleSetDisplayNameLocale(int32_t index
, UErrorCode
& status
) const {
982 if (U_FAILURE(status
)) {
985 if (localizations
&& index
>= 0 && index
< localizations
->getNumberOfDisplayLocales()) {
986 UnicodeString
name(TRUE
, localizations
->getLocaleName(index
), -1);
988 int32_t cap
= name
.length() + 1;
991 bp
= (char *)uprv_malloc(cap
);
993 status
= U_MEMORY_ALLOCATION_ERROR
;
997 name
.extract(0, name
.length(), bp
, cap
, UnicodeString::kInvariant
);
998 Locale
retLocale(bp
);
1004 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1010 RuleBasedNumberFormat::getRuleSetDisplayName(int32_t index
, const Locale
& localeParam
) {
1011 if (localizations
&& index
>= 0 && index
< localizations
->getNumberOfRuleSets()) {
1012 UnicodeString
localeName(localeParam
.getBaseName(), -1, UnicodeString::kInvariant
);
1013 int32_t len
= localeName
.length();
1014 UChar
* localeStr
= localeName
.getBuffer(len
+ 1);
1017 int32_t ix
= localizations
->indexForLocale(localeStr
);
1019 UnicodeString
name(TRUE
, localizations
->getDisplayName(ix
, index
), -1);
1023 // trim trailing portion, skipping over ommitted sections
1024 do { --len
;} while (len
> 0 && localeStr
[len
] != 0x005f); // underscore
1025 while (len
> 0 && localeStr
[len
-1] == 0x005F) --len
;
1027 UnicodeString
name(TRUE
, localizations
->getRuleSetName(index
), -1);
1030 UnicodeString bogus
;
1036 RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString
& ruleSetName
, const Locale
& localeParam
) {
1037 if (localizations
) {
1038 UnicodeString
rsn(ruleSetName
);
1039 int32_t ix
= localizations
->indexForRuleSet(rsn
.getTerminatedBuffer());
1040 return getRuleSetDisplayName(ix
, localeParam
);
1042 UnicodeString bogus
;
1048 RuleBasedNumberFormat::findRuleSet(const UnicodeString
& name
, UErrorCode
& status
) const
1050 if (U_SUCCESS(status
) && ruleSets
) {
1051 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
1053 if (rs
->isNamed(name
)) {
1057 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1063 RuleBasedNumberFormat::format(int32_t number
,
1064 UnicodeString
& toAppendTo
,
1065 FieldPosition
& /* pos */) const
1067 if (defaultRuleSet
) {
1068 int32_t startPos
= toAppendTo
.length();
1069 defaultRuleSet
->format((int64_t)number
, toAppendTo
, toAppendTo
.length());
1070 adjustForCapitalizationContext(startPos
, toAppendTo
);
1077 RuleBasedNumberFormat::format(int64_t number
,
1078 UnicodeString
& toAppendTo
,
1079 FieldPosition
& /* pos */) const
1081 if (defaultRuleSet
) {
1082 int32_t startPos
= toAppendTo
.length();
1083 defaultRuleSet
->format(number
, toAppendTo
, toAppendTo
.length());
1084 adjustForCapitalizationContext(startPos
, toAppendTo
);
1091 RuleBasedNumberFormat::format(double number
,
1092 UnicodeString
& toAppendTo
,
1093 FieldPosition
& /* pos */) const
1095 int32_t startPos
= toAppendTo
.length();
1096 // Special case for NaN; adapted from what DecimalFormat::_format( double number,...) does.
1097 if (uprv_isNaN(number
)) {
1098 DecimalFormatSymbols
* decFmtSyms
= getDecimalFormatSymbols(); // RuleBasedNumberFormat internal
1100 toAppendTo
+= decFmtSyms
->getConstSymbol(DecimalFormatSymbols::kNaNSymbol
);
1102 } else if (defaultRuleSet
) {
1103 defaultRuleSet
->format(number
, toAppendTo
, toAppendTo
.length());
1105 return adjustForCapitalizationContext(startPos
, toAppendTo
);
1110 RuleBasedNumberFormat::format(int32_t number
,
1111 const UnicodeString
& ruleSetName
,
1112 UnicodeString
& toAppendTo
,
1113 FieldPosition
& /* pos */,
1114 UErrorCode
& status
) const
1116 // return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
1117 if (U_SUCCESS(status
)) {
1118 if (ruleSetName
.indexOf(gPercentPercent
, 2, 0) == 0) {
1119 // throw new IllegalArgumentException("Can't use internal rule set");
1120 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1122 NFRuleSet
*rs
= findRuleSet(ruleSetName
, status
);
1124 int32_t startPos
= toAppendTo
.length();
1125 rs
->format((int64_t)number
, toAppendTo
, toAppendTo
.length());
1126 adjustForCapitalizationContext(startPos
, toAppendTo
);
1135 RuleBasedNumberFormat::format(int64_t number
,
1136 const UnicodeString
& ruleSetName
,
1137 UnicodeString
& toAppendTo
,
1138 FieldPosition
& /* pos */,
1139 UErrorCode
& status
) const
1141 if (U_SUCCESS(status
)) {
1142 if (ruleSetName
.indexOf(gPercentPercent
, 2, 0) == 0) {
1143 // throw new IllegalArgumentException("Can't use internal rule set");
1144 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1146 NFRuleSet
*rs
= findRuleSet(ruleSetName
, status
);
1148 int32_t startPos
= toAppendTo
.length();
1149 rs
->format(number
, toAppendTo
, toAppendTo
.length());
1150 adjustForCapitalizationContext(startPos
, toAppendTo
);
1159 RuleBasedNumberFormat::format(double number
,
1160 const UnicodeString
& ruleSetName
,
1161 UnicodeString
& toAppendTo
,
1162 FieldPosition
& /* pos */,
1163 UErrorCode
& status
) const
1165 if (U_SUCCESS(status
)) {
1166 if (ruleSetName
.indexOf(gPercentPercent
, 2, 0) == 0) {
1167 // throw new IllegalArgumentException("Can't use internal rule set");
1168 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1170 NFRuleSet
*rs
= findRuleSet(ruleSetName
, status
);
1172 int32_t startPos
= toAppendTo
.length();
1173 rs
->format(number
, toAppendTo
, toAppendTo
.length());
1174 adjustForCapitalizationContext(startPos
, toAppendTo
);
1182 RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos
,
1183 UnicodeString
& currentResult
) const
1185 #if !UCONFIG_NO_BREAK_ITERATION
1186 if (startPos
==0 && currentResult
.length() > 0) {
1187 // capitalize currentResult according to context
1188 UChar32 ch
= currentResult
.char32At(0);
1189 UErrorCode status
= U_ZERO_ERROR
;
1190 UDisplayContext capitalizationContext
= getContext(UDISPCTX_TYPE_CAPITALIZATION
, status
);
1191 if ( u_islower(ch
) && U_SUCCESS(status
) && capitalizationBrkIter
!= NULL
&&
1192 ( capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
||
1193 (capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
&& capitalizationForUIListMenu
) ||
1194 (capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_STANDALONE
&& capitalizationForStandAlone
)) ) {
1195 // titlecase first word of currentResult, here use sentence iterator unlike current implementations
1196 // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
1197 currentResult
.toTitle(capitalizationBrkIter
, locale
, U_TITLECASE_NO_LOWERCASE
| U_TITLECASE_NO_BREAK_ADJUSTMENT
);
1201 return currentResult
;
1206 RuleBasedNumberFormat::parse(const UnicodeString
& text
,
1207 Formattable
& result
,
1208 ParsePosition
& parsePosition
) const
1211 parsePosition
.setErrorIndex(0);
1215 UnicodeString
workingText(text
, parsePosition
.getIndex());
1216 ParsePosition
workingPos(0);
1218 ParsePosition
high_pp(0);
1219 Formattable high_result
;
1221 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
1223 if (rp
->isPublic() && rp
->isParseable()) {
1224 ParsePosition
working_pp(0);
1225 Formattable working_result
;
1227 rp
->parse(workingText
, working_pp
, kMaxDouble
, working_result
, lenient
);
1228 if (working_pp
.getIndex() > high_pp
.getIndex()) {
1229 high_pp
= working_pp
;
1230 high_result
= working_result
;
1232 if (high_pp
.getIndex() == workingText
.length()) {
1239 int32_t startIndex
= parsePosition
.getIndex();
1240 parsePosition
.setIndex(startIndex
+ high_pp
.getIndex());
1241 if (high_pp
.getIndex() > 0) {
1242 parsePosition
.setErrorIndex(-1);
1244 int32_t errorIndex
= (high_pp
.getErrorIndex()>0)? high_pp
.getErrorIndex(): 0;
1245 parsePosition
.setErrorIndex(startIndex
+ errorIndex
);
1247 result
= high_result
;
1248 if (result
.getType() == Formattable::kDouble
) {
1249 int32_t r
= (int32_t)result
.getDouble();
1250 if ((double)r
== result
.getDouble()) {
1256 #if !UCONFIG_NO_COLLATION
1259 RuleBasedNumberFormat::setLenient(UBool enabled
)
1262 if (!enabled
&& collator
) {
1271 RuleBasedNumberFormat::setDefaultRuleSet(const UnicodeString
& ruleSetName
, UErrorCode
& status
) {
1272 if (U_SUCCESS(status
)) {
1273 if (ruleSetName
.isEmpty()) {
1274 if (localizations
) {
1275 UnicodeString
name(TRUE
, localizations
->getRuleSetName(0), -1);
1276 defaultRuleSet
= findRuleSet(name
, status
);
1278 initDefaultRuleSet();
1280 } else if (ruleSetName
.startsWith(UNICODE_STRING_SIMPLE("%%"))) {
1281 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1283 NFRuleSet
* result
= findRuleSet(ruleSetName
, status
);
1284 if (result
!= NULL
) {
1285 defaultRuleSet
= result
;
1292 RuleBasedNumberFormat::getDefaultRuleSetName() const {
1293 UnicodeString result
;
1294 if (defaultRuleSet
&& defaultRuleSet
->isPublic()) {
1295 defaultRuleSet
->getName(result
);
1297 result
.setToBogus();
1303 RuleBasedNumberFormat::initDefaultRuleSet()
1305 defaultRuleSet
= NULL
;
1310 const UnicodeString spellout
= UNICODE_STRING_SIMPLE("%spellout-numbering");
1311 const UnicodeString ordinal
= UNICODE_STRING_SIMPLE("%digits-ordinal");
1312 const UnicodeString duration
= UNICODE_STRING_SIMPLE("%duration");
1314 NFRuleSet
**p
= &ruleSets
[0];
1316 if ((*p
)->isNamed(spellout
) || (*p
)->isNamed(ordinal
) || (*p
)->isNamed(duration
)) {
1317 defaultRuleSet
= *p
;
1324 defaultRuleSet
= *--p
;
1325 if (!defaultRuleSet
->isPublic()) {
1326 while (p
!= ruleSets
) {
1327 if ((*--p
)->isPublic()) {
1328 defaultRuleSet
= *p
;
1337 RuleBasedNumberFormat::init(const UnicodeString
& rules
, LocalizationInfo
* localizationInfos
,
1338 UParseError
& pErr
, UErrorCode
& status
)
1340 // TODO: implement UParseError
1341 uprv_memset(&pErr
, 0, sizeof(UParseError
));
1342 // Note: this can leave ruleSets == NULL, so remaining code should check
1343 if (U_FAILURE(status
)) {
1347 this->localizations
= localizationInfos
== NULL
? NULL
: localizationInfos
->ref();
1349 UnicodeString
description(rules
);
1350 if (!description
.length()) {
1351 status
= U_MEMORY_ALLOCATION_ERROR
;
1355 // start by stripping the trailing whitespace from all the rules
1356 // (this is all the whitespace follwing each semicolon in the
1357 // description). This allows us to look for rule-set boundaries
1358 // by searching for ";%" without having to worry about whitespace
1359 // between the ; and the %
1360 stripWhitespace(description
);
1362 // check to see if there's a set of lenient-parse rules. If there
1363 // is, pull them out into our temporary holding place for them,
1364 // and delete them from the description before the real desciption-
1365 // parsing code sees them
1366 int32_t lp
= description
.indexOf(gLenientParse
, -1, 0);
1368 // we've got to make sure we're not in the middle of a rule
1369 // (where "%%lenient-parse" would actually get treated as
1371 if (lp
== 0 || description
.charAt(lp
- 1) == gSemiColon
) {
1372 // locate the beginning and end of the actual collation
1373 // rules (there may be whitespace between the name and
1374 // the first token in the description)
1375 int lpEnd
= description
.indexOf(gSemiPercent
, 2, lp
);
1378 lpEnd
= description
.length() - 1;
1380 int lpStart
= lp
+ u_strlen(gLenientParse
);
1381 while (PatternProps::isWhiteSpace(description
.charAt(lpStart
))) {
1385 // copy out the lenient-parse rules and delete them
1386 // from the description
1387 lenientParseRules
= new UnicodeString();
1389 if (lenientParseRules
== 0) {
1390 status
= U_MEMORY_ALLOCATION_ERROR
;
1393 lenientParseRules
->setTo(description
, lpStart
, lpEnd
- lpStart
);
1395 description
.remove(lp
, lpEnd
+ 1 - lp
);
1399 // pre-flight parsing the description and count the number of
1400 // rule sets (";%" marks the end of one rule set and the beginning
1403 for (int32_t p
= description
.indexOf(gSemiPercent
, 2, 0); p
!= -1; p
= description
.indexOf(gSemiPercent
, 2, p
)) {
1409 // our rule list is an array of the appropriate size
1410 ruleSets
= (NFRuleSet
**)uprv_malloc((numRuleSets
+ 1) * sizeof(NFRuleSet
*));
1412 if (ruleSets
== 0) {
1413 status
= U_MEMORY_ALLOCATION_ERROR
;
1417 for (int i
= 0; i
<= numRuleSets
; ++i
) {
1421 // divide up the descriptions into individual rule-set descriptions
1422 // and store them in a temporary array. At each step, we also
1423 // new up a rule set, but all this does is initialize its name
1424 // and remove it from its description. We can't actually parse
1425 // the rest of the descriptions and finish initializing everything
1426 // because we have to know the names and locations of all the rule
1427 // sets before we can actually set everything up
1429 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1433 ruleSetDescriptions
= new UnicodeString
[numRuleSets
];
1434 if (ruleSetDescriptions
== 0) {
1435 status
= U_MEMORY_ALLOCATION_ERROR
;
1442 for (int32_t p
= description
.indexOf(gSemiPercent
, 2, 0); p
!= -1; p
= description
.indexOf(gSemiPercent
, 2, start
)) {
1443 ruleSetDescriptions
[curRuleSet
].setTo(description
, start
, p
+ 1 - start
);
1444 ruleSets
[curRuleSet
] = new NFRuleSet(ruleSetDescriptions
, curRuleSet
, status
);
1445 if (ruleSets
[curRuleSet
] == 0) {
1446 status
= U_MEMORY_ALLOCATION_ERROR
;
1452 ruleSetDescriptions
[curRuleSet
].setTo(description
, start
, description
.length() - start
);
1453 ruleSets
[curRuleSet
] = new NFRuleSet(ruleSetDescriptions
, curRuleSet
, status
);
1454 if (ruleSets
[curRuleSet
] == 0) {
1455 status
= U_MEMORY_ALLOCATION_ERROR
;
1460 // now we can take note of the formatter's default rule set, which
1461 // is the last public rule set in the description (it's the last
1462 // rather than the first so that a user can create a new formatter
1463 // from an existing formatter and change its default behavior just
1464 // by appending more rule sets to the end)
1466 // {dlf} Initialization of a fraction rule set requires the default rule
1467 // set to be known. For purposes of initialization, this is always the
1468 // last public rule set, no matter what the localization data says.
1469 initDefaultRuleSet();
1471 // finally, we can go back through the temporary descriptions
1472 // list and finish seting up the substructure (and we throw
1473 // away the temporary descriptions as we go)
1475 for (int i
= 0; i
< numRuleSets
; i
++) {
1476 ruleSets
[i
]->parseRules(ruleSetDescriptions
[i
], this, status
);
1480 // Now that the rules are initialized, the 'real' default rule
1481 // set can be adjusted by the localization data.
1483 // The C code keeps the localization array as is, rather than building
1484 // a separate array of the public rule set names, so we have less work
1485 // to do here-- but we still need to check the names.
1487 if (localizationInfos
) {
1488 // confirm the names, if any aren't in the rules, that's an error
1489 // it is ok if the rules contain public rule sets that are not in this list
1490 for (int32_t i
= 0; i
< localizationInfos
->getNumberOfRuleSets(); ++i
) {
1491 UnicodeString
name(TRUE
, localizationInfos
->getRuleSetName(i
), -1);
1492 NFRuleSet
* rs
= findRuleSet(name
, status
);
1497 defaultRuleSet
= rs
;
1501 defaultRuleSet
= getDefaultRuleSet();
1503 originalDescription
= rules
;
1506 // override the NumberFormat implementation in order to
1507 // lazily initialize relevant items
1509 RuleBasedNumberFormat::setContext(UDisplayContext value
, UErrorCode
& status
)
1511 NumberFormat::setContext(value
, status
);
1512 if (U_SUCCESS(status
)) {
1513 if (!capitalizationInfoSet
&&
1514 (value
==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
|| value
==UDISPCTX_CAPITALIZATION_FOR_STANDALONE
)) {
1515 initCapitalizationContextInfo(locale
);
1516 capitalizationInfoSet
= TRUE
;
1518 #if !UCONFIG_NO_BREAK_ITERATION
1519 if ( capitalizationBrkIter
== NULL
&& (value
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
||
1520 (value
==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
&& capitalizationForUIListMenu
) ||
1521 (value
==UDISPCTX_CAPITALIZATION_FOR_STANDALONE
&& capitalizationForStandAlone
)) ) {
1522 UErrorCode status
= U_ZERO_ERROR
;
1523 capitalizationBrkIter
= BreakIterator::createSentenceInstance(locale
, status
);
1524 if (U_FAILURE(status
)) {
1525 delete capitalizationBrkIter
;
1526 capitalizationBrkIter
= NULL
;
1534 RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale
& thelocale
)
1536 #if !UCONFIG_NO_BREAK_ITERATION
1537 const char * localeID
= (thelocale
!= NULL
)? thelocale
.getBaseName(): NULL
;
1538 UErrorCode status
= U_ZERO_ERROR
;
1539 UResourceBundle
*rb
= ures_open(NULL
, localeID
, &status
);
1540 rb
= ures_getByKeyWithFallback(rb
, "contextTransforms", rb
, &status
);
1541 rb
= ures_getByKeyWithFallback(rb
, "number-spellout", rb
, &status
);
1542 if (U_SUCCESS(status
) && rb
!= NULL
) {
1544 const int32_t * intVector
= ures_getIntVector(rb
, &len
, &status
);
1545 if (U_SUCCESS(status
) && intVector
!= NULL
&& len
>= 2) {
1546 capitalizationForUIListMenu
= intVector
[0];
1547 capitalizationForStandAlone
= intVector
[1];
1555 RuleBasedNumberFormat::stripWhitespace(UnicodeString
& description
)
1557 // iterate through the characters...
1558 UnicodeString result
;
1561 while (start
!= -1 && start
< description
.length()) {
1562 // seek to the first non-whitespace character...
1563 while (start
< description
.length()
1564 && PatternProps::isWhiteSpace(description
.charAt(start
))) {
1568 // locate the next semicolon in the text and copy the text from
1569 // our current position up to that semicolon into the result
1570 int32_t p
= description
.indexOf(gSemiColon
, start
);
1572 // or if we don't find a semicolon, just copy the rest of
1573 // the string into the result
1574 result
.append(description
, start
, description
.length() - start
);
1577 else if (p
< description
.length()) {
1578 result
.append(description
, start
, p
+ 1 - start
);
1582 // when we get here, we've seeked off the end of the sring, and
1583 // we terminate the loop (we continue until *start* is -1 rather
1584 // than until *p* is -1, because otherwise we'd miss the last
1585 // rule in the description)
1591 description
.setTo(result
);
1596 RuleBasedNumberFormat::dispose()
1599 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
1602 uprv_free(ruleSets
);
1606 if (ruleSetDescriptions
) {
1607 delete [] ruleSetDescriptions
;
1610 #if !UCONFIG_NO_COLLATION
1615 delete decimalFormatSymbols
;
1616 decimalFormatSymbols
= NULL
;
1618 delete lenientParseRules
;
1619 lenientParseRules
= NULL
;
1621 #if !UCONFIG_NO_BREAK_ITERATION
1622 delete capitalizationBrkIter
;
1623 capitalizationBrkIter
= NULL
;
1626 if (localizations
) localizations
= localizations
->unref();
1630 //-----------------------------------------------------------------------
1631 // package-internal API
1632 //-----------------------------------------------------------------------
1635 * Returns the collator to use for lenient parsing. The collator is lazily created:
1636 * this function creates it the first time it's called.
1637 * @return The collator to use for lenient parsing, or null if lenient parsing
1640 const RuleBasedCollator
*
1641 RuleBasedNumberFormat::getCollator() const
1643 #if !UCONFIG_NO_COLLATION
1648 // lazy-evaluate the collator
1649 if (collator
== NULL
&& lenient
) {
1650 // create a default collator based on the formatter's locale,
1651 // then pull out that collator's rules, append any additional
1652 // rules specified in the description, and create a _new_
1653 // collator based on the combinaiton of those rules
1655 UErrorCode status
= U_ZERO_ERROR
;
1657 Collator
* temp
= Collator::createInstance(locale
, status
);
1658 RuleBasedCollator
* newCollator
;
1659 if (U_SUCCESS(status
) && (newCollator
= dynamic_cast<RuleBasedCollator
*>(temp
)) != NULL
) {
1660 if (lenientParseRules
) {
1661 UnicodeString
rules(newCollator
->getRules());
1662 rules
.append(*lenientParseRules
);
1664 newCollator
= new RuleBasedCollator(rules
, status
);
1665 // Exit if newCollator could not be created.
1666 if (newCollator
== NULL
) {
1672 if (U_SUCCESS(status
)) {
1673 newCollator
->setAttribute(UCOL_DECOMPOSITION_MODE
, UCOL_ON
, status
);
1675 ((RuleBasedNumberFormat
*)this)->collator
= newCollator
;
1684 // if lenient-parse mode is off, this will be null
1685 // (see setLenientParseMode())
1691 * Returns the DecimalFormatSymbols object that should be used by all DecimalFormat
1692 * instances owned by this formatter. This object is lazily created: this function
1693 * creates it the first time it's called.
1694 * @return The DecimalFormatSymbols object that should be used by all DecimalFormat
1695 * instances owned by this formatter.
1697 DecimalFormatSymbols
*
1698 RuleBasedNumberFormat::getDecimalFormatSymbols() const
1700 // lazy-evaluate the DecimalFormatSymbols object. This object
1701 // is shared by all DecimalFormat instances belonging to this
1703 if (decimalFormatSymbols
== NULL
) {
1704 UErrorCode status
= U_ZERO_ERROR
;
1705 DecimalFormatSymbols
* temp
= new DecimalFormatSymbols(locale
, status
);
1706 if (U_SUCCESS(status
)) {
1707 ((RuleBasedNumberFormat
*)this)->decimalFormatSymbols
= temp
;
1712 return decimalFormatSymbols
;
1715 // De-owning the current localized symbols and adopt the new symbols.
1717 RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols
* symbolsToAdopt
)
1719 if (symbolsToAdopt
== NULL
) {
1720 return; // do not allow caller to set decimalFormatSymbols to NULL
1723 if (decimalFormatSymbols
!= NULL
) {
1724 delete decimalFormatSymbols
;
1727 decimalFormatSymbols
= symbolsToAdopt
;
1730 // Apply the new decimalFormatSymbols by reparsing the rulesets
1731 UErrorCode status
= U_ZERO_ERROR
;
1733 for (int32_t i
= 0; i
< numRuleSets
; i
++) {
1734 ruleSets
[i
]->parseRules(ruleSetDescriptions
[i
], this, status
);
1739 // Setting the symbols is equlivalent to adopting a newly created localized symbols.
1741 RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols
& symbols
)
1743 adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols
));