Home | History | Annotate | Download | only in i18n
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 2007-2016, International Business Machines Corporation and
      6 * others. All Rights Reserved.
      7 *******************************************************************************
      8 *
      9 * File plurrule.cpp
     10 */
     11 
     12 #include <math.h>
     13 #include <stdio.h>
     14 
     15 #include "unicode/utypes.h"
     16 #include "unicode/localpointer.h"
     17 #include "unicode/plurrule.h"
     18 #include "unicode/upluralrules.h"
     19 #include "unicode/ures.h"
     20 #include "unicode/numfmt.h"
     21 #include "unicode/decimfmt.h"
     22 #include "charstr.h"
     23 #include "cmemory.h"
     24 #include "cstring.h"
     25 #include "digitlst.h"
     26 #include "hash.h"
     27 #include "locutil.h"
     28 #include "mutex.h"
     29 #include "patternprops.h"
     30 #include "plurrule_impl.h"
     31 #include "putilimp.h"
     32 #include "ucln_in.h"
     33 #include "ustrfmt.h"
     34 #include "uassert.h"
     35 #include "uvectr32.h"
     36 #include "sharedpluralrules.h"
     37 #include "unifiedcache.h"
     38 #include "digitinterval.h"
     39 #include "visibledigits.h"
     40 
     41 #if !UCONFIG_NO_FORMATTING
     42 
     43 U_NAMESPACE_BEGIN
     44 
     45 static const UChar PLURAL_KEYWORD_OTHER[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,0};
     46 static const UChar PLURAL_DEFAULT_RULE[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,COLON,SPACE,LOW_N,0};
     47 static const UChar PK_IN[]={LOW_I,LOW_N,0};
     48 static const UChar PK_NOT[]={LOW_N,LOW_O,LOW_T,0};
     49 static const UChar PK_IS[]={LOW_I,LOW_S,0};
     50 static const UChar PK_MOD[]={LOW_M,LOW_O,LOW_D,0};
     51 static const UChar PK_AND[]={LOW_A,LOW_N,LOW_D,0};
     52 static const UChar PK_OR[]={LOW_O,LOW_R,0};
     53 static const UChar PK_VAR_N[]={LOW_N,0};
     54 static const UChar PK_VAR_I[]={LOW_I,0};
     55 static const UChar PK_VAR_F[]={LOW_F,0};
     56 static const UChar PK_VAR_T[]={LOW_T,0};
     57 static const UChar PK_VAR_V[]={LOW_V,0};
     58 static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
     59 static const UChar PK_DECIMAL[]={LOW_D,LOW_E,LOW_C,LOW_I,LOW_M,LOW_A,LOW_L,0};
     60 static const UChar PK_INTEGER[]={LOW_I,LOW_N,LOW_T,LOW_E,LOW_G,LOW_E,LOW_R,0};
     61 
     62 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules)
     63 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
     64 
     65 PluralRules::PluralRules(UErrorCode& /*status*/)
     66 :   UObject(),
     67     mRules(NULL)
     68 {
     69 }
     70 
     71 PluralRules::PluralRules(const PluralRules& other)
     72 : UObject(other),
     73     mRules(NULL)
     74 {
     75     *this=other;
     76 }
     77 
     78 PluralRules::~PluralRules() {
     79     delete mRules;
     80 }
     81 
     82 SharedPluralRules::~SharedPluralRules() {
     83     delete ptr;
     84 }
     85 
     86 PluralRules*
     87 PluralRules::clone() const {
     88     return new PluralRules(*this);
     89 }
     90 
     91 PluralRules&
     92 PluralRules::operator=(const PluralRules& other) {
     93     if (this != &other) {
     94         delete mRules;
     95         if (other.mRules==NULL) {
     96             mRules = NULL;
     97         }
     98         else {
     99             mRules = new RuleChain(*other.mRules);
    100         }
    101     }
    102 
    103     return *this;
    104 }
    105 
    106 StringEnumeration* PluralRules::getAvailableLocales(UErrorCode &status) {
    107     StringEnumeration *result = new PluralAvailableLocalesEnumeration(status);
    108     if (result == NULL && U_SUCCESS(status)) {
    109         status = U_MEMORY_ALLOCATION_ERROR;
    110     }
    111     if (U_FAILURE(status)) {
    112         delete result;
    113         result = NULL;
    114     }
    115     return result;
    116 }
    117 
    118 
    119 PluralRules* U_EXPORT2
    120 PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
    121     if (U_FAILURE(status)) {
    122         return NULL;
    123     }
    124 
    125     PluralRuleParser parser;
    126     PluralRules *newRules = new PluralRules(status);
    127     if (U_SUCCESS(status) && newRules == NULL) {
    128         status = U_MEMORY_ALLOCATION_ERROR;
    129     }
    130     parser.parse(description, newRules, status);
    131     if (U_FAILURE(status)) {
    132         delete newRules;
    133         newRules = NULL;
    134     }
    135     return newRules;
    136 }
    137 
    138 
    139 PluralRules* U_EXPORT2
    140 PluralRules::createDefaultRules(UErrorCode& status) {
    141     return createRules(UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1), status);
    142 }
    143 
    144 /******************************************************************************/
    145 /* Create PluralRules cache */
    146 
    147 template<> U_I18N_API
    148 const SharedPluralRules *LocaleCacheKey<SharedPluralRules>::createObject(
    149         const void * /*unused*/, UErrorCode &status) const {
    150     const char *localeId = fLoc.getName();
    151     PluralRules *pr = PluralRules::internalForLocale(
    152             localeId, UPLURAL_TYPE_CARDINAL, status);
    153     if (U_FAILURE(status)) {
    154         return NULL;
    155     }
    156     SharedPluralRules *result = new SharedPluralRules(pr);
    157     if (result == NULL) {
    158         status = U_MEMORY_ALLOCATION_ERROR;
    159         delete pr;
    160         return NULL;
    161     }
    162     result->addRef();
    163     return result;
    164 }
    165 
    166 /* end plural rules cache */
    167 /******************************************************************************/
    168 
    169 const SharedPluralRules* U_EXPORT2
    170 PluralRules::createSharedInstance(
    171         const Locale& locale, UPluralType type, UErrorCode& status) {
    172     if (U_FAILURE(status)) {
    173         return NULL;
    174     }
    175     if (type != UPLURAL_TYPE_CARDINAL) {
    176         status = U_UNSUPPORTED_ERROR;
    177         return NULL;
    178     }
    179     const SharedPluralRules *result = NULL;
    180     UnifiedCache::getByLocale(locale, result, status);
    181     return result;
    182 }
    183 
    184 PluralRules* U_EXPORT2
    185 PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
    186     return forLocale(locale, UPLURAL_TYPE_CARDINAL, status);
    187 }
    188 
    189 PluralRules* U_EXPORT2
    190 PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
    191     if (type != UPLURAL_TYPE_CARDINAL) {
    192         return internalForLocale(locale, type, status);
    193     }
    194     const SharedPluralRules *shared = createSharedInstance(
    195             locale, type, status);
    196     if (U_FAILURE(status)) {
    197         return NULL;
    198     }
    199     PluralRules *result = (*shared)->clone();
    200     shared->removeRef();
    201     if (result == NULL) {
    202         status = U_MEMORY_ALLOCATION_ERROR;
    203     }
    204     return result;
    205 }
    206 
    207 PluralRules* U_EXPORT2
    208 PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
    209     if (U_FAILURE(status)) {
    210         return NULL;
    211     }
    212     if (type >= UPLURAL_TYPE_COUNT) {
    213         status = U_ILLEGAL_ARGUMENT_ERROR;
    214         return NULL;
    215     }
    216     PluralRules *newObj = new PluralRules(status);
    217     if (newObj==NULL || U_FAILURE(status)) {
    218         delete newObj;
    219         return NULL;
    220     }
    221     UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
    222     // TODO: which errors, if any, should be returned?
    223     if (locRule.length() == 0) {
    224         // Locales with no specific rules (all numbers have the "other" category
    225         //   will return a U_MISSING_RESOURCE_ERROR at this point. This is not
    226         //   an error.
    227         locRule =  UnicodeString(PLURAL_DEFAULT_RULE);
    228         status = U_ZERO_ERROR;
    229     }
    230     PluralRuleParser parser;
    231     parser.parse(locRule, newObj, status);
    232         //  TODO: should rule parse errors be returned, or
    233         //        should we silently use default rules?
    234         //        Original impl used default rules.
    235         //        Ask the question to ICU Core.
    236 
    237     return newObj;
    238 }
    239 
    240 UnicodeString
    241 PluralRules::select(int32_t number) const {
    242     return select(FixedDecimal(number));
    243 }
    244 
    245 UnicodeString
    246 PluralRules::select(double number) const {
    247     return select(FixedDecimal(number));
    248 }
    249 
    250 UnicodeString
    251 PluralRules::select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const {
    252     if (U_SUCCESS(status)) {
    253         const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
    254         if (decFmt != NULL) {
    255             VisibleDigitsWithExponent digits;
    256             decFmt->initVisibleDigitsWithExponent(obj, digits, status);
    257             if (U_SUCCESS(status)) {
    258                 return select(digits);
    259             }
    260         } else {
    261             double number = obj.getDouble(status);
    262             if (U_SUCCESS(status)) {
    263                 return select(number);
    264             }
    265         }
    266     }
    267     return UnicodeString();
    268 }
    269 
    270 UnicodeString
    271 PluralRules::select(const IFixedDecimal &number) const {
    272     if (mRules == NULL) {
    273         return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1);
    274     }
    275     else {
    276         return mRules->select(number);
    277     }
    278 }
    279 
    280 UnicodeString
    281 PluralRules::select(const VisibleDigitsWithExponent &number) const {
    282     if (number.getExponent() != NULL) {
    283         return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1);
    284     }
    285     return select(FixedDecimal(number.getMantissa()));
    286 }
    287 
    288 
    289 
    290 StringEnumeration*
    291 PluralRules::getKeywords(UErrorCode& status) const {
    292     if (U_FAILURE(status))  return NULL;
    293     StringEnumeration* nameEnumerator = new PluralKeywordEnumeration(mRules, status);
    294     if (U_FAILURE(status)) {
    295       delete nameEnumerator;
    296       return NULL;
    297     }
    298 
    299     return nameEnumerator;
    300 }
    301 
    302 double
    303 PluralRules::getUniqueKeywordValue(const UnicodeString& /* keyword */) {
    304   // Not Implemented.
    305   return UPLRULES_NO_UNIQUE_VALUE;
    306 }
    307 
    308 int32_t
    309 PluralRules::getAllKeywordValues(const UnicodeString & /* keyword */, double * /* dest */,
    310                                  int32_t /* destCapacity */, UErrorCode& error) {
    311     error = U_UNSUPPORTED_ERROR;
    312     return 0;
    313 }
    314 
    315 
    316 static double scaleForInt(double d) {
    317     double scale = 1.0;
    318     while (d != floor(d)) {
    319         d = d * 10.0;
    320         scale = scale * 10.0;
    321     }
    322     return scale;
    323 }
    324 
    325 static int32_t
    326 getSamplesFromString(const UnicodeString &samples, double *dest,
    327                         int32_t destCapacity, UErrorCode& status) {
    328     int32_t sampleCount = 0;
    329     int32_t sampleStartIdx = 0;
    330     int32_t sampleEndIdx = 0;
    331 
    332     //std::string ss;  // TODO: debugging.
    333     // std::cout << "PluralRules::getSamples(), samples = \"" << samples.toUTF8String(ss) << "\"\n";
    334     for (sampleCount = 0; sampleCount < destCapacity && sampleStartIdx < samples.length(); ) {
    335         sampleEndIdx = samples.indexOf(COMMA, sampleStartIdx);
    336         if (sampleEndIdx == -1) {
    337             sampleEndIdx = samples.length();
    338         }
    339         const UnicodeString &sampleRange = samples.tempSubStringBetween(sampleStartIdx, sampleEndIdx);
    340         // ss.erase();
    341         // std::cout << "PluralRules::getSamples(), samplesRange = \"" << sampleRange.toUTF8String(ss) << "\"\n";
    342         int32_t tildeIndex = sampleRange.indexOf(TILDE);
    343         if (tildeIndex < 0) {
    344             FixedDecimal fixed(sampleRange, status);
    345             double sampleValue = fixed.source;
    346             if (fixed.visibleDecimalDigitCount == 0 || sampleValue != floor(sampleValue)) {
    347                 dest[sampleCount++] = sampleValue;
    348             }
    349         } else {
    350 
    351             FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
    352             FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
    353             double rangeLo = fixedLo.source;
    354             double rangeHi = fixedHi.source;
    355             if (U_FAILURE(status)) {
    356                 break;
    357             }
    358             if (rangeHi < rangeLo) {
    359                 status = U_INVALID_FORMAT_ERROR;
    360                 break;
    361             }
    362 
    363             // For ranges of samples with fraction decimal digits, scale the number up so that we
    364             //   are adding one in the units place. Avoids roundoffs from repetitive adds of tenths.
    365 
    366             double scale = scaleForInt(rangeLo);
    367             double t = scaleForInt(rangeHi);
    368             if (t > scale) {
    369                 scale = t;
    370             }
    371             rangeLo *= scale;
    372             rangeHi *= scale;
    373             for (double n=rangeLo; n<=rangeHi; n+=1) {
    374                 // Hack Alert: don't return any decimal samples with integer values that
    375                 //    originated from a format with trailing decimals.
    376                 //    This API is returning doubles, which can't distinguish having displayed
    377                 //    zeros to the right of the decimal.
    378                 //    This results in test failures with values mapping back to a different keyword.
    379                 double sampleValue = n/scale;
    380                 if (!(sampleValue == floor(sampleValue) && fixedLo.visibleDecimalDigitCount > 0)) {
    381                     dest[sampleCount++] = sampleValue;
    382                 }
    383                 if (sampleCount >= destCapacity) {
    384                     break;
    385                 }
    386             }
    387         }
    388         sampleStartIdx = sampleEndIdx + 1;
    389     }
    390     return sampleCount;
    391 }
    392 
    393 
    394 int32_t
    395 PluralRules::getSamples(const UnicodeString &keyword, double *dest,
    396                         int32_t destCapacity, UErrorCode& status) {
    397     RuleChain *rc = rulesForKeyword(keyword);
    398     if (rc == NULL || destCapacity == 0 || U_FAILURE(status)) {
    399         return 0;
    400     }
    401     int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, dest, destCapacity, status);
    402     if (numSamples == 0) {
    403         numSamples = getSamplesFromString(rc->fDecimalSamples, dest, destCapacity, status);
    404     }
    405     return numSamples;
    406 }
    407 
    408 
    409 RuleChain *PluralRules::rulesForKeyword(const UnicodeString &keyword) const {
    410     RuleChain *rc;
    411     for (rc = mRules; rc != NULL; rc = rc->fNext) {
    412         if (rc->fKeyword == keyword) {
    413             break;
    414         }
    415     }
    416     return rc;
    417 }
    418 
    419 
    420 UBool
    421 PluralRules::isKeyword(const UnicodeString& keyword) const {
    422     if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
    423         return true;
    424     }
    425     return rulesForKeyword(keyword) != NULL;
    426 }
    427 
    428 UnicodeString
    429 PluralRules::getKeywordOther() const {
    430     return UnicodeString(TRUE, PLURAL_KEYWORD_OTHER, 5);
    431 }
    432 
    433 UBool
    434 PluralRules::operator==(const PluralRules& other) const  {
    435     const UnicodeString *ptrKeyword;
    436     UErrorCode status= U_ZERO_ERROR;
    437 
    438     if ( this == &other ) {
    439         return TRUE;
    440     }
    441     LocalPointer<StringEnumeration> myKeywordList(getKeywords(status));
    442     LocalPointer<StringEnumeration> otherKeywordList(other.getKeywords(status));
    443     if (U_FAILURE(status)) {
    444         return FALSE;
    445     }
    446 
    447     if (myKeywordList->count(status)!=otherKeywordList->count(status)) {
    448         return FALSE;
    449     }
    450     myKeywordList->reset(status);
    451     while ((ptrKeyword=myKeywordList->snext(status))!=NULL) {
    452         if (!other.isKeyword(*ptrKeyword)) {
    453             return FALSE;
    454         }
    455     }
    456     otherKeywordList->reset(status);
    457     while ((ptrKeyword=otherKeywordList->snext(status))!=NULL) {
    458         if (!this->isKeyword(*ptrKeyword)) {
    459             return FALSE;
    460         }
    461     }
    462     if (U_FAILURE(status)) {
    463         return FALSE;
    464     }
    465 
    466     return TRUE;
    467 }
    468 
    469 
    470 void
    471 PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErrorCode &status)
    472 {
    473     if (U_FAILURE(status)) {
    474         return;
    475     }
    476     U_ASSERT(ruleIndex == 0);    // Parsers are good for a single use only!
    477     ruleSrc = &ruleData;
    478 
    479     while (ruleIndex< ruleSrc->length()) {
    480         getNextToken(status);
    481         if (U_FAILURE(status)) {
    482             return;
    483         }
    484         checkSyntax(status);
    485         if (U_FAILURE(status)) {
    486             return;
    487         }
    488         switch (type) {
    489         case tAnd:
    490             U_ASSERT(curAndConstraint != NULL);
    491             curAndConstraint = curAndConstraint->add();
    492             break;
    493         case tOr:
    494             {
    495                 U_ASSERT(currentChain != NULL);
    496                 OrConstraint *orNode=currentChain->ruleHeader;
    497                 while (orNode->next != NULL) {
    498                     orNode = orNode->next;
    499                 }
    500                 orNode->next= new OrConstraint();
    501                 orNode=orNode->next;
    502                 orNode->next=NULL;
    503                 curAndConstraint = orNode->add();
    504             }
    505             break;
    506         case tIs:
    507             U_ASSERT(curAndConstraint != NULL);
    508             U_ASSERT(curAndConstraint->value == -1);
    509             U_ASSERT(curAndConstraint->rangeList == NULL);
    510             break;
    511         case tNot:
    512             U_ASSERT(curAndConstraint != NULL);
    513             curAndConstraint->negated=TRUE;
    514             break;
    515 
    516         case tNotEqual:
    517             curAndConstraint->negated=TRUE;
    518             U_FALLTHROUGH;
    519         case tIn:
    520         case tWithin:
    521         case tEqual:
    522             U_ASSERT(curAndConstraint != NULL);
    523             curAndConstraint->rangeList = new UVector32(status);
    524             curAndConstraint->rangeList->addElement(-1, status);  // range Low
    525             curAndConstraint->rangeList->addElement(-1, status);  // range Hi
    526             rangeLowIdx = 0;
    527             rangeHiIdx  = 1;
    528             curAndConstraint->value=PLURAL_RANGE_HIGH;
    529             curAndConstraint->integerOnly = (type != tWithin);
    530             break;
    531         case tNumber:
    532             U_ASSERT(curAndConstraint != NULL);
    533             if ( (curAndConstraint->op==AndConstraint::MOD)&&
    534                  (curAndConstraint->opNum == -1 ) ) {
    535                 curAndConstraint->opNum=getNumberValue(token);
    536             }
    537             else {
    538                 if (curAndConstraint->rangeList == NULL) {
    539                     // this is for an 'is' rule
    540                     curAndConstraint->value = getNumberValue(token);
    541                 } else {
    542                     // this is for an 'in' or 'within' rule
    543                     if (curAndConstraint->rangeList->elementAti(rangeLowIdx) == -1) {
    544                         curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeLowIdx);
    545                         curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeHiIdx);
    546                     }
    547                     else {
    548                         curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeHiIdx);
    549                         if (curAndConstraint->rangeList->elementAti(rangeLowIdx) >
    550                                 curAndConstraint->rangeList->elementAti(rangeHiIdx)) {
    551                             // Range Lower bound > Range Upper bound.
    552                             // U_UNEXPECTED_TOKEN seems a little funny, but it is consistently
    553                             // used for all plural rule parse errors.
    554                             status = U_UNEXPECTED_TOKEN;
    555                             break;
    556                         }
    557                     }
    558                 }
    559             }
    560             break;
    561         case tComma:
    562             // TODO: rule syntax checking is inadequate, can happen with badly formed rules.
    563             //       Catch cases like "n mod 10, is 1" here instead.
    564             if (curAndConstraint == NULL || curAndConstraint->rangeList == NULL) {
    565                 status = U_UNEXPECTED_TOKEN;
    566                 break;
    567             }
    568             U_ASSERT(curAndConstraint->rangeList->size() >= 2);
    569             rangeLowIdx = curAndConstraint->rangeList->size();
    570             curAndConstraint->rangeList->addElement(-1, status);  // range Low
    571             rangeHiIdx = curAndConstraint->rangeList->size();
    572             curAndConstraint->rangeList->addElement(-1, status);  // range Hi
    573             break;
    574         case tMod:
    575             U_ASSERT(curAndConstraint != NULL);
    576             curAndConstraint->op=AndConstraint::MOD;
    577             break;
    578         case tVariableN:
    579         case tVariableI:
    580         case tVariableF:
    581         case tVariableT:
    582         case tVariableV:
    583             U_ASSERT(curAndConstraint != NULL);
    584             curAndConstraint->digitsType = type;
    585             break;
    586         case tKeyword:
    587             {
    588             RuleChain *newChain = new RuleChain;
    589             if (newChain == NULL) {
    590                 status = U_MEMORY_ALLOCATION_ERROR;
    591                 break;
    592             }
    593             newChain->fKeyword = token;
    594             if (prules->mRules == NULL) {
    595                 prules->mRules = newChain;
    596             } else {
    597                 // The new rule chain goes at the end of the linked list of rule chains,
    598                 //   unless there is an "other" keyword & chain. "other" must remain last.
    599                 RuleChain *insertAfter = prules->mRules;
    600                 while (insertAfter->fNext!=NULL &&
    601                        insertAfter->fNext->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5) != 0 ){
    602                     insertAfter=insertAfter->fNext;
    603                 }
    604                 newChain->fNext = insertAfter->fNext;
    605                 insertAfter->fNext = newChain;
    606             }
    607             OrConstraint *orNode = new OrConstraint();
    608             newChain->ruleHeader = orNode;
    609             curAndConstraint = orNode->add();
    610             currentChain = newChain;
    611             }
    612             break;
    613 
    614         case tInteger:
    615             for (;;) {
    616                 getNextToken(status);
    617                 if (U_FAILURE(status) || type == tSemiColon || type == tEOF || type == tAt) {
    618                     break;
    619                 }
    620                 if (type == tEllipsis) {
    621                     currentChain->fIntegerSamplesUnbounded = TRUE;
    622                     continue;
    623                 }
    624                 currentChain->fIntegerSamples.append(token);
    625             }
    626             break;
    627 
    628         case tDecimal:
    629             for (;;) {
    630                 getNextToken(status);
    631                 if (U_FAILURE(status) || type == tSemiColon || type == tEOF || type == tAt) {
    632                     break;
    633                 }
    634                 if (type == tEllipsis) {
    635                     currentChain->fDecimalSamplesUnbounded = TRUE;
    636                     continue;
    637                 }
    638                 currentChain->fDecimalSamples.append(token);
    639             }
    640             break;
    641 
    642         default:
    643             break;
    644         }
    645         prevType=type;
    646         if (U_FAILURE(status)) {
    647             break;
    648         }
    649     }
    650 }
    651 
    652 UnicodeString
    653 PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& errCode) {
    654     UnicodeString emptyStr;
    655 
    656     if (U_FAILURE(errCode)) {
    657         return emptyStr;
    658     }
    659     LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &errCode));
    660     if(U_FAILURE(errCode)) {
    661         return emptyStr;
    662     }
    663     const char *typeKey;
    664     switch (type) {
    665     case UPLURAL_TYPE_CARDINAL:
    666         typeKey = "locales";
    667         break;
    668     case UPLURAL_TYPE_ORDINAL:
    669         typeKey = "locales_ordinals";
    670         break;
    671     default:
    672         // Must not occur: The caller should have checked for valid types.
    673         errCode = U_ILLEGAL_ARGUMENT_ERROR;
    674         return emptyStr;
    675     }
    676     LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, NULL, &errCode));
    677     if(U_FAILURE(errCode)) {
    678         return emptyStr;
    679     }
    680     int32_t resLen=0;
    681     const char *curLocaleName=locale.getName();
    682     const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode);
    683 
    684     if (s == NULL) {
    685         // Check parent locales.
    686         UErrorCode status = U_ZERO_ERROR;
    687         char parentLocaleName[ULOC_FULLNAME_CAPACITY];
    688         const char *curLocaleName=locale.getName();
    689         uprv_strcpy(parentLocaleName, curLocaleName);
    690 
    691         while (uloc_getParent(parentLocaleName, parentLocaleName,
    692                                        ULOC_FULLNAME_CAPACITY, &status) > 0) {
    693             resLen=0;
    694             s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status);
    695             if (s != NULL) {
    696                 errCode = U_ZERO_ERROR;
    697                 break;
    698             }
    699             status = U_ZERO_ERROR;
    700         }
    701     }
    702     if (s==NULL) {
    703         return emptyStr;
    704     }
    705 
    706     char setKey[256];
    707     u_UCharsToChars(s, setKey, resLen + 1);
    708     // printf("\n PluralRule: %s\n", setKey);
    709 
    710     LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", NULL, &errCode));
    711     if(U_FAILURE(errCode)) {
    712         return emptyStr;
    713     }
    714     LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, NULL, &errCode));
    715     if (U_FAILURE(errCode)) {
    716         return emptyStr;
    717     }
    718 
    719     int32_t numberKeys = ures_getSize(setRes.getAlias());
    720     UnicodeString result;
    721     const char *key=NULL;
    722     for(int32_t i=0; i<numberKeys; ++i) {   // Keys are zero, one, few, ...
    723         UnicodeString rules = ures_getNextUnicodeString(setRes.getAlias(), &key, &errCode);
    724         UnicodeString uKey(key, -1, US_INV);
    725         result.append(uKey);
    726         result.append(COLON);
    727         result.append(rules);
    728         result.append(SEMI_COLON);
    729     }
    730     return result;
    731 }
    732 
    733 
    734 UnicodeString
    735 PluralRules::getRules() const {
    736     UnicodeString rules;
    737     if (mRules != NULL) {
    738         mRules->dumpRules(rules);
    739     }
    740     return rules;
    741 }
    742 
    743 
    744 AndConstraint::AndConstraint() {
    745     op = AndConstraint::NONE;
    746     opNum=-1;
    747     value = -1;
    748     rangeList = NULL;
    749     negated = FALSE;
    750     integerOnly = FALSE;
    751     digitsType = none;
    752     next=NULL;
    753 }
    754 
    755 
    756 AndConstraint::AndConstraint(const AndConstraint& other) {
    757     this->op = other.op;
    758     this->opNum=other.opNum;
    759     this->value=other.value;
    760     this->rangeList=NULL;
    761     if (other.rangeList != NULL) {
    762         UErrorCode status = U_ZERO_ERROR;
    763         this->rangeList = new UVector32(status);
    764         this->rangeList->assign(*other.rangeList, status);
    765     }
    766     this->integerOnly=other.integerOnly;
    767     this->negated=other.negated;
    768     this->digitsType = other.digitsType;
    769     if (other.next==NULL) {
    770         this->next=NULL;
    771     }
    772     else {
    773         this->next = new AndConstraint(*other.next);
    774     }
    775 }
    776 
    777 AndConstraint::~AndConstraint() {
    778     delete rangeList;
    779     if (next!=NULL) {
    780         delete next;
    781     }
    782 }
    783 
    784 
    785 UBool
    786 AndConstraint::isFulfilled(const IFixedDecimal &number) {
    787     UBool result = TRUE;
    788     if (digitsType == none) {
    789         // An empty AndConstraint, created by a rule with a keyword but no following expression.
    790         return TRUE;
    791     }
    792 
    793     PluralOperand operand = tokenTypeToPluralOperand(digitsType);
    794     double n = number.getPluralOperand(operand);     // pulls n | i | v | f value for the number.
    795                                                      // Will always be positive.
    796                                                      // May be non-integer (n option only)
    797     do {
    798         if (integerOnly && n != uprv_floor(n)) {
    799             result = FALSE;
    800             break;
    801         }
    802 
    803         if (op == MOD) {
    804             n = fmod(n, opNum);
    805         }
    806         if (rangeList == NULL) {
    807             result = value == -1 ||    // empty rule
    808                      n == value;       //  'is' rule
    809             break;
    810         }
    811         result = FALSE;                // 'in' or 'within' rule
    812         for (int32_t r=0; r<rangeList->size(); r+=2) {
    813             if (rangeList->elementAti(r) <= n && n <= rangeList->elementAti(r+1)) {
    814                 result = TRUE;
    815                 break;
    816             }
    817         }
    818     } while (FALSE);
    819 
    820     if (negated) {
    821         result = !result;
    822     }
    823     return result;
    824 }
    825 
    826 
    827 AndConstraint*
    828 AndConstraint::add()
    829 {
    830     this->next = new AndConstraint();
    831     return this->next;
    832 }
    833 
    834 OrConstraint::OrConstraint() {
    835     childNode=NULL;
    836     next=NULL;
    837 }
    838 
    839 OrConstraint::OrConstraint(const OrConstraint& other) {
    840     if ( other.childNode == NULL ) {
    841         this->childNode = NULL;
    842     }
    843     else {
    844         this->childNode = new AndConstraint(*(other.childNode));
    845     }
    846     if (other.next == NULL ) {
    847         this->next = NULL;
    848     }
    849     else {
    850         this->next = new OrConstraint(*(other.next));
    851     }
    852 }
    853 
    854 OrConstraint::~OrConstraint() {
    855     if (childNode!=NULL) {
    856         delete childNode;
    857     }
    858     if (next!=NULL) {
    859         delete next;
    860     }
    861 }
    862 
    863 AndConstraint*
    864 OrConstraint::add()
    865 {
    866     OrConstraint *curOrConstraint=this;
    867     {
    868         while (curOrConstraint->next!=NULL) {
    869             curOrConstraint = curOrConstraint->next;
    870         }
    871         U_ASSERT(curOrConstraint->childNode == NULL);
    872         curOrConstraint->childNode = new AndConstraint();
    873     }
    874     return curOrConstraint->childNode;
    875 }
    876 
    877 UBool
    878 OrConstraint::isFulfilled(const IFixedDecimal &number) {
    879     OrConstraint* orRule=this;
    880     UBool result=FALSE;
    881 
    882     while (orRule!=NULL && !result) {
    883         result=TRUE;
    884         AndConstraint* andRule = orRule->childNode;
    885         while (andRule!=NULL && result) {
    886             result = andRule->isFulfilled(number);
    887             andRule=andRule->next;
    888         }
    889         orRule = orRule->next;
    890     }
    891 
    892     return result;
    893 }
    894 
    895 
    896 RuleChain::RuleChain(): fKeyword(), fNext(NULL), ruleHeader(NULL), fDecimalSamples(), fIntegerSamples(),
    897                         fDecimalSamplesUnbounded(FALSE), fIntegerSamplesUnbounded(FALSE) {
    898 }
    899 
    900 RuleChain::RuleChain(const RuleChain& other) :
    901         fKeyword(other.fKeyword), fNext(NULL), ruleHeader(NULL), fDecimalSamples(other.fDecimalSamples),
    902         fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded),
    903         fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded) {
    904     if (other.ruleHeader != NULL) {
    905         this->ruleHeader = new OrConstraint(*(other.ruleHeader));
    906     }
    907     if (other.fNext != NULL ) {
    908         this->fNext = new RuleChain(*other.fNext);
    909     }
    910 }
    911 
    912 RuleChain::~RuleChain() {
    913     delete fNext;
    914     delete ruleHeader;
    915 }
    916 
    917 
    918 UnicodeString
    919 RuleChain::select(const IFixedDecimal &number) const {
    920     if (!number.isNaN() && !number.isInfinite()) {
    921         for (const RuleChain *rules = this; rules != NULL; rules = rules->fNext) {
    922              if (rules->ruleHeader->isFulfilled(number)) {
    923                  return rules->fKeyword;
    924              }
    925         }
    926     }
    927     return UnicodeString(TRUE, PLURAL_KEYWORD_OTHER, 5);
    928 }
    929 
    930 static UnicodeString tokenString(tokenType tok) {
    931     UnicodeString s;
    932     switch (tok) {
    933       case tVariableN:
    934         s.append(LOW_N); break;
    935       case tVariableI:
    936         s.append(LOW_I); break;
    937       case tVariableF:
    938         s.append(LOW_F); break;
    939       case tVariableV:
    940         s.append(LOW_V); break;
    941       case tVariableT:
    942         s.append(LOW_T); break;
    943       default:
    944         s.append(TILDE);
    945     }
    946     return s;
    947 }
    948 
    949 void
    950 RuleChain::dumpRules(UnicodeString& result) {
    951     UChar digitString[16];
    952 
    953     if ( ruleHeader != NULL ) {
    954         result +=  fKeyword;
    955         result += COLON;
    956         result += SPACE;
    957         OrConstraint* orRule=ruleHeader;
    958         while ( orRule != NULL ) {
    959             AndConstraint* andRule=orRule->childNode;
    960             while ( andRule != NULL ) {
    961                 if ((andRule->op==AndConstraint::NONE) &&  (andRule->rangeList==NULL) && (andRule->value == -1)) {
    962                     // Empty Rules.
    963                 } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==NULL) ) {
    964                     result += tokenString(andRule->digitsType);
    965                     result += UNICODE_STRING_SIMPLE(" is ");
    966                     if (andRule->negated) {
    967                         result += UNICODE_STRING_SIMPLE("not ");
    968                     }
    969                     uprv_itou(digitString,16, andRule->value,10,0);
    970                     result += UnicodeString(digitString);
    971                 }
    972                 else {
    973                     result += tokenString(andRule->digitsType);
    974                     result += SPACE;
    975                     if (andRule->op==AndConstraint::MOD) {
    976                         result += UNICODE_STRING_SIMPLE("mod ");
    977                         uprv_itou(digitString,16, andRule->opNum,10,0);
    978                         result += UnicodeString(digitString);
    979                     }
    980                     if (andRule->rangeList==NULL) {
    981                         if (andRule->negated) {
    982                             result += UNICODE_STRING_SIMPLE(" is not ");
    983                             uprv_itou(digitString,16, andRule->value,10,0);
    984                             result += UnicodeString(digitString);
    985                         }
    986                         else {
    987                             result += UNICODE_STRING_SIMPLE(" is ");
    988                             uprv_itou(digitString,16, andRule->value,10,0);
    989                             result += UnicodeString(digitString);
    990                         }
    991                     }
    992                     else {
    993                         if (andRule->negated) {
    994                             if ( andRule->integerOnly ) {
    995                                 result += UNICODE_STRING_SIMPLE(" not in ");
    996                             }
    997                             else {
    998                                 result += UNICODE_STRING_SIMPLE(" not within ");
    999                             }
   1000                         }
   1001                         else {
   1002                             if ( andRule->integerOnly ) {
   1003                                 result += UNICODE_STRING_SIMPLE(" in ");
   1004                             }
   1005                             else {
   1006                                 result += UNICODE_STRING_SIMPLE(" within ");
   1007                             }
   1008                         }
   1009                         for (int32_t r=0; r<andRule->rangeList->size(); r+=2) {
   1010                             int32_t rangeLo = andRule->rangeList->elementAti(r);
   1011                             int32_t rangeHi = andRule->rangeList->elementAti(r+1);
   1012                             uprv_itou(digitString,16, rangeLo, 10, 0);
   1013                             result += UnicodeString(digitString);
   1014                             result += UNICODE_STRING_SIMPLE("..");
   1015                             uprv_itou(digitString,16, rangeHi, 10,0);
   1016                             result += UnicodeString(digitString);
   1017                             if (r+2 < andRule->rangeList->size()) {
   1018                                 result += UNICODE_STRING_SIMPLE(", ");
   1019                             }
   1020                         }
   1021                     }
   1022                 }
   1023                 if ( (andRule=andRule->next) != NULL) {
   1024                     result += UNICODE_STRING_SIMPLE(" and ");
   1025                 }
   1026             }
   1027             if ( (orRule = orRule->next) != NULL ) {
   1028                 result += UNICODE_STRING_SIMPLE(" or ");
   1029             }
   1030         }
   1031     }
   1032     if ( fNext != NULL ) {
   1033         result += UNICODE_STRING_SIMPLE("; ");
   1034         fNext->dumpRules(result);
   1035     }
   1036 }
   1037 
   1038 
   1039 UErrorCode
   1040 RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
   1041     if ( arraySize < capacityOfKeywords-1 ) {
   1042         keywords[arraySize++]=fKeyword;
   1043     }
   1044     else {
   1045         return U_BUFFER_OVERFLOW_ERROR;
   1046     }
   1047 
   1048     if ( fNext != NULL ) {
   1049         return fNext->getKeywords(capacityOfKeywords, keywords, arraySize);
   1050     }
   1051     else {
   1052         return U_ZERO_ERROR;
   1053     }
   1054 }
   1055 
   1056 UBool
   1057 RuleChain::isKeyword(const UnicodeString& keywordParam) const {
   1058     if ( fKeyword == keywordParam ) {
   1059         return TRUE;
   1060     }
   1061 
   1062     if ( fNext != NULL ) {
   1063         return fNext->isKeyword(keywordParam);
   1064     }
   1065     else {
   1066         return FALSE;
   1067     }
   1068 }
   1069 
   1070 
   1071 PluralRuleParser::PluralRuleParser() :
   1072         ruleIndex(0), token(), type(none), prevType(none),
   1073         curAndConstraint(NULL), currentChain(NULL), rangeLowIdx(-1), rangeHiIdx(-1)
   1074 {
   1075 }
   1076 
   1077 PluralRuleParser::~PluralRuleParser() {
   1078 }
   1079 
   1080 
   1081 int32_t
   1082 PluralRuleParser::getNumberValue(const UnicodeString& token) {
   1083     int32_t i;
   1084     char digits[128];
   1085 
   1086     i = token.extract(0, token.length(), digits, UPRV_LENGTHOF(digits), US_INV);
   1087     digits[i]='\0';
   1088 
   1089     return((int32_t)atoi(digits));
   1090 }
   1091 
   1092 
   1093 void
   1094 PluralRuleParser::checkSyntax(UErrorCode &status)
   1095 {
   1096     if (U_FAILURE(status)) {
   1097         return;
   1098     }
   1099     if (!(prevType==none || prevType==tSemiColon)) {
   1100         type = getKeyType(token, type);  // Switch token type from tKeyword if we scanned a reserved word,
   1101                                                //   and we are not at the start of a rule, where a
   1102                                                //   keyword is expected.
   1103     }
   1104 
   1105     switch(prevType) {
   1106     case none:
   1107     case tSemiColon:
   1108         if (type!=tKeyword && type != tEOF) {
   1109             status = U_UNEXPECTED_TOKEN;
   1110         }
   1111         break;
   1112     case tVariableN:
   1113     case tVariableI:
   1114     case tVariableF:
   1115     case tVariableT:
   1116     case tVariableV:
   1117         if (type != tIs && type != tMod && type != tIn &&
   1118             type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
   1119             status = U_UNEXPECTED_TOKEN;
   1120         }
   1121         break;
   1122     case tKeyword:
   1123         if (type != tColon) {
   1124             status = U_UNEXPECTED_TOKEN;
   1125         }
   1126         break;
   1127     case tColon:
   1128         if (!(type == tVariableN ||
   1129               type == tVariableI ||
   1130               type == tVariableF ||
   1131               type == tVariableT ||
   1132               type == tVariableV ||
   1133               type == tAt)) {
   1134             status = U_UNEXPECTED_TOKEN;
   1135         }
   1136         break;
   1137     case tIs:
   1138         if ( type != tNumber && type != tNot) {
   1139             status = U_UNEXPECTED_TOKEN;
   1140         }
   1141         break;
   1142     case tNot:
   1143         if (type != tNumber && type != tIn && type != tWithin) {
   1144             status = U_UNEXPECTED_TOKEN;
   1145         }
   1146         break;
   1147     case tMod:
   1148     case tDot2:
   1149     case tIn:
   1150     case tWithin:
   1151     case tEqual:
   1152     case tNotEqual:
   1153         if (type != tNumber) {
   1154             status = U_UNEXPECTED_TOKEN;
   1155         }
   1156         break;
   1157     case tAnd:
   1158     case tOr:
   1159         if ( type != tVariableN &&
   1160              type != tVariableI &&
   1161              type != tVariableF &&
   1162              type != tVariableT &&
   1163              type != tVariableV) {
   1164             status = U_UNEXPECTED_TOKEN;
   1165         }
   1166         break;
   1167     case tComma:
   1168         if (type != tNumber) {
   1169             status = U_UNEXPECTED_TOKEN;
   1170         }
   1171         break;
   1172     case tNumber:
   1173         if (type != tDot2  && type != tSemiColon && type != tIs       && type != tNot    &&
   1174             type != tIn    && type != tEqual     && type != tNotEqual && type != tWithin &&
   1175             type != tAnd   && type != tOr        && type != tComma    && type != tAt     &&
   1176             type != tEOF)
   1177         {
   1178             status = U_UNEXPECTED_TOKEN;
   1179         }
   1180         // TODO: a comma following a number that is not part of a range will be allowed.
   1181         //       It's not the only case of this sort of thing. Parser needs a re-write.
   1182         break;
   1183     case tAt:
   1184         if (type != tDecimal && type != tInteger) {
   1185             status = U_UNEXPECTED_TOKEN;
   1186         }
   1187         break;
   1188     default:
   1189         status = U_UNEXPECTED_TOKEN;
   1190         break;
   1191     }
   1192 }
   1193 
   1194 
   1195 /*
   1196  *  Scan the next token from the input rules.
   1197  *     rules and returned token type are in the parser state variables.
   1198  */
   1199 void
   1200 PluralRuleParser::getNextToken(UErrorCode &status)
   1201 {
   1202     if (U_FAILURE(status)) {
   1203         return;
   1204     }
   1205 
   1206     UChar ch;
   1207     while (ruleIndex < ruleSrc->length()) {
   1208         ch = ruleSrc->charAt(ruleIndex);
   1209         type = charType(ch);
   1210         if (type != tSpace) {
   1211             break;
   1212         }
   1213         ++(ruleIndex);
   1214     }
   1215     if (ruleIndex >= ruleSrc->length()) {
   1216         type = tEOF;
   1217         return;
   1218     }
   1219     int32_t curIndex= ruleIndex;
   1220 
   1221     switch (type) {
   1222       case tColon:
   1223       case tSemiColon:
   1224       case tComma:
   1225       case tEllipsis:
   1226       case tTilde:   // scanned '~'
   1227       case tAt:      // scanned '@'
   1228       case tEqual:   // scanned '='
   1229       case tMod:     // scanned '%'
   1230         // Single character tokens.
   1231         ++curIndex;
   1232         break;
   1233 
   1234       case tNotEqual:  // scanned '!'
   1235         if (ruleSrc->charAt(curIndex+1) == EQUALS) {
   1236             curIndex += 2;
   1237         } else {
   1238             type = none;
   1239             curIndex += 1;
   1240         }
   1241         break;
   1242 
   1243       case tKeyword:
   1244          while (type == tKeyword && ++curIndex < ruleSrc->length()) {
   1245              ch = ruleSrc->charAt(curIndex);
   1246              type = charType(ch);
   1247          }
   1248          type = tKeyword;
   1249          break;
   1250 
   1251       case tNumber:
   1252          while (type == tNumber && ++curIndex < ruleSrc->length()) {
   1253              ch = ruleSrc->charAt(curIndex);
   1254              type = charType(ch);
   1255          }
   1256          type = tNumber;
   1257          break;
   1258 
   1259        case tDot:
   1260          // We could be looking at either ".." in a range, or "..." at the end of a sample.
   1261          if (curIndex+1 >= ruleSrc->length() || ruleSrc->charAt(curIndex+1) != DOT) {
   1262              ++curIndex;
   1263              break; // Single dot
   1264          }
   1265          if (curIndex+2 >= ruleSrc->length() || ruleSrc->charAt(curIndex+2) != DOT) {
   1266              curIndex += 2;
   1267              type = tDot2;
   1268              break; // double dot
   1269          }
   1270          type = tEllipsis;
   1271          curIndex += 3;
   1272          break;     // triple dot
   1273 
   1274        default:
   1275          status = U_UNEXPECTED_TOKEN;
   1276          ++curIndex;
   1277          break;
   1278     }
   1279 
   1280     U_ASSERT(ruleIndex <= ruleSrc->length());
   1281     U_ASSERT(curIndex <= ruleSrc->length());
   1282     token=UnicodeString(*ruleSrc, ruleIndex, curIndex-ruleIndex);
   1283     ruleIndex = curIndex;
   1284 }
   1285 
   1286 tokenType
   1287 PluralRuleParser::charType(UChar ch) {
   1288     if ((ch>=U_ZERO) && (ch<=U_NINE)) {
   1289         return tNumber;
   1290     }
   1291     if (ch>=LOW_A && ch<=LOW_Z) {
   1292         return tKeyword;
   1293     }
   1294     switch (ch) {
   1295     case COLON:
   1296         return tColon;
   1297     case SPACE:
   1298         return tSpace;
   1299     case SEMI_COLON:
   1300         return tSemiColon;
   1301     case DOT:
   1302         return tDot;
   1303     case COMMA:
   1304         return tComma;
   1305     case EXCLAMATION:
   1306         return tNotEqual;
   1307     case EQUALS:
   1308         return tEqual;
   1309     case PERCENT_SIGN:
   1310         return tMod;
   1311     case AT:
   1312         return tAt;
   1313     case ELLIPSIS:
   1314         return tEllipsis;
   1315     case TILDE:
   1316         return tTilde;
   1317     default :
   1318         return none;
   1319     }
   1320 }
   1321 
   1322 
   1323 //  Set token type for reserved words in the Plural Rule syntax.
   1324 
   1325 tokenType
   1326 PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
   1327 {
   1328     if (keyType != tKeyword) {
   1329         return keyType;
   1330     }
   1331 
   1332     if (0 == token.compare(PK_VAR_N, 1)) {
   1333         keyType = tVariableN;
   1334     } else if (0 == token.compare(PK_VAR_I, 1)) {
   1335         keyType = tVariableI;
   1336     } else if (0 == token.compare(PK_VAR_F, 1)) {
   1337         keyType = tVariableF;
   1338     } else if (0 == token.compare(PK_VAR_T, 1)) {
   1339         keyType = tVariableT;
   1340     } else if (0 == token.compare(PK_VAR_V, 1)) {
   1341         keyType = tVariableV;
   1342     } else if (0 == token.compare(PK_IS, 2)) {
   1343         keyType = tIs;
   1344     } else if (0 == token.compare(PK_AND, 3)) {
   1345         keyType = tAnd;
   1346     } else if (0 == token.compare(PK_IN, 2)) {
   1347         keyType = tIn;
   1348     } else if (0 == token.compare(PK_WITHIN, 6)) {
   1349         keyType = tWithin;
   1350     } else if (0 == token.compare(PK_NOT, 3)) {
   1351         keyType = tNot;
   1352     } else if (0 == token.compare(PK_MOD, 3)) {
   1353         keyType = tMod;
   1354     } else if (0 == token.compare(PK_OR, 2)) {
   1355         keyType = tOr;
   1356     } else if (0 == token.compare(PK_DECIMAL, 7)) {
   1357         keyType = tDecimal;
   1358     } else if (0 == token.compare(PK_INTEGER, 7)) {
   1359         keyType = tInteger;
   1360     }
   1361     return keyType;
   1362 }
   1363 
   1364 
   1365 PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode& status)
   1366         : pos(0), fKeywordNames(status) {
   1367     if (U_FAILURE(status)) {
   1368         return;
   1369     }
   1370     fKeywordNames.setDeleter(uprv_deleteUObject);
   1371     UBool  addKeywordOther=TRUE;
   1372     RuleChain *node=header;
   1373     while(node!=NULL) {
   1374         fKeywordNames.addElement(new UnicodeString(node->fKeyword), status);
   1375         if (U_FAILURE(status)) {
   1376             return;
   1377         }
   1378         if (0 == node->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
   1379             addKeywordOther= FALSE;
   1380         }
   1381         node=node->fNext;
   1382     }
   1383 
   1384     if (addKeywordOther) {
   1385         fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status);
   1386     }
   1387 }
   1388 
   1389 const UnicodeString*
   1390 PluralKeywordEnumeration::snext(UErrorCode& status) {
   1391     if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
   1392         return (const UnicodeString*)fKeywordNames.elementAt(pos++);
   1393     }
   1394     return NULL;
   1395 }
   1396 
   1397 void
   1398 PluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
   1399     pos=0;
   1400 }
   1401 
   1402 int32_t
   1403 PluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
   1404        return fKeywordNames.size();
   1405 }
   1406 
   1407 PluralKeywordEnumeration::~PluralKeywordEnumeration() {
   1408 }
   1409 
   1410 PluralOperand tokenTypeToPluralOperand(tokenType tt) {
   1411     switch(tt) {
   1412     case tVariableN:
   1413         return PLURAL_OPERAND_N;
   1414     case tVariableI:
   1415         return PLURAL_OPERAND_I;
   1416     case tVariableF:
   1417         return PLURAL_OPERAND_F;
   1418     case tVariableV:
   1419         return PLURAL_OPERAND_V;
   1420     case tVariableT:
   1421         return PLURAL_OPERAND_T;
   1422     default:
   1423         U_ASSERT(FALSE);  // unexpected.
   1424         return PLURAL_OPERAND_N;
   1425     }
   1426 }
   1427 
   1428 IFixedDecimal::~IFixedDecimal() = default;
   1429 
   1430 FixedDecimal::FixedDecimal(const VisibleDigits &digits) {
   1431     digits.getFixedDecimal(
   1432             source, intValue, decimalDigits,
   1433             decimalDigitsWithoutTrailingZeros,
   1434             visibleDecimalDigitCount, hasIntegerValue);
   1435     isNegative = digits.isNegative();
   1436     _isNaN = digits.isNaN();
   1437     _isInfinite = digits.isInfinite();
   1438 }
   1439 
   1440 FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) {
   1441     init(n, v, f);
   1442     // check values. TODO make into unit test.
   1443     //
   1444     //            long visiblePower = (int) Math.pow(10, v);
   1445     //            if (decimalDigits > visiblePower) {
   1446     //                throw new IllegalArgumentException();
   1447     //            }
   1448     //            double fraction = intValue + (decimalDigits / (double) visiblePower);
   1449     //            if (fraction != source) {
   1450     //                double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source));
   1451     //                if (diff > 0.00000001d) {
   1452     //                    throw new IllegalArgumentException();
   1453     //                }
   1454     //            }
   1455 }
   1456 
   1457 FixedDecimal::FixedDecimal(double n, int32_t v) {
   1458     // Ugly, but for samples we don't care.
   1459     init(n, v, getFractionalDigits(n, v));
   1460 }
   1461 
   1462 FixedDecimal::FixedDecimal(double n) {
   1463     init(n);
   1464 }
   1465 
   1466 FixedDecimal::FixedDecimal() {
   1467     init(0, 0, 0);
   1468 }
   1469 
   1470 
   1471 // Create a FixedDecimal from a UnicodeString containing a number.
   1472 //    Inefficient, but only used for samples, so simplicity trumps efficiency.
   1473 
   1474 FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) {
   1475     CharString cs;
   1476     cs.appendInvariantChars(num, status);
   1477     DigitList dl;
   1478     dl.set(cs.toStringPiece(), status);
   1479     if (U_FAILURE(status)) {
   1480         init(0, 0, 0);
   1481         return;
   1482     }
   1483     int32_t decimalPoint = num.indexOf(DOT);
   1484     double n = dl.getDouble();
   1485     if (decimalPoint == -1) {
   1486         init(n, 0, 0);
   1487     } else {
   1488         int32_t v = num.length() - decimalPoint - 1;
   1489         init(n, v, getFractionalDigits(n, v));
   1490     }
   1491 }
   1492 
   1493 
   1494 FixedDecimal::FixedDecimal(const FixedDecimal &other) {
   1495     source = other.source;
   1496     visibleDecimalDigitCount = other.visibleDecimalDigitCount;
   1497     decimalDigits = other.decimalDigits;
   1498     decimalDigitsWithoutTrailingZeros = other.decimalDigitsWithoutTrailingZeros;
   1499     intValue = other.intValue;
   1500     hasIntegerValue = other.hasIntegerValue;
   1501     isNegative = other.isNegative;
   1502     _isNaN = other._isNaN;
   1503     _isInfinite = other._isInfinite;
   1504 }
   1505 
   1506 FixedDecimal::~FixedDecimal() = default;
   1507 
   1508 
   1509 void FixedDecimal::init(double n) {
   1510     int32_t numFractionDigits = decimals(n);
   1511     init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
   1512 }
   1513 
   1514 
   1515 void FixedDecimal::init(double n, int32_t v, int64_t f) {
   1516     isNegative = n < 0.0;
   1517     source = fabs(n);
   1518     _isNaN = uprv_isNaN(source);
   1519     _isInfinite = uprv_isInfinite(source);
   1520     if (_isNaN || _isInfinite) {
   1521         v = 0;
   1522         f = 0;
   1523         intValue = 0;
   1524         hasIntegerValue = FALSE;
   1525     } else {
   1526         intValue = (int64_t)source;
   1527         hasIntegerValue = (source == intValue);
   1528     }
   1529 
   1530     visibleDecimalDigitCount = v;
   1531     decimalDigits = f;
   1532     if (f == 0) {
   1533          decimalDigitsWithoutTrailingZeros = 0;
   1534     } else {
   1535         int64_t fdwtz = f;
   1536         while ((fdwtz%10) == 0) {
   1537             fdwtz /= 10;
   1538         }
   1539         decimalDigitsWithoutTrailingZeros = fdwtz;
   1540     }
   1541 }
   1542 
   1543 
   1544 //  Fast path only exact initialization. Return true if successful.
   1545 //     Note: Do not multiply by 10 each time through loop, rounding cruft can build
   1546 //           up that makes the check for an integer result fail.
   1547 //           A single multiply of the original number works more reliably.
   1548 static int32_t p10[] = {1, 10, 100, 1000, 10000};
   1549 UBool FixedDecimal::quickInit(double n) {
   1550     UBool success = FALSE;
   1551     n = fabs(n);
   1552     int32_t numFractionDigits;
   1553     for (numFractionDigits = 0; numFractionDigits <= 3; numFractionDigits++) {
   1554         double scaledN = n * p10[numFractionDigits];
   1555         if (scaledN == floor(scaledN)) {
   1556             success = TRUE;
   1557             break;
   1558         }
   1559     }
   1560     if (success) {
   1561         init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
   1562     }
   1563     return success;
   1564 }
   1565 
   1566 
   1567 
   1568 int32_t FixedDecimal::decimals(double n) {
   1569     // Count the number of decimal digits in the fraction part of the number, excluding trailing zeros.
   1570     // fastpath the common cases, integers or fractions with 3 or fewer digits
   1571     n = fabs(n);
   1572     for (int ndigits=0; ndigits<=3; ndigits++) {
   1573         double scaledN = n * p10[ndigits];
   1574         if (scaledN == floor(scaledN)) {
   1575             return ndigits;
   1576         }
   1577     }
   1578 
   1579     // Slow path, convert with sprintf, parse converted output.
   1580     char  buf[30] = {0};
   1581     sprintf(buf, "%1.15e", n);
   1582     // formatted number looks like this: 1.234567890123457e-01
   1583     int exponent = atoi(buf+18);
   1584     int numFractionDigits = 15;
   1585     for (int i=16; ; --i) {
   1586         if (buf[i] != '0') {
   1587             break;
   1588         }
   1589         --numFractionDigits;
   1590     }
   1591     numFractionDigits -= exponent;   // Fraction part of fixed point representation.
   1592     return numFractionDigits;
   1593 }
   1594 
   1595 
   1596 // Get the fraction digits of a double, represented as an integer.
   1597 //    v is the number of visible fraction digits in the displayed form of the number.
   1598 //       Example: n = 1001.234, v = 6, result = 234000
   1599 //    TODO: need to think through how this is used in the plural rule context.
   1600 //          This function can easily encounter integer overflow,
   1601 //          and can easily return noise digits when the precision of a double is exceeded.
   1602 
   1603 int64_t FixedDecimal::getFractionalDigits(double n, int32_t v) {
   1604     if (v == 0 || n == floor(n) || uprv_isNaN(n) || uprv_isPositiveInfinity(n)) {
   1605         return 0;
   1606     }
   1607     n = fabs(n);
   1608     double fract = n - floor(n);
   1609     switch (v) {
   1610       case 1: return (int64_t)(fract*10.0 + 0.5);
   1611       case 2: return (int64_t)(fract*100.0 + 0.5);
   1612       case 3: return (int64_t)(fract*1000.0 + 0.5);
   1613       default:
   1614           double scaled = floor(fract * pow(10.0, (double)v) + 0.5);
   1615           if (scaled > U_INT64_MAX) {
   1616               return U_INT64_MAX;
   1617           } else {
   1618               return (int64_t)scaled;
   1619           }
   1620       }
   1621 }
   1622 
   1623 
   1624 void FixedDecimal::adjustForMinFractionDigits(int32_t minFractionDigits) {
   1625     int32_t numTrailingFractionZeros = minFractionDigits - visibleDecimalDigitCount;
   1626     if (numTrailingFractionZeros > 0) {
   1627         for (int32_t i=0; i<numTrailingFractionZeros; i++) {
   1628             // Do not let the decimalDigits value overflow if there are many trailing zeros.
   1629             // Limit the value to 18 digits, the most that a 64 bit int can fully represent.
   1630             if (decimalDigits >= 100000000000000000LL) {
   1631                 break;
   1632             }
   1633             decimalDigits *= 10;
   1634         }
   1635         visibleDecimalDigitCount += numTrailingFractionZeros;
   1636     }
   1637 }
   1638 
   1639 
   1640 double FixedDecimal::getPluralOperand(PluralOperand operand) const {
   1641     switch(operand) {
   1642         case PLURAL_OPERAND_N: return source;
   1643         case PLURAL_OPERAND_I: return static_cast<double>(intValue);
   1644         case PLURAL_OPERAND_F: return static_cast<double>(decimalDigits);
   1645         case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
   1646         case PLURAL_OPERAND_V: return visibleDecimalDigitCount;
   1647         default:
   1648              U_ASSERT(FALSE);  // unexpected.
   1649              return source;
   1650     }
   1651 }
   1652 
   1653 bool FixedDecimal::isNaN() const {
   1654     return _isNaN;
   1655 }
   1656 
   1657 bool FixedDecimal::isInfinite() const {
   1658     return _isInfinite;
   1659 }
   1660 
   1661 bool FixedDecimal::isNanOrInfinity() const {
   1662     return _isNaN || _isInfinite;
   1663 }
   1664 
   1665 int32_t FixedDecimal::getVisibleFractionDigitCount() const {
   1666     return visibleDecimalDigitCount;
   1667 }
   1668 
   1669 
   1670 
   1671 PluralAvailableLocalesEnumeration::PluralAvailableLocalesEnumeration(UErrorCode &status) {
   1672     fLocales = NULL;
   1673     fRes = NULL;
   1674     fOpenStatus = status;
   1675     if (U_FAILURE(status)) {
   1676         return;
   1677     }
   1678     fOpenStatus = U_ZERO_ERROR;
   1679     LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &fOpenStatus));
   1680     fLocales = ures_getByKey(rb.getAlias(), "locales", NULL, &fOpenStatus);
   1681 }
   1682 
   1683 PluralAvailableLocalesEnumeration::~PluralAvailableLocalesEnumeration() {
   1684     ures_close(fLocales);
   1685     ures_close(fRes);
   1686     fLocales = NULL;
   1687     fRes = NULL;
   1688 }
   1689 
   1690 const char *PluralAvailableLocalesEnumeration::next(int32_t *resultLength, UErrorCode &status) {
   1691     if (U_FAILURE(status)) {
   1692         return NULL;
   1693     }
   1694     if (U_FAILURE(fOpenStatus)) {
   1695         status = fOpenStatus;
   1696         return NULL;
   1697     }
   1698     fRes = ures_getNextResource(fLocales, fRes, &status);
   1699     if (fRes == NULL || U_FAILURE(status)) {
   1700         if (status == U_INDEX_OUTOFBOUNDS_ERROR) {
   1701             status = U_ZERO_ERROR;
   1702         }
   1703         return NULL;
   1704     }
   1705     const char *result = ures_getKey(fRes);
   1706     if (resultLength != NULL) {
   1707         *resultLength = static_cast<int32_t>(uprv_strlen(result));
   1708     }
   1709     return result;
   1710 }
   1711 
   1712 
   1713 void PluralAvailableLocalesEnumeration::reset(UErrorCode &status) {
   1714     if (U_FAILURE(status)) {
   1715        return;
   1716     }
   1717     if (U_FAILURE(fOpenStatus)) {
   1718         status = fOpenStatus;
   1719         return;
   1720     }
   1721     ures_resetIterator(fLocales);
   1722 }
   1723 
   1724 int32_t PluralAvailableLocalesEnumeration::count(UErrorCode &status) const {
   1725     if (U_FAILURE(status)) {
   1726         return 0;
   1727     }
   1728     if (U_FAILURE(fOpenStatus)) {
   1729         status = fOpenStatus;
   1730         return 0;
   1731     }
   1732     return ures_getSize(fLocales);
   1733 }
   1734 
   1735 U_NAMESPACE_END
   1736 
   1737 
   1738 #endif /* #if !UCONFIG_NO_FORMATTING */
   1739 
   1740 //eof
   1741