Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2516)

Unified Diff: icu46/source/i18n/plurrule.cpp

Issue 5516007: Check in the pristine copy of ICU 4.6... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/third_party/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « icu46/source/i18n/plurfmt.cpp ('k') | icu46/source/i18n/plurrule_impl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: icu46/source/i18n/plurrule.cpp
===================================================================
--- icu46/source/i18n/plurrule.cpp (revision 0)
+++ icu46/source/i18n/plurrule.cpp (revision 0)
@@ -0,0 +1,1212 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007-2010, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File PLURRULE.CPP
+*
+* Modification History:
+*
+* Date Name Description
+*******************************************************************************
+*/
+
+
+#include "unicode/uniset.h"
+#include "unicode/utypes.h"
+#include "unicode/ures.h"
+#include "unicode/plurrule.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "hash.h"
+#include "mutex.h"
+#include "plurrule_impl.h"
+#include "putilimp.h"
+#include "ucln_in.h"
+#include "ustrfmt.h"
+#include "locutil.h"
+
+/*
+// TODO(claireho): remove stdio
+#include "stdio.h"
+*/
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+
+#define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
+
+static const UChar PLURAL_KEYWORD_ZERO[] = {LOW_Z,LOW_E,LOW_R,LOW_O, 0};
+static const UChar PLURAL_KEYWORD_ONE[]={LOW_O,LOW_N,LOW_E,0};
+static const UChar PLURAL_KEYWORD_TWO[]={LOW_T,LOW_W,LOW_O,0};
+static const UChar PLURAL_KEYWORD_FEW[]={LOW_F,LOW_E,LOW_W,0};
+static const UChar PLURAL_KEYWORD_MANY[]={LOW_M,LOW_A,LOW_N,LOW_Y,0};
+static const UChar PLURAL_KEYWORD_OTHER[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,0};
+static const UChar PLURAL_DEFAULT_RULE[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,COLON,SPACE,LOW_N,0};
+static const UChar PK_IN[]={LOW_I,LOW_N,0};
+static const UChar PK_NOT[]={LOW_N,LOW_O,LOW_T,0};
+static const UChar PK_IS[]={LOW_I,LOW_S,0};
+static const UChar PK_MOD[]={LOW_M,LOW_O,LOW_D,0};
+static const UChar PK_AND[]={LOW_A,LOW_N,LOW_D,0};
+static const UChar PK_OR[]={LOW_O,LOW_R,0};
+static const UChar PK_VAR_N[]={LOW_N,0};
+static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
+
+PluralRules::PluralRules(UErrorCode& status)
+: UObject(),
+ mRules(NULL)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ mParser = new RuleParser();
+ if (mParser==NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+PluralRules::PluralRules(const PluralRules& other)
+: UObject(other),
+ mRules(NULL),
+ mParser(new RuleParser())
+{
+ *this=other;
+}
+
+PluralRules::~PluralRules() {
+ delete mRules;
+ delete mParser;
+}
+
+PluralRules*
+PluralRules::clone() const {
+ return new PluralRules(*this);
+}
+
+PluralRules&
+PluralRules::operator=(const PluralRules& other) {
+ if (this != &other) {
+ delete mRules;
+ if (other.mRules==NULL) {
+ mRules = NULL;
+ }
+ else {
+ mRules = new RuleChain(*other.mRules);
+ }
+ delete mParser;
+ mParser = new RuleParser();
+ }
+
+ return *this;
+}
+
+PluralRules* U_EXPORT2
+PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
+ RuleChain rules;
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ PluralRules *newRules = new PluralRules(status);
+ if ( (newRules != NULL)&& U_SUCCESS(status) ) {
+ newRules->parseDescription((UnicodeString &)description, rules, status);
+ if (U_SUCCESS(status)) {
+ newRules->addRules(rules);
+ }
+ }
+ if (U_FAILURE(status)) {
+ delete newRules;
+ return NULL;
+ }
+ else {
+ return newRules;
+ }
+}
+
+PluralRules* U_EXPORT2
+PluralRules::createDefaultRules(UErrorCode& status) {
+ return createRules(PLURAL_DEFAULT_RULE, status);
+}
+
+PluralRules* U_EXPORT2
+PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
+ RuleChain rChain;
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ PluralRules *newObj = new PluralRules(status);
+ if (newObj==NULL || U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString locRule = newObj->getRuleFromResource(locale, status);
+ if ((locRule.length() != 0) && U_SUCCESS(status)) {
+ newObj->parseDescription(locRule, rChain, status);
+ if (U_SUCCESS(status)) {
+ newObj->addRules(rChain);
+ }
+ }
+ if (U_FAILURE(status)||(locRule.length() == 0)) {
+ // use default plural rule
+ status = U_ZERO_ERROR;
+ UnicodeString defRule = UnicodeString(PLURAL_DEFAULT_RULE);
+ newObj->parseDescription(defRule, rChain, status);
+ newObj->addRules(rChain);
+ }
+
+ return newObj;
+}
+
+UnicodeString
+PluralRules::select(int32_t number) const {
+ if (mRules == NULL) {
+ return PLURAL_DEFAULT_RULE;
+ }
+ else {
+ return mRules->select(number);
+ }
+}
+
+UnicodeString
+PluralRules::select(double number) const {
+ if (mRules == NULL) {
+ return PLURAL_DEFAULT_RULE;
+ }
+ else {
+ return mRules->select(number);
+ }
+}
+
+StringEnumeration*
+PluralRules::getKeywords(UErrorCode& status) const {
+ if (U_FAILURE(status)) return NULL;
+ StringEnumeration* nameEnumerator = new PluralKeywordEnumeration(mRules, status);
+ if (U_FAILURE(status)) return NULL;
+
+ return nameEnumerator;
+}
+
+
+UBool
+PluralRules::isKeyword(const UnicodeString& keyword) const {
+ if ( keyword == PLURAL_KEYWORD_OTHER ) {
+ return true;
+ }
+ else {
+ if (mRules==NULL) {
+ return false;
+ }
+ else {
+ return mRules->isKeyword(keyword);
+ }
+ }
+}
+
+UnicodeString
+PluralRules::getKeywordOther() const {
+ return PLURAL_KEYWORD_OTHER;
+}
+
+UBool
+PluralRules::operator==(const PluralRules& other) const {
+ int32_t limit;
+ UBool sameList = TRUE;
+ const UnicodeString *ptrKeyword;
+ UErrorCode status= U_ZERO_ERROR;
+
+ if ( this == &other ) {
+ return TRUE;
+ }
+ StringEnumeration* myKeywordList = getKeywords(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ StringEnumeration* otherKeywordList =other.getKeywords(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ if (myKeywordList->count(status)!=otherKeywordList->count(status) ||
+ U_FAILURE(status)) {
+ sameList = FALSE;
+ }
+ else {
+ myKeywordList->reset(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ while (sameList && (ptrKeyword=myKeywordList->snext(status))!=NULL) {
+ if (U_FAILURE(status) || !other.isKeyword(*ptrKeyword)) {
+ sameList = FALSE;
+ }
+ }
+ otherKeywordList->reset(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ while (sameList && (ptrKeyword=otherKeywordList->snext(status))!=NULL) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (!this->isKeyword(*ptrKeyword)) {
+ sameList = FALSE;
+ }
+ }
+ delete myKeywordList;
+ delete otherKeywordList;
+ if (!sameList) {
+ return FALSE;
+ }
+ }
+
+ if ((limit=this->getRepeatLimit()) != other.getRepeatLimit()) {
+ return FALSE;
+ }
+ UnicodeString myKeyword, otherKeyword;
+ for (int32_t i=0; i<limit; ++i) {
+ myKeyword = this->select(i);
+ otherKeyword = other.select(i);
+ if (myKeyword!=otherKeyword) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void
+PluralRules::parseDescription(UnicodeString& data, RuleChain& rules, UErrorCode &status)
+{
+ int32_t ruleIndex=0;
+ UnicodeString token;
+ tokenType type;
+ tokenType prevType=none;
+ RuleChain *ruleChain=NULL;
+ AndConstraint *curAndConstraint=NULL;
+ OrConstraint *orNode=NULL;
+ RuleChain *lastChain=NULL;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UnicodeString ruleData = data.toLower();
+ while (ruleIndex< ruleData.length()) {
+ mParser->getNextToken(ruleData, &ruleIndex, token, type, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ mParser->checkSyntax(prevType, type, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ switch (type) {
+ case tAnd:
+ curAndConstraint = curAndConstraint->add();
+ break;
+ case tOr:
+ lastChain = &rules;
+ while (lastChain->next !=NULL) {
+ lastChain = lastChain->next;
+ }
+ orNode=lastChain->ruleHeader;
+ while (orNode->next != NULL) {
+ orNode = orNode->next;
+ }
+ orNode->next= new OrConstraint();
+ orNode=orNode->next;
+ orNode->next=NULL;
+ curAndConstraint = orNode->add();
+ break;
+ case tIs:
+ curAndConstraint->rangeHigh=-1;
+ break;
+ case tNot:
+ curAndConstraint->notIn=TRUE;
+ break;
+ case tIn:
+ curAndConstraint->rangeHigh=PLURAL_RANGE_HIGH;
+ curAndConstraint->integerOnly = TRUE;
+ break;
+ case tWithin:
+ curAndConstraint->rangeHigh=PLURAL_RANGE_HIGH;
+ break;
+ case tNumber:
+ if ( (curAndConstraint->op==AndConstraint::MOD)&&
+ (curAndConstraint->opNum == -1 ) ) {
+ curAndConstraint->opNum=getNumberValue(token);
+ }
+ else {
+ if (curAndConstraint->rangeLow == -1) {
+ curAndConstraint->rangeLow=getNumberValue(token);
+ }
+ else {
+ curAndConstraint->rangeHigh=getNumberValue(token);
+ }
+ }
+ break;
+ case tMod:
+ curAndConstraint->op=AndConstraint::MOD;
+ break;
+ case tKeyword:
+ if (ruleChain==NULL) {
+ ruleChain = &rules;
+ }
+ else {
+ while (ruleChain->next!=NULL){
+ ruleChain=ruleChain->next;
+ }
+ ruleChain=ruleChain->next=new RuleChain();
+ }
+ orNode = ruleChain->ruleHeader = new OrConstraint();
+ curAndConstraint = orNode->add();
+ ruleChain->keyword = token;
+ break;
+ default:
+ break;
+ }
+ prevType=type;
+ }
+}
+
+int32_t
+PluralRules::getNumberValue(const UnicodeString& token) const {
+ int32_t i;
+ char digits[128];
+
+ i = token.extract(0, token.length(), digits, ARRAY_SIZE(digits), US_INV);
+ digits[i]='\0';
+
+ return((int32_t)atoi(digits));
+}
+
+
+void
+PluralRules::getNextLocale(const UnicodeString& localeData, int32_t* curIndex, UnicodeString& localeName) {
+ int32_t i=*curIndex;
+
+ localeName.remove();
+ while (i< localeData.length()) {
+ if ( (localeData.charAt(i)!= SPACE) && (localeData.charAt(i)!= COMMA) ) {
+ break;
+ }
+ i++;
+ }
+
+ while (i< localeData.length()) {
+ if ( (localeData.charAt(i)== SPACE) || (localeData.charAt(i)== COMMA) ) {
+ break;
+ }
+ localeName+=localeData.charAt(i++);
+ }
+ *curIndex=i;
+}
+
+
+int32_t
+PluralRules::getRepeatLimit() const {
+ if (mRules!=NULL) {
+ return mRules->getRepeatLimit();
+ }
+ else {
+ return 0;
+ }
+}
+
+
+void
+PluralRules::addRules(RuleChain& rules) {
+ RuleChain *newRule = new RuleChain(rules);
+ this->mRules=newRule;
+ newRule->setRepeatLimit();
+}
+
+UnicodeString
+PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
+ UnicodeString emptyStr;
+
+ if (U_FAILURE(errCode)) {
+ return emptyStr;
+ }
+ UResourceBundle *rb=ures_openDirect(NULL, "plurals", &errCode);
+ if(U_FAILURE(errCode)) {
+ /* total failure, not even root could be opened */
+ return emptyStr;
+ }
+ UResourceBundle *locRes=ures_getByKey(rb, "locales", NULL, &errCode);
+ if(U_FAILURE(errCode)) {
+ ures_close(rb);
+ return emptyStr;
+ }
+ int32_t resLen=0;
+ const char *curLocaleName=locale.getName();
+ const UChar* s = ures_getStringByKey(locRes, curLocaleName, &resLen, &errCode);
+
+ if (s == NULL) {
+ // Check parent locales.
+ UErrorCode status = U_ZERO_ERROR;
+ char parentLocaleName[ULOC_FULLNAME_CAPACITY];
+ const char *curLocaleName=locale.getName();
+ int32_t localeNameLen=0;
+ uprv_strcpy(parentLocaleName, curLocaleName);
+
+ while ((localeNameLen=uloc_getParent(parentLocaleName, parentLocaleName,
+ ULOC_FULLNAME_CAPACITY, &status)) > 0) {
+ resLen=0;
+ s = ures_getStringByKey(locRes, parentLocaleName, &resLen, &status);
+ if (s != NULL) {
+ errCode = U_ZERO_ERROR;
+ break;
+ }
+ status = U_ZERO_ERROR;
+ }
+ }
+ if (s==NULL) {
+ ures_close(locRes);
+ ures_close(rb);
+ return emptyStr;
+ }
+
+ char setKey[256];
+ UChar result[256];
+ u_UCharsToChars(s, setKey, resLen + 1);
+ // printf("\n PluralRule: %s\n", setKey);
+
+
+ UResourceBundle *ruleRes=ures_getByKey(rb, "rules", NULL, &errCode);
+ if(U_FAILURE(errCode)) {
+ ures_close(locRes);
+ ures_close(rb);
+ return emptyStr;
+ }
+ resLen=0;
+ UResourceBundle *setRes = ures_getByKey(ruleRes, setKey, NULL, &errCode);
+ if (U_FAILURE(errCode)) {
+ ures_close(ruleRes);
+ ures_close(locRes);
+ ures_close(rb);
+ return emptyStr;
+ }
+
+ int32_t numberKeys = ures_getSize(setRes);
+ char *key=NULL;
+ int32_t len=0;
+ for(int32_t i=0; i<numberKeys; ++i) {
+ int32_t keyLen;
+ resLen=0;
+ s=ures_getNextString(setRes, &resLen, (const char**)&key, &errCode);
+ keyLen = (int32_t)uprv_strlen(key);
+ u_charsToUChars(key, result+len, keyLen);
+ len += keyLen;
+ result[len++]=COLON;
+ uprv_memcpy(result+len, s, resLen*sizeof(UChar));
+ len += resLen;
+ result[len++]=SEMI_COLON;
+ }
+ result[len++]=0;
+ u_UCharsToChars(result, setKey, len);
+ // printf(" Rule: %s\n", setKey);
+
+ ures_close(setRes);
+ ures_close(ruleRes);
+ ures_close(locRes);
+ ures_close(rb);
+ return UnicodeString(result);
+
+}
+
+AndConstraint::AndConstraint() {
+ op = AndConstraint::NONE;
+ opNum=-1;
+ rangeLow=-1;
+ rangeHigh=-1;
+ notIn=FALSE;
+ integerOnly=FALSE;
+ next=NULL;
+}
+
+
+AndConstraint::AndConstraint(const AndConstraint& other) {
+ this->op = other.op;
+ this->opNum=other.opNum;
+ this->rangeLow=other.rangeLow;
+ this->rangeHigh=other.rangeHigh;
+ this->integerOnly=other.integerOnly;
+ this->notIn=other.notIn;
+ if (other.next==NULL) {
+ this->next=NULL;
+ }
+ else {
+ this->next = new AndConstraint(*other.next);
+ }
+}
+
+AndConstraint::~AndConstraint() {
+ if (next!=NULL) {
+ delete next;
+ }
+}
+
+
+UBool
+AndConstraint::isFulfilled(double number) {
+ UBool result=TRUE;
+ double value=number;
+
+ if ( op == MOD ) {
+ value = (int32_t)value % opNum;
+ }
+ if ( rangeHigh == -1 ) {
+ if ( rangeLow == -1 ) {
+ result = TRUE; // empty rule
+ }
+ else {
+ if ( value == rangeLow ) {
+ result = TRUE;
+ }
+ else {
+ result = FALSE;
+ }
+ }
+ }
+ else {
+ if ((rangeLow <= value) && (value <= rangeHigh)) {
+ if (integerOnly) {
+ if ( value != (int32_t)value) {
+ result = FALSE;
+ }
+ else {
+ result = TRUE;
+ }
+ }
+ else {
+ result = TRUE;
+ }
+ }
+ else {
+ result = FALSE;
+ }
+ }
+ if (notIn) {
+ return !result;
+ }
+ else {
+ return result;
+ }
+}
+
+int32_t
+AndConstraint::updateRepeatLimit(int32_t maxLimit) {
+
+ if ( op == MOD ) {
+ return uprv_max(opNum, maxLimit);
+ }
+ else {
+ if ( rangeHigh == -1 ) {
+ return uprv_max(rangeLow, maxLimit);
+ }
+ else{
+ return uprv_max(rangeHigh, maxLimit);
+ }
+ }
+}
+
+
+AndConstraint*
+AndConstraint::add()
+{
+ this->next = new AndConstraint();
+ return this->next;
+}
+
+OrConstraint::OrConstraint() {
+ childNode=NULL;
+ next=NULL;
+}
+
+OrConstraint::OrConstraint(const OrConstraint& other) {
+ if ( other.childNode == NULL ) {
+ this->childNode = NULL;
+ }
+ else {
+ this->childNode = new AndConstraint(*(other.childNode));
+ }
+ if (other.next == NULL ) {
+ this->next = NULL;
+ }
+ else {
+ this->next = new OrConstraint(*(other.next));
+ }
+}
+
+OrConstraint::~OrConstraint() {
+ if (childNode!=NULL) {
+ delete childNode;
+ }
+ if (next!=NULL) {
+ delete next;
+ }
+}
+
+AndConstraint*
+OrConstraint::add()
+{
+ OrConstraint *curOrConstraint=this;
+ {
+ while (curOrConstraint->next!=NULL) {
+ curOrConstraint = curOrConstraint->next;
+ }
+ curOrConstraint->next = NULL;
+ curOrConstraint->childNode = new AndConstraint();
+ }
+ return curOrConstraint->childNode;
+}
+
+UBool
+OrConstraint::isFulfilled(double number) {
+ OrConstraint* orRule=this;
+ UBool result=FALSE;
+
+ while (orRule!=NULL && !result) {
+ result=TRUE;
+ AndConstraint* andRule = orRule->childNode;
+ while (andRule!=NULL && result) {
+ result = andRule->isFulfilled(number);
+ andRule=andRule->next;
+ }
+ orRule = orRule->next;
+ }
+
+ return result;
+}
+
+
+RuleChain::RuleChain() {
+ ruleHeader=NULL;
+ next = NULL;
+ repeatLimit=0;
+}
+
+RuleChain::RuleChain(const RuleChain& other) {
+ this->repeatLimit = other.repeatLimit;
+ this->keyword=other.keyword;
+ if (other.ruleHeader != NULL) {
+ this->ruleHeader = new OrConstraint(*(other.ruleHeader));
+ }
+ else {
+ this->ruleHeader = NULL;
+ }
+ if (other.next != NULL ) {
+ this->next = new RuleChain(*other.next);
+ }
+ else
+ {
+ this->next = NULL;
+ }
+}
+
+RuleChain::~RuleChain() {
+ if (next != NULL) {
+ delete next;
+ }
+ if ( ruleHeader != NULL ) {
+ delete ruleHeader;
+ }
+}
+
+UnicodeString
+RuleChain::select(double number) const {
+
+ if ( ruleHeader != NULL ) {
+ if (ruleHeader->isFulfilled(number)) {
+ return keyword;
+ }
+ }
+ if ( next != NULL ) {
+ return next->select(number);
+ }
+ else {
+ return PLURAL_KEYWORD_OTHER;
+ }
+
+}
+
+void
+RuleChain::dumpRules(UnicodeString& result) {
+ UChar digitString[16];
+
+ if ( ruleHeader != NULL ) {
+ result += keyword;
+ OrConstraint* orRule=ruleHeader;
+ while ( orRule != NULL ) {
+ AndConstraint* andRule=orRule->childNode;
+ while ( andRule != NULL ) {
+ if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeHigh==-1) ) {
+ result += UNICODE_STRING_SIMPLE(" n is ");
+ if (andRule->notIn) {
+ result += UNICODE_STRING_SIMPLE("not ");
+ }
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ if (andRule->op==AndConstraint::MOD) {
+ result += UNICODE_STRING_SIMPLE(" n mod ");
+ uprv_itou(digitString,16, andRule->opNum,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" n ");
+ }
+ if (andRule->rangeHigh==-1) {
+ if (andRule->notIn) {
+ result += UNICODE_STRING_SIMPLE(" is not ");
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" is ");
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ }
+ }
+ else {
+ if (andRule->notIn) {
+ if ( andRule->integerOnly ) {
+ result += UNICODE_STRING_SIMPLE(" not in ");
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" not within ");
+ }
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ result += UNICODE_STRING_SIMPLE(" .. ");
+ uprv_itou(digitString,16, andRule->rangeHigh,10,0);
+ result += UnicodeString(digitString);
+ }
+ else {
+ if ( andRule->integerOnly ) {
+ result += UNICODE_STRING_SIMPLE(" in ");
+ }
+ else {
+ result += UNICODE_STRING_SIMPLE(" within ");
+ }
+ uprv_itou(digitString,16, andRule->rangeLow,10,0);
+ result += UnicodeString(digitString);
+ result += UNICODE_STRING_SIMPLE(" .. ");
+ uprv_itou(digitString,16, andRule->rangeHigh,10,0);
+ }
+ }
+ }
+ if ( (andRule=andRule->next) != NULL) {
+ result += PK_AND;
+ }
+ }
+ if ( (orRule = orRule->next) != NULL ) {
+ result += PK_OR;
+ }
+ }
+ }
+ if ( next != NULL ) {
+ next->dumpRules(result);
+ }
+}
+
+int32_t
+RuleChain::getRepeatLimit () {
+ return repeatLimit;
+}
+
+void
+RuleChain::setRepeatLimit () {
+ int32_t limit=0;
+
+ if ( next != NULL ) {
+ next->setRepeatLimit();
+ limit = next->repeatLimit;
+ }
+
+ if ( ruleHeader != NULL ) {
+ OrConstraint* orRule=ruleHeader;
+ while ( orRule != NULL ) {
+ AndConstraint* andRule=orRule->childNode;
+ while ( andRule != NULL ) {
+ limit = andRule->updateRepeatLimit(limit);
+ andRule = andRule->next;
+ }
+ orRule = orRule->next;
+ }
+ }
+ repeatLimit = limit;
+}
+
+UErrorCode
+RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
+ if ( arraySize < capacityOfKeywords-1 ) {
+ keywords[arraySize++]=keyword;
+ }
+ else {
+ return U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ if ( next != NULL ) {
+ return next->getKeywords(capacityOfKeywords, keywords, arraySize);
+ }
+ else {
+ return U_ZERO_ERROR;
+ }
+}
+
+UBool
+RuleChain::isKeyword(const UnicodeString& keywordParam) const {
+ if ( keyword == keywordParam ) {
+ return TRUE;
+ }
+
+ if ( next != NULL ) {
+ return next->isKeyword(keywordParam);
+ }
+ else {
+ return FALSE;
+ }
+}
+
+
+RuleParser::RuleParser() {
+ UErrorCode err=U_ZERO_ERROR;
+ const UnicodeString idStart=UNICODE_STRING_SIMPLE("[[a-z]]");
+ const UnicodeString idContinue=UNICODE_STRING_SIMPLE("[[a-z][A-Z][_][0-9]]");
+ idStartFilter = new UnicodeSet(idStart, err);
+ idContinueFilter = new UnicodeSet(idContinue, err);
+}
+
+RuleParser::~RuleParser() {
+ delete idStartFilter;
+ delete idContinueFilter;
+}
+
+void
+RuleParser::checkSyntax(tokenType prevType, tokenType curType, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ switch(prevType) {
+ case none:
+ case tSemiColon:
+ if (curType!=tKeyword) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tVariableN :
+ if (curType != tIs && curType != tMod && curType != tIn &&
+ curType != tNot && curType != tWithin) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tZero:
+ case tOne:
+ case tTwo:
+ case tFew:
+ case tMany:
+ case tOther:
+ case tKeyword:
+ if (curType != tColon) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tColon :
+ if (curType != tVariableN) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tIs:
+ if ( curType != tNumber && curType != tNot) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tNot:
+ if (curType != tNumber && curType != tIn && curType != tWithin) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tMod:
+ case tDot:
+ case tIn:
+ case tWithin:
+ case tAnd:
+ case tOr:
+ if (curType != tNumber && curType != tVariableN) {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ case tNumber:
+ if (curType != tDot && curType != tSemiColon && curType != tIs && curType != tNot &&
+ curType != tIn && curType != tWithin && curType != tAnd && curType != tOr)
+ {
+ status = U_UNEXPECTED_TOKEN;
+ }
+ break;
+ default:
+ status = U_UNEXPECTED_TOKEN;
+ break;
+ }
+}
+
+void
+RuleParser::getNextToken(const UnicodeString& ruleData,
+ int32_t *ruleIndex,
+ UnicodeString& token,
+ tokenType& type,
+ UErrorCode &status)
+{
+ int32_t curIndex= *ruleIndex;
+ UChar ch;
+ tokenType prevType=none;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ while (curIndex<ruleData.length()) {
+ ch = ruleData.charAt(curIndex);
+ if ( !inRange(ch, type) ) {
+ status = U_ILLEGAL_CHARACTER;
+ return;
+ }
+ switch (type) {
+ case tSpace:
+ if ( *ruleIndex != curIndex ) { // letter
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ *ruleIndex=curIndex;
+ type=prevType;
+ getKeyType(token, type, status);
+ return;
+ }
+ else {
+ *ruleIndex=*ruleIndex+1;
+ }
+ break; // consective space
+ case tColon:
+ case tSemiColon:
+ if ( *ruleIndex != curIndex ) {
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ *ruleIndex=curIndex;
+ type=prevType;
+ getKeyType(token, type, status);
+ return;
+ }
+ else {
+ *ruleIndex=curIndex+1;
+ return;
+ }
+ case tLetter:
+ if ((type==prevType)||(prevType==none)) {
+ prevType=type;
+ break;
+ }
+ break;
+ case tNumber:
+ if ((type==prevType)||(prevType==none)) {
+ prevType=type;
+ break;
+ }
+ else {
+ *ruleIndex=curIndex+1;
+ return;
+ }
+ case tDot:
+ if (prevType==none) { // first dot
+ prevType=type;
+ continue;
+ }
+ else {
+ if ( *ruleIndex != curIndex ) {
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ *ruleIndex=curIndex; // letter
+ type=prevType;
+ getKeyType(token, type, status);
+ return;
+ }
+ else { // two consective dots
+ *ruleIndex=curIndex+2;
+ return;
+ }
+ }
+ break;
+ default:
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ curIndex++;
+ }
+ if ( curIndex>=ruleData.length() ) {
+ if ( (type == tLetter)||(type == tNumber) ) {
+ token=UnicodeString(ruleData, *ruleIndex, curIndex-*ruleIndex);
+ getKeyType(token, type, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ *ruleIndex = ruleData.length();
+ }
+}
+
+UBool
+RuleParser::inRange(UChar ch, tokenType& type) {
+ if ((ch>=CAP_A) && (ch<=CAP_Z)) {
+ // we assume all characters are in lower case already.
+ return FALSE;
+ }
+ if ((ch>=LOW_A) && (ch<=LOW_Z)) {
+ type = tLetter;
+ return TRUE;
+ }
+ if ((ch>=U_ZERO) && (ch<=U_NINE)) {
+ type = tNumber;
+ return TRUE;
+ }
+ switch (ch) {
+ case COLON:
+ type = tColon;
+ return TRUE;
+ case SPACE:
+ type = tSpace;
+ return TRUE;
+ case SEMI_COLON:
+ type = tSemiColon;
+ return TRUE;
+ case DOT:
+ type = tDot;
+ return TRUE;
+ default :
+ type = none;
+ return FALSE;
+ }
+}
+
+
+void
+RuleParser::getKeyType(const UnicodeString& token, tokenType& keyType, UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if ( keyType==tNumber) {
+ }
+ else if (token==PK_VAR_N) {
+ keyType = tVariableN;
+ }
+ else if (token==PK_IS) {
+ keyType = tIs;
+ }
+ else if (token==PK_AND) {
+ keyType = tAnd;
+ }
+ else if (token==PK_IN) {
+ keyType = tIn;
+ }
+ else if (token==PK_WITHIN) {
+ keyType = tWithin;
+ }
+ else if (token==PK_NOT) {
+ keyType = tNot;
+ }
+ else if (token==PK_MOD) {
+ keyType = tMod;
+ }
+ else if (token==PK_OR) {
+ keyType = tOr;
+ }
+ else if ( isValidKeyword(token) ) {
+ keyType = tKeyword;
+ }
+ else {
+ status = U_UNEXPECTED_TOKEN;
+ }
+}
+
+UBool
+RuleParser::isValidKeyword(const UnicodeString& token) {
+ if ( token.length()==0 ) {
+ return FALSE;
+ }
+ if ( idStartFilter->contains(token.charAt(0) )==TRUE ) {
+ int32_t i;
+ for (i=1; i< token.length(); i++) {
+ if (idContinueFilter->contains(token.charAt(i))== FALSE) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode& status) :
+fKeywordNames(status)
+{
+ RuleChain *node=header;
+ UBool addKeywordOther=true;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ pos=0;
+ fKeywordNames.removeAllElements();
+ while(node!=NULL) {
+ fKeywordNames.addElement(new UnicodeString(node->keyword), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (node->keyword == PLURAL_KEYWORD_OTHER) {
+ addKeywordOther= false;
+ }
+ node=node->next;
+ }
+
+ if (addKeywordOther) {
+ fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+}
+
+const UnicodeString*
+PluralKeywordEnumeration::snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
+ return (const UnicodeString*)fKeywordNames.elementAt(pos++);
+ }
+ return NULL;
+}
+
+void
+PluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
+ pos=0;
+}
+
+int32_t
+PluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
+ return fKeywordNames.size();
+}
+
+PluralKeywordEnumeration::~PluralKeywordEnumeration() {
+ UnicodeString *s;
+ for (int32_t i=0; i<fKeywordNames.size(); ++i) {
+ if ((s=(UnicodeString *)fKeywordNames.elementAt(i))!=NULL) {
+ delete s;
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
Property changes on: icu46/source/i18n/plurrule.cpp
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « icu46/source/i18n/plurfmt.cpp ('k') | icu46/source/i18n/plurrule_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698