2 *******************************************************************************
3 * Copyright (C) 2007-2010, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
9 * Modification History:
11 * Date Name Description
12 *******************************************************************************
16 #include "unicode/uniset.h"
17 #include "unicode/utypes.h"
18 #include "unicode/ures.h"
19 #include "unicode/plurrule.h"
24 #include "plurrule_impl.h"
31 // TODO(claireho): remove stdio
35 #if !UCONFIG_NO_FORMATTING
40 #define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
42 static const UChar PLURAL_KEYWORD_ZERO
[] = {LOW_Z
,LOW_E
,LOW_R
,LOW_O
, 0};
43 static const UChar PLURAL_KEYWORD_ONE
[]={LOW_O
,LOW_N
,LOW_E
,0};
44 static const UChar PLURAL_KEYWORD_TWO
[]={LOW_T
,LOW_W
,LOW_O
,0};
45 static const UChar PLURAL_KEYWORD_FEW
[]={LOW_F
,LOW_E
,LOW_W
,0};
46 static const UChar PLURAL_KEYWORD_MANY
[]={LOW_M
,LOW_A
,LOW_N
,LOW_Y
,0};
47 static const UChar PLURAL_KEYWORD_OTHER
[]={LOW_O
,LOW_T
,LOW_H
,LOW_E
,LOW_R
,0};
48 static const UChar PLURAL_DEFAULT_RULE
[]={LOW_O
,LOW_T
,LOW_H
,LOW_E
,LOW_R
,COLON
,SPACE
,LOW_N
,0};
49 static const UChar PK_IN
[]={LOW_I
,LOW_N
,0};
50 static const UChar PK_NOT
[]={LOW_N
,LOW_O
,LOW_T
,0};
51 static const UChar PK_IS
[]={LOW_I
,LOW_S
,0};
52 static const UChar PK_MOD
[]={LOW_M
,LOW_O
,LOW_D
,0};
53 static const UChar PK_AND
[]={LOW_A
,LOW_N
,LOW_D
,0};
54 static const UChar PK_OR
[]={LOW_O
,LOW_R
,0};
55 static const UChar PK_VAR_N
[]={LOW_N
,0};
56 static const UChar PK_WITHIN
[]={LOW_W
,LOW_I
,LOW_T
,LOW_H
,LOW_I
,LOW_N
,0};
58 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules
)
59 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration
)
61 PluralRules::PluralRules(UErrorCode
& status
)
65 if (U_FAILURE(status
)) {
68 mParser
= new RuleParser();
70 status
= U_MEMORY_ALLOCATION_ERROR
;
74 PluralRules::PluralRules(const PluralRules
& other
)
77 mParser(new RuleParser())
82 PluralRules::~PluralRules() {
88 PluralRules::clone() const {
89 return new PluralRules(*this);
93 PluralRules::operator=(const PluralRules
& other
) {
96 if (other
.mRules
==NULL
) {
100 mRules
= new RuleChain(*other
.mRules
);
103 mParser
= new RuleParser();
109 PluralRules
* U_EXPORT2
110 PluralRules::createRules(const UnicodeString
& description
, UErrorCode
& status
) {
113 if (U_FAILURE(status
)) {
116 PluralRules
*newRules
= new PluralRules(status
);
117 if ( (newRules
!= NULL
)&& U_SUCCESS(status
) ) {
118 newRules
->parseDescription((UnicodeString
&)description
, rules
, status
);
119 if (U_SUCCESS(status
)) {
120 newRules
->addRules(rules
);
123 if (U_FAILURE(status
)) {
132 PluralRules
* U_EXPORT2
133 PluralRules::createDefaultRules(UErrorCode
& status
) {
134 return createRules(PLURAL_DEFAULT_RULE
, status
);
137 PluralRules
* U_EXPORT2
138 PluralRules::forLocale(const Locale
& locale
, UErrorCode
& status
) {
140 if (U_FAILURE(status
)) {
143 PluralRules
*newObj
= new PluralRules(status
);
144 if (newObj
==NULL
|| U_FAILURE(status
)) {
147 UnicodeString locRule
= newObj
->getRuleFromResource(locale
, status
);
148 if ((locRule
.length() != 0) && U_SUCCESS(status
)) {
149 newObj
->parseDescription(locRule
, rChain
, status
);
150 if (U_SUCCESS(status
)) {
151 newObj
->addRules(rChain
);
154 if (U_FAILURE(status
)||(locRule
.length() == 0)) {
155 // use default plural rule
156 status
= U_ZERO_ERROR
;
157 UnicodeString defRule
= UnicodeString(PLURAL_DEFAULT_RULE
);
158 newObj
->parseDescription(defRule
, rChain
, status
);
159 newObj
->addRules(rChain
);
166 PluralRules::select(int32_t number
) const {
167 if (mRules
== NULL
) {
168 return PLURAL_DEFAULT_RULE
;
171 return mRules
->select(number
);
176 PluralRules::select(double number
) const {
177 if (mRules
== NULL
) {
178 return PLURAL_DEFAULT_RULE
;
181 return mRules
->select(number
);
186 PluralRules::getKeywords(UErrorCode
& status
) const {
187 if (U_FAILURE(status
)) return NULL
;
188 StringEnumeration
* nameEnumerator
= new PluralKeywordEnumeration(mRules
, status
);
189 if (U_FAILURE(status
)) return NULL
;
191 return nameEnumerator
;
196 PluralRules::isKeyword(const UnicodeString
& keyword
) const {
197 if ( keyword
== PLURAL_KEYWORD_OTHER
) {
205 return mRules
->isKeyword(keyword
);
211 PluralRules::getKeywordOther() const {
212 return PLURAL_KEYWORD_OTHER
;
216 PluralRules::operator==(const PluralRules
& other
) const {
218 UBool sameList
= TRUE
;
219 const UnicodeString
*ptrKeyword
;
220 UErrorCode status
= U_ZERO_ERROR
;
222 if ( this == &other
) {
225 StringEnumeration
* myKeywordList
= getKeywords(status
);
226 if (U_FAILURE(status
)) {
229 StringEnumeration
* otherKeywordList
=other
.getKeywords(status
);
230 if (U_FAILURE(status
)) {
234 if (myKeywordList
->count(status
)!=otherKeywordList
->count(status
) ||
239 myKeywordList
->reset(status
);
240 if (U_FAILURE(status
)) {
243 while (sameList
&& (ptrKeyword
=myKeywordList
->snext(status
))!=NULL
) {
244 if (U_FAILURE(status
) || !other
.isKeyword(*ptrKeyword
)) {
248 otherKeywordList
->reset(status
);
249 if (U_FAILURE(status
)) {
252 while (sameList
&& (ptrKeyword
=otherKeywordList
->snext(status
))!=NULL
) {
253 if (U_FAILURE(status
)) {
256 if (!this->isKeyword(*ptrKeyword
)) {
260 delete myKeywordList
;
261 delete otherKeywordList
;
267 if ((limit
=this->getRepeatLimit()) != other
.getRepeatLimit()) {
270 UnicodeString myKeyword
, otherKeyword
;
271 for (int32_t i
=0; i
<limit
; ++i
) {
272 myKeyword
= this->select(i
);
273 otherKeyword
= other
.select(i
);
274 if (myKeyword
!=otherKeyword
) {
282 PluralRules::parseDescription(UnicodeString
& data
, RuleChain
& rules
, UErrorCode
&status
)
287 tokenType prevType
=none
;
288 RuleChain
*ruleChain
=NULL
;
289 AndConstraint
*curAndConstraint
=NULL
;
290 OrConstraint
*orNode
=NULL
;
291 RuleChain
*lastChain
=NULL
;
293 if (U_FAILURE(status
)) {
296 UnicodeString ruleData
= data
.toLower();
297 while (ruleIndex
< ruleData
.length()) {
298 mParser
->getNextToken(ruleData
, &ruleIndex
, token
, type
, status
);
299 if (U_FAILURE(status
)) {
302 mParser
->checkSyntax(prevType
, type
, status
);
303 if (U_FAILURE(status
)) {
308 curAndConstraint
= curAndConstraint
->add();
312 while (lastChain
->next
!=NULL
) {
313 lastChain
= lastChain
->next
;
315 orNode
=lastChain
->ruleHeader
;
316 while (orNode
->next
!= NULL
) {
317 orNode
= orNode
->next
;
319 orNode
->next
= new OrConstraint();
322 curAndConstraint
= orNode
->add();
325 curAndConstraint
->rangeHigh
=-1;
328 curAndConstraint
->notIn
=TRUE
;
331 curAndConstraint
->rangeHigh
=PLURAL_RANGE_HIGH
;
332 curAndConstraint
->integerOnly
= TRUE
;
335 curAndConstraint
->rangeHigh
=PLURAL_RANGE_HIGH
;
338 if ( (curAndConstraint
->op
==AndConstraint::MOD
)&&
339 (curAndConstraint
->opNum
== -1 ) ) {
340 curAndConstraint
->opNum
=getNumberValue(token
);
343 if (curAndConstraint
->rangeLow
== -1) {
344 curAndConstraint
->rangeLow
=getNumberValue(token
);
347 curAndConstraint
->rangeHigh
=getNumberValue(token
);
352 curAndConstraint
->op
=AndConstraint::MOD
;
355 if (ruleChain
==NULL
) {
359 while (ruleChain
->next
!=NULL
){
360 ruleChain
=ruleChain
->next
;
362 ruleChain
=ruleChain
->next
=new RuleChain();
364 orNode
= ruleChain
->ruleHeader
= new OrConstraint();
365 curAndConstraint
= orNode
->add();
366 ruleChain
->keyword
= token
;
376 PluralRules::getNumberValue(const UnicodeString
& token
) const {
380 i
= token
.extract(0, token
.length(), digits
, ARRAY_SIZE(digits
), US_INV
);
383 return((int32_t)atoi(digits
));
388 PluralRules::getNextLocale(const UnicodeString
& localeData
, int32_t* curIndex
, UnicodeString
& localeName
) {
392 while (i
< localeData
.length()) {
393 if ( (localeData
.charAt(i
)!= SPACE
) && (localeData
.charAt(i
)!= COMMA
) ) {
399 while (i
< localeData
.length()) {
400 if ( (localeData
.charAt(i
)== SPACE
) || (localeData
.charAt(i
)== COMMA
) ) {
403 localeName
+=localeData
.charAt(i
++);
410 PluralRules::getRepeatLimit() const {
412 return mRules
->getRepeatLimit();
421 PluralRules::addRules(RuleChain
& rules
) {
422 RuleChain
*newRule
= new RuleChain(rules
);
423 this->mRules
=newRule
;
424 newRule
->setRepeatLimit();
428 PluralRules::getRuleFromResource(const Locale
& locale
, UErrorCode
& errCode
) {
429 UnicodeString emptyStr
;
431 if (U_FAILURE(errCode
)) {
434 UResourceBundle
*rb
=ures_openDirect(NULL
, "plurals", &errCode
);
435 if(U_FAILURE(errCode
)) {
436 /* total failure, not even root could be opened */
439 UResourceBundle
*locRes
=ures_getByKey(rb
, "locales", NULL
, &errCode
);
440 if(U_FAILURE(errCode
)) {
445 const char *curLocaleName
=locale
.getName();
446 const UChar
* s
= ures_getStringByKey(locRes
, curLocaleName
, &resLen
, &errCode
);
449 // Check parent locales.
450 UErrorCode status
= U_ZERO_ERROR
;
451 char parentLocaleName
[ULOC_FULLNAME_CAPACITY
];
452 const char *curLocaleName
=locale
.getName();
453 int32_t localeNameLen
=0;
454 uprv_strcpy(parentLocaleName
, curLocaleName
);
456 while ((localeNameLen
=uloc_getParent(parentLocaleName
, parentLocaleName
,
457 ULOC_FULLNAME_CAPACITY
, &status
)) > 0) {
459 s
= ures_getStringByKey(locRes
, parentLocaleName
, &resLen
, &status
);
461 errCode
= U_ZERO_ERROR
;
464 status
= U_ZERO_ERROR
;
475 u_UCharsToChars(s
, setKey
, resLen
+ 1);
476 // printf("\n PluralRule: %s\n", setKey);
479 UResourceBundle
*ruleRes
=ures_getByKey(rb
, "rules", NULL
, &errCode
);
480 if(U_FAILURE(errCode
)) {
486 UResourceBundle
*setRes
= ures_getByKey(ruleRes
, setKey
, NULL
, &errCode
);
487 if (U_FAILURE(errCode
)) {
494 int32_t numberKeys
= ures_getSize(setRes
);
497 for(int32_t i
=0; i
<numberKeys
; ++i
) {
500 s
=ures_getNextString(setRes
, &resLen
, (const char**)&key
, &errCode
);
501 keyLen
= (int32_t)uprv_strlen(key
);
502 u_charsToUChars(key
, result
+len
, keyLen
);
505 uprv_memcpy(result
+len
, s
, resLen
*sizeof(UChar
));
507 result
[len
++]=SEMI_COLON
;
510 u_UCharsToChars(result
, setKey
, len
);
511 // printf(" Rule: %s\n", setKey);
517 return UnicodeString(result
);
521 AndConstraint::AndConstraint() {
522 op
= AndConstraint::NONE
;
532 AndConstraint::AndConstraint(const AndConstraint
& other
) {
534 this->opNum
=other
.opNum
;
535 this->rangeLow
=other
.rangeLow
;
536 this->rangeHigh
=other
.rangeHigh
;
537 this->integerOnly
=other
.integerOnly
;
538 this->notIn
=other
.notIn
;
539 if (other
.next
==NULL
) {
543 this->next
= new AndConstraint(*other
.next
);
547 AndConstraint::~AndConstraint() {
555 AndConstraint::isFulfilled(double number
) {
560 value
= (int32_t)value
% opNum
;
562 if ( rangeHigh
== -1 ) {
563 if ( rangeLow
== -1 ) {
564 result
= TRUE
; // empty rule
567 if ( value
== rangeLow
) {
576 if ((rangeLow
<= value
) && (value
<= rangeHigh
)) {
578 if ( value
!= (int32_t)value
) {
602 AndConstraint::updateRepeatLimit(int32_t maxLimit
) {
605 return uprv_max(opNum
, maxLimit
);
608 if ( rangeHigh
== -1 ) {
609 return uprv_max(rangeLow
, maxLimit
);
612 return uprv_max(rangeHigh
, maxLimit
);
621 this->next
= new AndConstraint();
625 OrConstraint::OrConstraint() {
630 OrConstraint::OrConstraint(const OrConstraint
& other
) {
631 if ( other
.childNode
== NULL
) {
632 this->childNode
= NULL
;
635 this->childNode
= new AndConstraint(*(other
.childNode
));
637 if (other
.next
== NULL
) {
641 this->next
= new OrConstraint(*(other
.next
));
645 OrConstraint::~OrConstraint() {
646 if (childNode
!=NULL
) {
657 OrConstraint
*curOrConstraint
=this;
659 while (curOrConstraint
->next
!=NULL
) {
660 curOrConstraint
= curOrConstraint
->next
;
662 curOrConstraint
->next
= NULL
;
663 curOrConstraint
->childNode
= new AndConstraint();
665 return curOrConstraint
->childNode
;
669 OrConstraint::isFulfilled(double number
) {
670 OrConstraint
* orRule
=this;
673 while (orRule
!=NULL
&& !result
) {
675 AndConstraint
* andRule
= orRule
->childNode
;
676 while (andRule
!=NULL
&& result
) {
677 result
= andRule
->isFulfilled(number
);
678 andRule
=andRule
->next
;
680 orRule
= orRule
->next
;
687 RuleChain::RuleChain() {
693 RuleChain::RuleChain(const RuleChain
& other
) {
694 this->repeatLimit
= other
.repeatLimit
;
695 this->keyword
=other
.keyword
;
696 if (other
.ruleHeader
!= NULL
) {
697 this->ruleHeader
= new OrConstraint(*(other
.ruleHeader
));
700 this->ruleHeader
= NULL
;
702 if (other
.next
!= NULL
) {
703 this->next
= new RuleChain(*other
.next
);
711 RuleChain::~RuleChain() {
715 if ( ruleHeader
!= NULL
) {
721 RuleChain::select(double number
) const {
723 if ( ruleHeader
!= NULL
) {
724 if (ruleHeader
->isFulfilled(number
)) {
728 if ( next
!= NULL
) {
729 return next
->select(number
);
732 return PLURAL_KEYWORD_OTHER
;
738 RuleChain::dumpRules(UnicodeString
& result
) {
739 UChar digitString
[16];
741 if ( ruleHeader
!= NULL
) {
743 OrConstraint
* orRule
=ruleHeader
;
744 while ( orRule
!= NULL
) {
745 AndConstraint
* andRule
=orRule
->childNode
;
746 while ( andRule
!= NULL
) {
747 if ( (andRule
->op
==AndConstraint::NONE
) && (andRule
->rangeHigh
==-1) ) {
748 result
+= UNICODE_STRING_SIMPLE(" n is ");
749 if (andRule
->notIn
) {
750 result
+= UNICODE_STRING_SIMPLE("not ");
752 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
753 result
+= UnicodeString(digitString
);
756 if (andRule
->op
==AndConstraint::MOD
) {
757 result
+= UNICODE_STRING_SIMPLE(" n mod ");
758 uprv_itou(digitString
,16, andRule
->opNum
,10,0);
759 result
+= UnicodeString(digitString
);
762 result
+= UNICODE_STRING_SIMPLE(" n ");
764 if (andRule
->rangeHigh
==-1) {
765 if (andRule
->notIn
) {
766 result
+= UNICODE_STRING_SIMPLE(" is not ");
767 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
768 result
+= UnicodeString(digitString
);
771 result
+= UNICODE_STRING_SIMPLE(" is ");
772 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
773 result
+= UnicodeString(digitString
);
777 if (andRule
->notIn
) {
778 if ( andRule
->integerOnly
) {
779 result
+= UNICODE_STRING_SIMPLE(" not in ");
782 result
+= UNICODE_STRING_SIMPLE(" not within ");
784 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
785 result
+= UnicodeString(digitString
);
786 result
+= UNICODE_STRING_SIMPLE(" .. ");
787 uprv_itou(digitString
,16, andRule
->rangeHigh
,10,0);
788 result
+= UnicodeString(digitString
);
791 if ( andRule
->integerOnly
) {
792 result
+= UNICODE_STRING_SIMPLE(" in ");
795 result
+= UNICODE_STRING_SIMPLE(" within ");
797 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
798 result
+= UnicodeString(digitString
);
799 result
+= UNICODE_STRING_SIMPLE(" .. ");
800 uprv_itou(digitString
,16, andRule
->rangeHigh
,10,0);
804 if ( (andRule
=andRule
->next
) != NULL
) {
808 if ( (orRule
= orRule
->next
) != NULL
) {
813 if ( next
!= NULL
) {
814 next
->dumpRules(result
);
819 RuleChain::getRepeatLimit () {
824 RuleChain::setRepeatLimit () {
827 if ( next
!= NULL
) {
828 next
->setRepeatLimit();
829 limit
= next
->repeatLimit
;
832 if ( ruleHeader
!= NULL
) {
833 OrConstraint
* orRule
=ruleHeader
;
834 while ( orRule
!= NULL
) {
835 AndConstraint
* andRule
=orRule
->childNode
;
836 while ( andRule
!= NULL
) {
837 limit
= andRule
->updateRepeatLimit(limit
);
838 andRule
= andRule
->next
;
840 orRule
= orRule
->next
;
847 RuleChain::getKeywords(int32_t capacityOfKeywords
, UnicodeString
* keywords
, int32_t& arraySize
) const {
848 if ( arraySize
< capacityOfKeywords
-1 ) {
849 keywords
[arraySize
++]=keyword
;
852 return U_BUFFER_OVERFLOW_ERROR
;
855 if ( next
!= NULL
) {
856 return next
->getKeywords(capacityOfKeywords
, keywords
, arraySize
);
864 RuleChain::isKeyword(const UnicodeString
& keywordParam
) const {
865 if ( keyword
== keywordParam
) {
869 if ( next
!= NULL
) {
870 return next
->isKeyword(keywordParam
);
878 RuleParser::RuleParser() {
879 UErrorCode err
=U_ZERO_ERROR
;
880 const UnicodeString idStart
=UNICODE_STRING_SIMPLE("[[a-z]]");
881 const UnicodeString idContinue
=UNICODE_STRING_SIMPLE("[[a-z][A-Z][_][0-9]]");
882 idStartFilter
= new UnicodeSet(idStart
, err
);
883 idContinueFilter
= new UnicodeSet(idContinue
, err
);
886 RuleParser::~RuleParser() {
887 delete idStartFilter
;
888 delete idContinueFilter
;
892 RuleParser::checkSyntax(tokenType prevType
, tokenType curType
, UErrorCode
&status
)
894 if (U_FAILURE(status
)) {
900 if (curType
!=tKeyword
) {
901 status
= U_UNEXPECTED_TOKEN
;
905 if (curType
!= tIs
&& curType
!= tMod
&& curType
!= tIn
&&
906 curType
!= tNot
&& curType
!= tWithin
) {
907 status
= U_UNEXPECTED_TOKEN
;
917 if (curType
!= tColon
) {
918 status
= U_UNEXPECTED_TOKEN
;
922 if (curType
!= tVariableN
) {
923 status
= U_UNEXPECTED_TOKEN
;
927 if ( curType
!= tNumber
&& curType
!= tNot
) {
928 status
= U_UNEXPECTED_TOKEN
;
932 if (curType
!= tNumber
&& curType
!= tIn
&& curType
!= tWithin
) {
933 status
= U_UNEXPECTED_TOKEN
;
942 if (curType
!= tNumber
&& curType
!= tVariableN
) {
943 status
= U_UNEXPECTED_TOKEN
;
947 if (curType
!= tDot
&& curType
!= tSemiColon
&& curType
!= tIs
&& curType
!= tNot
&&
948 curType
!= tIn
&& curType
!= tWithin
&& curType
!= tAnd
&& curType
!= tOr
)
950 status
= U_UNEXPECTED_TOKEN
;
954 status
= U_UNEXPECTED_TOKEN
;
960 RuleParser::getNextToken(const UnicodeString
& ruleData
,
962 UnicodeString
& token
,
966 int32_t curIndex
= *ruleIndex
;
968 tokenType prevType
=none
;
970 if (U_FAILURE(status
)) {
973 while (curIndex
<ruleData
.length()) {
974 ch
= ruleData
.charAt(curIndex
);
975 if ( !inRange(ch
, type
) ) {
976 status
= U_ILLEGAL_CHARACTER
;
981 if ( *ruleIndex
!= curIndex
) { // letter
982 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
985 getKeyType(token
, type
, status
);
989 *ruleIndex
=*ruleIndex
+1;
991 break; // consective space
994 if ( *ruleIndex
!= curIndex
) {
995 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
998 getKeyType(token
, type
, status
);
1002 *ruleIndex
=curIndex
+1;
1006 if ((type
==prevType
)||(prevType
==none
)) {
1012 if ((type
==prevType
)||(prevType
==none
)) {
1017 *ruleIndex
=curIndex
+1;
1021 if (prevType
==none
) { // first dot
1026 if ( *ruleIndex
!= curIndex
) {
1027 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
1028 *ruleIndex
=curIndex
; // letter
1030 getKeyType(token
, type
, status
);
1033 else { // two consective dots
1034 *ruleIndex
=curIndex
+2;
1040 status
= U_UNEXPECTED_TOKEN
;
1045 if ( curIndex
>=ruleData
.length() ) {
1046 if ( (type
== tLetter
)||(type
== tNumber
) ) {
1047 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
1048 getKeyType(token
, type
, status
);
1049 if (U_FAILURE(status
)) {
1053 *ruleIndex
= ruleData
.length();
1058 RuleParser::inRange(UChar ch
, tokenType
& type
) {
1059 if ((ch
>=CAP_A
) && (ch
<=CAP_Z
)) {
1060 // we assume all characters are in lower case already.
1063 if ((ch
>=LOW_A
) && (ch
<=LOW_Z
)) {
1067 if ((ch
>=U_ZERO
) && (ch
<=U_NINE
)) {
1092 RuleParser::getKeyType(const UnicodeString
& token
, tokenType
& keyType
, UErrorCode
&status
)
1094 if (U_FAILURE(status
)) {
1097 if ( keyType
==tNumber
) {
1099 else if (token
==PK_VAR_N
) {
1100 keyType
= tVariableN
;
1102 else if (token
==PK_IS
) {
1105 else if (token
==PK_AND
) {
1108 else if (token
==PK_IN
) {
1111 else if (token
==PK_WITHIN
) {
1114 else if (token
==PK_NOT
) {
1117 else if (token
==PK_MOD
) {
1120 else if (token
==PK_OR
) {
1123 else if ( isValidKeyword(token
) ) {
1127 status
= U_UNEXPECTED_TOKEN
;
1132 RuleParser::isValidKeyword(const UnicodeString
& token
) {
1133 if ( token
.length()==0 ) {
1136 if ( idStartFilter
->contains(token
.charAt(0) )==TRUE
) {
1138 for (i
=1; i
< token
.length(); i
++) {
1139 if (idContinueFilter
->contains(token
.charAt(i
))== FALSE
) {
1150 PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain
*header
, UErrorCode
& status
) :
1151 fKeywordNames(status
)
1153 RuleChain
*node
=header
;
1154 UBool addKeywordOther
=true;
1156 if (U_FAILURE(status
)) {
1160 fKeywordNames
.removeAllElements();
1162 fKeywordNames
.addElement(new UnicodeString(node
->keyword
), status
);
1163 if (U_FAILURE(status
)) {
1166 if (node
->keyword
== PLURAL_KEYWORD_OTHER
) {
1167 addKeywordOther
= false;
1172 if (addKeywordOther
) {
1173 fKeywordNames
.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER
), status
);
1174 if (U_FAILURE(status
)) {
1180 const UnicodeString
*
1181 PluralKeywordEnumeration::snext(UErrorCode
& status
) {
1182 if (U_SUCCESS(status
) && pos
< fKeywordNames
.size()) {
1183 return (const UnicodeString
*)fKeywordNames
.elementAt(pos
++);
1189 PluralKeywordEnumeration::reset(UErrorCode
& /*status*/) {
1194 PluralKeywordEnumeration::count(UErrorCode
& /*status*/) const {
1195 return fKeywordNames
.size();
1198 PluralKeywordEnumeration::~PluralKeywordEnumeration() {
1200 for (int32_t i
=0; i
<fKeywordNames
.size(); ++i
) {
1201 if ((s
=(UnicodeString
*)fKeywordNames
.elementAt(i
))!=NULL
) {
1210 #endif /* #if !UCONFIG_NO_FORMATTING */