Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* |
michael@0 | 2 | ******************************************************************************* |
michael@0 | 3 | * Copyright (C) 2010-2013, International Business Machines Corporation and |
michael@0 | 4 | * others. All Rights Reserved. |
michael@0 | 5 | ******************************************************************************* |
michael@0 | 6 | * |
michael@0 | 7 | * |
michael@0 | 8 | * File NUMSYS.CPP |
michael@0 | 9 | * |
michael@0 | 10 | * Modification History:* |
michael@0 | 11 | * Date Name Description |
michael@0 | 12 | * |
michael@0 | 13 | ******************************************************************************** |
michael@0 | 14 | */ |
michael@0 | 15 | |
michael@0 | 16 | #include "unicode/utypes.h" |
michael@0 | 17 | #include "unicode/localpointer.h" |
michael@0 | 18 | #include "unicode/uchar.h" |
michael@0 | 19 | #include "unicode/unistr.h" |
michael@0 | 20 | #include "unicode/ures.h" |
michael@0 | 21 | #include "unicode/ustring.h" |
michael@0 | 22 | #include "unicode/uloc.h" |
michael@0 | 23 | #include "unicode/schriter.h" |
michael@0 | 24 | #include "unicode/numsys.h" |
michael@0 | 25 | #include "cstring.h" |
michael@0 | 26 | #include "uresimp.h" |
michael@0 | 27 | #include "numsys_impl.h" |
michael@0 | 28 | |
michael@0 | 29 | #if !UCONFIG_NO_FORMATTING |
michael@0 | 30 | |
michael@0 | 31 | U_NAMESPACE_BEGIN |
michael@0 | 32 | |
michael@0 | 33 | // Useful constants |
michael@0 | 34 | |
michael@0 | 35 | #define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789"); |
michael@0 | 36 | static const char gNumberingSystems[] = "numberingSystems"; |
michael@0 | 37 | static const char gNumberElements[] = "NumberElements"; |
michael@0 | 38 | static const char gDefault[] = "default"; |
michael@0 | 39 | static const char gNative[] = "native"; |
michael@0 | 40 | static const char gTraditional[] = "traditional"; |
michael@0 | 41 | static const char gFinance[] = "finance"; |
michael@0 | 42 | static const char gDesc[] = "desc"; |
michael@0 | 43 | static const char gRadix[] = "radix"; |
michael@0 | 44 | static const char gAlgorithmic[] = "algorithmic"; |
michael@0 | 45 | static const char gLatn[] = "latn"; |
michael@0 | 46 | |
michael@0 | 47 | |
michael@0 | 48 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem) |
michael@0 | 49 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration) |
michael@0 | 50 | |
michael@0 | 51 | /** |
michael@0 | 52 | * Default Constructor. |
michael@0 | 53 | * |
michael@0 | 54 | * @draft ICU 4.2 |
michael@0 | 55 | */ |
michael@0 | 56 | |
michael@0 | 57 | NumberingSystem::NumberingSystem() { |
michael@0 | 58 | radix = 10; |
michael@0 | 59 | algorithmic = FALSE; |
michael@0 | 60 | UnicodeString defaultDigits = DEFAULT_DIGITS; |
michael@0 | 61 | desc.setTo(defaultDigits); |
michael@0 | 62 | uprv_strcpy(name,gLatn); |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | /** |
michael@0 | 66 | * Copy constructor. |
michael@0 | 67 | * @draft ICU 4.2 |
michael@0 | 68 | */ |
michael@0 | 69 | |
michael@0 | 70 | NumberingSystem::NumberingSystem(const NumberingSystem& other) |
michael@0 | 71 | : UObject(other) { |
michael@0 | 72 | *this=other; |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | NumberingSystem* U_EXPORT2 |
michael@0 | 76 | NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) { |
michael@0 | 77 | |
michael@0 | 78 | if (U_FAILURE(status)) { |
michael@0 | 79 | return NULL; |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | if ( radix_in < 2 ) { |
michael@0 | 83 | status = U_ILLEGAL_ARGUMENT_ERROR; |
michael@0 | 84 | return NULL; |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | if ( !isAlgorithmic_in ) { |
michael@0 | 88 | if ( desc_in.countChar32() != radix_in || !isValidDigitString(desc_in)) { |
michael@0 | 89 | status = U_ILLEGAL_ARGUMENT_ERROR; |
michael@0 | 90 | return NULL; |
michael@0 | 91 | } |
michael@0 | 92 | } |
michael@0 | 93 | |
michael@0 | 94 | NumberingSystem *ns = new NumberingSystem(); |
michael@0 | 95 | |
michael@0 | 96 | ns->setRadix(radix_in); |
michael@0 | 97 | ns->setDesc(desc_in); |
michael@0 | 98 | ns->setAlgorithmic(isAlgorithmic_in); |
michael@0 | 99 | ns->setName(NULL); |
michael@0 | 100 | return ns; |
michael@0 | 101 | |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | |
michael@0 | 105 | NumberingSystem* U_EXPORT2 |
michael@0 | 106 | NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) { |
michael@0 | 107 | |
michael@0 | 108 | if (U_FAILURE(status)) { |
michael@0 | 109 | return NULL; |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | UBool nsResolved = TRUE; |
michael@0 | 113 | UBool usingFallback = FALSE; |
michael@0 | 114 | char buffer[ULOC_KEYWORDS_CAPACITY]; |
michael@0 | 115 | int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status); |
michael@0 | 116 | if ( count > 0 ) { // @numbers keyword was specified in the locale |
michael@0 | 117 | buffer[count] = '\0'; // Make sure it is null terminated. |
michael@0 | 118 | if ( !uprv_strcmp(buffer,gDefault) || !uprv_strcmp(buffer,gNative) || |
michael@0 | 119 | !uprv_strcmp(buffer,gTraditional) || !uprv_strcmp(buffer,gFinance)) { |
michael@0 | 120 | nsResolved = FALSE; |
michael@0 | 121 | } |
michael@0 | 122 | } else { |
michael@0 | 123 | uprv_strcpy(buffer,gDefault); |
michael@0 | 124 | nsResolved = FALSE; |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | if (!nsResolved) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system |
michael@0 | 128 | UErrorCode localStatus = U_ZERO_ERROR; |
michael@0 | 129 | UResourceBundle *resource = ures_open(NULL, inLocale.getName(), &localStatus); |
michael@0 | 130 | UResourceBundle *numberElementsRes = ures_getByKey(resource,gNumberElements,NULL,&localStatus); |
michael@0 | 131 | while (!nsResolved) { |
michael@0 | 132 | localStatus = U_ZERO_ERROR; |
michael@0 | 133 | count = 0; |
michael@0 | 134 | const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes, buffer, &count, &localStatus); |
michael@0 | 135 | if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // numbering system found |
michael@0 | 136 | u_UCharsToChars(nsName,buffer,count); |
michael@0 | 137 | buffer[count] = '\0'; // Make sure it is null terminated. |
michael@0 | 138 | nsResolved = TRUE; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | if (!nsResolved) { // Fallback behavior per TR35 - traditional falls back to native, finance and native fall back to default |
michael@0 | 142 | if (!uprv_strcmp(buffer,gNative) || !uprv_strcmp(buffer,gFinance)) { |
michael@0 | 143 | uprv_strcpy(buffer,gDefault); |
michael@0 | 144 | } else if (!uprv_strcmp(buffer,gTraditional)) { |
michael@0 | 145 | uprv_strcpy(buffer,gNative); |
michael@0 | 146 | } else { // If we get here we couldn't find even the default numbering system |
michael@0 | 147 | usingFallback = TRUE; |
michael@0 | 148 | nsResolved = TRUE; |
michael@0 | 149 | } |
michael@0 | 150 | } |
michael@0 | 151 | } |
michael@0 | 152 | ures_close(numberElementsRes); |
michael@0 | 153 | ures_close(resource); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | if (usingFallback) { |
michael@0 | 157 | status = U_USING_FALLBACK_WARNING; |
michael@0 | 158 | NumberingSystem *ns = new NumberingSystem(); |
michael@0 | 159 | return ns; |
michael@0 | 160 | } else { |
michael@0 | 161 | return NumberingSystem::createInstanceByName(buffer,status); |
michael@0 | 162 | } |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | NumberingSystem* U_EXPORT2 |
michael@0 | 166 | NumberingSystem::createInstance(UErrorCode& status) { |
michael@0 | 167 | return NumberingSystem::createInstance(Locale::getDefault(), status); |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | NumberingSystem* U_EXPORT2 |
michael@0 | 171 | NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) { |
michael@0 | 172 | UResourceBundle *numberingSystemsInfo = NULL; |
michael@0 | 173 | UResourceBundle *nsTop, *nsCurrent; |
michael@0 | 174 | int32_t radix = 10; |
michael@0 | 175 | int32_t algorithmic = 0; |
michael@0 | 176 | |
michael@0 | 177 | numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status); |
michael@0 | 178 | nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status); |
michael@0 | 179 | nsTop = ures_getByKey(nsCurrent,name,NULL,&status); |
michael@0 | 180 | UnicodeString nsd = ures_getUnicodeStringByKey(nsTop,gDesc,&status); |
michael@0 | 181 | |
michael@0 | 182 | ures_getByKey(nsTop,gRadix,nsCurrent,&status); |
michael@0 | 183 | radix = ures_getInt(nsCurrent,&status); |
michael@0 | 184 | |
michael@0 | 185 | ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status); |
michael@0 | 186 | algorithmic = ures_getInt(nsCurrent,&status); |
michael@0 | 187 | |
michael@0 | 188 | UBool isAlgorithmic = ( algorithmic == 1 ); |
michael@0 | 189 | |
michael@0 | 190 | ures_close(nsCurrent); |
michael@0 | 191 | ures_close(nsTop); |
michael@0 | 192 | ures_close(numberingSystemsInfo); |
michael@0 | 193 | |
michael@0 | 194 | if (U_FAILURE(status)) { |
michael@0 | 195 | status = U_UNSUPPORTED_ERROR; |
michael@0 | 196 | return NULL; |
michael@0 | 197 | } |
michael@0 | 198 | |
michael@0 | 199 | NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status); |
michael@0 | 200 | ns->setName(name); |
michael@0 | 201 | return ns; |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | /** |
michael@0 | 205 | * Destructor. |
michael@0 | 206 | * @draft ICU 4.2 |
michael@0 | 207 | */ |
michael@0 | 208 | NumberingSystem::~NumberingSystem() { |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | int32_t NumberingSystem::getRadix() const { |
michael@0 | 212 | return radix; |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | UnicodeString NumberingSystem::getDescription() const { |
michael@0 | 216 | return desc; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | const char * NumberingSystem::getName() const { |
michael@0 | 220 | return name; |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | void NumberingSystem::setRadix(int32_t r) { |
michael@0 | 224 | radix = r; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | void NumberingSystem::setAlgorithmic(UBool c) { |
michael@0 | 228 | algorithmic = c; |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | void NumberingSystem::setDesc(UnicodeString d) { |
michael@0 | 232 | desc.setTo(d); |
michael@0 | 233 | } |
michael@0 | 234 | void NumberingSystem::setName(const char *n) { |
michael@0 | 235 | if ( n == NULL ) { |
michael@0 | 236 | name[0] = (char) 0; |
michael@0 | 237 | } else { |
michael@0 | 238 | uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY); |
michael@0 | 239 | name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated. |
michael@0 | 240 | } |
michael@0 | 241 | } |
michael@0 | 242 | UBool NumberingSystem::isAlgorithmic() const { |
michael@0 | 243 | return ( algorithmic ); |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) { |
michael@0 | 247 | |
michael@0 | 248 | static StringEnumeration* availableNames = NULL; |
michael@0 | 249 | |
michael@0 | 250 | if (U_FAILURE(status)) { |
michael@0 | 251 | return NULL; |
michael@0 | 252 | } |
michael@0 | 253 | |
michael@0 | 254 | if ( availableNames == NULL ) { |
michael@0 | 255 | UVector *fNumsysNames = new UVector(uprv_deleteUObject, NULL, status); |
michael@0 | 256 | if (U_FAILURE(status)) { |
michael@0 | 257 | status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 258 | return NULL; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | UErrorCode rbstatus = U_ZERO_ERROR; |
michael@0 | 262 | UResourceBundle *numberingSystemsInfo = ures_openDirect(NULL, "numberingSystems", &rbstatus); |
michael@0 | 263 | numberingSystemsInfo = ures_getByKey(numberingSystemsInfo,"numberingSystems",numberingSystemsInfo,&rbstatus); |
michael@0 | 264 | if(U_FAILURE(rbstatus)) { |
michael@0 | 265 | status = U_MISSING_RESOURCE_ERROR; |
michael@0 | 266 | ures_close(numberingSystemsInfo); |
michael@0 | 267 | return NULL; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | while ( ures_hasNext(numberingSystemsInfo) ) { |
michael@0 | 271 | UResourceBundle *nsCurrent = ures_getNextResource(numberingSystemsInfo,NULL,&rbstatus); |
michael@0 | 272 | const char *nsName = ures_getKey(nsCurrent); |
michael@0 | 273 | fNumsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status); |
michael@0 | 274 | ures_close(nsCurrent); |
michael@0 | 275 | } |
michael@0 | 276 | |
michael@0 | 277 | ures_close(numberingSystemsInfo); |
michael@0 | 278 | availableNames = new NumsysNameEnumeration(fNumsysNames,status); |
michael@0 | 279 | |
michael@0 | 280 | } |
michael@0 | 281 | |
michael@0 | 282 | return availableNames; |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | UBool NumberingSystem::isValidDigitString(const UnicodeString& str) { |
michael@0 | 286 | |
michael@0 | 287 | StringCharacterIterator it(str); |
michael@0 | 288 | UChar32 c; |
michael@0 | 289 | int32_t i = 0; |
michael@0 | 290 | |
michael@0 | 291 | for ( it.setToStart(); it.hasNext(); ) { |
michael@0 | 292 | c = it.next32PostInc(); |
michael@0 | 293 | if ( c > 0xFFFF ) { // Digits outside the BMP are not currently supported |
michael@0 | 294 | return FALSE; |
michael@0 | 295 | } |
michael@0 | 296 | i++; |
michael@0 | 297 | } |
michael@0 | 298 | return TRUE; |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | NumsysNameEnumeration::NumsysNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) { |
michael@0 | 302 | pos=0; |
michael@0 | 303 | fNumsysNames = fNameList; |
michael@0 | 304 | } |
michael@0 | 305 | |
michael@0 | 306 | const UnicodeString* |
michael@0 | 307 | NumsysNameEnumeration::snext(UErrorCode& status) { |
michael@0 | 308 | if (U_SUCCESS(status) && pos < fNumsysNames->size()) { |
michael@0 | 309 | return (const UnicodeString*)fNumsysNames->elementAt(pos++); |
michael@0 | 310 | } |
michael@0 | 311 | return NULL; |
michael@0 | 312 | } |
michael@0 | 313 | |
michael@0 | 314 | void |
michael@0 | 315 | NumsysNameEnumeration::reset(UErrorCode& /*status*/) { |
michael@0 | 316 | pos=0; |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | int32_t |
michael@0 | 320 | NumsysNameEnumeration::count(UErrorCode& /*status*/) const { |
michael@0 | 321 | return (fNumsysNames==NULL) ? 0 : fNumsysNames->size(); |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | NumsysNameEnumeration::~NumsysNameEnumeration() { |
michael@0 | 325 | delete fNumsysNames; |
michael@0 | 326 | } |
michael@0 | 327 | U_NAMESPACE_END |
michael@0 | 328 | |
michael@0 | 329 | #endif /* #if !UCONFIG_NO_FORMATTING */ |
michael@0 | 330 | |
michael@0 | 331 | //eof |