• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2010-2015, International Business Machines Corporation and
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 "uassert.h"
29 #include "uresimp.h"
30 #include "numsys_impl.h"
31 
32 #if !UCONFIG_NO_FORMATTING
33 
34 U_NAMESPACE_BEGIN
35 
36 // Useful constants
37 
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";
49 
50 
51 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem)
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration)52 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration)
53 
54     /**
55      * Default Constructor.
56      *
57      * @draft ICU 4.2
58      */
59 
60 NumberingSystem::NumberingSystem() {
61      radix = 10;
62      algorithmic = FALSE;
63      UnicodeString defaultDigits = DEFAULT_DIGITS;
64      desc.setTo(defaultDigits);
65      uprv_strcpy(name,gLatn);
66 }
67 
68     /**
69      * Copy constructor.
70      * @draft ICU 4.2
71      */
72 
NumberingSystem(const NumberingSystem & other)73 NumberingSystem::NumberingSystem(const NumberingSystem& other)
74 :  UObject(other) {
75     *this=other;
76 }
77 
78 NumberingSystem* U_EXPORT2
createInstance(int32_t radix_in,UBool isAlgorithmic_in,const UnicodeString & desc_in,UErrorCode & status)79 NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
80 
81     if (U_FAILURE(status)) {
82         return NULL;
83     }
84 
85     if ( radix_in < 2 ) {
86         status = U_ILLEGAL_ARGUMENT_ERROR;
87         return NULL;
88     }
89 
90     if ( !isAlgorithmic_in ) {
91        if ( desc_in.countChar32() != radix_in ) {
92            status = U_ILLEGAL_ARGUMENT_ERROR;
93            return NULL;
94        }
95     }
96 
97     NumberingSystem *ns = new NumberingSystem();
98 
99     ns->setRadix(radix_in);
100     ns->setDesc(desc_in);
101     ns->setAlgorithmic(isAlgorithmic_in);
102     ns->setName(NULL);
103     return ns;
104 
105 }
106 
107 
108 NumberingSystem* U_EXPORT2
createInstance(const Locale & inLocale,UErrorCode & status)109 NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
110 
111     if (U_FAILURE(status)) {
112         return NULL;
113     }
114 
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.
121         count = 0;
122         status = U_ZERO_ERROR;
123     }
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)) {
129             nsResolved = FALSE;
130         }
131     } else {
132         uprv_strcpy(buffer,gDefault);
133         nsResolved = FALSE;
134     }
135 
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;
142             count = 0;
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.
147                 nsResolved = TRUE;
148             }
149 
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;
157                     nsResolved = TRUE;
158                 }
159             }
160         }
161         ures_close(numberElementsRes);
162         ures_close(resource);
163     }
164 
165     if (usingFallback) {
166         status = U_USING_FALLBACK_WARNING;
167         NumberingSystem *ns = new NumberingSystem();
168         return ns;
169     } else {
170         return NumberingSystem::createInstanceByName(buffer,status);
171     }
172  }
173 
174 NumberingSystem* U_EXPORT2
createInstance(UErrorCode & status)175 NumberingSystem::createInstance(UErrorCode& status) {
176     return NumberingSystem::createInstance(Locale::getDefault(), status);
177 }
178 
179 NumberingSystem* U_EXPORT2
createInstanceByName(const char * name,UErrorCode & status)180 NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) {
181     UResourceBundle *numberingSystemsInfo = NULL;
182     UResourceBundle *nsTop, *nsCurrent;
183     int32_t radix = 10;
184     int32_t algorithmic = 0;
185 
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);
190 
191     ures_getByKey(nsTop,gRadix,nsCurrent,&status);
192     radix = ures_getInt(nsCurrent,&status);
193 
194     ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status);
195     algorithmic = ures_getInt(nsCurrent,&status);
196 
197     UBool isAlgorithmic = ( algorithmic == 1 );
198 
199     ures_close(nsCurrent);
200     ures_close(nsTop);
201     ures_close(numberingSystemsInfo);
202 
203     if (U_FAILURE(status)) {
204         status = U_UNSUPPORTED_ERROR;
205         return NULL;
206     }
207 
208     NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status);
209     ns->setName(name);
210     return ns;
211 }
212 
213     /**
214      * Destructor.
215      * @draft ICU 4.2
216      */
~NumberingSystem()217 NumberingSystem::~NumberingSystem() {
218 }
219 
getRadix() const220 int32_t NumberingSystem::getRadix() const {
221     return radix;
222 }
223 
getDescription() const224 UnicodeString NumberingSystem::getDescription() const {
225     return desc;
226 }
227 
getName() const228 const char * NumberingSystem::getName() const {
229     return name;
230 }
231 
setRadix(int32_t r)232 void NumberingSystem::setRadix(int32_t r) {
233     radix = r;
234 }
235 
setAlgorithmic(UBool c)236 void NumberingSystem::setAlgorithmic(UBool c) {
237     algorithmic = c;
238 }
239 
setDesc(const UnicodeString & d)240 void NumberingSystem::setDesc(const UnicodeString &d) {
241     desc.setTo(d);
242 }
setName(const char * n)243 void NumberingSystem::setName(const char *n) {
244     if ( n == NULL ) {
245         name[0] = (char) 0;
246     } else {
247         uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY);
248         name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated.
249     }
250 }
isAlgorithmic() const251 UBool NumberingSystem::isAlgorithmic() const {
252     return ( algorithmic );
253 }
254 
getAvailableNames(UErrorCode & status)255 StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
256     // TODO(ticket #11908): Init-once static cache, with u_cleanup() callback.
257     static StringEnumeration* availableNames = NULL;
258 
259     if (U_FAILURE(status)) {
260         return NULL;
261     }
262 
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)) {
267             return NULL;
268         }
269 
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);
276             return NULL;
277         }
278 
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);
284         }
285 
286         ures_close(numberingSystemsInfo);
287         if (U_FAILURE(status)) {
288             return NULL;
289         }
290         availableNames = new NumsysNameEnumeration(numsysNames.getAlias(), status);
291         if (availableNames == NULL) {
292             status = U_MEMORY_ALLOCATION_ERROR;
293             return NULL;
294         }
295         numsysNames.orphan();  // The names got adopted.
296     }
297 
298     return availableNames;
299 }
300 
NumsysNameEnumeration(UVector * numsysNames,UErrorCode &)301 NumsysNameEnumeration::NumsysNameEnumeration(UVector *numsysNames, UErrorCode& /*status*/) {
302     pos=0;
303     fNumsysNames = numsysNames;
304 }
305 
306 const UnicodeString*
snext(UErrorCode & status)307 NumsysNameEnumeration::snext(UErrorCode& status) {
308     if (U_SUCCESS(status) && pos < fNumsysNames->size()) {
309         return (const UnicodeString*)fNumsysNames->elementAt(pos++);
310     }
311     return NULL;
312 }
313 
314 void
reset(UErrorCode &)315 NumsysNameEnumeration::reset(UErrorCode& /*status*/) {
316     pos=0;
317 }
318 
319 int32_t
count(UErrorCode &) const320 NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
321     return (fNumsysNames==NULL) ? 0 : fNumsysNames->size();
322 }
323 
~NumsysNameEnumeration()324 NumsysNameEnumeration::~NumsysNameEnumeration() {
325     delete fNumsysNames;
326 }
327 U_NAMESPACE_END
328 
329 #endif /* #if !UCONFIG_NO_FORMATTING */
330 
331 //eof
332