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