static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) { RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec); if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) { fmt->setDefaultRuleSet(defaultRuleSet, ec); if (U_FAILURE(ec)) { // ignore unrecognized default rule set ec = U_ZERO_ERROR; } } return fmt; }
U_CAPI void U_EXPORT2 unum_setTextAttribute( UNumberFormat* fmt, UNumberFormatTextAttribute tag, const UChar* newValue, int32_t newValueLength, UErrorCode *status) { if(U_FAILURE(*status)) return; int32_t len = (newValueLength == -1 ? u_strlen(newValue) : newValueLength); const UnicodeString val((UChar*)newValue, len, len); NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt); DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); if (df != NULL) { switch(tag) { case UNUM_POSITIVE_PREFIX: df->setPositivePrefix(val); break; case UNUM_POSITIVE_SUFFIX: df->setPositiveSuffix(val); break; case UNUM_NEGATIVE_PREFIX: df->setNegativePrefix(val); break; case UNUM_NEGATIVE_SUFFIX: df->setNegativeSuffix(val); break; case UNUM_PADDING_CHARACTER: df->setPadCharacter(*newValue); break; case UNUM_CURRENCY_CODE: df->setCurrency(newValue, *status); break; default: *status = U_UNSUPPORTED_ERROR; break; } } else { RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf); U_ASSERT(rbnf != NULL); if (tag == UNUM_DEFAULT_RULESET) { rbnf->setDefaultRuleSet(newValue, *status); } else { *status = U_UNSUPPORTED_ERROR; } } }
//If it doesn't format as expected, try to use time format, as Pierre suggests... void XLinuxIntlMgr::FormatDuration(const VDuration& inDuration, VString& outDuration) const { double val=inDuration.GetReal()/1000; //We want sec, not ms UErrorCode err=U_ZERO_ERROR; RuleBasedNumberFormat durationFmt (URBNF_DURATION, fLocale, err); xbox_assert(err==U_ZERO_ERROR); icu::UnicodeString tmpDuration; durationFmt.format(val, tmpDuration); outDuration=VString(tmpDuration.getTerminatedBuffer()); }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, EStyles style, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= kStyleCount) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } #ifdef U_WINDOWS char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat if (count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case kNumberStyle: curr = FALSE; // fall-through case kCurrencyStyle: case kIsoCurrencyStyle: // do not support plural formatting here case kPluralCurrencyStyle: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } #endif NumberFormat* f = NULL; DecimalFormatSymbols* symbolsToAdopt = NULL; UnicodeString pattern; UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status); UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status); NumberingSystem *ns = NULL; UBool deleteSymbols = TRUE; UHashtable * cache = NULL; int32_t hashKey; UBool getCache = FALSE; UBool deleteNS = FALSE; if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. symbolsToAdopt = new DecimalFormatSymbols(status); // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // If not all the styled patterns exists for the NumberFormat in this locale, // sets the status code to failure and returns nil. if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0])) -2 ) { //minus 2: ISO and plural status = U_INVALID_FORMAT_ERROR; goto cleanup; } // Loads the decimal symbols of the desired locale. symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status); int32_t patLen = 0; /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE, * the pattern is the same as the pattern of CURRENCYSTYLE * but by replacing the single currency sign with * double currency sign or triple currency sign. */ int styleInNumberPattern = ((style == kIsoCurrencyStyle || style == kPluralCurrencyStyle) ? kCurrencyStyle : style); const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)styleInNumberPattern, &patLen, &status); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status) || symbolsToAdopt == NULL) { goto cleanup; } if(style==kCurrencyStyle || style == kIsoCurrencyStyle){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } // Use numbering system cache hashtable UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache); if (getCache) { umtx_lock(&nscacheMutex); cache = NumberingSystem_cache; umtx_unlock(&nscacheMutex); } // Check cache we got, create if non-existant status = U_ZERO_ERROR; if (cache == NULL) { cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); if (cache == NULL || U_FAILURE(status)) { // cache not created - out of memory cache = NULL; } else { // cache created uhash_setValueDeleter(cache, deleteNumberingSystem); // set final NumberingSystem_cache value UHashtable* h = NULL; UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache); if (getCache) { umtx_lock(&nscacheMutex); h = NumberingSystem_cache; umtx_unlock(&nscacheMutex); } if (h == NULL) { umtx_lock(&nscacheMutex); NumberingSystem_cache = h = cache; cache = NULL; ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); umtx_unlock(&nscacheMutex); } if(cache != NULL) { uhash_close(cache); } cache = h; } } // Get cached numbering system if (cache != NULL) { hashKey = desiredLocale.hashCode(); umtx_lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(cache, hashKey, (void*)ns, &status); } umtx_unlock(&nscacheMutex); } else { ns = NumberingSystem::createInstance(desiredLocale,status); deleteNS = TRUE; } // check results of getting a numbering system if ((ns == NULL) || (U_FAILURE(status))) { goto cleanup; } if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; UnicodeString nsRuleSetName; Locale nsLoc; URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; nsDesc.setTo(ns->getDescription()); int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { char nsLocID[ULOC_FULLNAME_CAPACITY]; nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { desiredRulesType = URBNF_SPELLOUT; } } else { nsLoc = desiredLocale; nsRuleSetName.setTo(nsDesc); } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); if (U_FAILURE(status) || r == NULL) { goto cleanup; } r->setDefaultRuleSet(nsRuleSetName,status); f = (NumberFormat *) r; } else { // replace single currency sign in the pattern with double currency sign // if the style is kIsoCurrencyStyle if (style == kIsoCurrencyStyle) { pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign); } f = new DecimalFormat(pattern, symbolsToAdopt, style, status); if (U_FAILURE(status) || f == NULL) { goto cleanup; } deleteSymbols = FALSE; } f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status), ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status)); cleanup: ures_close(numberPatterns); ures_close(resource); if (deleteNS && ns) { delete ns; } if (U_FAILURE(status)) { /* If f exists, then it will delete the symbols */ if (f==NULL) { delete symbolsToAdopt; } else { delete f; } return NULL; } if (f == NULL || symbolsToAdopt == NULL) { status = U_MEMORY_ALLOCATION_ERROR; f = NULL; } if (deleteSymbols && symbolsToAdopt != NULL) { delete symbolsToAdopt; } return f; }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, UNumberFormatStyle style, UBool mustBeDecimalFormat, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // Some styles are not supported. This is a result of merging // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle. // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations: // this one and unum_open(). // The UNUM_PATTERN_ styles are not supported here // because this method does not take a pattern string. if (!isStyleSupported(style)) { status = U_UNSUPPORTED_ERROR; return NULL; } #if U_PLATFORM_USES_ONLY_WIN32_API if (!mustBeDecimalFormat) { char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case UNUM_DECIMAL: curr = FALSE; // fall-through case UNUM_CURRENCY: case UNUM_CURRENCY_ISO: // do not support plural formatting here case UNUM_CURRENCY_PLURAL: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } } #endif // Use numbering system cache hashtable umtx_initOnce(gNSCacheInitOnce, &nscacheInit); // Get cached numbering system LocalPointer<NumberingSystem> ownedNs; NumberingSystem *ns = NULL; if (NumberingSystem_cache != NULL) { // TODO: Bad hash key usage, see ticket #8504. int32_t hashKey = desiredLocale.hashCode(); Mutex lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status); } } else { ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); ns = ownedNs.getAlias(); } // check results of getting a numbering system if (U_FAILURE(status)) { return NULL; } if (mustBeDecimalFormat && ns->isAlgorithmic()) { status = U_UNSUPPORTED_ERROR; return NULL; } LocalPointer<DecimalFormatSymbols> symbolsToAdopt; UnicodeString pattern; LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status)); if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // Loads the decimal symbols of the desired locale. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } UResourceBundle *resource = ownedResource.orphan(); UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status); resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); ownedResource.adoptInstead(resource); int32_t patLen = 0; const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); // Didn't find a pattern specific to the numbering system, so fall back to "latn" if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) { status = U_ZERO_ERROR; resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); } ures_close(numElements); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status)) { return NULL; } if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } NumberFormat *f; if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; UnicodeString nsRuleSetName; Locale nsLoc; URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; nsDesc.setTo(ns->getDescription()); int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { CharString nsLocID; nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID.data()); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { desiredRulesType = URBNF_SPELLOUT; } } else { nsLoc = desiredLocale; nsRuleSetName.setTo(nsDesc); } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); if (r == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } r->setDefaultRuleSet(nsRuleSetName,status); f = r; } else { // replace single currency sign in the pattern with double currency sign // if the style is UNUM_CURRENCY_ISO if (style == UNUM_CURRENCY_ISO) { pattern.findAndReplace(UnicodeString(TRUE, gSingleCurrencySign, 1), UnicodeString(TRUE, gDoubleCurrencySign, 2)); } // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); f = new DecimalFormat(pattern, syms, style, status); if (f == NULL) { delete syms; status = U_MEMORY_ALLOCATION_ERROR; return NULL; } } f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); if (U_FAILURE(status)) { delete f; return NULL; } return f; }
static jstring formatDoubleRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jdouble value, jobject field, jstring fieldType, jobject attributes) { // LOGI("ENTER formatDoubleRBNFImpl"); const char * fieldPositionClassName = "java/text/FieldPosition"; const char * stringBufferClassName = "java/lang/StringBuffer"; jclass fieldPositionClass = env->FindClass(fieldPositionClassName); jclass stringBufferClass = env->FindClass(stringBufferClassName); jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, "setBeginIndex", "(I)V"); jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, "setEndIndex", "(I)V"); jmethodID appendMethodID = env->GetMethodID(stringBufferClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); const char * fieldName = NULL; if(fieldType != NULL) { fieldName = env->GetStringUTFChars(fieldType, NULL); } uint32_t reslenneeded; double val = value; UChar *result = NULL; FieldPosition fp; fp.setField(FieldPosition::DONT_CARE); UErrorCode status = U_ZERO_ERROR; RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr; UnicodeString res; fmt->format(val, res, fp); reslenneeded = res.extract(NULL, 0, status); if(status==U_BUFFER_OVERFLOW_ERROR) { status=U_ZERO_ERROR; result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1)); res.extract(result, reslenneeded + 1, status); } if (icuError(env, status) != FALSE) { free(result); return NULL; } if(fieldType != NULL) { env->ReleaseStringUTFChars(fieldType, fieldName); } jstring resulting = env->NewString(result, reslenneeded); free(result); return resulting; }
U_CAPI void U_EXPORT2 unum_setAttribute( UNumberFormat* fmt, UNumberFormatAttribute attr, int32_t newValue) { NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt); DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); if (df != NULL) { switch(attr) { case UNUM_PARSE_INT_ONLY: df->setParseIntegerOnly(newValue!=0); break; case UNUM_GROUPING_USED: df->setGroupingUsed(newValue!=0); break; case UNUM_DECIMAL_ALWAYS_SHOWN: df->setDecimalSeparatorAlwaysShown(newValue!=0); break; case UNUM_MAX_INTEGER_DIGITS: df->setMaximumIntegerDigits(newValue); break; case UNUM_MIN_INTEGER_DIGITS: df->setMinimumIntegerDigits(newValue); break; case UNUM_INTEGER_DIGITS: df->setMinimumIntegerDigits(newValue); df->setMaximumIntegerDigits(newValue); break; case UNUM_MAX_FRACTION_DIGITS: df->setMaximumFractionDigits(newValue); break; case UNUM_MIN_FRACTION_DIGITS: df->setMinimumFractionDigits(newValue); break; case UNUM_FRACTION_DIGITS: df->setMinimumFractionDigits(newValue); df->setMaximumFractionDigits(newValue); break; case UNUM_SIGNIFICANT_DIGITS_USED: df->setSignificantDigitsUsed(newValue!=0); break; case UNUM_MAX_SIGNIFICANT_DIGITS: df->setMaximumSignificantDigits(newValue); break; case UNUM_MIN_SIGNIFICANT_DIGITS: df->setMinimumSignificantDigits(newValue); break; case UNUM_MULTIPLIER: df->setMultiplier(newValue); break; case UNUM_GROUPING_SIZE: df->setGroupingSize(newValue); break; case UNUM_ROUNDING_MODE: df->setRoundingMode((DecimalFormat::ERoundingMode)newValue); break; case UNUM_FORMAT_WIDTH: df->setFormatWidth(newValue); break; case UNUM_PADDING_POSITION: /** The position at which padding will take place. */ df->setPadPosition((DecimalFormat::EPadPosition)newValue); break; case UNUM_SECONDARY_GROUPING_SIZE: df->setSecondaryGroupingSize(newValue); break; case UNUM_LENIENT_PARSE: df->setParseStrict(newValue == 0); break; default: /* Shouldn't get here anyway */ break; } } else { RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf); U_ASSERT(rbnf != NULL); if (attr == UNUM_LENIENT_PARSE) { #if !UCONFIG_NO_COLLATION rbnf->setLenient((UBool)newValue); #endif } } }
void NUMBER_Format(sLONG_PTR *pResult, PackagePtr pParams) { C_REAL Param1; C_TEXT Param2; C_LONGINT Param3; C_TEXT Param4; C_TEXT Param5; C_LONGINT returnValue; Param1.fromParamAtIndex(pParams, 1); Param3.fromParamAtIndex(pParams, 3); Param4.fromParamAtIndex(pParams, 4); Param5.fromParamAtIndex(pParams, 5); // --- write the code of NUMBER_Format here... UErrorCode status = U_ZERO_ERROR; UParseError perror; Locale locale; if(Param4.getUTF16Length()){ CUTF8String u; Param4.copyUTF8String(&u); Locale inLocale = Locale((const char *)u.c_str()); if(!inLocale.isBogus()){ locale = Locale(inLocale); }else{ status = U_ILLEGAL_ARGUMENT_ERROR; } } if(status == U_ZERO_ERROR){ int mode = Param3.getIntValue(); if(mode == NUMBER_FORMAT_CUSTOM){ if(Param5.getUTF16Length()){ UnicodeString rules = UnicodeString((const UChar *)Param5.getUTF16StringPtr()); RuleBasedNumberFormat fmt = RuleBasedNumberFormat(rules, locale, perror, status); if(status == U_ZERO_ERROR || status == U_USING_DEFAULT_WARNING || status == U_USING_FALLBACK_WARNING){ UnicodeString numberString; fmt.format(Param1.getDoubleValue(), numberString); DT::setUnicodeString(Param2, numberString); status = U_ZERO_ERROR; } }else{ status = U_ILLEGAL_ARGUMENT_ERROR; } }else{ switch (mode) { case NUMBER_FORMAT_SPELLOUT: case NUMBER_FORMAT_ORDINAL: case NUMBER_FORMAT_DURATION: case NUMBER_FORMAT_NUMBERING_SYSTEM: case NUMBER_FORMAT_COUNT: { RuleBasedNumberFormat fmt = RuleBasedNumberFormat((URBNFRuleSetTag)mode, locale, status); if(status == U_ZERO_ERROR || status == U_USING_DEFAULT_WARNING || status == U_USING_FALLBACK_WARNING){ UnicodeString numberString; fmt.format(Param1.getDoubleValue(), numberString); DT::setUnicodeString(Param2, numberString); status = U_ZERO_ERROR; } } break; default: status = U_ILLEGAL_ARGUMENT_ERROR; break; } } } Param2.toParamAtIndex(pParams, 2); returnValue.setIntValue(status); returnValue.setReturn(pResult); }