1 /*
2 *******************************************************************************
3 * Copyright (C) 2007-2010, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 *
7 * File PLURRULE.CPP
8 *
9 * Modification History:
10 *
11 * Date Name Description
12 *******************************************************************************
13 */
14
15
16 #include "unicode/uniset.h"
17 #include "unicode/utypes.h"
18 #include "unicode/ures.h"
19 #include "unicode/plurrule.h"
20 #include "cmemory.h"
21 #include "cstring.h"
22 #include "hash.h"
23 #include "mutex.h"
24 #include "plurrule_impl.h"
25 #include "putilimp.h"
26 #include "ucln_in.h"
27 #include "ustrfmt.h"
28 #include "locutil.h"
29
30 /*
31 // TODO(claireho): remove stdio
32 #include "stdio.h"
33 */
34
35 #if !UCONFIG_NO_FORMATTING
36
37 U_NAMESPACE_BEGIN
38
39
40 #define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
41
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};
57
58 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)59 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
60
61 PluralRules::PluralRules(UErrorCode& status)
62 : UObject(),
63 mRules(NULL)
64 {
65 if (U_FAILURE(status)) {
66 return;
67 }
68 mParser = new RuleParser();
69 if (mParser==NULL) {
70 status = U_MEMORY_ALLOCATION_ERROR;
71 }
72 }
73
PluralRules(const PluralRules & other)74 PluralRules::PluralRules(const PluralRules& other)
75 : UObject(other),
76 mRules(NULL),
77 mParser(new RuleParser())
78 {
79 *this=other;
80 }
81
~PluralRules()82 PluralRules::~PluralRules() {
83 delete mRules;
84 delete mParser;
85 }
86
87 PluralRules*
clone() const88 PluralRules::clone() const {
89 return new PluralRules(*this);
90 }
91
92 PluralRules&
operator =(const PluralRules & other)93 PluralRules::operator=(const PluralRules& other) {
94 if (this != &other) {
95 delete mRules;
96 if (other.mRules==NULL) {
97 mRules = NULL;
98 }
99 else {
100 mRules = new RuleChain(*other.mRules);
101 }
102 delete mParser;
103 mParser = new RuleParser();
104 }
105
106 return *this;
107 }
108
109 PluralRules* U_EXPORT2
createRules(const UnicodeString & description,UErrorCode & status)110 PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
111 RuleChain rules;
112
113 if (U_FAILURE(status)) {
114 return NULL;
115 }
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);
121 }
122 }
123 if (U_FAILURE(status)) {
124 delete newRules;
125 return NULL;
126 }
127 else {
128 return newRules;
129 }
130 }
131
132 PluralRules* U_EXPORT2
createDefaultRules(UErrorCode & status)133 PluralRules::createDefaultRules(UErrorCode& status) {
134 return createRules(PLURAL_DEFAULT_RULE, status);
135 }
136
137 PluralRules* U_EXPORT2
forLocale(const Locale & locale,UErrorCode & status)138 PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
139 RuleChain rChain;
140 if (U_FAILURE(status)) {
141 return NULL;
142 }
143 PluralRules *newObj = new PluralRules(status);
144 if (newObj==NULL || U_FAILURE(status)) {
145 return NULL;
146 }
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);
152 }
153 }
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);
160 }
161
162 return newObj;
163 }
164
165 UnicodeString
select(int32_t number) const166 PluralRules::select(int32_t number) const {
167 if (mRules == NULL) {
168 return PLURAL_DEFAULT_RULE;
169 }
170 else {
171 return mRules->select(number);
172 }
173 }
174
175 UnicodeString
select(double number) const176 PluralRules::select(double number) const {
177 if (mRules == NULL) {
178 return PLURAL_DEFAULT_RULE;
179 }
180 else {
181 return mRules->select(number);
182 }
183 }
184
185 StringEnumeration*
getKeywords(UErrorCode & status) const186 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;
190
191 return nameEnumerator;
192 }
193
194
195 UBool
isKeyword(const UnicodeString & keyword) const196 PluralRules::isKeyword(const UnicodeString& keyword) const {
197 if ( keyword == PLURAL_KEYWORD_OTHER ) {
198 return true;
199 }
200 else {
201 if (mRules==NULL) {
202 return false;
203 }
204 else {
205 return mRules->isKeyword(keyword);
206 }
207 }
208 }
209
210 UnicodeString
getKeywordOther() const211 PluralRules::getKeywordOther() const {
212 return PLURAL_KEYWORD_OTHER;
213 }
214
215 UBool
operator ==(const PluralRules & other) const216 PluralRules::operator==(const PluralRules& other) const {
217 int32_t limit;
218 UBool sameList = TRUE;
219 const UnicodeString *ptrKeyword;
220 UErrorCode status= U_ZERO_ERROR;
221
222 if ( this == &other ) {
223 return TRUE;
224 }
225 StringEnumeration* myKeywordList = getKeywords(status);
226 if (U_FAILURE(status)) {
227 return FALSE;
228 }
229 StringEnumeration* otherKeywordList =other.getKeywords(status);
230 if (U_FAILURE(status)) {
231 return FALSE;
232 }
233
234 if (myKeywordList->count(status)!=otherKeywordList->count(status) ||
235 U_FAILURE(status)) {
236 sameList = FALSE;
237 }
238 else {
239 myKeywordList->reset(status);
240 if (U_FAILURE(status)) {
241 return FALSE;
242 }
243 while (sameList && (ptrKeyword=myKeywordList->snext(status))!=NULL) {
244 if (U_FAILURE(status) || !other.isKeyword(*ptrKeyword)) {
245 sameList = FALSE;
246 }
247 }
248 otherKeywordList->reset(status);
249 if (U_FAILURE(status)) {
250 return FALSE;
251 }
252 while (sameList && (ptrKeyword=otherKeywordList->snext(status))!=NULL) {
253 if (U_FAILURE(status)) {
254 return FALSE;
255 }
256 if (!this->isKeyword(*ptrKeyword)) {
257 sameList = FALSE;
258 }
259 }
260 delete myKeywordList;
261 delete otherKeywordList;
262 if (!sameList) {
263 return FALSE;
264 }
265 }
266
267 if ((limit=this->getRepeatLimit()) != other.getRepeatLimit()) {
268 return FALSE;
269 }
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) {
275 return FALSE;
276 }
277 }
278 return TRUE;
279 }
280
281 void
parseDescription(UnicodeString & data,RuleChain & rules,UErrorCode & status)282 PluralRules::parseDescription(UnicodeString& data, RuleChain& rules, UErrorCode &status)
283 {
284 int32_t ruleIndex=0;
285 UnicodeString token;
286 tokenType type;
287 tokenType prevType=none;
288 RuleChain *ruleChain=NULL;
289 AndConstraint *curAndConstraint=NULL;
290 OrConstraint *orNode=NULL;
291 RuleChain *lastChain=NULL;
292
293 if (U_FAILURE(status)) {
294 return;
295 }
296 UnicodeString ruleData = data.toLower();
297 while (ruleIndex< ruleData.length()) {
298 mParser->getNextToken(ruleData, &ruleIndex, token, type, status);
299 if (U_FAILURE(status)) {
300 return;
301 }
302 mParser->checkSyntax(prevType, type, status);
303 if (U_FAILURE(status)) {
304 return;
305 }
306 switch (type) {
307 case tAnd:
308 curAndConstraint = curAndConstraint->add();
309 break;
310 case tOr:
311 lastChain = &rules;
312 while (lastChain->next !=NULL) {
313 lastChain = lastChain->next;
314 }
315 orNode=lastChain->ruleHeader;
316 while (orNode->next != NULL) {
317 orNode = orNode->next;
318 }
319 orNode->next= new OrConstraint();
320 orNode=orNode->next;
321 orNode->next=NULL;
322 curAndConstraint = orNode->add();
323 break;
324 case tIs:
325 curAndConstraint->rangeHigh=-1;
326 break;
327 case tNot:
328 curAndConstraint->notIn=TRUE;
329 break;
330 case tIn:
331 curAndConstraint->rangeHigh=PLURAL_RANGE_HIGH;
332 curAndConstraint->integerOnly = TRUE;
333 break;
334 case tWithin:
335 curAndConstraint->rangeHigh=PLURAL_RANGE_HIGH;
336 break;
337 case tNumber:
338 if ( (curAndConstraint->op==AndConstraint::MOD)&&
339 (curAndConstraint->opNum == -1 ) ) {
340 curAndConstraint->opNum=getNumberValue(token);
341 }
342 else {
343 if (curAndConstraint->rangeLow == -1) {
344 curAndConstraint->rangeLow=getNumberValue(token);
345 }
346 else {
347 curAndConstraint->rangeHigh=getNumberValue(token);
348 }
349 }
350 break;
351 case tMod:
352 curAndConstraint->op=AndConstraint::MOD;
353 break;
354 case tKeyword:
355 if (ruleChain==NULL) {
356 ruleChain = &rules;
357 }
358 else {
359 while (ruleChain->next!=NULL){
360 ruleChain=ruleChain->next;
361 }
362 ruleChain=ruleChain->next=new RuleChain();
363 }
364 orNode = ruleChain->ruleHeader = new OrConstraint();
365 curAndConstraint = orNode->add();
366 ruleChain->keyword = token;
367 break;
368 default:
369 break;
370 }
371 prevType=type;
372 }
373 }
374
375 int32_t
getNumberValue(const UnicodeString & token) const376 PluralRules::getNumberValue(const UnicodeString& token) const {
377 int32_t i;
378 char digits[128];
379
380 i = token.extract(0, token.length(), digits, ARRAY_SIZE(digits), US_INV);
381 digits[i]='\0';
382
383 return((int32_t)atoi(digits));
384 }
385
386
387 void
getNextLocale(const UnicodeString & localeData,int32_t * curIndex,UnicodeString & localeName)388 PluralRules::getNextLocale(const UnicodeString& localeData, int32_t* curIndex, UnicodeString& localeName) {
389 int32_t i=*curIndex;
390
391 localeName.remove();
392 while (i< localeData.length()) {
393 if ( (localeData.charAt(i)!= SPACE) && (localeData.charAt(i)!= COMMA) ) {
394 break;
395 }
396 i++;
397 }
398
399 while (i< localeData.length()) {
400 if ( (localeData.charAt(i)== SPACE) || (localeData.charAt(i)== COMMA) ) {
401 break;
402 }
403 localeName+=localeData.charAt(i++);
404 }
405 *curIndex=i;
406 }
407
408
409 int32_t
getRepeatLimit() const410 PluralRules::getRepeatLimit() const {
411 if (mRules!=NULL) {
412 return mRules->getRepeatLimit();
413 }
414 else {
415 return 0;
416 }
417 }
418
419
420 void
addRules(RuleChain & rules)421 PluralRules::addRules(RuleChain& rules) {
422 RuleChain *newRule = new RuleChain(rules);
423 this->mRules=newRule;
424 newRule->setRepeatLimit();
425 }
426
427 UnicodeString
getRuleFromResource(const Locale & locale,UErrorCode & errCode)428 PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
429 UnicodeString emptyStr;
430
431 if (U_FAILURE(errCode)) {
432 return emptyStr;
433 }
434 UResourceBundle *rb=ures_openDirect(NULL, "plurals", &errCode);
435 if(U_FAILURE(errCode)) {
436 /* total failure, not even root could be opened */
437 return emptyStr;
438 }
439 UResourceBundle *locRes=ures_getByKey(rb, "locales", NULL, &errCode);
440 if(U_FAILURE(errCode)) {
441 ures_close(rb);
442 return emptyStr;
443 }
444 int32_t resLen=0;
445 const char *curLocaleName=locale.getName();
446 const UChar* s = ures_getStringByKey(locRes, curLocaleName, &resLen, &errCode);
447
448 if (s == NULL) {
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);
455
456 while ((localeNameLen=uloc_getParent(parentLocaleName, parentLocaleName,
457 ULOC_FULLNAME_CAPACITY, &status)) > 0) {
458 resLen=0;
459 s = ures_getStringByKey(locRes, parentLocaleName, &resLen, &status);
460 if (s != NULL) {
461 errCode = U_ZERO_ERROR;
462 break;
463 }
464 status = U_ZERO_ERROR;
465 }
466 }
467 if (s==NULL) {
468 ures_close(locRes);
469 ures_close(rb);
470 return emptyStr;
471 }
472
473 char setKey[256];
474 UChar result[256];
475 u_UCharsToChars(s, setKey, resLen + 1);
476 // printf("\n PluralRule: %s\n", setKey);
477
478
479 UResourceBundle *ruleRes=ures_getByKey(rb, "rules", NULL, &errCode);
480 if(U_FAILURE(errCode)) {
481 ures_close(locRes);
482 ures_close(rb);
483 return emptyStr;
484 }
485 resLen=0;
486 UResourceBundle *setRes = ures_getByKey(ruleRes, setKey, NULL, &errCode);
487 if (U_FAILURE(errCode)) {
488 ures_close(ruleRes);
489 ures_close(locRes);
490 ures_close(rb);
491 return emptyStr;
492 }
493
494 int32_t numberKeys = ures_getSize(setRes);
495 char *key=NULL;
496 int32_t len=0;
497 for(int32_t i=0; i<numberKeys; ++i) {
498 int32_t keyLen;
499 resLen=0;
500 s=ures_getNextString(setRes, &resLen, (const char**)&key, &errCode);
501 keyLen = (int32_t)uprv_strlen(key);
502 u_charsToUChars(key, result+len, keyLen);
503 len += keyLen;
504 result[len++]=COLON;
505 uprv_memcpy(result+len, s, resLen*sizeof(UChar));
506 len += resLen;
507 result[len++]=SEMI_COLON;
508 }
509 result[len++]=0;
510 u_UCharsToChars(result, setKey, len);
511 // printf(" Rule: %s\n", setKey);
512
513 ures_close(setRes);
514 ures_close(ruleRes);
515 ures_close(locRes);
516 ures_close(rb);
517 return UnicodeString(result);
518
519 }
520
AndConstraint()521 AndConstraint::AndConstraint() {
522 op = AndConstraint::NONE;
523 opNum=-1;
524 rangeLow=-1;
525 rangeHigh=-1;
526 notIn=FALSE;
527 integerOnly=FALSE;
528 next=NULL;
529 }
530
531
AndConstraint(const AndConstraint & other)532 AndConstraint::AndConstraint(const AndConstraint& other) {
533 this->op = other.op;
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) {
540 this->next=NULL;
541 }
542 else {
543 this->next = new AndConstraint(*other.next);
544 }
545 }
546
~AndConstraint()547 AndConstraint::~AndConstraint() {
548 if (next!=NULL) {
549 delete next;
550 }
551 }
552
553
554 UBool
isFulfilled(double number)555 AndConstraint::isFulfilled(double number) {
556 UBool result=TRUE;
557 double value=number;
558
559 if ( op == MOD ) {
560 value = (int32_t)value % opNum;
561 }
562 if ( rangeHigh == -1 ) {
563 if ( rangeLow == -1 ) {
564 result = TRUE; // empty rule
565 }
566 else {
567 if ( value == rangeLow ) {
568 result = TRUE;
569 }
570 else {
571 result = FALSE;
572 }
573 }
574 }
575 else {
576 if ((rangeLow <= value) && (value <= rangeHigh)) {
577 if (integerOnly) {
578 if ( value != (int32_t)value) {
579 result = FALSE;
580 }
581 else {
582 result = TRUE;
583 }
584 }
585 else {
586 result = TRUE;
587 }
588 }
589 else {
590 result = FALSE;
591 }
592 }
593 if (notIn) {
594 return !result;
595 }
596 else {
597 return result;
598 }
599 }
600
601 int32_t
updateRepeatLimit(int32_t maxLimit)602 AndConstraint::updateRepeatLimit(int32_t maxLimit) {
603
604 if ( op == MOD ) {
605 return uprv_max(opNum, maxLimit);
606 }
607 else {
608 if ( rangeHigh == -1 ) {
609 return uprv_max(rangeLow, maxLimit);
610 }
611 else{
612 return uprv_max(rangeHigh, maxLimit);
613 }
614 }
615 }
616
617
618 AndConstraint*
add()619 AndConstraint::add()
620 {
621 this->next = new AndConstraint();
622 return this->next;
623 }
624
OrConstraint()625 OrConstraint::OrConstraint() {
626 childNode=NULL;
627 next=NULL;
628 }
629
OrConstraint(const OrConstraint & other)630 OrConstraint::OrConstraint(const OrConstraint& other) {
631 if ( other.childNode == NULL ) {
632 this->childNode = NULL;
633 }
634 else {
635 this->childNode = new AndConstraint(*(other.childNode));
636 }
637 if (other.next == NULL ) {
638 this->next = NULL;
639 }
640 else {
641 this->next = new OrConstraint(*(other.next));
642 }
643 }
644
~OrConstraint()645 OrConstraint::~OrConstraint() {
646 if (childNode!=NULL) {
647 delete childNode;
648 }
649 if (next!=NULL) {
650 delete next;
651 }
652 }
653
654 AndConstraint*
add()655 OrConstraint::add()
656 {
657 OrConstraint *curOrConstraint=this;
658 {
659 while (curOrConstraint->next!=NULL) {
660 curOrConstraint = curOrConstraint->next;
661 }
662 curOrConstraint->next = NULL;
663 curOrConstraint->childNode = new AndConstraint();
664 }
665 return curOrConstraint->childNode;
666 }
667
668 UBool
isFulfilled(double number)669 OrConstraint::isFulfilled(double number) {
670 OrConstraint* orRule=this;
671 UBool result=FALSE;
672
673 while (orRule!=NULL && !result) {
674 result=TRUE;
675 AndConstraint* andRule = orRule->childNode;
676 while (andRule!=NULL && result) {
677 result = andRule->isFulfilled(number);
678 andRule=andRule->next;
679 }
680 orRule = orRule->next;
681 }
682
683 return result;
684 }
685
686
RuleChain()687 RuleChain::RuleChain() {
688 ruleHeader=NULL;
689 next = NULL;
690 repeatLimit=0;
691 }
692
RuleChain(const RuleChain & other)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));
698 }
699 else {
700 this->ruleHeader = NULL;
701 }
702 if (other.next != NULL ) {
703 this->next = new RuleChain(*other.next);
704 }
705 else
706 {
707 this->next = NULL;
708 }
709 }
710
~RuleChain()711 RuleChain::~RuleChain() {
712 if (next != NULL) {
713 delete next;
714 }
715 if ( ruleHeader != NULL ) {
716 delete ruleHeader;
717 }
718 }
719
720 UnicodeString
select(double number) const721 RuleChain::select(double number) const {
722
723 if ( ruleHeader != NULL ) {
724 if (ruleHeader->isFulfilled(number)) {
725 return keyword;
726 }
727 }
728 if ( next != NULL ) {
729 return next->select(number);
730 }
731 else {
732 return PLURAL_KEYWORD_OTHER;
733 }
734
735 }
736
737 void
dumpRules(UnicodeString & result)738 RuleChain::dumpRules(UnicodeString& result) {
739 UChar digitString[16];
740
741 if ( ruleHeader != NULL ) {
742 result += keyword;
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 ");
751 }
752 uprv_itou(digitString,16, andRule->rangeLow,10,0);
753 result += UnicodeString(digitString);
754 }
755 else {
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);
760 }
761 else {
762 result += UNICODE_STRING_SIMPLE(" n ");
763 }
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);
769 }
770 else {
771 result += UNICODE_STRING_SIMPLE(" is ");
772 uprv_itou(digitString,16, andRule->rangeLow,10,0);
773 result += UnicodeString(digitString);
774 }
775 }
776 else {
777 if (andRule->notIn) {
778 if ( andRule->integerOnly ) {
779 result += UNICODE_STRING_SIMPLE(" not in ");
780 }
781 else {
782 result += UNICODE_STRING_SIMPLE(" not within ");
783 }
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);
789 }
790 else {
791 if ( andRule->integerOnly ) {
792 result += UNICODE_STRING_SIMPLE(" in ");
793 }
794 else {
795 result += UNICODE_STRING_SIMPLE(" within ");
796 }
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);
801 }
802 }
803 }
804 if ( (andRule=andRule->next) != NULL) {
805 result += PK_AND;
806 }
807 }
808 if ( (orRule = orRule->next) != NULL ) {
809 result += PK_OR;
810 }
811 }
812 }
813 if ( next != NULL ) {
814 next->dumpRules(result);
815 }
816 }
817
818 int32_t
getRepeatLimit()819 RuleChain::getRepeatLimit () {
820 return repeatLimit;
821 }
822
823 void
setRepeatLimit()824 RuleChain::setRepeatLimit () {
825 int32_t limit=0;
826
827 if ( next != NULL ) {
828 next->setRepeatLimit();
829 limit = next->repeatLimit;
830 }
831
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;
839 }
840 orRule = orRule->next;
841 }
842 }
843 repeatLimit = limit;
844 }
845
846 UErrorCode
getKeywords(int32_t capacityOfKeywords,UnicodeString * keywords,int32_t & arraySize) const847 RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
848 if ( arraySize < capacityOfKeywords-1 ) {
849 keywords[arraySize++]=keyword;
850 }
851 else {
852 return U_BUFFER_OVERFLOW_ERROR;
853 }
854
855 if ( next != NULL ) {
856 return next->getKeywords(capacityOfKeywords, keywords, arraySize);
857 }
858 else {
859 return U_ZERO_ERROR;
860 }
861 }
862
863 UBool
isKeyword(const UnicodeString & keywordParam) const864 RuleChain::isKeyword(const UnicodeString& keywordParam) const {
865 if ( keyword == keywordParam ) {
866 return TRUE;
867 }
868
869 if ( next != NULL ) {
870 return next->isKeyword(keywordParam);
871 }
872 else {
873 return FALSE;
874 }
875 }
876
877
RuleParser()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);
884 }
885
~RuleParser()886 RuleParser::~RuleParser() {
887 delete idStartFilter;
888 delete idContinueFilter;
889 }
890
891 void
checkSyntax(tokenType prevType,tokenType curType,UErrorCode & status)892 RuleParser::checkSyntax(tokenType prevType, tokenType curType, UErrorCode &status)
893 {
894 if (U_FAILURE(status)) {
895 return;
896 }
897 switch(prevType) {
898 case none:
899 case tSemiColon:
900 if (curType!=tKeyword) {
901 status = U_UNEXPECTED_TOKEN;
902 }
903 break;
904 case tVariableN :
905 if (curType != tIs && curType != tMod && curType != tIn &&
906 curType != tNot && curType != tWithin) {
907 status = U_UNEXPECTED_TOKEN;
908 }
909 break;
910 case tZero:
911 case tOne:
912 case tTwo:
913 case tFew:
914 case tMany:
915 case tOther:
916 case tKeyword:
917 if (curType != tColon) {
918 status = U_UNEXPECTED_TOKEN;
919 }
920 break;
921 case tColon :
922 if (curType != tVariableN) {
923 status = U_UNEXPECTED_TOKEN;
924 }
925 break;
926 case tIs:
927 if ( curType != tNumber && curType != tNot) {
928 status = U_UNEXPECTED_TOKEN;
929 }
930 break;
931 case tNot:
932 if (curType != tNumber && curType != tIn && curType != tWithin) {
933 status = U_UNEXPECTED_TOKEN;
934 }
935 break;
936 case tMod:
937 case tDot:
938 case tIn:
939 case tWithin:
940 case tAnd:
941 case tOr:
942 if (curType != tNumber && curType != tVariableN) {
943 status = U_UNEXPECTED_TOKEN;
944 }
945 break;
946 case tNumber:
947 if (curType != tDot && curType != tSemiColon && curType != tIs && curType != tNot &&
948 curType != tIn && curType != tWithin && curType != tAnd && curType != tOr)
949 {
950 status = U_UNEXPECTED_TOKEN;
951 }
952 break;
953 default:
954 status = U_UNEXPECTED_TOKEN;
955 break;
956 }
957 }
958
959 void
getNextToken(const UnicodeString & ruleData,int32_t * ruleIndex,UnicodeString & token,tokenType & type,UErrorCode & status)960 RuleParser::getNextToken(const UnicodeString& ruleData,
961 int32_t *ruleIndex,
962 UnicodeString& token,
963 tokenType& type,
964 UErrorCode &status)
965 {
966 int32_t curIndex= *ruleIndex;
967 UChar ch;
968 tokenType prevType=none;
969
970 if (U_FAILURE(status)) {
971 return;
972 }
973 while (curIndex<ruleData.length()) {
974 ch = ruleData.charAt(curIndex);
975 if ( !inRange(ch, type) ) {
976 status = U_ILLEGAL_CHARACTER;
977 return;
978 }
979 switch (type) {
980 case tSpace:
981 if ( *ruleIndex != curIndex ) { // letter
982 token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
983 *ruleIndex=curIndex;
984 type=prevType;
985 getKeyType(token, type, status);
986 return;
987 }
988 else {
989 *ruleIndex=*ruleIndex+1;
990 }
991 break; // consective space
992 case tColon:
993 case tSemiColon:
994 if ( *ruleIndex != curIndex ) {
995 token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
996 *ruleIndex=curIndex;
997 type=prevType;
998 getKeyType(token, type, status);
999 return;
1000 }
1001 else {
1002 *ruleIndex=curIndex+1;
1003 return;
1004 }
1005 case tLetter:
1006 if ((type==prevType)||(prevType==none)) {
1007 prevType=type;
1008 break;
1009 }
1010 break;
1011 case tNumber:
1012 if ((type==prevType)||(prevType==none)) {
1013 prevType=type;
1014 break;
1015 }
1016 else {
1017 *ruleIndex=curIndex+1;
1018 return;
1019 }
1020 case tDot:
1021 if (prevType==none) { // first dot
1022 prevType=type;
1023 continue;
1024 }
1025 else {
1026 if ( *ruleIndex != curIndex ) {
1027 token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
1028 *ruleIndex=curIndex; // letter
1029 type=prevType;
1030 getKeyType(token, type, status);
1031 return;
1032 }
1033 else { // two consective dots
1034 *ruleIndex=curIndex+2;
1035 return;
1036 }
1037 }
1038 break;
1039 default:
1040 status = U_UNEXPECTED_TOKEN;
1041 return;
1042 }
1043 curIndex++;
1044 }
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)) {
1050 return;
1051 }
1052 }
1053 *ruleIndex = ruleData.length();
1054 }
1055 }
1056
1057 UBool
inRange(UChar ch,tokenType & type)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.
1061 return FALSE;
1062 }
1063 if ((ch>=LOW_A) && (ch<=LOW_Z)) {
1064 type = tLetter;
1065 return TRUE;
1066 }
1067 if ((ch>=U_ZERO) && (ch<=U_NINE)) {
1068 type = tNumber;
1069 return TRUE;
1070 }
1071 switch (ch) {
1072 case COLON:
1073 type = tColon;
1074 return TRUE;
1075 case SPACE:
1076 type = tSpace;
1077 return TRUE;
1078 case SEMI_COLON:
1079 type = tSemiColon;
1080 return TRUE;
1081 case DOT:
1082 type = tDot;
1083 return TRUE;
1084 default :
1085 type = none;
1086 return FALSE;
1087 }
1088 }
1089
1090
1091 void
getKeyType(const UnicodeString & token,tokenType & keyType,UErrorCode & status)1092 RuleParser::getKeyType(const UnicodeString& token, tokenType& keyType, UErrorCode &status)
1093 {
1094 if (U_FAILURE(status)) {
1095 return;
1096 }
1097 if ( keyType==tNumber) {
1098 }
1099 else if (token==PK_VAR_N) {
1100 keyType = tVariableN;
1101 }
1102 else if (token==PK_IS) {
1103 keyType = tIs;
1104 }
1105 else if (token==PK_AND) {
1106 keyType = tAnd;
1107 }
1108 else if (token==PK_IN) {
1109 keyType = tIn;
1110 }
1111 else if (token==PK_WITHIN) {
1112 keyType = tWithin;
1113 }
1114 else if (token==PK_NOT) {
1115 keyType = tNot;
1116 }
1117 else if (token==PK_MOD) {
1118 keyType = tMod;
1119 }
1120 else if (token==PK_OR) {
1121 keyType = tOr;
1122 }
1123 else if ( isValidKeyword(token) ) {
1124 keyType = tKeyword;
1125 }
1126 else {
1127 status = U_UNEXPECTED_TOKEN;
1128 }
1129 }
1130
1131 UBool
isValidKeyword(const UnicodeString & token)1132 RuleParser::isValidKeyword(const UnicodeString& token) {
1133 if ( token.length()==0 ) {
1134 return FALSE;
1135 }
1136 if ( idStartFilter->contains(token.charAt(0) )==TRUE ) {
1137 int32_t i;
1138 for (i=1; i< token.length(); i++) {
1139 if (idContinueFilter->contains(token.charAt(i))== FALSE) {
1140 return FALSE;
1141 }
1142 }
1143 return TRUE;
1144 }
1145 else {
1146 return FALSE;
1147 }
1148 }
1149
PluralKeywordEnumeration(RuleChain * header,UErrorCode & status)1150 PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode& status) :
1151 fKeywordNames(status)
1152 {
1153 RuleChain *node=header;
1154 UBool addKeywordOther=true;
1155
1156 if (U_FAILURE(status)) {
1157 return;
1158 }
1159 pos=0;
1160 fKeywordNames.removeAllElements();
1161 while(node!=NULL) {
1162 fKeywordNames.addElement(new UnicodeString(node->keyword), status);
1163 if (U_FAILURE(status)) {
1164 return;
1165 }
1166 if (node->keyword == PLURAL_KEYWORD_OTHER) {
1167 addKeywordOther= false;
1168 }
1169 node=node->next;
1170 }
1171
1172 if (addKeywordOther) {
1173 fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status);
1174 if (U_FAILURE(status)) {
1175 return;
1176 }
1177 }
1178 }
1179
1180 const UnicodeString*
snext(UErrorCode & status)1181 PluralKeywordEnumeration::snext(UErrorCode& status) {
1182 if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
1183 return (const UnicodeString*)fKeywordNames.elementAt(pos++);
1184 }
1185 return NULL;
1186 }
1187
1188 void
reset(UErrorCode &)1189 PluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
1190 pos=0;
1191 }
1192
1193 int32_t
count(UErrorCode &) const1194 PluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
1195 return fKeywordNames.size();
1196 }
1197
~PluralKeywordEnumeration()1198 PluralKeywordEnumeration::~PluralKeywordEnumeration() {
1199 UnicodeString *s;
1200 for (int32_t i=0; i<fKeywordNames.size(); ++i) {
1201 if ((s=(UnicodeString *)fKeywordNames.elementAt(i))!=NULL) {
1202 delete s;
1203 }
1204 }
1205 }
1206
1207 U_NAMESPACE_END
1208
1209
1210 #endif /* #if !UCONFIG_NO_FORMATTING */
1211
1212 //eof
1213