2 *******************************************************************************
3 * Copyright (C) 1997-2015, 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/plurfmt.h"
17 #include "unicode/tblcoll.h"
18 #include "unicode/uchar.h"
19 #include "unicode/ucol.h"
20 #include "unicode/uloc.h"
21 #include "unicode/unum.h"
22 #include "unicode/ures.h"
23 #include "unicode/ustring.h"
24 #include "unicode/utf16.h"
25 #include "unicode/udata.h"
26 #include "unicode/udisplaycontext.h"
27 #include "unicode/brkiter.h"
32 #include "patternprops.h"
42 #define U_ICUDATA_RBNF U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "rbnf"
44 static const UChar gPercentPercent
[] =
49 // All urbnf objects are created through openRules, so we init all of the
50 // Unicode string constants required by rbnf, nfrs, or nfr here.
51 static const UChar gLenientParse
[] =
53 0x25, 0x25, 0x6C, 0x65, 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x70, 0x61, 0x72, 0x73, 0x65, 0x3A, 0
54 }; /* "%%lenient-parse:" */
55 static const UChar gSemiColon
= 0x003B;
56 static const UChar gSemiPercent
[] =
61 #define kSomeNumberOfBitsDiv2 22
62 #define kHalfMaxDouble (double)(1 << kSomeNumberOfBitsDiv2)
63 #define kMaxDouble (kHalfMaxDouble * kHalfMaxDouble)
67 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat
)
70 This is a utility class. It does not use ICU's RTTI.
71 If ICU's RTTI is needed again, you can uncomment the RTTI code and derive from UObject.
72 Please make sure that intltest passes on Windows in Release mode,
73 since the string pooling per compilation unit will mess up how RTTI works.
74 The RTTI code was also removed due to lack of code coverage.
76 class LocalizationInfo
: public UMemory
{
78 virtual ~LocalizationInfo();
82 LocalizationInfo() : refcount(0) {}
84 LocalizationInfo
* ref(void) {
89 LocalizationInfo
* unref(void) {
90 if (refcount
&& --refcount
== 0) {
96 virtual UBool
operator==(const LocalizationInfo
* rhs
) const;
97 inline UBool
operator!=(const LocalizationInfo
* rhs
) const { return !operator==(rhs
); }
99 virtual int32_t getNumberOfRuleSets(void) const = 0;
100 virtual const UChar
* getRuleSetName(int32_t index
) const = 0;
101 virtual int32_t getNumberOfDisplayLocales(void) const = 0;
102 virtual const UChar
* getLocaleName(int32_t index
) const = 0;
103 virtual const UChar
* getDisplayName(int32_t localeIndex
, int32_t ruleIndex
) const = 0;
105 virtual int32_t indexForLocale(const UChar
* locale
) const;
106 virtual int32_t indexForRuleSet(const UChar
* ruleset
) const;
108 // virtual UClassID getDynamicClassID() const = 0;
109 // static UClassID getStaticClassID(void);
112 LocalizationInfo::~LocalizationInfo() {}
114 //UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(LocalizationInfo)
116 // if both strings are NULL, this returns TRUE
118 streq(const UChar
* lhs
, const UChar
* rhs
) {
123 return u_strcmp(lhs
, rhs
) == 0;
129 LocalizationInfo::operator==(const LocalizationInfo
* rhs
) const {
135 int32_t rsc
= getNumberOfRuleSets();
136 if (rsc
== rhs
->getNumberOfRuleSets()) {
137 for (int i
= 0; i
< rsc
; ++i
) {
138 if (!streq(getRuleSetName(i
), rhs
->getRuleSetName(i
))) {
142 int32_t dlc
= getNumberOfDisplayLocales();
143 if (dlc
== rhs
->getNumberOfDisplayLocales()) {
144 for (int i
= 0; i
< dlc
; ++i
) {
145 const UChar
* locale
= getLocaleName(i
);
146 int32_t ix
= rhs
->indexForLocale(locale
);
147 // if no locale, ix is -1, getLocaleName returns null, so streq returns false
148 if (!streq(locale
, rhs
->getLocaleName(ix
))) {
151 for (int j
= 0; j
< rsc
; ++j
) {
152 if (!streq(getDisplayName(i
, j
), rhs
->getDisplayName(ix
, j
))) {
165 LocalizationInfo::indexForLocale(const UChar
* locale
) const {
166 for (int i
= 0; i
< getNumberOfDisplayLocales(); ++i
) {
167 if (streq(locale
, getLocaleName(i
))) {
175 LocalizationInfo::indexForRuleSet(const UChar
* ruleset
) const {
177 for (int i
= 0; i
< getNumberOfRuleSets(); ++i
) {
178 if (streq(ruleset
, getRuleSetName(i
))) {
187 typedef void (*Fn_Deleter
)(void*);
195 VArray() : buf(NULL
), cap(0), size(0), deleter(NULL
) {}
197 VArray(Fn_Deleter del
) : buf(NULL
), cap(0), size(0), deleter(del
) {}
201 for (int i
= 0; i
< size
; ++i
) {
212 void add(void* elem
, UErrorCode
& status
) {
213 if (U_SUCCESS(status
)) {
217 } else if (cap
< 256) {
223 buf
= (void**)uprv_malloc(cap
* sizeof(void*));
225 buf
= (void**)uprv_realloc(buf
, cap
* sizeof(void*));
228 // if we couldn't realloc, we leak the memory we've already allocated, but we're in deep trouble anyway
229 status
= U_MEMORY_ALLOCATION_ERROR
;
232 void* start
= &buf
[size
];
233 size_t count
= (cap
- size
) * sizeof(void*);
234 uprv_memset(start
, 0, count
); // fill with nulls, just because
240 void** release(void) {
251 class StringLocalizationInfo
: public LocalizationInfo
{
257 friend class LocDataParser
;
259 StringLocalizationInfo(UChar
* i
, UChar
*** d
, int32_t numRS
, int32_t numLocs
)
260 : info(i
), data(d
), numRuleSets(numRS
), numLocales(numLocs
)
265 static StringLocalizationInfo
* create(const UnicodeString
& info
, UParseError
& perror
, UErrorCode
& status
);
267 virtual ~StringLocalizationInfo();
268 virtual int32_t getNumberOfRuleSets(void) const { return numRuleSets
; }
269 virtual const UChar
* getRuleSetName(int32_t index
) const;
270 virtual int32_t getNumberOfDisplayLocales(void) const { return numLocales
; }
271 virtual const UChar
* getLocaleName(int32_t index
) const;
272 virtual const UChar
* getDisplayName(int32_t localeIndex
, int32_t ruleIndex
) const;
274 // virtual UClassID getDynamicClassID() const;
275 // static UClassID getStaticClassID(void);
278 void init(UErrorCode
& status
) const;
283 OPEN_ANGLE
= 0x003c, /* '<' */
284 CLOSE_ANGLE
= 0x003e, /* '>' */
292 * Utility for parsing a localization string and returning a StringLocalizationInfo*.
294 class LocDataParser
{
303 LocDataParser(UParseError
& parseError
, UErrorCode
& status
)
304 : data(NULL
), e(NULL
), p(NULL
), ch(0xffff), pe(parseError
), ec(status
) {}
308 * On a successful parse, return a StringLocalizationInfo*, otherwise delete locData, set perror and status,
309 * and return NULL. The StringLocalizationInfo will adopt locData if it is created.
311 StringLocalizationInfo
* parse(UChar
* data
, int32_t len
);
315 void inc(void) { ++p
; ch
= 0xffff; }
316 UBool
checkInc(UChar c
) { if (p
< e
&& (ch
== c
|| *p
== c
)) { inc(); return TRUE
; } return FALSE
; }
317 UBool
check(UChar c
) { return p
< e
&& (ch
== c
|| *p
== c
); }
318 void skipWhitespace(void) { while (p
< e
&& PatternProps::isWhiteSpace(ch
!= 0xffff ? ch
: *p
)) inc();}
319 UBool
inList(UChar c
, const UChar
* list
) const {
320 if (*list
== SPACE
&& PatternProps::isWhiteSpace(c
)) return TRUE
;
321 while (*list
&& *list
!= c
) ++list
; return *list
== c
;
323 void parseError(const char* msg
);
325 StringLocalizationInfo
* doParse(void);
327 UChar
** nextArray(int32_t& requiredLength
);
328 UChar
* nextString(void);
332 #define ERROR(msg) parseError(msg); return NULL;
333 #define EXPLANATION_ARG explanationArg
335 #define ERROR(msg) parseError(NULL); return NULL;
336 #define EXPLANATION_ARG
340 static const UChar DQUOTE_STOPLIST
[] = {
344 static const UChar SQUOTE_STOPLIST
[] = {
348 static const UChar NOQUOTE_STOPLIST
[] = {
349 SPACE
, COMMA
, CLOSE_ANGLE
, OPEN_ANGLE
, TICK
, QUOTE
, 0
357 StringLocalizationInfo
*
358 LocDataParser::parse(UChar
* _data
, int32_t len
) {
360 if (_data
) uprv_free(_data
);
366 pe
.postContext
[0] = 0;
367 pe
.preContext
[0] = 0;
370 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
375 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
389 StringLocalizationInfo
*
390 LocDataParser::doParse(void) {
392 if (!checkInc(OPEN_ANGLE
)) {
393 ERROR("Missing open angle");
395 VArray
array(DeleteFn
);
396 UBool mightHaveNext
= TRUE
;
397 int32_t requiredLength
= -1;
398 while (mightHaveNext
) {
399 mightHaveNext
= FALSE
;
400 UChar
** elem
= nextArray(requiredLength
);
402 UBool haveComma
= check(COMMA
);
407 mightHaveNext
= TRUE
;
409 } else if (haveComma
) {
410 ERROR("Unexpected character");
415 if (!checkInc(CLOSE_ANGLE
)) {
416 if (check(OPEN_ANGLE
)) {
417 ERROR("Missing comma in outer array");
419 ERROR("Missing close angle bracket in outer array");
425 ERROR("Extra text after close of localization data");
430 int32_t numLocs
= array
.length() - 2; // subtract first, NULL
431 UChar
*** result
= (UChar
***)array
.release();
433 return new StringLocalizationInfo(data
, result
, requiredLength
-2, numLocs
); // subtract first, NULL
437 ERROR("Unknown error");
441 LocDataParser::nextArray(int32_t& requiredLength
) {
447 if (!checkInc(OPEN_ANGLE
)) {
448 ERROR("Missing open angle");
452 UBool mightHaveNext
= TRUE
;
453 while (mightHaveNext
) {
454 mightHaveNext
= FALSE
;
455 UChar
* elem
= nextString();
457 UBool haveComma
= check(COMMA
);
462 mightHaveNext
= TRUE
;
464 } else if (haveComma
) {
465 ERROR("Unexpected comma");
469 if (!checkInc(CLOSE_ANGLE
)) {
470 if (check(OPEN_ANGLE
)) {
471 ERROR("Missing close angle bracket in inner array");
473 ERROR("Missing comma in inner array");
479 if (requiredLength
== -1) {
480 requiredLength
= array
.length() + 1;
481 } else if (array
.length() != requiredLength
) {
482 ec
= U_ILLEGAL_ARGUMENT_ERROR
;
483 ERROR("Array not of required length");
486 return (UChar
**)array
.release();
488 ERROR("Unknown Error");
492 LocDataParser::nextString() {
493 UChar
* result
= NULL
;
497 const UChar
* terminators
;
499 UBool haveQuote
= c
== QUOTE
|| c
== TICK
;
502 terminators
= c
== QUOTE
? DQUOTE_STOPLIST
: SQUOTE_STOPLIST
;
504 terminators
= NOQUOTE_STOPLIST
;
507 while (p
< e
&& !inList(*p
, terminators
)) ++p
;
509 ERROR("Unexpected end of data");
515 *p
= 0x0; // terminate by writing to data
516 result
= start
; // just point into data
520 ERROR("Missing matching quote");
521 } else if (p
== start
) {
522 ERROR("Empty string");
525 } else if (x
== OPEN_ANGLE
|| x
== TICK
|| x
== QUOTE
) {
526 ERROR("Unexpected character in string");
530 // ok for there to be no next string
534 void LocDataParser::parseError(const char* EXPLANATION_ARG
)
540 const UChar
* start
= p
- U_PARSE_CONTEXT_LEN
- 1;
544 for (UChar
* x
= p
; --x
>= start
;) {
550 const UChar
* limit
= p
+ U_PARSE_CONTEXT_LEN
- 1;
554 u_strncpy(pe
.preContext
, start
, (int32_t)(p
-start
));
555 pe
.preContext
[p
-start
] = 0;
556 u_strncpy(pe
.postContext
, p
, (int32_t)(limit
-p
));
557 pe
.postContext
[limit
-p
] = 0;
558 pe
.offset
= (int32_t)(p
- data
);
561 fprintf(stderr
, "%s at or near character %ld: ", EXPLANATION_ARG
, p
-data
);
564 msg
.append(start
, p
- start
);
565 msg
.append((UChar
)0x002f); /* SOLIDUS/SLASH */
566 msg
.append(p
, limit
-p
);
567 msg
.append(UNICODE_STRING_SIMPLE("'"));
570 int32_t len
= msg
.extract(0, msg
.length(), buf
, 128);
576 fprintf(stderr
, "%s\n", buf
);
590 //UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringLocalizationInfo)
592 StringLocalizationInfo
*
593 StringLocalizationInfo::create(const UnicodeString
& info
, UParseError
& perror
, UErrorCode
& status
) {
594 if (U_FAILURE(status
)) {
598 int32_t len
= info
.length();
600 return NULL
; // no error;
603 UChar
* p
= (UChar
*)uprv_malloc(len
* sizeof(UChar
));
605 status
= U_MEMORY_ALLOCATION_ERROR
;
608 info
.extract(p
, len
, status
);
609 if (!U_FAILURE(status
)) {
610 status
= U_ZERO_ERROR
; // clear warning about non-termination
613 LocDataParser
parser(perror
, status
);
614 return parser
.parse(p
, len
);
617 StringLocalizationInfo::~StringLocalizationInfo() {
618 for (UChar
*** p
= (UChar
***)data
; *p
; ++p
) {
619 // remaining data is simply pointer into our unicode string data.
620 if (*p
) uprv_free(*p
);
622 if (data
) uprv_free(data
);
623 if (info
) uprv_free(info
);
628 StringLocalizationInfo::getRuleSetName(int32_t index
) const {
629 if (index
>= 0 && index
< getNumberOfRuleSets()) {
630 return data
[0][index
];
636 StringLocalizationInfo::getLocaleName(int32_t index
) const {
637 if (index
>= 0 && index
< getNumberOfDisplayLocales()) {
638 return data
[index
+1][0];
644 StringLocalizationInfo::getDisplayName(int32_t localeIndex
, int32_t ruleIndex
) const {
645 if (localeIndex
>= 0 && localeIndex
< getNumberOfDisplayLocales() &&
646 ruleIndex
>= 0 && ruleIndex
< getNumberOfRuleSets()) {
647 return data
[localeIndex
+1][ruleIndex
+1];
654 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
655 const UnicodeString
& locs
,
656 const Locale
& alocale
, UParseError
& perror
, UErrorCode
& status
)
658 , ruleSetDescriptions(NULL
)
660 , defaultRuleSet(NULL
)
663 , decimalFormatSymbols(NULL
)
664 , defaultInfinityRule(NULL
)
665 , defaultNaNRule(NULL
)
667 , lenientParseRules(NULL
)
668 , localizations(NULL
)
669 , capitalizationInfoSet(FALSE
)
670 , capitalizationForUIListMenu(FALSE
)
671 , capitalizationForStandAlone(FALSE
)
672 , capitalizationBrkIter(NULL
)
674 LocalizationInfo
* locinfo
= StringLocalizationInfo::create(locs
, perror
, status
);
675 init(description
, locinfo
, perror
, status
);
678 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
679 const UnicodeString
& locs
,
680 UParseError
& perror
, UErrorCode
& status
)
682 , ruleSetDescriptions(NULL
)
684 , defaultRuleSet(NULL
)
685 , locale(Locale::getDefault())
687 , decimalFormatSymbols(NULL
)
688 , defaultInfinityRule(NULL
)
689 , defaultNaNRule(NULL
)
691 , lenientParseRules(NULL
)
692 , localizations(NULL
)
693 , capitalizationInfoSet(FALSE
)
694 , capitalizationForUIListMenu(FALSE
)
695 , capitalizationForStandAlone(FALSE
)
696 , capitalizationBrkIter(NULL
)
698 LocalizationInfo
* locinfo
= StringLocalizationInfo::create(locs
, perror
, status
);
699 init(description
, locinfo
, perror
, status
);
702 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
703 LocalizationInfo
* info
,
704 const Locale
& alocale
, UParseError
& perror
, UErrorCode
& status
)
706 , ruleSetDescriptions(NULL
)
708 , defaultRuleSet(NULL
)
711 , decimalFormatSymbols(NULL
)
712 , defaultInfinityRule(NULL
)
713 , defaultNaNRule(NULL
)
715 , lenientParseRules(NULL
)
716 , localizations(NULL
)
717 , capitalizationInfoSet(FALSE
)
718 , capitalizationForUIListMenu(FALSE
)
719 , capitalizationForStandAlone(FALSE
)
720 , capitalizationBrkIter(NULL
)
722 init(description
, info
, perror
, status
);
725 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
729 , ruleSetDescriptions(NULL
)
731 , defaultRuleSet(NULL
)
732 , locale(Locale::getDefault())
734 , decimalFormatSymbols(NULL
)
735 , defaultInfinityRule(NULL
)
736 , defaultNaNRule(NULL
)
738 , lenientParseRules(NULL
)
739 , localizations(NULL
)
740 , capitalizationInfoSet(FALSE
)
741 , capitalizationForUIListMenu(FALSE
)
742 , capitalizationForStandAlone(FALSE
)
743 , capitalizationBrkIter(NULL
)
745 init(description
, NULL
, perror
, status
);
748 RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString
& description
,
749 const Locale
& aLocale
,
753 , ruleSetDescriptions(NULL
)
755 , defaultRuleSet(NULL
)
758 , decimalFormatSymbols(NULL
)
759 , defaultInfinityRule(NULL
)
760 , defaultNaNRule(NULL
)
762 , lenientParseRules(NULL
)
763 , localizations(NULL
)
764 , capitalizationInfoSet(FALSE
)
765 , capitalizationForUIListMenu(FALSE
)
766 , capitalizationForStandAlone(FALSE
)
767 , capitalizationBrkIter(NULL
)
769 init(description
, NULL
, perror
, status
);
772 RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag
, const Locale
& alocale
, UErrorCode
& status
)
774 , ruleSetDescriptions(NULL
)
776 , defaultRuleSet(NULL
)
779 , decimalFormatSymbols(NULL
)
780 , defaultInfinityRule(NULL
)
781 , defaultNaNRule(NULL
)
783 , lenientParseRules(NULL
)
784 , localizations(NULL
)
785 , capitalizationInfoSet(FALSE
)
786 , capitalizationForUIListMenu(FALSE
)
787 , capitalizationForStandAlone(FALSE
)
788 , capitalizationBrkIter(NULL
)
790 if (U_FAILURE(status
)) {
794 const char* rules_tag
= "RBNFRules";
795 const char* fmt_tag
= "";
797 case URBNF_SPELLOUT
: fmt_tag
= "SpelloutRules"; break;
798 case URBNF_ORDINAL
: fmt_tag
= "OrdinalRules"; break;
799 case URBNF_DURATION
: fmt_tag
= "DurationRules"; break;
800 case URBNF_NUMBERING_SYSTEM
: fmt_tag
= "NumberingSystemRules"; break;
801 default: status
= U_ILLEGAL_ARGUMENT_ERROR
; return;
804 // TODO: read localization info from resource
805 LocalizationInfo
* locinfo
= NULL
;
807 UResourceBundle
* nfrb
= ures_open(U_ICUDATA_RBNF
, locale
.getName(), &status
);
808 if (U_SUCCESS(status
)) {
809 setLocaleIDs(ures_getLocaleByType(nfrb
, ULOC_VALID_LOCALE
, &status
),
810 ures_getLocaleByType(nfrb
, ULOC_ACTUAL_LOCALE
, &status
));
812 UResourceBundle
* rbnfRules
= ures_getByKeyWithFallback(nfrb
, rules_tag
, NULL
, &status
);
813 if (U_FAILURE(status
)) {
816 UResourceBundle
* ruleSets
= ures_getByKeyWithFallback(rbnfRules
, fmt_tag
, NULL
, &status
);
817 if (U_FAILURE(status
)) {
818 ures_close(rbnfRules
);
824 while (ures_hasNext(ruleSets
)) {
825 desc
.append(ures_getNextUnicodeString(ruleSets
,NULL
,&status
));
829 init(desc
, locinfo
, perror
, status
);
831 ures_close(ruleSets
);
832 ures_close(rbnfRules
);
837 RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat
& rhs
)
840 , ruleSetDescriptions(NULL
)
842 , defaultRuleSet(NULL
)
845 , decimalFormatSymbols(NULL
)
846 , defaultInfinityRule(NULL
)
847 , defaultNaNRule(NULL
)
849 , lenientParseRules(NULL
)
850 , localizations(NULL
)
851 , capitalizationInfoSet(FALSE
)
852 , capitalizationForUIListMenu(FALSE
)
853 , capitalizationForStandAlone(FALSE
)
854 , capitalizationBrkIter(NULL
)
856 this->operator=(rhs
);
861 RuleBasedNumberFormat
&
862 RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat
& rhs
)
867 NumberFormat::operator=(rhs
);
868 UErrorCode status
= U_ZERO_ERROR
;
871 lenient
= rhs
.lenient
;
874 setDecimalFormatSymbols(*rhs
.getDecimalFormatSymbols());
875 init(rhs
.originalDescription
, rhs
.localizations
? rhs
.localizations
->ref() : NULL
, perror
, status
);
876 setDefaultRuleSet(rhs
.getDefaultRuleSetName(), status
);
878 capitalizationInfoSet
= rhs
.capitalizationInfoSet
;
879 capitalizationForUIListMenu
= rhs
.capitalizationForUIListMenu
;
880 capitalizationForStandAlone
= rhs
.capitalizationForStandAlone
;
881 #if !UCONFIG_NO_BREAK_ITERATION
882 capitalizationBrkIter
= (rhs
.capitalizationBrkIter
!=NULL
)? rhs
.capitalizationBrkIter
->clone(): NULL
;
888 RuleBasedNumberFormat::~RuleBasedNumberFormat()
894 RuleBasedNumberFormat::clone(void) const
896 return new RuleBasedNumberFormat(*this);
900 RuleBasedNumberFormat::operator==(const Format
& other
) const
902 if (this == &other
) {
906 if (typeid(*this) == typeid(other
)) {
907 const RuleBasedNumberFormat
& rhs
= (const RuleBasedNumberFormat
&)other
;
908 // test for capitalization info equality is adequately handled
909 // by the NumberFormat test for fCapitalizationContext equality;
910 // the info here is just derived from that.
911 if (locale
== rhs
.locale
&&
912 lenient
== rhs
.lenient
&&
913 (localizations
== NULL
914 ? rhs
.localizations
== NULL
915 : (rhs
.localizations
== NULL
917 : *localizations
== rhs
.localizations
))) {
919 NFRuleSet
** p
= ruleSets
;
920 NFRuleSet
** q
= rhs
.ruleSets
;
923 } else if (q
== NULL
) {
926 while (*p
&& *q
&& (**p
== **q
)) {
930 return *q
== NULL
&& *p
== NULL
;
938 RuleBasedNumberFormat::getRules() const
940 UnicodeString result
;
941 if (ruleSets
!= NULL
) {
942 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
943 (*p
)->appendRules(result
);
950 RuleBasedNumberFormat::getRuleSetName(int32_t index
) const
953 UnicodeString
string(TRUE
, localizations
->getRuleSetName(index
), (int32_t)-1);
957 UnicodeString result
;
958 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
960 if (rs
->isPublic()) {
973 RuleBasedNumberFormat::getNumberOfRuleSetNames() const
977 result
= localizations
->getNumberOfRuleSets();
980 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
981 if ((**p
).isPublic()) {
990 RuleBasedNumberFormat::getNumberOfRuleSetDisplayNameLocales(void) const {
992 return localizations
->getNumberOfDisplayLocales();
998 RuleBasedNumberFormat::getRuleSetDisplayNameLocale(int32_t index
, UErrorCode
& status
) const {
999 if (U_FAILURE(status
)) {
1002 if (localizations
&& index
>= 0 && index
< localizations
->getNumberOfDisplayLocales()) {
1003 UnicodeString
name(TRUE
, localizations
->getLocaleName(index
), -1);
1005 int32_t cap
= name
.length() + 1;
1008 bp
= (char *)uprv_malloc(cap
);
1010 status
= U_MEMORY_ALLOCATION_ERROR
;
1014 name
.extract(0, name
.length(), bp
, cap
, UnicodeString::kInvariant
);
1015 Locale
retLocale(bp
);
1021 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1027 RuleBasedNumberFormat::getRuleSetDisplayName(int32_t index
, const Locale
& localeParam
) {
1028 if (localizations
&& index
>= 0 && index
< localizations
->getNumberOfRuleSets()) {
1029 UnicodeString
localeName(localeParam
.getBaseName(), -1, UnicodeString::kInvariant
);
1030 int32_t len
= localeName
.length();
1031 UChar
* localeStr
= localeName
.getBuffer(len
+ 1);
1034 int32_t ix
= localizations
->indexForLocale(localeStr
);
1036 UnicodeString
name(TRUE
, localizations
->getDisplayName(ix
, index
), -1);
1040 // trim trailing portion, skipping over ommitted sections
1041 do { --len
;} while (len
> 0 && localeStr
[len
] != 0x005f); // underscore
1042 while (len
> 0 && localeStr
[len
-1] == 0x005F) --len
;
1044 UnicodeString
name(TRUE
, localizations
->getRuleSetName(index
), -1);
1047 UnicodeString bogus
;
1053 RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString
& ruleSetName
, const Locale
& localeParam
) {
1054 if (localizations
) {
1055 UnicodeString
rsn(ruleSetName
);
1056 int32_t ix
= localizations
->indexForRuleSet(rsn
.getTerminatedBuffer());
1057 return getRuleSetDisplayName(ix
, localeParam
);
1059 UnicodeString bogus
;
1065 RuleBasedNumberFormat::findRuleSet(const UnicodeString
& name
, UErrorCode
& status
) const
1067 if (U_SUCCESS(status
) && ruleSets
) {
1068 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
1070 if (rs
->isNamed(name
)) {
1074 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1080 RuleBasedNumberFormat::format(int32_t number
,
1081 UnicodeString
& toAppendTo
,
1082 FieldPosition
& /* pos */) const
1084 if (defaultRuleSet
) {
1085 UErrorCode status
= U_ZERO_ERROR
;
1086 int32_t startPos
= toAppendTo
.length();
1087 defaultRuleSet
->format((int64_t)number
, toAppendTo
, toAppendTo
.length(), 0, status
);
1088 adjustForCapitalizationContext(startPos
, toAppendTo
);
1095 RuleBasedNumberFormat::format(int64_t number
,
1096 UnicodeString
& toAppendTo
,
1097 FieldPosition
& /* pos */) const
1099 if (defaultRuleSet
) {
1100 UErrorCode status
= U_ZERO_ERROR
;
1101 int32_t startPos
= toAppendTo
.length();
1102 defaultRuleSet
->format(number
, toAppendTo
, toAppendTo
.length(), 0, status
);
1103 adjustForCapitalizationContext(startPos
, toAppendTo
);
1110 RuleBasedNumberFormat::format(double number
,
1111 UnicodeString
& toAppendTo
,
1112 FieldPosition
& /* pos */) const
1114 int32_t startPos
= toAppendTo
.length();
1115 if (defaultRuleSet
) {
1116 UErrorCode status
= U_ZERO_ERROR
;
1117 defaultRuleSet
->format(number
, toAppendTo
, toAppendTo
.length(), 0, status
);
1119 return adjustForCapitalizationContext(startPos
, toAppendTo
);
1124 RuleBasedNumberFormat::format(int32_t number
,
1125 const UnicodeString
& ruleSetName
,
1126 UnicodeString
& toAppendTo
,
1127 FieldPosition
& /* pos */,
1128 UErrorCode
& status
) const
1130 // return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
1131 if (U_SUCCESS(status
)) {
1132 if (ruleSetName
.indexOf(gPercentPercent
, 2, 0) == 0) {
1133 // throw new IllegalArgumentException("Can't use internal rule set");
1134 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1136 NFRuleSet
*rs
= findRuleSet(ruleSetName
, status
);
1138 int32_t startPos
= toAppendTo
.length();
1139 rs
->format((int64_t)number
, toAppendTo
, toAppendTo
.length(), 0, status
);
1140 adjustForCapitalizationContext(startPos
, toAppendTo
);
1149 RuleBasedNumberFormat::format(int64_t number
,
1150 const UnicodeString
& ruleSetName
,
1151 UnicodeString
& toAppendTo
,
1152 FieldPosition
& /* pos */,
1153 UErrorCode
& status
) const
1155 if (U_SUCCESS(status
)) {
1156 if (ruleSetName
.indexOf(gPercentPercent
, 2, 0) == 0) {
1157 // throw new IllegalArgumentException("Can't use internal rule set");
1158 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1160 NFRuleSet
*rs
= findRuleSet(ruleSetName
, status
);
1162 int32_t startPos
= toAppendTo
.length();
1163 rs
->format(number
, toAppendTo
, toAppendTo
.length(), 0, status
);
1164 adjustForCapitalizationContext(startPos
, toAppendTo
);
1173 RuleBasedNumberFormat::format(double number
,
1174 const UnicodeString
& ruleSetName
,
1175 UnicodeString
& toAppendTo
,
1176 FieldPosition
& /* pos */,
1177 UErrorCode
& status
) const
1179 if (U_SUCCESS(status
)) {
1180 if (ruleSetName
.indexOf(gPercentPercent
, 2, 0) == 0) {
1181 // throw new IllegalArgumentException("Can't use internal rule set");
1182 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1184 NFRuleSet
*rs
= findRuleSet(ruleSetName
, status
);
1186 int32_t startPos
= toAppendTo
.length();
1187 rs
->format(number
, toAppendTo
, toAppendTo
.length(), 0, status
);
1188 adjustForCapitalizationContext(startPos
, toAppendTo
);
1196 RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos
,
1197 UnicodeString
& currentResult
) const
1199 #if !UCONFIG_NO_BREAK_ITERATION
1200 if (startPos
==0 && currentResult
.length() > 0) {
1201 // capitalize currentResult according to context
1202 UChar32 ch
= currentResult
.char32At(0);
1203 UErrorCode status
= U_ZERO_ERROR
;
1204 UDisplayContext capitalizationContext
= getContext(UDISPCTX_TYPE_CAPITALIZATION
, status
);
1205 if ( u_islower(ch
) && U_SUCCESS(status
) && capitalizationBrkIter
!= NULL
&&
1206 ( capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
||
1207 (capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
&& capitalizationForUIListMenu
) ||
1208 (capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_STANDALONE
&& capitalizationForStandAlone
)) ) {
1209 // titlecase first word of currentResult, here use sentence iterator unlike current implementations
1210 // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
1211 currentResult
.toTitle(capitalizationBrkIter
, locale
, U_TITLECASE_NO_LOWERCASE
| U_TITLECASE_NO_BREAK_ADJUSTMENT
);
1215 return currentResult
;
1220 RuleBasedNumberFormat::parse(const UnicodeString
& text
,
1221 Formattable
& result
,
1222 ParsePosition
& parsePosition
) const
1225 parsePosition
.setErrorIndex(0);
1229 UnicodeString
workingText(text
, parsePosition
.getIndex());
1230 ParsePosition
workingPos(0);
1232 ParsePosition
high_pp(0);
1233 Formattable high_result
;
1235 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
1237 if (rp
->isPublic() && rp
->isParseable()) {
1238 ParsePosition
working_pp(0);
1239 Formattable working_result
;
1241 rp
->parse(workingText
, working_pp
, kMaxDouble
, working_result
, lenient
);
1242 if (working_pp
.getIndex() > high_pp
.getIndex()) {
1243 high_pp
= working_pp
;
1244 high_result
= working_result
;
1246 if (high_pp
.getIndex() == workingText
.length()) {
1253 int32_t startIndex
= parsePosition
.getIndex();
1254 parsePosition
.setIndex(startIndex
+ high_pp
.getIndex());
1255 if (high_pp
.getIndex() > 0) {
1256 parsePosition
.setErrorIndex(-1);
1258 int32_t errorIndex
= (high_pp
.getErrorIndex()>0)? high_pp
.getErrorIndex(): 0;
1259 parsePosition
.setErrorIndex(startIndex
+ errorIndex
);
1261 result
= high_result
;
1262 if (result
.getType() == Formattable::kDouble
) {
1263 double d
= result
.getDouble();
1264 if (!uprv_isNaN(d
) && d
== uprv_trunc(d
) && INT32_MIN
<= d
&& d
<= INT32_MAX
) {
1265 // Note: casting a double to an int when the double is too large or small
1266 // to fit the destination is undefined behavior. The explicit range checks,
1267 // above, are required. Just casting and checking the result value is undefined.
1268 result
.setLong(static_cast<int32_t>(d
));
1273 #if !UCONFIG_NO_COLLATION
1276 RuleBasedNumberFormat::setLenient(UBool enabled
)
1279 if (!enabled
&& collator
) {
1288 RuleBasedNumberFormat::setDefaultRuleSet(const UnicodeString
& ruleSetName
, UErrorCode
& status
) {
1289 if (U_SUCCESS(status
)) {
1290 if (ruleSetName
.isEmpty()) {
1291 if (localizations
) {
1292 UnicodeString
name(TRUE
, localizations
->getRuleSetName(0), -1);
1293 defaultRuleSet
= findRuleSet(name
, status
);
1295 initDefaultRuleSet();
1297 } else if (ruleSetName
.startsWith(UNICODE_STRING_SIMPLE("%%"))) {
1298 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1300 NFRuleSet
* result
= findRuleSet(ruleSetName
, status
);
1301 if (result
!= NULL
) {
1302 defaultRuleSet
= result
;
1309 RuleBasedNumberFormat::getDefaultRuleSetName() const {
1310 UnicodeString result
;
1311 if (defaultRuleSet
&& defaultRuleSet
->isPublic()) {
1312 defaultRuleSet
->getName(result
);
1314 result
.setToBogus();
1320 RuleBasedNumberFormat::initDefaultRuleSet()
1322 defaultRuleSet
= NULL
;
1327 const UnicodeString
spellout(UNICODE_STRING_SIMPLE("%spellout-numbering"));
1328 const UnicodeString
ordinal(UNICODE_STRING_SIMPLE("%digits-ordinal"));
1329 const UnicodeString
duration(UNICODE_STRING_SIMPLE("%duration"));
1331 NFRuleSet
**p
= &ruleSets
[0];
1333 if ((*p
)->isNamed(spellout
) || (*p
)->isNamed(ordinal
) || (*p
)->isNamed(duration
)) {
1334 defaultRuleSet
= *p
;
1341 defaultRuleSet
= *--p
;
1342 if (!defaultRuleSet
->isPublic()) {
1343 while (p
!= ruleSets
) {
1344 if ((*--p
)->isPublic()) {
1345 defaultRuleSet
= *p
;
1354 RuleBasedNumberFormat::init(const UnicodeString
& rules
, LocalizationInfo
* localizationInfos
,
1355 UParseError
& pErr
, UErrorCode
& status
)
1357 // TODO: implement UParseError
1358 uprv_memset(&pErr
, 0, sizeof(UParseError
));
1359 // Note: this can leave ruleSets == NULL, so remaining code should check
1360 if (U_FAILURE(status
)) {
1364 initializeDecimalFormatSymbols(status
);
1365 initializeDefaultInfinityRule(status
);
1366 initializeDefaultNaNRule(status
);
1367 if (U_FAILURE(status
)) {
1371 this->localizations
= localizationInfos
== NULL
? NULL
: localizationInfos
->ref();
1373 UnicodeString
description(rules
);
1374 if (!description
.length()) {
1375 status
= U_MEMORY_ALLOCATION_ERROR
;
1379 // start by stripping the trailing whitespace from all the rules
1380 // (this is all the whitespace follwing each semicolon in the
1381 // description). This allows us to look for rule-set boundaries
1382 // by searching for ";%" without having to worry about whitespace
1383 // between the ; and the %
1384 stripWhitespace(description
);
1386 // check to see if there's a set of lenient-parse rules. If there
1387 // is, pull them out into our temporary holding place for them,
1388 // and delete them from the description before the real desciption-
1389 // parsing code sees them
1390 int32_t lp
= description
.indexOf(gLenientParse
, -1, 0);
1392 // we've got to make sure we're not in the middle of a rule
1393 // (where "%%lenient-parse" would actually get treated as
1395 if (lp
== 0 || description
.charAt(lp
- 1) == gSemiColon
) {
1396 // locate the beginning and end of the actual collation
1397 // rules (there may be whitespace between the name and
1398 // the first token in the description)
1399 int lpEnd
= description
.indexOf(gSemiPercent
, 2, lp
);
1402 lpEnd
= description
.length() - 1;
1404 int lpStart
= lp
+ u_strlen(gLenientParse
);
1405 while (PatternProps::isWhiteSpace(description
.charAt(lpStart
))) {
1409 // copy out the lenient-parse rules and delete them
1410 // from the description
1411 lenientParseRules
= new UnicodeString();
1413 if (lenientParseRules
== 0) {
1414 status
= U_MEMORY_ALLOCATION_ERROR
;
1417 lenientParseRules
->setTo(description
, lpStart
, lpEnd
- lpStart
);
1419 description
.remove(lp
, lpEnd
+ 1 - lp
);
1423 // pre-flight parsing the description and count the number of
1424 // rule sets (";%" marks the end of one rule set and the beginning
1427 for (int32_t p
= description
.indexOf(gSemiPercent
, 2, 0); p
!= -1; p
= description
.indexOf(gSemiPercent
, 2, p
)) {
1433 // our rule list is an array of the appropriate size
1434 ruleSets
= (NFRuleSet
**)uprv_malloc((numRuleSets
+ 1) * sizeof(NFRuleSet
*));
1436 if (ruleSets
== 0) {
1437 status
= U_MEMORY_ALLOCATION_ERROR
;
1441 for (int i
= 0; i
<= numRuleSets
; ++i
) {
1445 // divide up the descriptions into individual rule-set descriptions
1446 // and store them in a temporary array. At each step, we also
1447 // new up a rule set, but all this does is initialize its name
1448 // and remove it from its description. We can't actually parse
1449 // the rest of the descriptions and finish initializing everything
1450 // because we have to know the names and locations of all the rule
1451 // sets before we can actually set everything up
1453 status
= U_ILLEGAL_ARGUMENT_ERROR
;
1457 ruleSetDescriptions
= new UnicodeString
[numRuleSets
];
1458 if (ruleSetDescriptions
== 0) {
1459 status
= U_MEMORY_ALLOCATION_ERROR
;
1466 for (int32_t p
= description
.indexOf(gSemiPercent
, 2, 0); p
!= -1; p
= description
.indexOf(gSemiPercent
, 2, start
)) {
1467 ruleSetDescriptions
[curRuleSet
].setTo(description
, start
, p
+ 1 - start
);
1468 ruleSets
[curRuleSet
] = new NFRuleSet(this, ruleSetDescriptions
, curRuleSet
, status
);
1469 if (ruleSets
[curRuleSet
] == 0) {
1470 status
= U_MEMORY_ALLOCATION_ERROR
;
1476 ruleSetDescriptions
[curRuleSet
].setTo(description
, start
, description
.length() - start
);
1477 ruleSets
[curRuleSet
] = new NFRuleSet(this, ruleSetDescriptions
, curRuleSet
, status
);
1478 if (ruleSets
[curRuleSet
] == 0) {
1479 status
= U_MEMORY_ALLOCATION_ERROR
;
1484 // now we can take note of the formatter's default rule set, which
1485 // is the last public rule set in the description (it's the last
1486 // rather than the first so that a user can create a new formatter
1487 // from an existing formatter and change its default behavior just
1488 // by appending more rule sets to the end)
1490 // {dlf} Initialization of a fraction rule set requires the default rule
1491 // set to be known. For purposes of initialization, this is always the
1492 // last public rule set, no matter what the localization data says.
1493 initDefaultRuleSet();
1495 // finally, we can go back through the temporary descriptions
1496 // list and finish seting up the substructure (and we throw
1497 // away the temporary descriptions as we go)
1499 for (int i
= 0; i
< numRuleSets
; i
++) {
1500 ruleSets
[i
]->parseRules(ruleSetDescriptions
[i
], status
);
1504 // Now that the rules are initialized, the 'real' default rule
1505 // set can be adjusted by the localization data.
1507 // The C code keeps the localization array as is, rather than building
1508 // a separate array of the public rule set names, so we have less work
1509 // to do here-- but we still need to check the names.
1511 if (localizationInfos
) {
1512 // confirm the names, if any aren't in the rules, that's an error
1513 // it is ok if the rules contain public rule sets that are not in this list
1514 for (int32_t i
= 0; i
< localizationInfos
->getNumberOfRuleSets(); ++i
) {
1515 UnicodeString
name(TRUE
, localizationInfos
->getRuleSetName(i
), -1);
1516 NFRuleSet
* rs
= findRuleSet(name
, status
);
1521 defaultRuleSet
= rs
;
1525 defaultRuleSet
= getDefaultRuleSet();
1527 originalDescription
= rules
;
1530 // override the NumberFormat implementation in order to
1531 // lazily initialize relevant items
1533 RuleBasedNumberFormat::setContext(UDisplayContext value
, UErrorCode
& status
)
1535 NumberFormat::setContext(value
, status
);
1536 if (U_SUCCESS(status
)) {
1537 if (!capitalizationInfoSet
&&
1538 (value
==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
|| value
==UDISPCTX_CAPITALIZATION_FOR_STANDALONE
)) {
1539 initCapitalizationContextInfo(locale
);
1540 capitalizationInfoSet
= TRUE
;
1542 #if !UCONFIG_NO_BREAK_ITERATION
1543 if ( capitalizationBrkIter
== NULL
&& (value
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
||
1544 (value
==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
&& capitalizationForUIListMenu
) ||
1545 (value
==UDISPCTX_CAPITALIZATION_FOR_STANDALONE
&& capitalizationForStandAlone
)) ) {
1546 UErrorCode status
= U_ZERO_ERROR
;
1547 capitalizationBrkIter
= BreakIterator::createSentenceInstance(locale
, status
);
1548 if (U_FAILURE(status
)) {
1549 delete capitalizationBrkIter
;
1550 capitalizationBrkIter
= NULL
;
1558 RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale
& thelocale
)
1560 #if !UCONFIG_NO_BREAK_ITERATION
1561 const char * localeID
= (thelocale
!= NULL
)? thelocale
.getBaseName(): NULL
;
1562 UErrorCode status
= U_ZERO_ERROR
;
1563 UResourceBundle
*rb
= ures_open(NULL
, localeID
, &status
);
1564 rb
= ures_getByKeyWithFallback(rb
, "contextTransforms", rb
, &status
);
1565 rb
= ures_getByKeyWithFallback(rb
, "number-spellout", rb
, &status
);
1566 if (U_SUCCESS(status
) && rb
!= NULL
) {
1568 const int32_t * intVector
= ures_getIntVector(rb
, &len
, &status
);
1569 if (U_SUCCESS(status
) && intVector
!= NULL
&& len
>= 2) {
1570 capitalizationForUIListMenu
= intVector
[0];
1571 capitalizationForStandAlone
= intVector
[1];
1579 RuleBasedNumberFormat::stripWhitespace(UnicodeString
& description
)
1581 // iterate through the characters...
1582 UnicodeString result
;
1585 while (start
!= -1 && start
< description
.length()) {
1586 // seek to the first non-whitespace character...
1587 while (start
< description
.length()
1588 && PatternProps::isWhiteSpace(description
.charAt(start
))) {
1592 // locate the next semicolon in the text and copy the text from
1593 // our current position up to that semicolon into the result
1594 int32_t p
= description
.indexOf(gSemiColon
, start
);
1596 // or if we don't find a semicolon, just copy the rest of
1597 // the string into the result
1598 result
.append(description
, start
, description
.length() - start
);
1601 else if (p
< description
.length()) {
1602 result
.append(description
, start
, p
+ 1 - start
);
1606 // when we get here, we've seeked off the end of the sring, and
1607 // we terminate the loop (we continue until *start* is -1 rather
1608 // than until *p* is -1, because otherwise we'd miss the last
1609 // rule in the description)
1615 description
.setTo(result
);
1620 RuleBasedNumberFormat::dispose()
1623 for (NFRuleSet
** p
= ruleSets
; *p
; ++p
) {
1626 uprv_free(ruleSets
);
1630 if (ruleSetDescriptions
) {
1631 delete [] ruleSetDescriptions
;
1632 ruleSetDescriptions
= NULL
;
1635 #if !UCONFIG_NO_COLLATION
1640 delete decimalFormatSymbols
;
1641 decimalFormatSymbols
= NULL
;
1643 delete defaultInfinityRule
;
1644 defaultInfinityRule
= NULL
;
1646 delete defaultNaNRule
;
1647 defaultNaNRule
= NULL
;
1649 delete lenientParseRules
;
1650 lenientParseRules
= NULL
;
1652 #if !UCONFIG_NO_BREAK_ITERATION
1653 delete capitalizationBrkIter
;
1654 capitalizationBrkIter
= NULL
;
1657 if (localizations
) {
1658 localizations
= localizations
->unref();
1663 //-----------------------------------------------------------------------
1664 // package-internal API
1665 //-----------------------------------------------------------------------
1668 * Returns the collator to use for lenient parsing. The collator is lazily created:
1669 * this function creates it the first time it's called.
1670 * @return The collator to use for lenient parsing, or null if lenient parsing
1673 const RuleBasedCollator
*
1674 RuleBasedNumberFormat::getCollator() const
1676 #if !UCONFIG_NO_COLLATION
1681 // lazy-evaluate the collator
1682 if (collator
== NULL
&& lenient
) {
1683 // create a default collator based on the formatter's locale,
1684 // then pull out that collator's rules, append any additional
1685 // rules specified in the description, and create a _new_
1686 // collator based on the combinaiton of those rules
1688 UErrorCode status
= U_ZERO_ERROR
;
1690 Collator
* temp
= Collator::createInstance(locale
, status
);
1691 RuleBasedCollator
* newCollator
;
1692 if (U_SUCCESS(status
) && (newCollator
= dynamic_cast<RuleBasedCollator
*>(temp
)) != NULL
) {
1693 if (lenientParseRules
) {
1694 UnicodeString
rules(newCollator
->getRules());
1695 rules
.append(*lenientParseRules
);
1697 newCollator
= new RuleBasedCollator(rules
, status
);
1698 // Exit if newCollator could not be created.
1699 if (newCollator
== NULL
) {
1705 if (U_SUCCESS(status
)) {
1706 newCollator
->setAttribute(UCOL_DECOMPOSITION_MODE
, UCOL_ON
, status
);
1708 ((RuleBasedNumberFormat
*)this)->collator
= newCollator
;
1717 // if lenient-parse mode is off, this will be null
1718 // (see setLenientParseMode())
1723 DecimalFormatSymbols
*
1724 RuleBasedNumberFormat::initializeDecimalFormatSymbols(UErrorCode
&status
)
1726 // lazy-evaluate the DecimalFormatSymbols object. This object
1727 // is shared by all DecimalFormat instances belonging to this
1729 if (decimalFormatSymbols
== NULL
) {
1730 DecimalFormatSymbols
* temp
= new DecimalFormatSymbols(locale
, status
);
1731 if (U_SUCCESS(status
)) {
1732 decimalFormatSymbols
= temp
;
1738 return decimalFormatSymbols
;
1742 * Returns the DecimalFormatSymbols object that should be used by all DecimalFormat
1743 * instances owned by this formatter.
1745 const DecimalFormatSymbols
*
1746 RuleBasedNumberFormat::getDecimalFormatSymbols() const
1748 return decimalFormatSymbols
;
1752 RuleBasedNumberFormat::initializeDefaultInfinityRule(UErrorCode
&status
)
1754 if (U_FAILURE(status
)) {
1757 if (defaultInfinityRule
== NULL
) {
1758 UnicodeString
rule(UNICODE_STRING_SIMPLE("Inf: "));
1759 rule
.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kInfinitySymbol
));
1760 NFRule
* temp
= new NFRule(this, rule
, status
);
1761 if (U_SUCCESS(status
)) {
1762 defaultInfinityRule
= temp
;
1768 return defaultInfinityRule
;
1772 RuleBasedNumberFormat::getDefaultInfinityRule() const
1774 return defaultInfinityRule
;
1778 RuleBasedNumberFormat::initializeDefaultNaNRule(UErrorCode
&status
)
1780 if (U_FAILURE(status
)) {
1783 if (defaultNaNRule
== NULL
) {
1784 UnicodeString
rule(UNICODE_STRING_SIMPLE("NaN: "));
1785 rule
.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kNaNSymbol
));
1786 NFRule
* temp
= new NFRule(this, rule
, status
);
1787 if (U_SUCCESS(status
)) {
1788 defaultNaNRule
= temp
;
1794 return defaultNaNRule
;
1798 RuleBasedNumberFormat::getDefaultNaNRule() const
1800 return defaultNaNRule
;
1803 // De-owning the current localized symbols and adopt the new symbols.
1805 RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols
* symbolsToAdopt
)
1807 if (symbolsToAdopt
== NULL
) {
1808 return; // do not allow caller to set decimalFormatSymbols to NULL
1811 if (decimalFormatSymbols
!= NULL
) {
1812 delete decimalFormatSymbols
;
1815 decimalFormatSymbols
= symbolsToAdopt
;
1818 // Apply the new decimalFormatSymbols by reparsing the rulesets
1819 UErrorCode status
= U_ZERO_ERROR
;
1821 delete defaultInfinityRule
;
1822 defaultInfinityRule
= NULL
;
1823 initializeDefaultInfinityRule(status
); // Reset with the new DecimalFormatSymbols
1825 delete defaultNaNRule
;
1826 defaultNaNRule
= NULL
;
1827 initializeDefaultNaNRule(status
); // Reset with the new DecimalFormatSymbols
1830 for (int32_t i
= 0; i
< numRuleSets
; i
++) {
1831 ruleSets
[i
]->setDecimalFormatSymbols(*symbolsToAdopt
, status
);
1837 // Setting the symbols is equlivalent to adopting a newly created localized symbols.
1839 RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols
& symbols
)
1841 adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols
));
1845 RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType
,
1846 const UnicodeString
&pattern
,
1847 UErrorCode
& status
) const
1849 return new PluralFormat(locale
, pluralType
, pattern
, status
);