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