1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2010-2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
12 * Modification History:*
13 * Date Name Description
15 ********************************************************************************
18 #include "unicode/utypes.h"
19 #include "unicode/localpointer.h"
20 #include "unicode/uchar.h"
21 #include "unicode/unistr.h"
22 #include "unicode/ures.h"
23 #include "unicode/ustring.h"
24 #include "unicode/uloc.h"
25 #include "unicode/schriter.h"
26 #include "unicode/numsys.h"
30 #include "numsys_impl.h"
32 #if !UCONFIG_NO_FORMATTING
38 #define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789");
39 static const char gNumberingSystems
[] = "numberingSystems";
40 static const char gNumberElements
[] = "NumberElements";
41 static const char gDefault
[] = "default";
42 static const char gNative
[] = "native";
43 static const char gTraditional
[] = "traditional";
44 static const char gFinance
[] = "finance";
45 static const char gDesc
[] = "desc";
46 static const char gRadix
[] = "radix";
47 static const char gAlgorithmic
[] = "algorithmic";
48 static const char gLatn
[] = "latn";
51 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem
)
52 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration
)
55 * Default Constructor.
60 NumberingSystem::NumberingSystem() {
63 UnicodeString defaultDigits
= DEFAULT_DIGITS
;
64 desc
.setTo(defaultDigits
);
65 uprv_strcpy(name
,gLatn
);
73 NumberingSystem::NumberingSystem(const NumberingSystem
& other
)
78 NumberingSystem
* U_EXPORT2
79 NumberingSystem::createInstance(int32_t radix_in
, UBool isAlgorithmic_in
, const UnicodeString
& desc_in
, UErrorCode
&status
) {
81 if (U_FAILURE(status
)) {
86 status
= U_ILLEGAL_ARGUMENT_ERROR
;
90 if ( !isAlgorithmic_in
) {
91 if ( desc_in
.countChar32() != radix_in
) {
92 status
= U_ILLEGAL_ARGUMENT_ERROR
;
97 NumberingSystem
*ns
= new NumberingSystem();
99 ns
->setRadix(radix_in
);
100 ns
->setDesc(desc_in
);
101 ns
->setAlgorithmic(isAlgorithmic_in
);
108 NumberingSystem
* U_EXPORT2
109 NumberingSystem::createInstance(const Locale
& inLocale
, UErrorCode
& status
) {
111 if (U_FAILURE(status
)) {
115 UBool nsResolved
= TRUE
;
116 UBool usingFallback
= FALSE
;
117 char buffer
[ULOC_KEYWORDS_CAPACITY
];
118 int32_t count
= inLocale
.getKeywordValue("numbers",buffer
, sizeof(buffer
),status
);
119 if (U_FAILURE(status
) || status
== U_STRING_NOT_TERMINATED_WARNING
) {
120 // the "numbers" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default.
122 status
= U_ZERO_ERROR
;
124 if ( count
> 0 ) { // @numbers keyword was specified in the locale
125 U_ASSERT(count
< ULOC_KEYWORDS_CAPACITY
);
126 buffer
[count
] = '\0'; // Make sure it is null terminated.
127 if ( !uprv_strcmp(buffer
,gDefault
) || !uprv_strcmp(buffer
,gNative
) ||
128 !uprv_strcmp(buffer
,gTraditional
) || !uprv_strcmp(buffer
,gFinance
)) {
132 uprv_strcpy(buffer
,gDefault
);
136 if (!nsResolved
) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system
137 UErrorCode localStatus
= U_ZERO_ERROR
;
138 UResourceBundle
*resource
= ures_open(NULL
, inLocale
.getName(), &localStatus
);
139 UResourceBundle
*numberElementsRes
= ures_getByKey(resource
,gNumberElements
,NULL
,&localStatus
);
140 while (!nsResolved
) {
141 localStatus
= U_ZERO_ERROR
;
143 const UChar
*nsName
= ures_getStringByKeyWithFallback(numberElementsRes
, buffer
, &count
, &localStatus
);
144 if ( count
> 0 && count
< ULOC_KEYWORDS_CAPACITY
) { // numbering system found
145 u_UCharsToChars(nsName
,buffer
,count
);
146 buffer
[count
] = '\0'; // Make sure it is null terminated.
150 if (!nsResolved
) { // Fallback behavior per TR35 - traditional falls back to native, finance and native fall back to default
151 if (!uprv_strcmp(buffer
,gNative
) || !uprv_strcmp(buffer
,gFinance
)) {
152 uprv_strcpy(buffer
,gDefault
);
153 } else if (!uprv_strcmp(buffer
,gTraditional
)) {
154 uprv_strcpy(buffer
,gNative
);
155 } else { // If we get here we couldn't find even the default numbering system
156 usingFallback
= TRUE
;
161 ures_close(numberElementsRes
);
162 ures_close(resource
);
166 status
= U_USING_FALLBACK_WARNING
;
167 NumberingSystem
*ns
= new NumberingSystem();
170 return NumberingSystem::createInstanceByName(buffer
,status
);
174 NumberingSystem
* U_EXPORT2
175 NumberingSystem::createInstance(UErrorCode
& status
) {
176 return NumberingSystem::createInstance(Locale::getDefault(), status
);
179 NumberingSystem
* U_EXPORT2
180 NumberingSystem::createInstanceByName(const char *name
, UErrorCode
& status
) {
181 UResourceBundle
*numberingSystemsInfo
= NULL
;
182 UResourceBundle
*nsTop
, *nsCurrent
;
184 int32_t algorithmic
= 0;
186 numberingSystemsInfo
= ures_openDirect(NULL
,gNumberingSystems
, &status
);
187 nsCurrent
= ures_getByKey(numberingSystemsInfo
,gNumberingSystems
,NULL
,&status
);
188 nsTop
= ures_getByKey(nsCurrent
,name
,NULL
,&status
);
189 UnicodeString nsd
= ures_getUnicodeStringByKey(nsTop
,gDesc
,&status
);
191 ures_getByKey(nsTop
,gRadix
,nsCurrent
,&status
);
192 radix
= ures_getInt(nsCurrent
,&status
);
194 ures_getByKey(nsTop
,gAlgorithmic
,nsCurrent
,&status
);
195 algorithmic
= ures_getInt(nsCurrent
,&status
);
197 UBool isAlgorithmic
= ( algorithmic
== 1 );
199 ures_close(nsCurrent
);
201 ures_close(numberingSystemsInfo
);
203 if (U_FAILURE(status
)) {
204 status
= U_UNSUPPORTED_ERROR
;
208 NumberingSystem
* ns
= NumberingSystem::createInstance(radix
,isAlgorithmic
,nsd
,status
);
217 NumberingSystem::~NumberingSystem() {
220 int32_t NumberingSystem::getRadix() const {
224 UnicodeString
NumberingSystem::getDescription() const {
228 const char * NumberingSystem::getName() const {
232 void NumberingSystem::setRadix(int32_t r
) {
236 void NumberingSystem::setAlgorithmic(UBool c
) {
240 void NumberingSystem::setDesc(const UnicodeString
&d
) {
243 void NumberingSystem::setName(const char *n
) {
247 uprv_strncpy(name
,n
,NUMSYS_NAME_CAPACITY
);
248 name
[NUMSYS_NAME_CAPACITY
] = (char)0; // Make sure it is null terminated.
251 UBool
NumberingSystem::isAlgorithmic() const {
252 return ( algorithmic
);
255 StringEnumeration
* NumberingSystem::getAvailableNames(UErrorCode
&status
) {
256 // TODO(ticket #11908): Init-once static cache, with u_cleanup() callback.
257 static StringEnumeration
* availableNames
= NULL
;
259 if (U_FAILURE(status
)) {
263 if ( availableNames
== NULL
) {
264 // TODO: Simple array of UnicodeString objects, based on length of table resource?
265 LocalPointer
<UVector
> numsysNames(new UVector(uprv_deleteUObject
, NULL
, status
), status
);
266 if (U_FAILURE(status
)) {
270 UErrorCode rbstatus
= U_ZERO_ERROR
;
271 UResourceBundle
*numberingSystemsInfo
= ures_openDirect(NULL
, "numberingSystems", &rbstatus
);
272 numberingSystemsInfo
= ures_getByKey(numberingSystemsInfo
,"numberingSystems",numberingSystemsInfo
,&rbstatus
);
273 if(U_FAILURE(rbstatus
)) {
274 status
= U_MISSING_RESOURCE_ERROR
;
275 ures_close(numberingSystemsInfo
);
279 while ( ures_hasNext(numberingSystemsInfo
) ) {
280 UResourceBundle
*nsCurrent
= ures_getNextResource(numberingSystemsInfo
,NULL
,&rbstatus
);
281 const char *nsName
= ures_getKey(nsCurrent
);
282 numsysNames
->addElement(new UnicodeString(nsName
, -1, US_INV
),status
);
283 ures_close(nsCurrent
);
286 ures_close(numberingSystemsInfo
);
287 if (U_FAILURE(status
)) {
290 availableNames
= new NumsysNameEnumeration(numsysNames
.getAlias(), status
);
291 if (availableNames
== NULL
) {
292 status
= U_MEMORY_ALLOCATION_ERROR
;
295 numsysNames
.orphan(); // The names got adopted.
298 return availableNames
;
301 NumsysNameEnumeration::NumsysNameEnumeration(UVector
*numsysNames
, UErrorCode
& /*status*/) {
303 fNumsysNames
= numsysNames
;
307 NumsysNameEnumeration::snext(UErrorCode
& status
) {
308 if (U_SUCCESS(status
) && pos
< fNumsysNames
->size()) {
309 return (const UnicodeString
*)fNumsysNames
->elementAt(pos
++);
315 NumsysNameEnumeration::reset(UErrorCode
& /*status*/) {
320 NumsysNameEnumeration::count(UErrorCode
& /*status*/) const {
321 return (fNumsysNames
==NULL
) ? 0 : fNumsysNames
->size();
324 NumsysNameEnumeration::~NumsysNameEnumeration() {
329 #endif /* #if !UCONFIG_NO_FORMATTING */