michael@0: /* michael@0: ******************************************************************************* michael@0: * Copyright (C) 2010-2013, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: ******************************************************************************* michael@0: * michael@0: * michael@0: * File NUMSYS.CPP michael@0: * michael@0: * Modification History:* michael@0: * Date Name Description michael@0: * michael@0: ******************************************************************************** michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: #include "unicode/localpointer.h" michael@0: #include "unicode/uchar.h" michael@0: #include "unicode/unistr.h" michael@0: #include "unicode/ures.h" michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/uloc.h" michael@0: #include "unicode/schriter.h" michael@0: #include "unicode/numsys.h" michael@0: #include "cstring.h" michael@0: #include "uresimp.h" michael@0: #include "numsys_impl.h" michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: // Useful constants michael@0: michael@0: #define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789"); michael@0: static const char gNumberingSystems[] = "numberingSystems"; michael@0: static const char gNumberElements[] = "NumberElements"; michael@0: static const char gDefault[] = "default"; michael@0: static const char gNative[] = "native"; michael@0: static const char gTraditional[] = "traditional"; michael@0: static const char gFinance[] = "finance"; michael@0: static const char gDesc[] = "desc"; michael@0: static const char gRadix[] = "radix"; michael@0: static const char gAlgorithmic[] = "algorithmic"; michael@0: static const char gLatn[] = "latn"; michael@0: michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem) michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration) michael@0: michael@0: /** michael@0: * Default Constructor. michael@0: * michael@0: * @draft ICU 4.2 michael@0: */ michael@0: michael@0: NumberingSystem::NumberingSystem() { michael@0: radix = 10; michael@0: algorithmic = FALSE; michael@0: UnicodeString defaultDigits = DEFAULT_DIGITS; michael@0: desc.setTo(defaultDigits); michael@0: uprv_strcpy(name,gLatn); michael@0: } michael@0: michael@0: /** michael@0: * Copy constructor. michael@0: * @draft ICU 4.2 michael@0: */ michael@0: michael@0: NumberingSystem::NumberingSystem(const NumberingSystem& other) michael@0: : UObject(other) { michael@0: *this=other; michael@0: } michael@0: michael@0: NumberingSystem* U_EXPORT2 michael@0: NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) { michael@0: michael@0: if (U_FAILURE(status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: if ( radix_in < 2 ) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return NULL; michael@0: } michael@0: michael@0: if ( !isAlgorithmic_in ) { michael@0: if ( desc_in.countChar32() != radix_in || !isValidDigitString(desc_in)) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: NumberingSystem *ns = new NumberingSystem(); michael@0: michael@0: ns->setRadix(radix_in); michael@0: ns->setDesc(desc_in); michael@0: ns->setAlgorithmic(isAlgorithmic_in); michael@0: ns->setName(NULL); michael@0: return ns; michael@0: michael@0: } michael@0: michael@0: michael@0: NumberingSystem* U_EXPORT2 michael@0: NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) { michael@0: michael@0: if (U_FAILURE(status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: UBool nsResolved = TRUE; michael@0: UBool usingFallback = FALSE; michael@0: char buffer[ULOC_KEYWORDS_CAPACITY]; michael@0: int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status); michael@0: if ( count > 0 ) { // @numbers keyword was specified in the locale michael@0: buffer[count] = '\0'; // Make sure it is null terminated. michael@0: if ( !uprv_strcmp(buffer,gDefault) || !uprv_strcmp(buffer,gNative) || michael@0: !uprv_strcmp(buffer,gTraditional) || !uprv_strcmp(buffer,gFinance)) { michael@0: nsResolved = FALSE; michael@0: } michael@0: } else { michael@0: uprv_strcpy(buffer,gDefault); michael@0: nsResolved = FALSE; michael@0: } michael@0: michael@0: if (!nsResolved) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system michael@0: UErrorCode localStatus = U_ZERO_ERROR; michael@0: UResourceBundle *resource = ures_open(NULL, inLocale.getName(), &localStatus); michael@0: UResourceBundle *numberElementsRes = ures_getByKey(resource,gNumberElements,NULL,&localStatus); michael@0: while (!nsResolved) { michael@0: localStatus = U_ZERO_ERROR; michael@0: count = 0; michael@0: const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes, buffer, &count, &localStatus); michael@0: if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // numbering system found michael@0: u_UCharsToChars(nsName,buffer,count); michael@0: buffer[count] = '\0'; // Make sure it is null terminated. michael@0: nsResolved = TRUE; michael@0: } michael@0: michael@0: if (!nsResolved) { // Fallback behavior per TR35 - traditional falls back to native, finance and native fall back to default michael@0: if (!uprv_strcmp(buffer,gNative) || !uprv_strcmp(buffer,gFinance)) { michael@0: uprv_strcpy(buffer,gDefault); michael@0: } else if (!uprv_strcmp(buffer,gTraditional)) { michael@0: uprv_strcpy(buffer,gNative); michael@0: } else { // If we get here we couldn't find even the default numbering system michael@0: usingFallback = TRUE; michael@0: nsResolved = TRUE; michael@0: } michael@0: } michael@0: } michael@0: ures_close(numberElementsRes); michael@0: ures_close(resource); michael@0: } michael@0: michael@0: if (usingFallback) { michael@0: status = U_USING_FALLBACK_WARNING; michael@0: NumberingSystem *ns = new NumberingSystem(); michael@0: return ns; michael@0: } else { michael@0: return NumberingSystem::createInstanceByName(buffer,status); michael@0: } michael@0: } michael@0: michael@0: NumberingSystem* U_EXPORT2 michael@0: NumberingSystem::createInstance(UErrorCode& status) { michael@0: return NumberingSystem::createInstance(Locale::getDefault(), status); michael@0: } michael@0: michael@0: NumberingSystem* U_EXPORT2 michael@0: NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) { michael@0: UResourceBundle *numberingSystemsInfo = NULL; michael@0: UResourceBundle *nsTop, *nsCurrent; michael@0: int32_t radix = 10; michael@0: int32_t algorithmic = 0; michael@0: michael@0: numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status); michael@0: nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status); michael@0: nsTop = ures_getByKey(nsCurrent,name,NULL,&status); michael@0: UnicodeString nsd = ures_getUnicodeStringByKey(nsTop,gDesc,&status); michael@0: michael@0: ures_getByKey(nsTop,gRadix,nsCurrent,&status); michael@0: radix = ures_getInt(nsCurrent,&status); michael@0: michael@0: ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status); michael@0: algorithmic = ures_getInt(nsCurrent,&status); michael@0: michael@0: UBool isAlgorithmic = ( algorithmic == 1 ); michael@0: michael@0: ures_close(nsCurrent); michael@0: ures_close(nsTop); michael@0: ures_close(numberingSystemsInfo); michael@0: michael@0: if (U_FAILURE(status)) { michael@0: status = U_UNSUPPORTED_ERROR; michael@0: return NULL; michael@0: } michael@0: michael@0: NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status); michael@0: ns->setName(name); michael@0: return ns; michael@0: } michael@0: michael@0: /** michael@0: * Destructor. michael@0: * @draft ICU 4.2 michael@0: */ michael@0: NumberingSystem::~NumberingSystem() { michael@0: } michael@0: michael@0: int32_t NumberingSystem::getRadix() const { michael@0: return radix; michael@0: } michael@0: michael@0: UnicodeString NumberingSystem::getDescription() const { michael@0: return desc; michael@0: } michael@0: michael@0: const char * NumberingSystem::getName() const { michael@0: return name; michael@0: } michael@0: michael@0: void NumberingSystem::setRadix(int32_t r) { michael@0: radix = r; michael@0: } michael@0: michael@0: void NumberingSystem::setAlgorithmic(UBool c) { michael@0: algorithmic = c; michael@0: } michael@0: michael@0: void NumberingSystem::setDesc(UnicodeString d) { michael@0: desc.setTo(d); michael@0: } michael@0: void NumberingSystem::setName(const char *n) { michael@0: if ( n == NULL ) { michael@0: name[0] = (char) 0; michael@0: } else { michael@0: uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY); michael@0: name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated. michael@0: } michael@0: } michael@0: UBool NumberingSystem::isAlgorithmic() const { michael@0: return ( algorithmic ); michael@0: } michael@0: michael@0: StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) { michael@0: michael@0: static StringEnumeration* availableNames = NULL; michael@0: michael@0: if (U_FAILURE(status)) { michael@0: return NULL; michael@0: } michael@0: michael@0: if ( availableNames == NULL ) { michael@0: UVector *fNumsysNames = new UVector(uprv_deleteUObject, NULL, status); michael@0: if (U_FAILURE(status)) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: michael@0: UErrorCode rbstatus = U_ZERO_ERROR; michael@0: UResourceBundle *numberingSystemsInfo = ures_openDirect(NULL, "numberingSystems", &rbstatus); michael@0: numberingSystemsInfo = ures_getByKey(numberingSystemsInfo,"numberingSystems",numberingSystemsInfo,&rbstatus); michael@0: if(U_FAILURE(rbstatus)) { michael@0: status = U_MISSING_RESOURCE_ERROR; michael@0: ures_close(numberingSystemsInfo); michael@0: return NULL; michael@0: } michael@0: michael@0: while ( ures_hasNext(numberingSystemsInfo) ) { michael@0: UResourceBundle *nsCurrent = ures_getNextResource(numberingSystemsInfo,NULL,&rbstatus); michael@0: const char *nsName = ures_getKey(nsCurrent); michael@0: fNumsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status); michael@0: ures_close(nsCurrent); michael@0: } michael@0: michael@0: ures_close(numberingSystemsInfo); michael@0: availableNames = new NumsysNameEnumeration(fNumsysNames,status); michael@0: michael@0: } michael@0: michael@0: return availableNames; michael@0: } michael@0: michael@0: UBool NumberingSystem::isValidDigitString(const UnicodeString& str) { michael@0: michael@0: StringCharacterIterator it(str); michael@0: UChar32 c; michael@0: int32_t i = 0; michael@0: michael@0: for ( it.setToStart(); it.hasNext(); ) { michael@0: c = it.next32PostInc(); michael@0: if ( c > 0xFFFF ) { // Digits outside the BMP are not currently supported michael@0: return FALSE; michael@0: } michael@0: i++; michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: NumsysNameEnumeration::NumsysNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) { michael@0: pos=0; michael@0: fNumsysNames = fNameList; michael@0: } michael@0: michael@0: const UnicodeString* michael@0: NumsysNameEnumeration::snext(UErrorCode& status) { michael@0: if (U_SUCCESS(status) && pos < fNumsysNames->size()) { michael@0: return (const UnicodeString*)fNumsysNames->elementAt(pos++); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: void michael@0: NumsysNameEnumeration::reset(UErrorCode& /*status*/) { michael@0: pos=0; michael@0: } michael@0: michael@0: int32_t michael@0: NumsysNameEnumeration::count(UErrorCode& /*status*/) const { michael@0: return (fNumsysNames==NULL) ? 0 : fNumsysNames->size(); michael@0: } michael@0: michael@0: NumsysNameEnumeration::~NumsysNameEnumeration() { michael@0: delete fNumsysNames; michael@0: } michael@0: U_NAMESPACE_END michael@0: michael@0: #endif /* #if !UCONFIG_NO_FORMATTING */ michael@0: michael@0: //eof