1c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru/*
2c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru*******************************************************************************
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Copyright (C) 2007-2014, International Business Machines Corporation and
4c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru* others. All Rights Reserved.
5c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru*******************************************************************************
6c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru*
754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius* File plurrule.cpp
8c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru*/
9c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1059d709d503bab6e2b61931737e662dd293b40578ccornelius#include <math.h>
1159d709d503bab6e2b61931737e662dd293b40578ccornelius#include <stdio.h>
1259d709d503bab6e2b61931737e662dd293b40578ccornelius
13c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "unicode/utypes.h"
14b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/localpointer.h"
15c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "unicode/plurrule.h"
1654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "unicode/upluralrules.h"
17b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "unicode/ures.h"
1859d709d503bab6e2b61931737e662dd293b40578ccornelius#include "charstr.h"
19c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "cmemory.h"
20c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "cstring.h"
2159d709d503bab6e2b61931737e662dd293b40578ccornelius#include "digitlst.h"
22c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "hash.h"
2359d709d503bab6e2b61931737e662dd293b40578ccornelius#include "locutil.h"
24c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "mutex.h"
25b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "patternprops.h"
26c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "plurrule_impl.h"
27c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "putilimp.h"
28c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "ucln_in.h"
29c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#include "ustrfmt.h"
30103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#include "uassert.h"
3159d709d503bab6e2b61931737e662dd293b40578ccornelius#include "uvectr32.h"
32fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "sharedpluralrules.h"
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "lrucache.h"
34c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
35c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
36c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic icu::LRUCache *gPluralRulesCache = NULL;
38fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UMutex gPluralRulesCacheMutex = U_MUTEX_INITIALIZER;
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic icu::UInitOnce gPluralRulesCacheInitOnce = U_INITONCE_INITIALIZER;
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_CDECL_BEGIN
42fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic UBool U_CALLCONV plurrules_cleanup(void) {
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gPluralRulesCacheInitOnce.reset();
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (gPluralRulesCache) {
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete gPluralRulesCache;
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        gPluralRulesCache = NULL;
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_CDECL_END
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
52c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruU_NAMESPACE_BEGIN
53c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
54c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#define ARRAY_SIZE(array) (int32_t)(sizeof array  / sizeof array[0])
55c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
56c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PLURAL_KEYWORD_OTHER[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,0};
57c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PLURAL_DEFAULT_RULE[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,COLON,SPACE,LOW_N,0};
58c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_IN[]={LOW_I,LOW_N,0};
59c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_NOT[]={LOW_N,LOW_O,LOW_T,0};
60c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_IS[]={LOW_I,LOW_S,0};
61c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_MOD[]={LOW_M,LOW_O,LOW_D,0};
62c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_AND[]={LOW_A,LOW_N,LOW_D,0};
63c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_OR[]={LOW_O,LOW_R,0};
64c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_VAR_N[]={LOW_N,0};
6559d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic const UChar PK_VAR_I[]={LOW_I,0};
6659d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic const UChar PK_VAR_F[]={LOW_F,0};
6759d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic const UChar PK_VAR_T[]={LOW_T,0};
6859d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic const UChar PK_VAR_V[]={LOW_V,0};
69c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
7059d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic const UChar PK_DECIMAL[]={LOW_D,LOW_E,LOW_C,LOW_I,LOW_M,LOW_A,LOW_L,0};
7159d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic const UChar PK_INTEGER[]={LOW_I,LOW_N,LOW_T,LOW_E,LOW_G,LOW_E,LOW_R,0};
72c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
73c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules)
74c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
75c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
7659d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRules::PluralRules(UErrorCode& /*status*/)
77c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru:   UObject(),
7859d709d503bab6e2b61931737e662dd293b40578ccornelius    mRules(NULL)
79c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
80c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
81c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
82c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::PluralRules(const PluralRules& other)
83c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru: UObject(other),
8459d709d503bab6e2b61931737e662dd293b40578ccornelius    mRules(NULL)
85c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
86c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    *this=other;
87c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
88c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
89c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::~PluralRules() {
90c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    delete mRules;
91c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
92c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSharedPluralRules::~SharedPluralRules() {
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    delete ptr;
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
97c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules*
98c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::clone() const {
99c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return new PluralRules(*this);
100c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
101c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
102c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules&
103c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::operator=(const PluralRules& other) {
104c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (this != &other) {
105c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        delete mRules;
106c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        if (other.mRules==NULL) {
107c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            mRules = NULL;
108c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
109c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        else {
110c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            mRules = new RuleChain(*other.mRules);
111c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
112c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
113c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
114c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return *this;
115c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
116c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
11759d709d503bab6e2b61931737e662dd293b40578ccorneliusStringEnumeration* PluralRules::getAvailableLocales(UErrorCode &status) {
11859d709d503bab6e2b61931737e662dd293b40578ccornelius    StringEnumeration *result = new PluralAvailableLocalesEnumeration(status);
11959d709d503bab6e2b61931737e662dd293b40578ccornelius    if (result == NULL && U_SUCCESS(status)) {
12059d709d503bab6e2b61931737e662dd293b40578ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
12159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
12259d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
12359d709d503bab6e2b61931737e662dd293b40578ccornelius        delete result;
12459d709d503bab6e2b61931737e662dd293b40578ccornelius        result = NULL;
12559d709d503bab6e2b61931737e662dd293b40578ccornelius    }
12659d709d503bab6e2b61931737e662dd293b40578ccornelius    return result;
12759d709d503bab6e2b61931737e662dd293b40578ccornelius}
12859d709d503bab6e2b61931737e662dd293b40578ccornelius
12959d709d503bab6e2b61931737e662dd293b40578ccornelius
130c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules* U_EXPORT2
131c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
13559d709d503bab6e2b61931737e662dd293b40578ccornelius
13659d709d503bab6e2b61931737e662dd293b40578ccornelius    PluralRuleParser parser;
137c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    PluralRules *newRules = new PluralRules(status);
13859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_SUCCESS(status) && newRules == NULL) {
13959d709d503bab6e2b61931737e662dd293b40578ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
140c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
14159d709d503bab6e2b61931737e662dd293b40578ccornelius    parser.parse(description, newRules, status);
142c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (U_FAILURE(status)) {
143c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        delete newRules;
14459d709d503bab6e2b61931737e662dd293b40578ccornelius        newRules = NULL;
145c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
14659d709d503bab6e2b61931737e662dd293b40578ccornelius    return newRules;
147c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
148c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
14959d709d503bab6e2b61931737e662dd293b40578ccornelius
150c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules* U_EXPORT2
151c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::createDefaultRules(UErrorCode& status) {
152103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return createRules(UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1), status);
153c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
154c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
155fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/******************************************************************************/
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/* Create PluralRules cache */
157fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic SharedObject *U_CALLCONV createSharedPluralRules(
159fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *localeId, UErrorCode &status) {
160fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
162fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
163fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    PluralRules *pr = PluralRules::internalForLocale(
164fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            localeId, UPLURAL_TYPE_CARDINAL, status);
165fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
166fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
167fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SharedObject *result = new SharedPluralRules(pr);
169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (result == NULL) {
170fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete pr;
172fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
174fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return result;
175fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
176fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
177fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void U_CALLCONV pluralRulesCacheInit(UErrorCode &status) {
178fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    U_ASSERT(gPluralRulesCache == NULL);
179fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ucln_i18n_registerCleanup(UCLN_I18N_PLURAL_RULE, plurrules_cleanup);
180fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gPluralRulesCache = new SimpleLRUCache(100, &createSharedPluralRules, status);
181fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
182fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete gPluralRulesCache;
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        gPluralRulesCache = NULL;
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
186fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
187fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic void getSharedPluralRulesFromCache(
188fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *locale,
189fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const SharedPluralRules *&ptr,
190fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
191fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    umtx_initOnce(gPluralRulesCacheInitOnce, &pluralRulesCacheInit, status);
192fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
193fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
194fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
195fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    Mutex lock(&gPluralRulesCacheMutex);
196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    gPluralRulesCache->get(locale, ptr, status);
197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/* end plural rules cache */
203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/******************************************************************************/
204fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
205fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusconst SharedPluralRules* U_EXPORT2
206fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusPluralRules::createSharedInstance(
207fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const Locale& locale, UPluralType type, UErrorCode& status) {
208fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
209fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
210fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
211fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (type != UPLURAL_TYPE_CARDINAL) {
212fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_UNSUPPORTED_ERROR;
213fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
214fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
215fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const SharedPluralRules *result = NULL;
216fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    getSharedPluralRulesFromCache(locale.getName(), result, status);
217fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return result;
218fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
219fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
220c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules* U_EXPORT2
221c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::forLocale(const Locale& locale, UErrorCode& status) {
22254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return forLocale(locale, UPLURAL_TYPE_CARDINAL, status);
22354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
22454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
22554dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusPluralRules* U_EXPORT2
22654dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusPluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
227fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (type != UPLURAL_TYPE_CARDINAL) {
228fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return internalForLocale(locale, type, status);
229fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
230fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const SharedPluralRules *shared = createSharedInstance(
231fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            locale, type, status);
232fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
233fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
234fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
235fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    PluralRules *result = (*shared)->clone();
236fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    shared->removeRef();
237fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (result == NULL) {
238fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
239fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
240fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return result;
241fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
242fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
243fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusPluralRules* U_EXPORT2
244fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusPluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
24854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (type >= UPLURAL_TYPE_COUNT) {
24954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        status = U_ILLEGAL_ARGUMENT_ERROR;
25054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        return NULL;
25154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
252c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    PluralRules *newObj = new PluralRules(status);
253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (newObj==NULL || U_FAILURE(status)) {
254b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        delete newObj;
255c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return NULL;
256c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
25754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
25859d709d503bab6e2b61931737e662dd293b40578ccornelius    // TODO: which errors, if any, should be returned?
25959d709d503bab6e2b61931737e662dd293b40578ccornelius    if (locRule.length() == 0) {
26059d709d503bab6e2b61931737e662dd293b40578ccornelius        // Locales with no specific rules (all numbers have the "other" category
26159d709d503bab6e2b61931737e662dd293b40578ccornelius        //   will return a U_MISSING_RESOURCE_ERROR at this point. This is not
26259d709d503bab6e2b61931737e662dd293b40578ccornelius        //   an error.
26359d709d503bab6e2b61931737e662dd293b40578ccornelius        locRule =  UnicodeString(PLURAL_DEFAULT_RULE);
264c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        status = U_ZERO_ERROR;
265c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
26659d709d503bab6e2b61931737e662dd293b40578ccornelius    PluralRuleParser parser;
26759d709d503bab6e2b61931737e662dd293b40578ccornelius    parser.parse(locRule, newObj, status);
26859d709d503bab6e2b61931737e662dd293b40578ccornelius        //  TODO: should rule parse errors be returned, or
26959d709d503bab6e2b61931737e662dd293b40578ccornelius        //        should we silently use default rules?
27059d709d503bab6e2b61931737e662dd293b40578ccornelius        //        Original impl used default rules.
27159d709d503bab6e2b61931737e662dd293b40578ccornelius        //        Ask the question to ICU Core.
272b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
273c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return newObj;
274c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
275c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
276c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUnicodeString
277c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::select(int32_t number) const {
27859d709d503bab6e2b61931737e662dd293b40578ccornelius    return select(FixedDecimal(number));
279c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
280c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
281c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUnicodeString
282c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::select(double number) const {
28359d709d503bab6e2b61931737e662dd293b40578ccornelius    return select(FixedDecimal(number));
28459d709d503bab6e2b61931737e662dd293b40578ccornelius}
28559d709d503bab6e2b61931737e662dd293b40578ccornelius
28659d709d503bab6e2b61931737e662dd293b40578ccorneliusUnicodeString
28759d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRules::select(const FixedDecimal &number) const {
288c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (mRules == NULL) {
289103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1);
290c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
291c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
292c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return mRules->select(number);
293c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
294c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
295c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
296c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruStringEnumeration*
297c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::getKeywords(UErrorCode& status) const {
298c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (U_FAILURE(status))  return NULL;
299c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    StringEnumeration* nameEnumerator = new PluralKeywordEnumeration(mRules, status);
300b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
301b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho      delete nameEnumerator;
302b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho      return NULL;
303b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
305c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return nameEnumerator;
306c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
307c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
308b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehodouble
30959d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRules::getUniqueKeywordValue(const UnicodeString& /* keyword */) {
31059d709d503bab6e2b61931737e662dd293b40578ccornelius  // Not Implemented.
31159d709d503bab6e2b61931737e662dd293b40578ccornelius  return UPLRULES_NO_UNIQUE_VALUE;
312b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
313b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
314b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoint32_t
31559d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRules::getAllKeywordValues(const UnicodeString & /* keyword */, double * /* dest */,
31659d709d503bab6e2b61931737e662dd293b40578ccornelius                                 int32_t /* destCapacity */, UErrorCode& error) {
31759d709d503bab6e2b61931737e662dd293b40578ccornelius    error = U_UNSUPPORTED_ERROR;
31859d709d503bab6e2b61931737e662dd293b40578ccornelius    return 0;
319b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
320b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
32159d709d503bab6e2b61931737e662dd293b40578ccornelius
32259d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic double scaleForInt(double d) {
32359d709d503bab6e2b61931737e662dd293b40578ccornelius    double scale = 1.0;
32459d709d503bab6e2b61931737e662dd293b40578ccornelius    while (d != floor(d)) {
32559d709d503bab6e2b61931737e662dd293b40578ccornelius        d = d * 10.0;
32659d709d503bab6e2b61931737e662dd293b40578ccornelius        scale = scale * 10.0;
327b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
32859d709d503bab6e2b61931737e662dd293b40578ccornelius    return scale;
32959d709d503bab6e2b61931737e662dd293b40578ccornelius}
330b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
33159d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic int32_t
33259d709d503bab6e2b61931737e662dd293b40578ccorneliusgetSamplesFromString(const UnicodeString &samples, double *dest,
33359d709d503bab6e2b61931737e662dd293b40578ccornelius                        int32_t destCapacity, UErrorCode& status) {
33459d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t sampleCount = 0;
33559d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t sampleStartIdx = 0;
33659d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t sampleEndIdx = 0;
33759d709d503bab6e2b61931737e662dd293b40578ccornelius
33859d709d503bab6e2b61931737e662dd293b40578ccornelius    //std::string ss;  // TODO: debugging.
33959d709d503bab6e2b61931737e662dd293b40578ccornelius    // std::cout << "PluralRules::getSamples(), samples = \"" << samples.toUTF8String(ss) << "\"\n";
34059d709d503bab6e2b61931737e662dd293b40578ccornelius    for (sampleCount = 0; sampleCount < destCapacity && sampleStartIdx < samples.length(); ) {
34159d709d503bab6e2b61931737e662dd293b40578ccornelius        sampleEndIdx = samples.indexOf(COMMA, sampleStartIdx);
34259d709d503bab6e2b61931737e662dd293b40578ccornelius        if (sampleEndIdx == -1) {
34359d709d503bab6e2b61931737e662dd293b40578ccornelius            sampleEndIdx = samples.length();
34459d709d503bab6e2b61931737e662dd293b40578ccornelius        }
34559d709d503bab6e2b61931737e662dd293b40578ccornelius        const UnicodeString &sampleRange = samples.tempSubStringBetween(sampleStartIdx, sampleEndIdx);
34659d709d503bab6e2b61931737e662dd293b40578ccornelius        // ss.erase();
34759d709d503bab6e2b61931737e662dd293b40578ccornelius        // std::cout << "PluralRules::getSamples(), samplesRange = \"" << sampleRange.toUTF8String(ss) << "\"\n";
34859d709d503bab6e2b61931737e662dd293b40578ccornelius        int32_t tildeIndex = sampleRange.indexOf(TILDE);
34959d709d503bab6e2b61931737e662dd293b40578ccornelius        if (tildeIndex < 0) {
35059d709d503bab6e2b61931737e662dd293b40578ccornelius            FixedDecimal fixed(sampleRange, status);
35159d709d503bab6e2b61931737e662dd293b40578ccornelius            double sampleValue = fixed.source;
35259d709d503bab6e2b61931737e662dd293b40578ccornelius            if (fixed.visibleDecimalDigitCount == 0 || sampleValue != floor(sampleValue)) {
35359d709d503bab6e2b61931737e662dd293b40578ccornelius                dest[sampleCount++] = sampleValue;
35459d709d503bab6e2b61931737e662dd293b40578ccornelius            }
35559d709d503bab6e2b61931737e662dd293b40578ccornelius        } else {
35659d709d503bab6e2b61931737e662dd293b40578ccornelius
35759d709d503bab6e2b61931737e662dd293b40578ccornelius            FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
35859d709d503bab6e2b61931737e662dd293b40578ccornelius            FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
35959d709d503bab6e2b61931737e662dd293b40578ccornelius            double rangeLo = fixedLo.source;
36059d709d503bab6e2b61931737e662dd293b40578ccornelius            double rangeHi = fixedHi.source;
36159d709d503bab6e2b61931737e662dd293b40578ccornelius            if (U_FAILURE(status)) {
36259d709d503bab6e2b61931737e662dd293b40578ccornelius                break;
36359d709d503bab6e2b61931737e662dd293b40578ccornelius            }
36459d709d503bab6e2b61931737e662dd293b40578ccornelius            if (rangeHi < rangeLo) {
36559d709d503bab6e2b61931737e662dd293b40578ccornelius                status = U_INVALID_FORMAT_ERROR;
36659d709d503bab6e2b61931737e662dd293b40578ccornelius                break;
36759d709d503bab6e2b61931737e662dd293b40578ccornelius            }
368b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
36959d709d503bab6e2b61931737e662dd293b40578ccornelius            // For ranges of samples with fraction decimal digits, scale the number up so that we
37059d709d503bab6e2b61931737e662dd293b40578ccornelius            //   are adding one in the units place. Avoids roundoffs from repetitive adds of tenths.
371b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
37259d709d503bab6e2b61931737e662dd293b40578ccornelius            double scale = scaleForInt(rangeLo);
37359d709d503bab6e2b61931737e662dd293b40578ccornelius            double t = scaleForInt(rangeHi);
37459d709d503bab6e2b61931737e662dd293b40578ccornelius            if (t > scale) {
37559d709d503bab6e2b61931737e662dd293b40578ccornelius                scale = t;
37659d709d503bab6e2b61931737e662dd293b40578ccornelius            }
37759d709d503bab6e2b61931737e662dd293b40578ccornelius            rangeLo *= scale;
37859d709d503bab6e2b61931737e662dd293b40578ccornelius            rangeHi *= scale;
37959d709d503bab6e2b61931737e662dd293b40578ccornelius            for (double n=rangeLo; n<=rangeHi; n+=1) {
38059d709d503bab6e2b61931737e662dd293b40578ccornelius                // Hack Alert: don't return any decimal samples with integer values that
38159d709d503bab6e2b61931737e662dd293b40578ccornelius                //    originated from a format with trailing decimals.
38259d709d503bab6e2b61931737e662dd293b40578ccornelius                //    This API is returning doubles, which can't distinguish having displayed
38359d709d503bab6e2b61931737e662dd293b40578ccornelius                //    zeros to the right of the decimal.
38459d709d503bab6e2b61931737e662dd293b40578ccornelius                //    This results in test failures with values mapping back to a different keyword.
38559d709d503bab6e2b61931737e662dd293b40578ccornelius                double sampleValue = n/scale;
38659d709d503bab6e2b61931737e662dd293b40578ccornelius                if (!(sampleValue == floor(sampleValue) && fixedLo.visibleDecimalDigitCount > 0)) {
38759d709d503bab6e2b61931737e662dd293b40578ccornelius                    dest[sampleCount++] = sampleValue;
38859d709d503bab6e2b61931737e662dd293b40578ccornelius                }
38959d709d503bab6e2b61931737e662dd293b40578ccornelius                if (sampleCount >= destCapacity) {
39059d709d503bab6e2b61931737e662dd293b40578ccornelius                    break;
39159d709d503bab6e2b61931737e662dd293b40578ccornelius                }
39259d709d503bab6e2b61931737e662dd293b40578ccornelius            }
393b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
39459d709d503bab6e2b61931737e662dd293b40578ccornelius        sampleStartIdx = sampleEndIdx + 1;
395b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
39659d709d503bab6e2b61931737e662dd293b40578ccornelius    return sampleCount;
39759d709d503bab6e2b61931737e662dd293b40578ccornelius}
398b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
39959d709d503bab6e2b61931737e662dd293b40578ccornelius
40059d709d503bab6e2b61931737e662dd293b40578ccorneliusint32_t
40159d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRules::getSamples(const UnicodeString &keyword, double *dest,
40259d709d503bab6e2b61931737e662dd293b40578ccornelius                        int32_t destCapacity, UErrorCode& status) {
40359d709d503bab6e2b61931737e662dd293b40578ccornelius    RuleChain *rc = rulesForKeyword(keyword);
40459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (rc == NULL || destCapacity == 0 || U_FAILURE(status)) {
40559d709d503bab6e2b61931737e662dd293b40578ccornelius        return 0;
406b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
40759d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, dest, destCapacity, status);
40859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (numSamples == 0) {
40959d709d503bab6e2b61931737e662dd293b40578ccornelius        numSamples = getSamplesFromString(rc->fDecimalSamples, dest, destCapacity, status);
410b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
41159d709d503bab6e2b61931737e662dd293b40578ccornelius    return numSamples;
41259d709d503bab6e2b61931737e662dd293b40578ccornelius}
41359d709d503bab6e2b61931737e662dd293b40578ccornelius
41459d709d503bab6e2b61931737e662dd293b40578ccornelius
41559d709d503bab6e2b61931737e662dd293b40578ccorneliusRuleChain *PluralRules::rulesForKeyword(const UnicodeString &keyword) const {
41659d709d503bab6e2b61931737e662dd293b40578ccornelius    RuleChain *rc;
41759d709d503bab6e2b61931737e662dd293b40578ccornelius    for (rc = mRules; rc != NULL; rc = rc->fNext) {
41859d709d503bab6e2b61931737e662dd293b40578ccornelius        if (rc->fKeyword == keyword) {
41959d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
42059d709d503bab6e2b61931737e662dd293b40578ccornelius        }
42159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
42259d709d503bab6e2b61931737e662dd293b40578ccornelius    return rc;
423b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
424b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
425c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
426c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUBool
427c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::isKeyword(const UnicodeString& keyword) const {
428103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
429c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return true;
430c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
43159d709d503bab6e2b61931737e662dd293b40578ccornelius    return rulesForKeyword(keyword) != NULL;
432c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
433c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
434c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUnicodeString
435c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::getKeywordOther() const {
436103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    return UnicodeString(TRUE, PLURAL_KEYWORD_OTHER, 5);
437c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
438c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
439c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUBool
440c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralRules::operator==(const PluralRules& other) const  {
441c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    const UnicodeString *ptrKeyword;
442c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    UErrorCode status= U_ZERO_ERROR;
443c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
444c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if ( this == &other ) {
445c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return TRUE;
446c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
447b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    LocalPointer<StringEnumeration> myKeywordList(getKeywords(status));
448b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    LocalPointer<StringEnumeration> otherKeywordList(other.getKeywords(status));
449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return FALSE;
451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
452c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
453b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (myKeywordList->count(status)!=otherKeywordList->count(status)) {
454b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return FALSE;
455c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
456b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    myKeywordList->reset(status);
457b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    while ((ptrKeyword=myKeywordList->snext(status))!=NULL) {
458b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (!other.isKeyword(*ptrKeyword)) {
459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
461b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
462b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    otherKeywordList->reset(status);
463b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    while ((ptrKeyword=otherKeywordList->snext(status))!=NULL) {
464b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (!this->isKeyword(*ptrKeyword)) {
465c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            return FALSE;
466c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
467c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
468b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(status)) {
469b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return FALSE;
470b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
471c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
472c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return TRUE;
473c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
474c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
47559d709d503bab6e2b61931737e662dd293b40578ccornelius
476c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruvoid
47759d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErrorCode &status)
478c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
48259d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(ruleIndex == 0);    // Parsers are good for a single use only!
48359d709d503bab6e2b61931737e662dd293b40578ccornelius    ruleSrc = &ruleData;
48459d709d503bab6e2b61931737e662dd293b40578ccornelius
48559d709d503bab6e2b61931737e662dd293b40578ccornelius    while (ruleIndex< ruleSrc->length()) {
48659d709d503bab6e2b61931737e662dd293b40578ccornelius        getNextToken(status);
487c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        if (U_FAILURE(status)) {
488c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            return;
489c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
49059d709d503bab6e2b61931737e662dd293b40578ccornelius        checkSyntax(status);
491c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        if (U_FAILURE(status)) {
492c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            return;
493c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
494c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        switch (type) {
495c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tAnd:
496103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(curAndConstraint != NULL);
497c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            curAndConstraint = curAndConstraint->add();
498c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
499c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tOr:
50059d709d503bab6e2b61931737e662dd293b40578ccornelius            {
50159d709d503bab6e2b61931737e662dd293b40578ccornelius                U_ASSERT(currentChain != NULL);
50259d709d503bab6e2b61931737e662dd293b40578ccornelius                OrConstraint *orNode=currentChain->ruleHeader;
50359d709d503bab6e2b61931737e662dd293b40578ccornelius                while (orNode->next != NULL) {
50459d709d503bab6e2b61931737e662dd293b40578ccornelius                    orNode = orNode->next;
50559d709d503bab6e2b61931737e662dd293b40578ccornelius                }
50659d709d503bab6e2b61931737e662dd293b40578ccornelius                orNode->next= new OrConstraint();
50759d709d503bab6e2b61931737e662dd293b40578ccornelius                orNode=orNode->next;
50859d709d503bab6e2b61931737e662dd293b40578ccornelius                orNode->next=NULL;
50959d709d503bab6e2b61931737e662dd293b40578ccornelius                curAndConstraint = orNode->add();
510c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
511c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
512c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tIs:
513103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(curAndConstraint != NULL);
51459d709d503bab6e2b61931737e662dd293b40578ccornelius            U_ASSERT(curAndConstraint->value == -1);
51559d709d503bab6e2b61931737e662dd293b40578ccornelius            U_ASSERT(curAndConstraint->rangeList == NULL);
516c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
517c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tNot:
518103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(curAndConstraint != NULL);
51959d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->negated=TRUE;
520c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
52159d709d503bab6e2b61931737e662dd293b40578ccornelius
52259d709d503bab6e2b61931737e662dd293b40578ccornelius        case tNotEqual:
52359d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->negated=TRUE;
524c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tIn:
525c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tWithin:
52659d709d503bab6e2b61931737e662dd293b40578ccornelius        case tEqual:
527103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(curAndConstraint != NULL);
52859d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->rangeList = new UVector32(status);
52959d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->rangeList->addElement(-1, status);  // range Low
53059d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->rangeList->addElement(-1, status);  // range Hi
53159d709d503bab6e2b61931737e662dd293b40578ccornelius            rangeLowIdx = 0;
53259d709d503bab6e2b61931737e662dd293b40578ccornelius            rangeHiIdx  = 1;
53359d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->value=PLURAL_RANGE_HIGH;
53459d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->integerOnly = (type != tWithin);
535c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
536c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tNumber:
537103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(curAndConstraint != NULL);
538c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if ( (curAndConstraint->op==AndConstraint::MOD)&&
539c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                 (curAndConstraint->opNum == -1 ) ) {
540c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                curAndConstraint->opNum=getNumberValue(token);
541c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
542c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            else {
54359d709d503bab6e2b61931737e662dd293b40578ccornelius                if (curAndConstraint->rangeList == NULL) {
54459d709d503bab6e2b61931737e662dd293b40578ccornelius                    // this is for an 'is' rule
54559d709d503bab6e2b61931737e662dd293b40578ccornelius                    curAndConstraint->value = getNumberValue(token);
54659d709d503bab6e2b61931737e662dd293b40578ccornelius                } else {
54759d709d503bab6e2b61931737e662dd293b40578ccornelius                    // this is for an 'in' or 'within' rule
54859d709d503bab6e2b61931737e662dd293b40578ccornelius                    if (curAndConstraint->rangeList->elementAti(rangeLowIdx) == -1) {
54959d709d503bab6e2b61931737e662dd293b40578ccornelius                        curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeLowIdx);
55059d709d503bab6e2b61931737e662dd293b40578ccornelius                        curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeHiIdx);
55159d709d503bab6e2b61931737e662dd293b40578ccornelius                    }
55259d709d503bab6e2b61931737e662dd293b40578ccornelius                    else {
55359d709d503bab6e2b61931737e662dd293b40578ccornelius                        curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeHiIdx);
55459d709d503bab6e2b61931737e662dd293b40578ccornelius                        if (curAndConstraint->rangeList->elementAti(rangeLowIdx) >
55559d709d503bab6e2b61931737e662dd293b40578ccornelius                                curAndConstraint->rangeList->elementAti(rangeHiIdx)) {
55659d709d503bab6e2b61931737e662dd293b40578ccornelius                            // Range Lower bound > Range Upper bound.
55759d709d503bab6e2b61931737e662dd293b40578ccornelius                            // U_UNEXPECTED_TOKEN seems a little funny, but it is consistently
55859d709d503bab6e2b61931737e662dd293b40578ccornelius                            // used for all plural rule parse errors.
55959d709d503bab6e2b61931737e662dd293b40578ccornelius                            status = U_UNEXPECTED_TOKEN;
56059d709d503bab6e2b61931737e662dd293b40578ccornelius                            break;
56159d709d503bab6e2b61931737e662dd293b40578ccornelius                        }
56259d709d503bab6e2b61931737e662dd293b40578ccornelius                    }
563c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
564c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
565c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
56659d709d503bab6e2b61931737e662dd293b40578ccornelius        case tComma:
56759d709d503bab6e2b61931737e662dd293b40578ccornelius            // TODO: rule syntax checking is inadequate, can happen with badly formed rules.
56859d709d503bab6e2b61931737e662dd293b40578ccornelius            //       Catch cases like "n mod 10, is 1" here instead.
56959d709d503bab6e2b61931737e662dd293b40578ccornelius            if (curAndConstraint == NULL || curAndConstraint->rangeList == NULL) {
57059d709d503bab6e2b61931737e662dd293b40578ccornelius                status = U_UNEXPECTED_TOKEN;
57159d709d503bab6e2b61931737e662dd293b40578ccornelius                break;
57259d709d503bab6e2b61931737e662dd293b40578ccornelius            }
57359d709d503bab6e2b61931737e662dd293b40578ccornelius            U_ASSERT(curAndConstraint->rangeList->size() >= 2);
57459d709d503bab6e2b61931737e662dd293b40578ccornelius            rangeLowIdx = curAndConstraint->rangeList->size();
57559d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->rangeList->addElement(-1, status);  // range Low
57659d709d503bab6e2b61931737e662dd293b40578ccornelius            rangeHiIdx = curAndConstraint->rangeList->size();
57759d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->rangeList->addElement(-1, status);  // range Hi
57859d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
579c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tMod:
580103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(curAndConstraint != NULL);
581c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            curAndConstraint->op=AndConstraint::MOD;
582c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
58359d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableN:
58459d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableI:
58559d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableF:
58659d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableT:
58759d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableV:
58859d709d503bab6e2b61931737e662dd293b40578ccornelius            U_ASSERT(curAndConstraint != NULL);
58959d709d503bab6e2b61931737e662dd293b40578ccornelius            curAndConstraint->digitsType = type;
59059d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
591c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        case tKeyword:
59259d709d503bab6e2b61931737e662dd293b40578ccornelius            {
59359d709d503bab6e2b61931737e662dd293b40578ccornelius            RuleChain *newChain = new RuleChain;
59459d709d503bab6e2b61931737e662dd293b40578ccornelius            if (newChain == NULL) {
59559d709d503bab6e2b61931737e662dd293b40578ccornelius                status = U_MEMORY_ALLOCATION_ERROR;
59659d709d503bab6e2b61931737e662dd293b40578ccornelius                break;
597c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
59859d709d503bab6e2b61931737e662dd293b40578ccornelius            newChain->fKeyword = token;
59959d709d503bab6e2b61931737e662dd293b40578ccornelius            if (prules->mRules == NULL) {
60059d709d503bab6e2b61931737e662dd293b40578ccornelius                prules->mRules = newChain;
60159d709d503bab6e2b61931737e662dd293b40578ccornelius            } else {
60259d709d503bab6e2b61931737e662dd293b40578ccornelius                // The new rule chain goes at the end of the linked list of rule chains,
60359d709d503bab6e2b61931737e662dd293b40578ccornelius                //   unless there is an "other" keyword & chain. "other" must remain last.
60459d709d503bab6e2b61931737e662dd293b40578ccornelius                RuleChain *insertAfter = prules->mRules;
60559d709d503bab6e2b61931737e662dd293b40578ccornelius                while (insertAfter->fNext!=NULL &&
60659d709d503bab6e2b61931737e662dd293b40578ccornelius                       insertAfter->fNext->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5) != 0 ){
60759d709d503bab6e2b61931737e662dd293b40578ccornelius                    insertAfter=insertAfter->fNext;
608c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
60959d709d503bab6e2b61931737e662dd293b40578ccornelius                newChain->fNext = insertAfter->fNext;
61059d709d503bab6e2b61931737e662dd293b40578ccornelius                insertAfter->fNext = newChain;
611b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
61259d709d503bab6e2b61931737e662dd293b40578ccornelius            OrConstraint *orNode = new OrConstraint();
61359d709d503bab6e2b61931737e662dd293b40578ccornelius            newChain->ruleHeader = orNode;
614c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            curAndConstraint = orNode->add();
61559d709d503bab6e2b61931737e662dd293b40578ccornelius            currentChain = newChain;
61659d709d503bab6e2b61931737e662dd293b40578ccornelius            }
617c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            break;
618c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
61959d709d503bab6e2b61931737e662dd293b40578ccornelius        case tInteger:
62059d709d503bab6e2b61931737e662dd293b40578ccornelius            for (;;) {
62159d709d503bab6e2b61931737e662dd293b40578ccornelius                getNextToken(status);
62259d709d503bab6e2b61931737e662dd293b40578ccornelius                if (U_FAILURE(status) || type == tSemiColon || type == tEOF || type == tAt) {
62359d709d503bab6e2b61931737e662dd293b40578ccornelius                    break;
624b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
62559d709d503bab6e2b61931737e662dd293b40578ccornelius                if (type == tEllipsis) {
62659d709d503bab6e2b61931737e662dd293b40578ccornelius                    currentChain->fIntegerSamplesUnbounded = TRUE;
62759d709d503bab6e2b61931737e662dd293b40578ccornelius                    continue;
62859d709d503bab6e2b61931737e662dd293b40578ccornelius                }
62959d709d503bab6e2b61931737e662dd293b40578ccornelius                currentChain->fIntegerSamples.append(token);
630b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
63159d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
632b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
63359d709d503bab6e2b61931737e662dd293b40578ccornelius        case tDecimal:
63459d709d503bab6e2b61931737e662dd293b40578ccornelius            for (;;) {
63559d709d503bab6e2b61931737e662dd293b40578ccornelius                getNextToken(status);
63659d709d503bab6e2b61931737e662dd293b40578ccornelius                if (U_FAILURE(status) || type == tSemiColon || type == tEOF || type == tAt) {
637b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    break;
638b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
63959d709d503bab6e2b61931737e662dd293b40578ccornelius                if (type == tEllipsis) {
64059d709d503bab6e2b61931737e662dd293b40578ccornelius                    currentChain->fDecimalSamplesUnbounded = TRUE;
64159d709d503bab6e2b61931737e662dd293b40578ccornelius                    continue;
64259d709d503bab6e2b61931737e662dd293b40578ccornelius                }
64359d709d503bab6e2b61931737e662dd293b40578ccornelius                currentChain->fDecimalSamples.append(token);
644b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
64559d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
64659d709d503bab6e2b61931737e662dd293b40578ccornelius
64759d709d503bab6e2b61931737e662dd293b40578ccornelius        default:
64859d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
649b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
65059d709d503bab6e2b61931737e662dd293b40578ccornelius        prevType=type;
65159d709d503bab6e2b61931737e662dd293b40578ccornelius        if (U_FAILURE(status)) {
65259d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
653b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
654b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
655c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
656c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
657c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUnicodeString
65854dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusPluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& errCode) {
659c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    UnicodeString emptyStr;
660b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
661b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(errCode)) {
662b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return emptyStr;
663b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
66454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &errCode));
665c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if(U_FAILURE(errCode)) {
666c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return emptyStr;
667c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
66854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    const char *typeKey;
66954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    switch (type) {
67054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    case UPLURAL_TYPE_CARDINAL:
67154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        typeKey = "locales";
67254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        break;
67354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    case UPLURAL_TYPE_ORDINAL:
67454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        typeKey = "locales_ordinals";
67554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        break;
67654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    default:
67754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        // Must not occur: The caller should have checked for valid types.
67854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        errCode = U_ILLEGAL_ARGUMENT_ERROR;
67954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        return emptyStr;
68054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
68154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, NULL, &errCode));
682c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if(U_FAILURE(errCode)) {
683c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return emptyStr;
684b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
685c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    int32_t resLen=0;
686c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    const char *curLocaleName=locale.getName();
68754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode);
688c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
689c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (s == NULL) {
690c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        // Check parent locales.
691c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        UErrorCode status = U_ZERO_ERROR;
692c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        char parentLocaleName[ULOC_FULLNAME_CAPACITY];
693c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        const char *curLocaleName=locale.getName();
694c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        uprv_strcpy(parentLocaleName, curLocaleName);
695b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
69654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        while (uloc_getParent(parentLocaleName, parentLocaleName,
69754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                                       ULOC_FULLNAME_CAPACITY, &status) > 0) {
698c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            resLen=0;
69954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status);
700c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if (s != NULL) {
701c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                errCode = U_ZERO_ERROR;
702c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                break;
703c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
704c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_ZERO_ERROR;
705c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
706c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
707c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (s==NULL) {
708c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return emptyStr;
709c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
710b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
711c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    char setKey[256];
712c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    u_UCharsToChars(s, setKey, resLen + 1);
713c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    // printf("\n PluralRule: %s\n", setKey);
714b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
71554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", NULL, &errCode));
716c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if(U_FAILURE(errCode)) {
717c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return emptyStr;
718c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
71954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, NULL, &errCode));
720c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (U_FAILURE(errCode)) {
721c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return emptyStr;
722c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
723c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
72454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t numberKeys = ures_getSize(setRes.getAlias());
72559d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString result;
72659d709d503bab6e2b61931737e662dd293b40578ccornelius    const char *key=NULL;
72759d709d503bab6e2b61931737e662dd293b40578ccornelius    for(int32_t i=0; i<numberKeys; ++i) {   // Keys are zero, one, few, ...
72859d709d503bab6e2b61931737e662dd293b40578ccornelius        UnicodeString rules = ures_getNextUnicodeString(setRes.getAlias(), &key, &errCode);
72959d709d503bab6e2b61931737e662dd293b40578ccornelius        UnicodeString uKey(key, -1, US_INV);
73059d709d503bab6e2b61931737e662dd293b40578ccornelius        result.append(uKey);
73159d709d503bab6e2b61931737e662dd293b40578ccornelius        result.append(COLON);
73259d709d503bab6e2b61931737e662dd293b40578ccornelius        result.append(rules);
73359d709d503bab6e2b61931737e662dd293b40578ccornelius        result.append(SEMI_COLON);
73459d709d503bab6e2b61931737e662dd293b40578ccornelius    }
73559d709d503bab6e2b61931737e662dd293b40578ccornelius    return result;
736c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
737c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
73859d709d503bab6e2b61931737e662dd293b40578ccornelius
73959d709d503bab6e2b61931737e662dd293b40578ccorneliusUnicodeString
74059d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRules::getRules() const {
74159d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString rules;
74259d709d503bab6e2b61931737e662dd293b40578ccornelius    if (mRules != NULL) {
74359d709d503bab6e2b61931737e662dd293b40578ccornelius        mRules->dumpRules(rules);
74459d709d503bab6e2b61931737e662dd293b40578ccornelius    }
74559d709d503bab6e2b61931737e662dd293b40578ccornelius    return rules;
74659d709d503bab6e2b61931737e662dd293b40578ccornelius}
74759d709d503bab6e2b61931737e662dd293b40578ccornelius
74859d709d503bab6e2b61931737e662dd293b40578ccornelius
749c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruAndConstraint::AndConstraint() {
750c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    op = AndConstraint::NONE;
751c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    opNum=-1;
75259d709d503bab6e2b61931737e662dd293b40578ccornelius    value = -1;
75359d709d503bab6e2b61931737e662dd293b40578ccornelius    rangeList = NULL;
75459d709d503bab6e2b61931737e662dd293b40578ccornelius    negated = FALSE;
75559d709d503bab6e2b61931737e662dd293b40578ccornelius    integerOnly = FALSE;
75659d709d503bab6e2b61931737e662dd293b40578ccornelius    digitsType = none;
757c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    next=NULL;
758c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
759c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
760c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
761c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruAndConstraint::AndConstraint(const AndConstraint& other) {
762c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    this->op = other.op;
763c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    this->opNum=other.opNum;
76459d709d503bab6e2b61931737e662dd293b40578ccornelius    this->value=other.value;
76559d709d503bab6e2b61931737e662dd293b40578ccornelius    this->rangeList=NULL;
76659d709d503bab6e2b61931737e662dd293b40578ccornelius    if (other.rangeList != NULL) {
76759d709d503bab6e2b61931737e662dd293b40578ccornelius        UErrorCode status = U_ZERO_ERROR;
76859d709d503bab6e2b61931737e662dd293b40578ccornelius        this->rangeList = new UVector32(status);
76959d709d503bab6e2b61931737e662dd293b40578ccornelius        this->rangeList->assign(*other.rangeList, status);
77059d709d503bab6e2b61931737e662dd293b40578ccornelius    }
771c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    this->integerOnly=other.integerOnly;
77259d709d503bab6e2b61931737e662dd293b40578ccornelius    this->negated=other.negated;
77359d709d503bab6e2b61931737e662dd293b40578ccornelius    this->digitsType = other.digitsType;
774c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (other.next==NULL) {
775c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->next=NULL;
776c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
777c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
778c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->next = new AndConstraint(*other.next);
779c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
780c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
781c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
782c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruAndConstraint::~AndConstraint() {
78359d709d503bab6e2b61931737e662dd293b40578ccornelius    delete rangeList;
784c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (next!=NULL) {
785c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        delete next;
786c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
787c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
788c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
789c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
790c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUBool
79159d709d503bab6e2b61931737e662dd293b40578ccorneliusAndConstraint::isFulfilled(const FixedDecimal &number) {
79259d709d503bab6e2b61931737e662dd293b40578ccornelius    UBool result = TRUE;
79359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (digitsType == none) {
79459d709d503bab6e2b61931737e662dd293b40578ccornelius        // An empty AndConstraint, created by a rule with a keyword but no following expression.
79559d709d503bab6e2b61931737e662dd293b40578ccornelius        return TRUE;
796b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
79759d709d503bab6e2b61931737e662dd293b40578ccornelius    double n = number.get(digitsType);  // pulls n | i | v | f value for the number.
79859d709d503bab6e2b61931737e662dd293b40578ccornelius                                        // Will always be positive.
79959d709d503bab6e2b61931737e662dd293b40578ccornelius                                        // May be non-integer (n option only)
80059d709d503bab6e2b61931737e662dd293b40578ccornelius    do {
80159d709d503bab6e2b61931737e662dd293b40578ccornelius        if (integerOnly && n != uprv_floor(n)) {
80259d709d503bab6e2b61931737e662dd293b40578ccornelius            result = FALSE;
80359d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
80459d709d503bab6e2b61931737e662dd293b40578ccornelius        }
805b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
80659d709d503bab6e2b61931737e662dd293b40578ccornelius        if (op == MOD) {
80759d709d503bab6e2b61931737e662dd293b40578ccornelius            n = fmod(n, opNum);
808c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
80959d709d503bab6e2b61931737e662dd293b40578ccornelius        if (rangeList == NULL) {
81059d709d503bab6e2b61931737e662dd293b40578ccornelius            result = value == -1 ||    // empty rule
81159d709d503bab6e2b61931737e662dd293b40578ccornelius                     n == value;       //  'is' rule
81259d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
813c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
81459d709d503bab6e2b61931737e662dd293b40578ccornelius        result = FALSE;                // 'in' or 'within' rule
81559d709d503bab6e2b61931737e662dd293b40578ccornelius        for (int32_t r=0; r<rangeList->size(); r+=2) {
81659d709d503bab6e2b61931737e662dd293b40578ccornelius            if (rangeList->elementAti(r) <= n && n <= rangeList->elementAti(r+1)) {
817c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                result = TRUE;
81859d709d503bab6e2b61931737e662dd293b40578ccornelius                break;
819c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
820c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
82159d709d503bab6e2b61931737e662dd293b40578ccornelius    } while (FALSE);
822b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
82359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (negated) {
82459d709d503bab6e2b61931737e662dd293b40578ccornelius        result = !result;
825c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
82659d709d503bab6e2b61931737e662dd293b40578ccornelius    return result;
827c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
828c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
829c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
830c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruAndConstraint*
831c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruAndConstraint::add()
832c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
833c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    this->next = new AndConstraint();
834c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return this->next;
835c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
836c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
837c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruOrConstraint::OrConstraint() {
838c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    childNode=NULL;
839c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    next=NULL;
840c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
841c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
842c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruOrConstraint::OrConstraint(const OrConstraint& other) {
843c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if ( other.childNode == NULL ) {
844c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->childNode = NULL;
845c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
846c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
847c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->childNode = new AndConstraint(*(other.childNode));
848c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
849c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (other.next == NULL ) {
850c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->next = NULL;
851c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
852c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
853c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->next = new OrConstraint(*(other.next));
854c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
855c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
856c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
857c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruOrConstraint::~OrConstraint() {
858c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (childNode!=NULL) {
859c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        delete childNode;
860c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
861c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (next!=NULL) {
862c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        delete next;
863c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
864c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
865c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
866c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruAndConstraint*
867c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruOrConstraint::add()
868c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
869c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    OrConstraint *curOrConstraint=this;
870c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    {
871c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        while (curOrConstraint->next!=NULL) {
872c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            curOrConstraint = curOrConstraint->next;
873c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
87459d709d503bab6e2b61931737e662dd293b40578ccornelius        U_ASSERT(curOrConstraint->childNode == NULL);
875c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        curOrConstraint->childNode = new AndConstraint();
876c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
877c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return curOrConstraint->childNode;
878c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
879c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
880c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUBool
88159d709d503bab6e2b61931737e662dd293b40578ccorneliusOrConstraint::isFulfilled(const FixedDecimal &number) {
882c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    OrConstraint* orRule=this;
883c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    UBool result=FALSE;
884b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
885c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    while (orRule!=NULL && !result) {
886c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        result=TRUE;
887c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        AndConstraint* andRule = orRule->childNode;
888c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        while (andRule!=NULL && result) {
889c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            result = andRule->isFulfilled(number);
890c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            andRule=andRule->next;
891c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
892c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        orRule = orRule->next;
893c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
894b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
895c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return result;
896c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
897c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
898c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
89959d709d503bab6e2b61931737e662dd293b40578ccorneliusRuleChain::RuleChain(): fKeyword(), fNext(NULL), ruleHeader(NULL), fDecimalSamples(), fIntegerSamples(),
90059d709d503bab6e2b61931737e662dd293b40578ccornelius                        fDecimalSamplesUnbounded(FALSE), fIntegerSamplesUnbounded(FALSE) {
901c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
902c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
90359d709d503bab6e2b61931737e662dd293b40578ccorneliusRuleChain::RuleChain(const RuleChain& other) :
90459d709d503bab6e2b61931737e662dd293b40578ccornelius        fKeyword(other.fKeyword), fNext(NULL), ruleHeader(NULL), fDecimalSamples(other.fDecimalSamples),
90559d709d503bab6e2b61931737e662dd293b40578ccornelius        fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded),
90659d709d503bab6e2b61931737e662dd293b40578ccornelius        fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded) {
907c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (other.ruleHeader != NULL) {
908c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        this->ruleHeader = new OrConstraint(*(other.ruleHeader));
909c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
91059d709d503bab6e2b61931737e662dd293b40578ccornelius    if (other.fNext != NULL ) {
91159d709d503bab6e2b61931737e662dd293b40578ccornelius        this->fNext = new RuleChain(*other.fNext);
912c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
913c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
914c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
915c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruRuleChain::~RuleChain() {
91659d709d503bab6e2b61931737e662dd293b40578ccornelius    delete fNext;
91759d709d503bab6e2b61931737e662dd293b40578ccornelius    delete ruleHeader;
918c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
919c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
920b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
92159d709d503bab6e2b61931737e662dd293b40578ccorneliusUnicodeString
92259d709d503bab6e2b61931737e662dd293b40578ccorneliusRuleChain::select(const FixedDecimal &number) const {
92359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (!number.isNanOrInfinity) {
92459d709d503bab6e2b61931737e662dd293b40578ccornelius        for (const RuleChain *rules = this; rules != NULL; rules = rules->fNext) {
92559d709d503bab6e2b61931737e662dd293b40578ccornelius             if (rules->ruleHeader->isFulfilled(number)) {
92659d709d503bab6e2b61931737e662dd293b40578ccornelius                 return rules->fKeyword;
92759d709d503bab6e2b61931737e662dd293b40578ccornelius             }
92859d709d503bab6e2b61931737e662dd293b40578ccornelius        }
92959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
93059d709d503bab6e2b61931737e662dd293b40578ccornelius    return UnicodeString(TRUE, PLURAL_KEYWORD_OTHER, 5);
93159d709d503bab6e2b61931737e662dd293b40578ccornelius}
932c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
93359d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic UnicodeString tokenString(tokenType tok) {
93459d709d503bab6e2b61931737e662dd293b40578ccornelius    UnicodeString s;
93559d709d503bab6e2b61931737e662dd293b40578ccornelius    switch (tok) {
93659d709d503bab6e2b61931737e662dd293b40578ccornelius      case tVariableN:
93759d709d503bab6e2b61931737e662dd293b40578ccornelius        s.append(LOW_N); break;
93859d709d503bab6e2b61931737e662dd293b40578ccornelius      case tVariableI:
93959d709d503bab6e2b61931737e662dd293b40578ccornelius        s.append(LOW_I); break;
94059d709d503bab6e2b61931737e662dd293b40578ccornelius      case tVariableF:
94159d709d503bab6e2b61931737e662dd293b40578ccornelius        s.append(LOW_F); break;
94259d709d503bab6e2b61931737e662dd293b40578ccornelius      case tVariableV:
94359d709d503bab6e2b61931737e662dd293b40578ccornelius        s.append(LOW_V); break;
94459d709d503bab6e2b61931737e662dd293b40578ccornelius      case tVariableT:
94559d709d503bab6e2b61931737e662dd293b40578ccornelius        s.append(LOW_T); break;
94659d709d503bab6e2b61931737e662dd293b40578ccornelius      default:
94759d709d503bab6e2b61931737e662dd293b40578ccornelius        s.append(TILDE);
94859d709d503bab6e2b61931737e662dd293b40578ccornelius    }
94959d709d503bab6e2b61931737e662dd293b40578ccornelius    return s;
950c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
951c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
952c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruvoid
953c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruRuleChain::dumpRules(UnicodeString& result) {
954c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    UChar digitString[16];
955b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
956c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if ( ruleHeader != NULL ) {
95759d709d503bab6e2b61931737e662dd293b40578ccornelius        result +=  fKeyword;
95859d709d503bab6e2b61931737e662dd293b40578ccornelius        result += COLON;
95959d709d503bab6e2b61931737e662dd293b40578ccornelius        result += SPACE;
960c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        OrConstraint* orRule=ruleHeader;
961c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        while ( orRule != NULL ) {
962c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            AndConstraint* andRule=orRule->childNode;
963c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            while ( andRule != NULL ) {
96459d709d503bab6e2b61931737e662dd293b40578ccornelius                if ((andRule->op==AndConstraint::NONE) &&  (andRule->rangeList==NULL) && (andRule->value == -1)) {
96559d709d503bab6e2b61931737e662dd293b40578ccornelius                    // Empty Rules.
96659d709d503bab6e2b61931737e662dd293b40578ccornelius                } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==NULL) ) {
96759d709d503bab6e2b61931737e662dd293b40578ccornelius                    result += tokenString(andRule->digitsType);
96859d709d503bab6e2b61931737e662dd293b40578ccornelius                    result += UNICODE_STRING_SIMPLE(" is ");
96959d709d503bab6e2b61931737e662dd293b40578ccornelius                    if (andRule->negated) {
970c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        result += UNICODE_STRING_SIMPLE("not ");
971c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    }
97259d709d503bab6e2b61931737e662dd293b40578ccornelius                    uprv_itou(digitString,16, andRule->value,10,0);
973c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    result += UnicodeString(digitString);
974c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
975c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                else {
97659d709d503bab6e2b61931737e662dd293b40578ccornelius                    result += tokenString(andRule->digitsType);
97759d709d503bab6e2b61931737e662dd293b40578ccornelius                    result += SPACE;
978c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    if (andRule->op==AndConstraint::MOD) {
97959d709d503bab6e2b61931737e662dd293b40578ccornelius                        result += UNICODE_STRING_SIMPLE("mod ");
980c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        uprv_itou(digitString,16, andRule->opNum,10,0);
981c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        result += UnicodeString(digitString);
982c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    }
98359d709d503bab6e2b61931737e662dd293b40578ccornelius                    if (andRule->rangeList==NULL) {
98459d709d503bab6e2b61931737e662dd293b40578ccornelius                        if (andRule->negated) {
985c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            result += UNICODE_STRING_SIMPLE(" is not ");
98659d709d503bab6e2b61931737e662dd293b40578ccornelius                            uprv_itou(digitString,16, andRule->value,10,0);
987c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            result += UnicodeString(digitString);
988c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        }
989c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        else {
990c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            result += UNICODE_STRING_SIMPLE(" is ");
99159d709d503bab6e2b61931737e662dd293b40578ccornelius                            uprv_itou(digitString,16, andRule->value,10,0);
992c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            result += UnicodeString(digitString);
993c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        }
994c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    }
995c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    else {
99659d709d503bab6e2b61931737e662dd293b40578ccornelius                        if (andRule->negated) {
997c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            if ( andRule->integerOnly ) {
99859d709d503bab6e2b61931737e662dd293b40578ccornelius                                result += UNICODE_STRING_SIMPLE(" not in ");
999c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            }
1000c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            else {
100159d709d503bab6e2b61931737e662dd293b40578ccornelius                                result += UNICODE_STRING_SIMPLE(" not within ");
1002c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            }
1003c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        }
1004c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        else {
1005c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            if ( andRule->integerOnly ) {
1006c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                                result += UNICODE_STRING_SIMPLE(" in ");
1007c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            }
1008c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            else {
1009c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                                result += UNICODE_STRING_SIMPLE(" within ");
1010c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            }
101159d709d503bab6e2b61931737e662dd293b40578ccornelius                        }
101259d709d503bab6e2b61931737e662dd293b40578ccornelius                        for (int32_t r=0; r<andRule->rangeList->size(); r+=2) {
101359d709d503bab6e2b61931737e662dd293b40578ccornelius                            int32_t rangeLo = andRule->rangeList->elementAti(r);
101459d709d503bab6e2b61931737e662dd293b40578ccornelius                            int32_t rangeHi = andRule->rangeList->elementAti(r+1);
101559d709d503bab6e2b61931737e662dd293b40578ccornelius                            uprv_itou(digitString,16, rangeLo, 10, 0);
101659d709d503bab6e2b61931737e662dd293b40578ccornelius                            result += UnicodeString(digitString);
101759d709d503bab6e2b61931737e662dd293b40578ccornelius                            result += UNICODE_STRING_SIMPLE("..");
101859d709d503bab6e2b61931737e662dd293b40578ccornelius                            uprv_itou(digitString,16, rangeHi, 10,0);
1019c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                            result += UnicodeString(digitString);
102059d709d503bab6e2b61931737e662dd293b40578ccornelius                            if (r+2 < andRule->rangeList->size()) {
102159d709d503bab6e2b61931737e662dd293b40578ccornelius                                result += UNICODE_STRING_SIMPLE(", ");
102259d709d503bab6e2b61931737e662dd293b40578ccornelius                            }
1023c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        }
1024c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    }
1025c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
1026c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                if ( (andRule=andRule->next) != NULL) {
102759d709d503bab6e2b61931737e662dd293b40578ccornelius                    result += UNICODE_STRING_SIMPLE(" and ");
1028c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
1029c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
1030c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if ( (orRule = orRule->next) != NULL ) {
103159d709d503bab6e2b61931737e662dd293b40578ccornelius                result += UNICODE_STRING_SIMPLE(" or ");
1032c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
1033c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1034c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
103559d709d503bab6e2b61931737e662dd293b40578ccornelius    if ( fNext != NULL ) {
103659d709d503bab6e2b61931737e662dd293b40578ccornelius        result += UNICODE_STRING_SIMPLE("; ");
103759d709d503bab6e2b61931737e662dd293b40578ccornelius        fNext->dumpRules(result);
1038c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1039c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1040c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1041c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1042c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUErrorCode
1043c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruRuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
1044c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if ( arraySize < capacityOfKeywords-1 ) {
104559d709d503bab6e2b61931737e662dd293b40578ccornelius        keywords[arraySize++]=fKeyword;
1046c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1047c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
1048c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return U_BUFFER_OVERFLOW_ERROR;
1049c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1050c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
105159d709d503bab6e2b61931737e662dd293b40578ccornelius    if ( fNext != NULL ) {
105259d709d503bab6e2b61931737e662dd293b40578ccornelius        return fNext->getKeywords(capacityOfKeywords, keywords, arraySize);
1053c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1054c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
1055c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return U_ZERO_ERROR;
1056c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1057c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1058c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1059c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUBool
1060c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruRuleChain::isKeyword(const UnicodeString& keywordParam) const {
106159d709d503bab6e2b61931737e662dd293b40578ccornelius    if ( fKeyword == keywordParam ) {
1062c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return TRUE;
1063c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1064c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
106559d709d503bab6e2b61931737e662dd293b40578ccornelius    if ( fNext != NULL ) {
106659d709d503bab6e2b61931737e662dd293b40578ccornelius        return fNext->isKeyword(keywordParam);
1067c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1068c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    else {
1069c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return FALSE;
1070c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1071c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1072c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1073c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
107459d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::PluralRuleParser() :
107559d709d503bab6e2b61931737e662dd293b40578ccornelius        ruleIndex(0), token(), type(none), prevType(none),
107659d709d503bab6e2b61931737e662dd293b40578ccornelius        curAndConstraint(NULL), currentChain(NULL), rangeLowIdx(-1), rangeHiIdx(-1)
107759d709d503bab6e2b61931737e662dd293b40578ccornelius{
1078c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1079c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
108059d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::~PluralRuleParser() {
108159d709d503bab6e2b61931737e662dd293b40578ccornelius}
108259d709d503bab6e2b61931737e662dd293b40578ccornelius
108359d709d503bab6e2b61931737e662dd293b40578ccornelius
108459d709d503bab6e2b61931737e662dd293b40578ccorneliusint32_t
108559d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::getNumberValue(const UnicodeString& token) {
108659d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t i;
108759d709d503bab6e2b61931737e662dd293b40578ccornelius    char digits[128];
108859d709d503bab6e2b61931737e662dd293b40578ccornelius
108959d709d503bab6e2b61931737e662dd293b40578ccornelius    i = token.extract(0, token.length(), digits, ARRAY_SIZE(digits), US_INV);
109059d709d503bab6e2b61931737e662dd293b40578ccornelius    digits[i]='\0';
109159d709d503bab6e2b61931737e662dd293b40578ccornelius
109259d709d503bab6e2b61931737e662dd293b40578ccornelius    return((int32_t)atoi(digits));
1093c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1094c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
109559d709d503bab6e2b61931737e662dd293b40578ccornelius
1096c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruvoid
109759d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::checkSyntax(UErrorCode &status)
1098c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
1099c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (U_FAILURE(status)) {
1100c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return;
1101c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
110259d709d503bab6e2b61931737e662dd293b40578ccornelius    if (!(prevType==none || prevType==tSemiColon)) {
110359d709d503bab6e2b61931737e662dd293b40578ccornelius        type = getKeyType(token, type);  // Switch token type from tKeyword if we scanned a reserved word,
110459d709d503bab6e2b61931737e662dd293b40578ccornelius                                               //   and we are not at the start of a rule, where a
110559d709d503bab6e2b61931737e662dd293b40578ccornelius                                               //   keyword is expected.
110659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
110759d709d503bab6e2b61931737e662dd293b40578ccornelius
1108c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    switch(prevType) {
1109c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case none:
1110c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tSemiColon:
111159d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type!=tKeyword && type != tEOF) {
1112c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1113c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1114c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
111559d709d503bab6e2b61931737e662dd293b40578ccornelius    case tVariableN:
111659d709d503bab6e2b61931737e662dd293b40578ccornelius    case tVariableI:
111759d709d503bab6e2b61931737e662dd293b40578ccornelius    case tVariableF:
111859d709d503bab6e2b61931737e662dd293b40578ccornelius    case tVariableT:
111959d709d503bab6e2b61931737e662dd293b40578ccornelius    case tVariableV:
112059d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tIs && type != tMod && type != tIn &&
112159d709d503bab6e2b61931737e662dd293b40578ccornelius            type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
1122c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1123c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1124c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1125c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tKeyword:
112659d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tColon) {
1127c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1128c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1129c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
113059d709d503bab6e2b61931737e662dd293b40578ccornelius    case tColon:
113159d709d503bab6e2b61931737e662dd293b40578ccornelius        if (!(type == tVariableN ||
113259d709d503bab6e2b61931737e662dd293b40578ccornelius              type == tVariableI ||
113359d709d503bab6e2b61931737e662dd293b40578ccornelius              type == tVariableF ||
113459d709d503bab6e2b61931737e662dd293b40578ccornelius              type == tVariableT ||
113559d709d503bab6e2b61931737e662dd293b40578ccornelius              type == tVariableV ||
113659d709d503bab6e2b61931737e662dd293b40578ccornelius              type == tAt)) {
1137c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1138c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1139c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1140c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tIs:
114159d709d503bab6e2b61931737e662dd293b40578ccornelius        if ( type != tNumber && type != tNot) {
1142c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1143c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1144c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1145c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tNot:
114659d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tNumber && type != tIn && type != tWithin) {
1147c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1148c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1149c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1150c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tMod:
115159d709d503bab6e2b61931737e662dd293b40578ccornelius    case tDot2:
1152c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tIn:
1153c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tWithin:
115459d709d503bab6e2b61931737e662dd293b40578ccornelius    case tEqual:
115559d709d503bab6e2b61931737e662dd293b40578ccornelius    case tNotEqual:
115659d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tNumber) {
115759d709d503bab6e2b61931737e662dd293b40578ccornelius            status = U_UNEXPECTED_TOKEN;
115859d709d503bab6e2b61931737e662dd293b40578ccornelius        }
115959d709d503bab6e2b61931737e662dd293b40578ccornelius        break;
1160c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tAnd:
1161c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tOr:
116259d709d503bab6e2b61931737e662dd293b40578ccornelius        if ( type != tVariableN &&
116359d709d503bab6e2b61931737e662dd293b40578ccornelius             type != tVariableI &&
116459d709d503bab6e2b61931737e662dd293b40578ccornelius             type != tVariableF &&
116559d709d503bab6e2b61931737e662dd293b40578ccornelius             type != tVariableT &&
116659d709d503bab6e2b61931737e662dd293b40578ccornelius             type != tVariableV) {
116759d709d503bab6e2b61931737e662dd293b40578ccornelius            status = U_UNEXPECTED_TOKEN;
116859d709d503bab6e2b61931737e662dd293b40578ccornelius        }
116959d709d503bab6e2b61931737e662dd293b40578ccornelius        break;
117059d709d503bab6e2b61931737e662dd293b40578ccornelius    case tComma:
117159d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tNumber) {
1172c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1173c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
1174c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1175c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case tNumber:
117659d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tDot2  && type != tSemiColon && type != tIs       && type != tNot    &&
117759d709d503bab6e2b61931737e662dd293b40578ccornelius            type != tIn    && type != tEqual     && type != tNotEqual && type != tWithin &&
117859d709d503bab6e2b61931737e662dd293b40578ccornelius            type != tAnd   && type != tOr        && type != tComma    && type != tAt     &&
117959d709d503bab6e2b61931737e662dd293b40578ccornelius            type != tEOF)
1180c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        {
1181c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_UNEXPECTED_TOKEN;
1182c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
118359d709d503bab6e2b61931737e662dd293b40578ccornelius        // TODO: a comma following a number that is not part of a range will be allowed.
118459d709d503bab6e2b61931737e662dd293b40578ccornelius        //       It's not the only case of this sort of thing. Parser needs a re-write.
118559d709d503bab6e2b61931737e662dd293b40578ccornelius        break;
118659d709d503bab6e2b61931737e662dd293b40578ccornelius    case tAt:
118759d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tDecimal && type != tInteger) {
118859d709d503bab6e2b61931737e662dd293b40578ccornelius            status = U_UNEXPECTED_TOKEN;
118959d709d503bab6e2b61931737e662dd293b40578ccornelius        }
1190c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1191c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    default:
1192c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        status = U_UNEXPECTED_TOKEN;
1193c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        break;
1194c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1195c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1196c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
119759d709d503bab6e2b61931737e662dd293b40578ccornelius
119859d709d503bab6e2b61931737e662dd293b40578ccornelius/*
119959d709d503bab6e2b61931737e662dd293b40578ccornelius *  Scan the next token from the input rules.
120059d709d503bab6e2b61931737e662dd293b40578ccornelius *     rules and returned token type are in the parser state variables.
120159d709d503bab6e2b61931737e662dd293b40578ccornelius */
1202c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruvoid
120359d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::getNextToken(UErrorCode &status)
1204c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
1205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
1206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
1207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
120859d709d503bab6e2b61931737e662dd293b40578ccornelius
120959d709d503bab6e2b61931737e662dd293b40578ccornelius    UChar ch;
121059d709d503bab6e2b61931737e662dd293b40578ccornelius    while (ruleIndex < ruleSrc->length()) {
121159d709d503bab6e2b61931737e662dd293b40578ccornelius        ch = ruleSrc->charAt(ruleIndex);
121259d709d503bab6e2b61931737e662dd293b40578ccornelius        type = charType(ch);
121359d709d503bab6e2b61931737e662dd293b40578ccornelius        if (type != tSpace) {
121459d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
1215c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
121659d709d503bab6e2b61931737e662dd293b40578ccornelius        ++(ruleIndex);
1217c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
121859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (ruleIndex >= ruleSrc->length()) {
121959d709d503bab6e2b61931737e662dd293b40578ccornelius        type = tEOF;
122059d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
1221c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
122259d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t curIndex= ruleIndex;
122359d709d503bab6e2b61931737e662dd293b40578ccornelius
122459d709d503bab6e2b61931737e662dd293b40578ccornelius    switch (type) {
122559d709d503bab6e2b61931737e662dd293b40578ccornelius      case tColon:
122659d709d503bab6e2b61931737e662dd293b40578ccornelius      case tSemiColon:
122759d709d503bab6e2b61931737e662dd293b40578ccornelius      case tComma:
122859d709d503bab6e2b61931737e662dd293b40578ccornelius      case tEllipsis:
122959d709d503bab6e2b61931737e662dd293b40578ccornelius      case tTilde:   // scanned '~'
123059d709d503bab6e2b61931737e662dd293b40578ccornelius      case tAt:      // scanned '@'
123159d709d503bab6e2b61931737e662dd293b40578ccornelius      case tEqual:   // scanned '='
123259d709d503bab6e2b61931737e662dd293b40578ccornelius      case tMod:     // scanned '%'
123359d709d503bab6e2b61931737e662dd293b40578ccornelius        // Single character tokens.
123459d709d503bab6e2b61931737e662dd293b40578ccornelius        ++curIndex;
123559d709d503bab6e2b61931737e662dd293b40578ccornelius        break;
123659d709d503bab6e2b61931737e662dd293b40578ccornelius
123759d709d503bab6e2b61931737e662dd293b40578ccornelius      case tNotEqual:  // scanned '!'
123859d709d503bab6e2b61931737e662dd293b40578ccornelius        if (ruleSrc->charAt(curIndex+1) == EQUALS) {
123959d709d503bab6e2b61931737e662dd293b40578ccornelius            curIndex += 2;
124059d709d503bab6e2b61931737e662dd293b40578ccornelius        } else {
124159d709d503bab6e2b61931737e662dd293b40578ccornelius            type = none;
124259d709d503bab6e2b61931737e662dd293b40578ccornelius            curIndex += 1;
124359d709d503bab6e2b61931737e662dd293b40578ccornelius        }
124459d709d503bab6e2b61931737e662dd293b40578ccornelius        break;
124559d709d503bab6e2b61931737e662dd293b40578ccornelius
124659d709d503bab6e2b61931737e662dd293b40578ccornelius      case tKeyword:
124759d709d503bab6e2b61931737e662dd293b40578ccornelius         while (type == tKeyword && ++curIndex < ruleSrc->length()) {
124859d709d503bab6e2b61931737e662dd293b40578ccornelius             ch = ruleSrc->charAt(curIndex);
124959d709d503bab6e2b61931737e662dd293b40578ccornelius             type = charType(ch);
125059d709d503bab6e2b61931737e662dd293b40578ccornelius         }
125159d709d503bab6e2b61931737e662dd293b40578ccornelius         type = tKeyword;
125259d709d503bab6e2b61931737e662dd293b40578ccornelius         break;
125359d709d503bab6e2b61931737e662dd293b40578ccornelius
125459d709d503bab6e2b61931737e662dd293b40578ccornelius      case tNumber:
125559d709d503bab6e2b61931737e662dd293b40578ccornelius         while (type == tNumber && ++curIndex < ruleSrc->length()) {
125659d709d503bab6e2b61931737e662dd293b40578ccornelius             ch = ruleSrc->charAt(curIndex);
125759d709d503bab6e2b61931737e662dd293b40578ccornelius             type = charType(ch);
125859d709d503bab6e2b61931737e662dd293b40578ccornelius         }
125959d709d503bab6e2b61931737e662dd293b40578ccornelius         type = tNumber;
126059d709d503bab6e2b61931737e662dd293b40578ccornelius         break;
126159d709d503bab6e2b61931737e662dd293b40578ccornelius
126259d709d503bab6e2b61931737e662dd293b40578ccornelius       case tDot:
126359d709d503bab6e2b61931737e662dd293b40578ccornelius         // We could be looking at either ".." in a range, or "..." at the end of a sample.
126459d709d503bab6e2b61931737e662dd293b40578ccornelius         if (curIndex+1 >= ruleSrc->length() || ruleSrc->charAt(curIndex+1) != DOT) {
126559d709d503bab6e2b61931737e662dd293b40578ccornelius             ++curIndex;
126659d709d503bab6e2b61931737e662dd293b40578ccornelius             break; // Single dot
126759d709d503bab6e2b61931737e662dd293b40578ccornelius         }
126859d709d503bab6e2b61931737e662dd293b40578ccornelius         if (curIndex+2 >= ruleSrc->length() || ruleSrc->charAt(curIndex+2) != DOT) {
126959d709d503bab6e2b61931737e662dd293b40578ccornelius             curIndex += 2;
127059d709d503bab6e2b61931737e662dd293b40578ccornelius             type = tDot2;
127159d709d503bab6e2b61931737e662dd293b40578ccornelius             break; // double dot
127259d709d503bab6e2b61931737e662dd293b40578ccornelius         }
127359d709d503bab6e2b61931737e662dd293b40578ccornelius         type = tEllipsis;
127459d709d503bab6e2b61931737e662dd293b40578ccornelius         curIndex += 3;
127559d709d503bab6e2b61931737e662dd293b40578ccornelius         break;     // triple dot
127659d709d503bab6e2b61931737e662dd293b40578ccornelius
127759d709d503bab6e2b61931737e662dd293b40578ccornelius       default:
127859d709d503bab6e2b61931737e662dd293b40578ccornelius         status = U_UNEXPECTED_TOKEN;
127959d709d503bab6e2b61931737e662dd293b40578ccornelius         ++curIndex;
128059d709d503bab6e2b61931737e662dd293b40578ccornelius         break;
128159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
128259d709d503bab6e2b61931737e662dd293b40578ccornelius
128359d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(ruleIndex <= ruleSrc->length());
128459d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(curIndex <= ruleSrc->length());
128559d709d503bab6e2b61931737e662dd293b40578ccornelius    token=UnicodeString(*ruleSrc, ruleIndex, curIndex-ruleIndex);
128659d709d503bab6e2b61931737e662dd293b40578ccornelius    ruleIndex = curIndex;
1287c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1288c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
128959d709d503bab6e2b61931737e662dd293b40578ccorneliustokenType
129059d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::charType(UChar ch) {
1291c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if ((ch>=U_ZERO) && (ch<=U_NINE)) {
129259d709d503bab6e2b61931737e662dd293b40578ccornelius        return tNumber;
129359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
129459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (ch>=LOW_A && ch<=LOW_Z) {
129559d709d503bab6e2b61931737e662dd293b40578ccornelius        return tKeyword;
1296c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1297c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    switch (ch) {
1298c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case COLON:
129959d709d503bab6e2b61931737e662dd293b40578ccornelius        return tColon;
1300c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case SPACE:
130159d709d503bab6e2b61931737e662dd293b40578ccornelius        return tSpace;
1302c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case SEMI_COLON:
130359d709d503bab6e2b61931737e662dd293b40578ccornelius        return tSemiColon;
1304c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    case DOT:
130559d709d503bab6e2b61931737e662dd293b40578ccornelius        return tDot;
130659d709d503bab6e2b61931737e662dd293b40578ccornelius    case COMMA:
130759d709d503bab6e2b61931737e662dd293b40578ccornelius        return tComma;
130859d709d503bab6e2b61931737e662dd293b40578ccornelius    case EXCLAMATION:
130959d709d503bab6e2b61931737e662dd293b40578ccornelius        return tNotEqual;
131059d709d503bab6e2b61931737e662dd293b40578ccornelius    case EQUALS:
131159d709d503bab6e2b61931737e662dd293b40578ccornelius        return tEqual;
131259d709d503bab6e2b61931737e662dd293b40578ccornelius    case PERCENT_SIGN:
131359d709d503bab6e2b61931737e662dd293b40578ccornelius        return tMod;
131459d709d503bab6e2b61931737e662dd293b40578ccornelius    case AT:
131559d709d503bab6e2b61931737e662dd293b40578ccornelius        return tAt;
131659d709d503bab6e2b61931737e662dd293b40578ccornelius    case ELLIPSIS:
131759d709d503bab6e2b61931737e662dd293b40578ccornelius        return tEllipsis;
131859d709d503bab6e2b61931737e662dd293b40578ccornelius    case TILDE:
131959d709d503bab6e2b61931737e662dd293b40578ccornelius        return tTilde;
1320c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    default :
132159d709d503bab6e2b61931737e662dd293b40578ccornelius        return none;
1322c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1323c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1324c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1325c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
132659d709d503bab6e2b61931737e662dd293b40578ccornelius//  Set token type for reserved words in the Plural Rule syntax.
132759d709d503bab6e2b61931737e662dd293b40578ccornelius
132859d709d503bab6e2b61931737e662dd293b40578ccorneliustokenType
132959d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
1330c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
133159d709d503bab6e2b61931737e662dd293b40578ccornelius    if (keyType != tKeyword) {
133259d709d503bab6e2b61931737e662dd293b40578ccornelius        return keyType;
1333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
133459d709d503bab6e2b61931737e662dd293b40578ccornelius
133559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (0 == token.compare(PK_VAR_N, 1)) {
1336c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tVariableN;
133759d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_VAR_I, 1)) {
133859d709d503bab6e2b61931737e662dd293b40578ccornelius        keyType = tVariableI;
133959d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_VAR_F, 1)) {
134059d709d503bab6e2b61931737e662dd293b40578ccornelius        keyType = tVariableF;
134159d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_VAR_T, 1)) {
134259d709d503bab6e2b61931737e662dd293b40578ccornelius        keyType = tVariableT;
134359d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_VAR_V, 1)) {
134459d709d503bab6e2b61931737e662dd293b40578ccornelius        keyType = tVariableV;
134559d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_IS, 2)) {
1346c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tIs;
134759d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_AND, 3)) {
1348c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tAnd;
134959d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_IN, 2)) {
1350c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tIn;
135159d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_WITHIN, 6)) {
1352c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tWithin;
135359d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_NOT, 3)) {
1354c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tNot;
135559d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_MOD, 3)) {
1356c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tMod;
135759d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_OR, 2)) {
1358c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        keyType = tOr;
135959d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_DECIMAL, 7)) {
136059d709d503bab6e2b61931737e662dd293b40578ccornelius        keyType = tDecimal;
136159d709d503bab6e2b61931737e662dd293b40578ccornelius    } else if (0 == token.compare(PK_INTEGER, 7)) {
136259d709d503bab6e2b61931737e662dd293b40578ccornelius        keyType = tInteger;
1363c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
136459d709d503bab6e2b61931737e662dd293b40578ccornelius    return keyType;
1365c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1366c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1367c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1368b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehoPluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode& status)
1369b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        : pos(0), fKeywordNames(status) {
1370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(status)) {
1371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
1372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1373103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    fKeywordNames.setDeleter(uprv_deleteUObject);
1374b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool  addKeywordOther=TRUE;
1375b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    RuleChain *node=header;
1376c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    while(node!=NULL) {
137759d709d503bab6e2b61931737e662dd293b40578ccornelius        fKeywordNames.addElement(new UnicodeString(node->fKeyword), status);
1378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(status)) {
1379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return;
1380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
138159d709d503bab6e2b61931737e662dd293b40578ccornelius        if (0 == node->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
1382b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            addKeywordOther= FALSE;
1383c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
138459d709d503bab6e2b61931737e662dd293b40578ccornelius        node=node->fNext;
1385c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1386b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1387c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (addKeywordOther) {
1388c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        fKeywordNames.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER), status);
1389c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1390c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1391c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1392c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruconst UnicodeString*
1393c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralKeywordEnumeration::snext(UErrorCode& status) {
1394c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
1395c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return (const UnicodeString*)fKeywordNames.elementAt(pos++);
1396c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1397c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return NULL;
1398c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1399c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1400c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruvoid
1401c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
1402c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    pos=0;
1403c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1404c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1405c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queruint32_t
1406c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
1407c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru       return fKeywordNames.size();
1408c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1409c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1410c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruPluralKeywordEnumeration::~PluralKeywordEnumeration() {
1411c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
1412c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
141359d709d503bab6e2b61931737e662dd293b40578ccornelius
141459d709d503bab6e2b61931737e662dd293b40578ccornelius
141559d709d503bab6e2b61931737e662dd293b40578ccorneliusFixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) {
141659d709d503bab6e2b61931737e662dd293b40578ccornelius    init(n, v, f);
141759d709d503bab6e2b61931737e662dd293b40578ccornelius    // check values. TODO make into unit test.
141859d709d503bab6e2b61931737e662dd293b40578ccornelius    //
141959d709d503bab6e2b61931737e662dd293b40578ccornelius    //            long visiblePower = (int) Math.pow(10, v);
142059d709d503bab6e2b61931737e662dd293b40578ccornelius    //            if (decimalDigits > visiblePower) {
142159d709d503bab6e2b61931737e662dd293b40578ccornelius    //                throw new IllegalArgumentException();
142259d709d503bab6e2b61931737e662dd293b40578ccornelius    //            }
142359d709d503bab6e2b61931737e662dd293b40578ccornelius    //            double fraction = intValue + (decimalDigits / (double) visiblePower);
142459d709d503bab6e2b61931737e662dd293b40578ccornelius    //            if (fraction != source) {
142559d709d503bab6e2b61931737e662dd293b40578ccornelius    //                double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source));
142659d709d503bab6e2b61931737e662dd293b40578ccornelius    //                if (diff > 0.00000001d) {
142759d709d503bab6e2b61931737e662dd293b40578ccornelius    //                    throw new IllegalArgumentException();
142859d709d503bab6e2b61931737e662dd293b40578ccornelius    //                }
142959d709d503bab6e2b61931737e662dd293b40578ccornelius    //            }
143059d709d503bab6e2b61931737e662dd293b40578ccornelius}
143159d709d503bab6e2b61931737e662dd293b40578ccornelius
143259d709d503bab6e2b61931737e662dd293b40578ccorneliusFixedDecimal::FixedDecimal(double n, int32_t v) {
143359d709d503bab6e2b61931737e662dd293b40578ccornelius    // Ugly, but for samples we don't care.
143459d709d503bab6e2b61931737e662dd293b40578ccornelius    init(n, v, getFractionalDigits(n, v));
143559d709d503bab6e2b61931737e662dd293b40578ccornelius}
143659d709d503bab6e2b61931737e662dd293b40578ccornelius
143759d709d503bab6e2b61931737e662dd293b40578ccorneliusFixedDecimal::FixedDecimal(double n) {
143859d709d503bab6e2b61931737e662dd293b40578ccornelius    init(n);
143959d709d503bab6e2b61931737e662dd293b40578ccornelius}
144059d709d503bab6e2b61931737e662dd293b40578ccornelius
144159d709d503bab6e2b61931737e662dd293b40578ccorneliusFixedDecimal::FixedDecimal() {
144259d709d503bab6e2b61931737e662dd293b40578ccornelius    init(0, 0, 0);
144359d709d503bab6e2b61931737e662dd293b40578ccornelius}
144459d709d503bab6e2b61931737e662dd293b40578ccornelius
144559d709d503bab6e2b61931737e662dd293b40578ccornelius
144659d709d503bab6e2b61931737e662dd293b40578ccornelius// Create a FixedDecimal from a UnicodeString containing a number.
144759d709d503bab6e2b61931737e662dd293b40578ccornelius//    Inefficient, but only used for samples, so simplicity trumps efficiency.
144859d709d503bab6e2b61931737e662dd293b40578ccornelius
144959d709d503bab6e2b61931737e662dd293b40578ccorneliusFixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) {
145059d709d503bab6e2b61931737e662dd293b40578ccornelius    CharString cs;
145159d709d503bab6e2b61931737e662dd293b40578ccornelius    cs.appendInvariantChars(num, status);
145259d709d503bab6e2b61931737e662dd293b40578ccornelius    DigitList dl;
145359d709d503bab6e2b61931737e662dd293b40578ccornelius    dl.set(cs.toStringPiece(), status);
145459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
145559d709d503bab6e2b61931737e662dd293b40578ccornelius        init(0, 0, 0);
145659d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
145759d709d503bab6e2b61931737e662dd293b40578ccornelius    }
145859d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t decimalPoint = num.indexOf(DOT);
145959d709d503bab6e2b61931737e662dd293b40578ccornelius    double n = dl.getDouble();
146059d709d503bab6e2b61931737e662dd293b40578ccornelius    if (decimalPoint == -1) {
146159d709d503bab6e2b61931737e662dd293b40578ccornelius        init(n, 0, 0);
146259d709d503bab6e2b61931737e662dd293b40578ccornelius    } else {
146359d709d503bab6e2b61931737e662dd293b40578ccornelius        int32_t v = num.length() - decimalPoint - 1;
146459d709d503bab6e2b61931737e662dd293b40578ccornelius        init(n, v, getFractionalDigits(n, v));
146559d709d503bab6e2b61931737e662dd293b40578ccornelius    }
146659d709d503bab6e2b61931737e662dd293b40578ccornelius}
146759d709d503bab6e2b61931737e662dd293b40578ccornelius
146859d709d503bab6e2b61931737e662dd293b40578ccornelius
146959d709d503bab6e2b61931737e662dd293b40578ccorneliusFixedDecimal::FixedDecimal(const FixedDecimal &other) {
147059d709d503bab6e2b61931737e662dd293b40578ccornelius    source = other.source;
147159d709d503bab6e2b61931737e662dd293b40578ccornelius    visibleDecimalDigitCount = other.visibleDecimalDigitCount;
147259d709d503bab6e2b61931737e662dd293b40578ccornelius    decimalDigits = other.decimalDigits;
147359d709d503bab6e2b61931737e662dd293b40578ccornelius    decimalDigitsWithoutTrailingZeros = other.decimalDigitsWithoutTrailingZeros;
147459d709d503bab6e2b61931737e662dd293b40578ccornelius    intValue = other.intValue;
147559d709d503bab6e2b61931737e662dd293b40578ccornelius    hasIntegerValue = other.hasIntegerValue;
147659d709d503bab6e2b61931737e662dd293b40578ccornelius    isNegative = other.isNegative;
147759d709d503bab6e2b61931737e662dd293b40578ccornelius    isNanOrInfinity = other.isNanOrInfinity;
147859d709d503bab6e2b61931737e662dd293b40578ccornelius}
147959d709d503bab6e2b61931737e662dd293b40578ccornelius
148059d709d503bab6e2b61931737e662dd293b40578ccornelius
148159d709d503bab6e2b61931737e662dd293b40578ccorneliusvoid FixedDecimal::init(double n) {
148259d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t numFractionDigits = decimals(n);
148359d709d503bab6e2b61931737e662dd293b40578ccornelius    init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
148459d709d503bab6e2b61931737e662dd293b40578ccornelius}
148559d709d503bab6e2b61931737e662dd293b40578ccornelius
148659d709d503bab6e2b61931737e662dd293b40578ccornelius
148759d709d503bab6e2b61931737e662dd293b40578ccorneliusvoid FixedDecimal::init(double n, int32_t v, int64_t f) {
148859d709d503bab6e2b61931737e662dd293b40578ccornelius    isNegative = n < 0.0;
148959d709d503bab6e2b61931737e662dd293b40578ccornelius    source = fabs(n);
149059d709d503bab6e2b61931737e662dd293b40578ccornelius    isNanOrInfinity = uprv_isNaN(source) || uprv_isPositiveInfinity(source);
149159d709d503bab6e2b61931737e662dd293b40578ccornelius    if (isNanOrInfinity) {
149259d709d503bab6e2b61931737e662dd293b40578ccornelius        v = 0;
149359d709d503bab6e2b61931737e662dd293b40578ccornelius        f = 0;
149459d709d503bab6e2b61931737e662dd293b40578ccornelius        intValue = 0;
149559d709d503bab6e2b61931737e662dd293b40578ccornelius        hasIntegerValue = FALSE;
149659d709d503bab6e2b61931737e662dd293b40578ccornelius    } else {
149759d709d503bab6e2b61931737e662dd293b40578ccornelius        intValue = (int64_t)source;
149859d709d503bab6e2b61931737e662dd293b40578ccornelius        hasIntegerValue = (source == intValue);
149959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
150059d709d503bab6e2b61931737e662dd293b40578ccornelius
150159d709d503bab6e2b61931737e662dd293b40578ccornelius    visibleDecimalDigitCount = v;
150259d709d503bab6e2b61931737e662dd293b40578ccornelius    decimalDigits = f;
150359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (f == 0) {
150459d709d503bab6e2b61931737e662dd293b40578ccornelius         decimalDigitsWithoutTrailingZeros = 0;
150559d709d503bab6e2b61931737e662dd293b40578ccornelius    } else {
150659d709d503bab6e2b61931737e662dd293b40578ccornelius        int64_t fdwtz = f;
150759d709d503bab6e2b61931737e662dd293b40578ccornelius        while ((fdwtz%10) == 0) {
150859d709d503bab6e2b61931737e662dd293b40578ccornelius            fdwtz /= 10;
150959d709d503bab6e2b61931737e662dd293b40578ccornelius        }
151059d709d503bab6e2b61931737e662dd293b40578ccornelius        decimalDigitsWithoutTrailingZeros = fdwtz;
151159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
151259d709d503bab6e2b61931737e662dd293b40578ccornelius}
151359d709d503bab6e2b61931737e662dd293b40578ccornelius
151459d709d503bab6e2b61931737e662dd293b40578ccornelius
151559d709d503bab6e2b61931737e662dd293b40578ccornelius//  Fast path only exact initialization. Return true if successful.
151659d709d503bab6e2b61931737e662dd293b40578ccornelius//     Note: Do not multiply by 10 each time through loop, rounding cruft can build
151759d709d503bab6e2b61931737e662dd293b40578ccornelius//           up that makes the check for an integer result fail.
151859d709d503bab6e2b61931737e662dd293b40578ccornelius//           A single multiply of the original number works more reliably.
151959d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic int32_t p10[] = {1, 10, 100, 1000, 10000};
152059d709d503bab6e2b61931737e662dd293b40578ccorneliusUBool FixedDecimal::quickInit(double n) {
152159d709d503bab6e2b61931737e662dd293b40578ccornelius    UBool success = FALSE;
152259d709d503bab6e2b61931737e662dd293b40578ccornelius    n = fabs(n);
152359d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t numFractionDigits;
152459d709d503bab6e2b61931737e662dd293b40578ccornelius    for (numFractionDigits = 0; numFractionDigits <= 3; numFractionDigits++) {
152559d709d503bab6e2b61931737e662dd293b40578ccornelius        double scaledN = n * p10[numFractionDigits];
152659d709d503bab6e2b61931737e662dd293b40578ccornelius        if (scaledN == floor(scaledN)) {
152759d709d503bab6e2b61931737e662dd293b40578ccornelius            success = TRUE;
152859d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
152959d709d503bab6e2b61931737e662dd293b40578ccornelius        }
153059d709d503bab6e2b61931737e662dd293b40578ccornelius    }
153159d709d503bab6e2b61931737e662dd293b40578ccornelius    if (success) {
153259d709d503bab6e2b61931737e662dd293b40578ccornelius        init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
153359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
153459d709d503bab6e2b61931737e662dd293b40578ccornelius    return success;
153559d709d503bab6e2b61931737e662dd293b40578ccornelius}
153659d709d503bab6e2b61931737e662dd293b40578ccornelius
153759d709d503bab6e2b61931737e662dd293b40578ccornelius
153859d709d503bab6e2b61931737e662dd293b40578ccornelius
153959d709d503bab6e2b61931737e662dd293b40578ccorneliusint32_t FixedDecimal::decimals(double n) {
154059d709d503bab6e2b61931737e662dd293b40578ccornelius    // Count the number of decimal digits in the fraction part of the number, excluding trailing zeros.
154159d709d503bab6e2b61931737e662dd293b40578ccornelius    // fastpath the common cases, integers or fractions with 3 or fewer digits
154259d709d503bab6e2b61931737e662dd293b40578ccornelius    n = fabs(n);
154359d709d503bab6e2b61931737e662dd293b40578ccornelius    for (int ndigits=0; ndigits<=3; ndigits++) {
154459d709d503bab6e2b61931737e662dd293b40578ccornelius        double scaledN = n * p10[ndigits];
154559d709d503bab6e2b61931737e662dd293b40578ccornelius        if (scaledN == floor(scaledN)) {
154659d709d503bab6e2b61931737e662dd293b40578ccornelius            return ndigits;
154759d709d503bab6e2b61931737e662dd293b40578ccornelius        }
154859d709d503bab6e2b61931737e662dd293b40578ccornelius    }
154959d709d503bab6e2b61931737e662dd293b40578ccornelius
155059d709d503bab6e2b61931737e662dd293b40578ccornelius    // Slow path, convert with sprintf, parse converted output.
155159d709d503bab6e2b61931737e662dd293b40578ccornelius    char  buf[30] = {0};
155259d709d503bab6e2b61931737e662dd293b40578ccornelius    sprintf(buf, "%1.15e", n);
155359d709d503bab6e2b61931737e662dd293b40578ccornelius    // formatted number looks like this: 1.234567890123457e-01
155459d709d503bab6e2b61931737e662dd293b40578ccornelius    int exponent = atoi(buf+18);
155559d709d503bab6e2b61931737e662dd293b40578ccornelius    int numFractionDigits = 15;
155659d709d503bab6e2b61931737e662dd293b40578ccornelius    for (int i=16; ; --i) {
155759d709d503bab6e2b61931737e662dd293b40578ccornelius        if (buf[i] != '0') {
155859d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
155959d709d503bab6e2b61931737e662dd293b40578ccornelius        }
156059d709d503bab6e2b61931737e662dd293b40578ccornelius        --numFractionDigits;
156159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
156259d709d503bab6e2b61931737e662dd293b40578ccornelius    numFractionDigits -= exponent;   // Fraction part of fixed point representation.
156359d709d503bab6e2b61931737e662dd293b40578ccornelius    return numFractionDigits;
156459d709d503bab6e2b61931737e662dd293b40578ccornelius}
156559d709d503bab6e2b61931737e662dd293b40578ccornelius
156659d709d503bab6e2b61931737e662dd293b40578ccornelius
156759d709d503bab6e2b61931737e662dd293b40578ccornelius// Get the fraction digits of a double, represented as an integer.
156859d709d503bab6e2b61931737e662dd293b40578ccornelius//    v is the number of visible fraction digits in the displayed form of the number.
156959d709d503bab6e2b61931737e662dd293b40578ccornelius//       Example: n = 1001.234, v = 6, result = 234000
157059d709d503bab6e2b61931737e662dd293b40578ccornelius//    TODO: need to think through how this is used in the plural rule context.
157159d709d503bab6e2b61931737e662dd293b40578ccornelius//          This function can easily encounter integer overflow,
157259d709d503bab6e2b61931737e662dd293b40578ccornelius//          and can easily return noise digits when the precision of a double is exceeded.
157359d709d503bab6e2b61931737e662dd293b40578ccornelius
157459d709d503bab6e2b61931737e662dd293b40578ccorneliusint64_t FixedDecimal::getFractionalDigits(double n, int32_t v) {
157559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (v == 0 || n == floor(n) || uprv_isNaN(n) || uprv_isPositiveInfinity(n)) {
157659d709d503bab6e2b61931737e662dd293b40578ccornelius        return 0;
157759d709d503bab6e2b61931737e662dd293b40578ccornelius    }
157859d709d503bab6e2b61931737e662dd293b40578ccornelius    n = fabs(n);
157959d709d503bab6e2b61931737e662dd293b40578ccornelius    double fract = n - floor(n);
158059d709d503bab6e2b61931737e662dd293b40578ccornelius    switch (v) {
158159d709d503bab6e2b61931737e662dd293b40578ccornelius      case 1: return (int64_t)(fract*10.0 + 0.5);
158259d709d503bab6e2b61931737e662dd293b40578ccornelius      case 2: return (int64_t)(fract*100.0 + 0.5);
158359d709d503bab6e2b61931737e662dd293b40578ccornelius      case 3: return (int64_t)(fract*1000.0 + 0.5);
158459d709d503bab6e2b61931737e662dd293b40578ccornelius      default:
158559d709d503bab6e2b61931737e662dd293b40578ccornelius          double scaled = floor(fract * pow(10.0, (double)v) + 0.5);
158659d709d503bab6e2b61931737e662dd293b40578ccornelius          if (scaled > U_INT64_MAX) {
158759d709d503bab6e2b61931737e662dd293b40578ccornelius              return U_INT64_MAX;
158859d709d503bab6e2b61931737e662dd293b40578ccornelius          } else {
158959d709d503bab6e2b61931737e662dd293b40578ccornelius              return (int64_t)scaled;
159059d709d503bab6e2b61931737e662dd293b40578ccornelius          }
159159d709d503bab6e2b61931737e662dd293b40578ccornelius      }
159259d709d503bab6e2b61931737e662dd293b40578ccornelius}
159359d709d503bab6e2b61931737e662dd293b40578ccornelius
159459d709d503bab6e2b61931737e662dd293b40578ccornelius
159559d709d503bab6e2b61931737e662dd293b40578ccorneliusvoid FixedDecimal::adjustForMinFractionDigits(int32_t minFractionDigits) {
159659d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t numTrailingFractionZeros = minFractionDigits - visibleDecimalDigitCount;
159759d709d503bab6e2b61931737e662dd293b40578ccornelius    if (numTrailingFractionZeros > 0) {
159859d709d503bab6e2b61931737e662dd293b40578ccornelius        for (int32_t i=0; i<numTrailingFractionZeros; i++) {
159959d709d503bab6e2b61931737e662dd293b40578ccornelius            // Do not let the decimalDigits value overflow if there are many trailing zeros.
160059d709d503bab6e2b61931737e662dd293b40578ccornelius            // Limit the value to 18 digits, the most that a 64 bit int can fully represent.
160159d709d503bab6e2b61931737e662dd293b40578ccornelius            if (decimalDigits >= 100000000000000000LL) {
160259d709d503bab6e2b61931737e662dd293b40578ccornelius                break;
160359d709d503bab6e2b61931737e662dd293b40578ccornelius            }
160459d709d503bab6e2b61931737e662dd293b40578ccornelius            decimalDigits *= 10;
160559d709d503bab6e2b61931737e662dd293b40578ccornelius        }
160659d709d503bab6e2b61931737e662dd293b40578ccornelius        visibleDecimalDigitCount += numTrailingFractionZeros;
160759d709d503bab6e2b61931737e662dd293b40578ccornelius    }
160859d709d503bab6e2b61931737e662dd293b40578ccornelius}
160959d709d503bab6e2b61931737e662dd293b40578ccornelius
161059d709d503bab6e2b61931737e662dd293b40578ccornelius
161159d709d503bab6e2b61931737e662dd293b40578ccorneliusdouble FixedDecimal::get(tokenType operand) const {
161259d709d503bab6e2b61931737e662dd293b40578ccornelius    switch(operand) {
161359d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableN: return source;
161459d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableI: return (double)intValue;
161559d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableF: return (double)decimalDigits;
161659d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableT: return (double)decimalDigitsWithoutTrailingZeros;
161759d709d503bab6e2b61931737e662dd293b40578ccornelius        case tVariableV: return visibleDecimalDigitCount;
161859d709d503bab6e2b61931737e662dd293b40578ccornelius        default:
161959d709d503bab6e2b61931737e662dd293b40578ccornelius             U_ASSERT(FALSE);  // unexpected.
162059d709d503bab6e2b61931737e662dd293b40578ccornelius             return source;
162159d709d503bab6e2b61931737e662dd293b40578ccornelius    }
162259d709d503bab6e2b61931737e662dd293b40578ccornelius}
162359d709d503bab6e2b61931737e662dd293b40578ccornelius
162459d709d503bab6e2b61931737e662dd293b40578ccorneliusint32_t FixedDecimal::getVisibleFractionDigitCount() const {
162559d709d503bab6e2b61931737e662dd293b40578ccornelius    return visibleDecimalDigitCount;
162659d709d503bab6e2b61931737e662dd293b40578ccornelius}
162759d709d503bab6e2b61931737e662dd293b40578ccornelius
162859d709d503bab6e2b61931737e662dd293b40578ccornelius
162959d709d503bab6e2b61931737e662dd293b40578ccornelius
163059d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralAvailableLocalesEnumeration::PluralAvailableLocalesEnumeration(UErrorCode &status) {
163159d709d503bab6e2b61931737e662dd293b40578ccornelius    fLocales = NULL;
163259d709d503bab6e2b61931737e662dd293b40578ccornelius    fRes = NULL;
163359d709d503bab6e2b61931737e662dd293b40578ccornelius    fOpenStatus = status;
163459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
163559d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
163659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
163759d709d503bab6e2b61931737e662dd293b40578ccornelius    fOpenStatus = U_ZERO_ERROR;
163859d709d503bab6e2b61931737e662dd293b40578ccornelius    LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &fOpenStatus));
163959d709d503bab6e2b61931737e662dd293b40578ccornelius    fLocales = ures_getByKey(rb.getAlias(), "locales", NULL, &fOpenStatus);
164059d709d503bab6e2b61931737e662dd293b40578ccornelius}
164159d709d503bab6e2b61931737e662dd293b40578ccornelius
164259d709d503bab6e2b61931737e662dd293b40578ccorneliusPluralAvailableLocalesEnumeration::~PluralAvailableLocalesEnumeration() {
164359d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_close(fLocales);
164459d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_close(fRes);
164559d709d503bab6e2b61931737e662dd293b40578ccornelius    fLocales = NULL;
164659d709d503bab6e2b61931737e662dd293b40578ccornelius    fRes = NULL;
164759d709d503bab6e2b61931737e662dd293b40578ccornelius}
164859d709d503bab6e2b61931737e662dd293b40578ccornelius
164959d709d503bab6e2b61931737e662dd293b40578ccorneliusconst char *PluralAvailableLocalesEnumeration::next(int32_t *resultLength, UErrorCode &status) {
165059d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
165159d709d503bab6e2b61931737e662dd293b40578ccornelius        return NULL;
165259d709d503bab6e2b61931737e662dd293b40578ccornelius    }
165359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(fOpenStatus)) {
165459d709d503bab6e2b61931737e662dd293b40578ccornelius        status = fOpenStatus;
165559d709d503bab6e2b61931737e662dd293b40578ccornelius        return NULL;
165659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
165759d709d503bab6e2b61931737e662dd293b40578ccornelius    fRes = ures_getNextResource(fLocales, fRes, &status);
165859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (fRes == NULL || U_FAILURE(status)) {
165959d709d503bab6e2b61931737e662dd293b40578ccornelius        if (status == U_INDEX_OUTOFBOUNDS_ERROR) {
166059d709d503bab6e2b61931737e662dd293b40578ccornelius            status = U_ZERO_ERROR;
166159d709d503bab6e2b61931737e662dd293b40578ccornelius        }
166259d709d503bab6e2b61931737e662dd293b40578ccornelius        return NULL;
166359d709d503bab6e2b61931737e662dd293b40578ccornelius    }
166459d709d503bab6e2b61931737e662dd293b40578ccornelius    const char *result = ures_getKey(fRes);
166559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (resultLength != NULL) {
166659d709d503bab6e2b61931737e662dd293b40578ccornelius        *resultLength = uprv_strlen(result);
166759d709d503bab6e2b61931737e662dd293b40578ccornelius    }
166859d709d503bab6e2b61931737e662dd293b40578ccornelius    return result;
166959d709d503bab6e2b61931737e662dd293b40578ccornelius}
167059d709d503bab6e2b61931737e662dd293b40578ccornelius
167159d709d503bab6e2b61931737e662dd293b40578ccornelius
167259d709d503bab6e2b61931737e662dd293b40578ccorneliusvoid PluralAvailableLocalesEnumeration::reset(UErrorCode &status) {
167359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
167459d709d503bab6e2b61931737e662dd293b40578ccornelius       return;
167559d709d503bab6e2b61931737e662dd293b40578ccornelius    }
167659d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(fOpenStatus)) {
167759d709d503bab6e2b61931737e662dd293b40578ccornelius        status = fOpenStatus;
167859d709d503bab6e2b61931737e662dd293b40578ccornelius        return;
167959d709d503bab6e2b61931737e662dd293b40578ccornelius    }
168059d709d503bab6e2b61931737e662dd293b40578ccornelius    ures_resetIterator(fLocales);
168159d709d503bab6e2b61931737e662dd293b40578ccornelius}
168259d709d503bab6e2b61931737e662dd293b40578ccornelius
168359d709d503bab6e2b61931737e662dd293b40578ccorneliusint32_t PluralAvailableLocalesEnumeration::count(UErrorCode &status) const {
168459d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(status)) {
168559d709d503bab6e2b61931737e662dd293b40578ccornelius        return 0;
168659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
168759d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_FAILURE(fOpenStatus)) {
168859d709d503bab6e2b61931737e662dd293b40578ccornelius        status = fOpenStatus;
168959d709d503bab6e2b61931737e662dd293b40578ccornelius        return 0;
169059d709d503bab6e2b61931737e662dd293b40578ccornelius    }
169159d709d503bab6e2b61931737e662dd293b40578ccornelius    return ures_getSize(fLocales);
169259d709d503bab6e2b61931737e662dd293b40578ccornelius}
169359d709d503bab6e2b61931737e662dd293b40578ccornelius
1694c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruU_NAMESPACE_END
1695c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1696c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1697c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
1698c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
1699c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru//eof
1700