U_CDECL_END static U_INLINE UNumberFormat * copyInvariantFormatter(ULocaleBundle *result, UNumberFormatStyle style) { if (result->fNumberFormat[style-1] == NULL) { UErrorCode status = U_ZERO_ERROR; UBool needsInit; UMTX_CHECK(NULL, gPosixNumberFormat[style-1] == NULL, needsInit); if (needsInit) { UNumberFormat *formatAlias = unum_open(style, NULL, 0, "en_US_POSIX", NULL, &status); /* Cache upon first request. */ if (U_SUCCESS(status)) { umtx_lock(NULL); gPosixNumberFormat[style-1] = formatAlias; ucln_io_registerCleanup(UCLN_IO_LOCBUND, locbund_cleanup); umtx_unlock(NULL); } } /* Copy the needed formatter. */ result->fNumberFormat[style-1] = unum_clone(gPosixNumberFormat[style-1], &status); } return result->fNumberFormat[style-1]; }
/* PAL Function: GetLocaleInfoGroupingSizes Obtains grouping sizes for decimal and currency Returns 1 for success, 0 otherwise */ extern "C" int32_t GlobalizationNative_GetLocaleInfoGroupingSizes( const UChar* localeName, LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } UNumberFormatStyle style; switch (localeGroupingData) { case Digit: style = UNUM_DECIMAL; break; case Monetary: style = UNUM_CURRENCY; break; default: return UErrorCodeToBool(U_UNSUPPORTED_ERROR); } UNumberFormat* numformat = unum_open(style, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE); *secondaryGroupSize = unum_getAttribute(numformat, UNUM_SECONDARY_GROUPING_SIZE); unum_close(numformat); } return UErrorCodeToBool(status); }
static jint openRBNFImpl2(JNIEnv* env, jclass clazz, jstring rule, jstring locale) { // LOGI("ENTER openRBNFImpl2"); // the errorcode returned by unum_open UErrorCode status = U_ZERO_ERROR; // prepare the pattern string for the call to unum_open const UChar *ruleChars = env->GetStringChars(rule, NULL); int ruleLen = env->GetStringLength(rule); // prepare the locale string for the call to unum_open const char *localeChars = env->GetStringUTFChars(locale, NULL); // open a rule based number format UNumberFormat *fmt = unum_open(UNUM_PATTERN_RULEBASED, ruleChars, ruleLen, localeChars, NULL, &status); // release the allocated strings env->ReleaseStringChars(rule, ruleChars); env->ReleaseStringUTFChars(locale, localeChars); // check for an error if ( icuError(env, status) != FALSE) { return 0; } // return the handle to the number format return (long) fmt; }
/*Test Various format patterns*/ static void TestPatterns(void) { int32_t pat_length, i, lneed; UNumberFormat *fmt; UChar upat[5]; UChar unewpat[5]; UChar unum[5]; UChar *unewp=NULL; UChar *str=NULL; UErrorCode status = U_ZERO_ERROR; const char* pat[] = { "#.#", "#.", ".#", "#" }; const char* newpat[] = { "0.#", "0.", "#.0", "0" }; const char* num[] = { "0", "0.", ".0", "0" }; log_verbose("\nTesting different format patterns\n"); pat_length = UPRV_LENGTHOF(pat); for (i=0; i < pat_length; ++i) { status = U_ZERO_ERROR; u_uastrcpy(upat, pat[i]); fmt= unum_open(UNUM_IGNORE,upat, u_strlen(upat), "en_US",NULL, &status); if (U_FAILURE(status)) { log_err_status(status, "FAIL: Number format constructor failed for pattern %s -> %s\n", pat[i], u_errorName(status)); continue; } lneed=0; lneed=unum_toPattern(fmt, FALSE, NULL, lneed, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status= U_ZERO_ERROR; unewp=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_toPattern(fmt, FALSE, unewp, lneed+1, &status); } if(U_FAILURE(status)){ log_err("FAIL: Number format extracting the pattern failed for %s\n", pat[i]); } u_uastrcpy(unewpat, newpat[i]); if(u_strcmp(unewp, unewpat) != 0) log_err("FAIL: Pattern %s should be transmute to %s; %s seen instead\n", pat[i], newpat[i], austrdup(unewp) ); lneed=0; lneed=unum_format(fmt, 0, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_format(fmt, 0, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } u_uastrcpy(unum, num[i]); if (u_strcmp(str, unum) != 0) { log_err("FAIL: Pattern %s should format zero as %s; %s Seen instead\n", pat[i], num[i], austrdup(str) ); } free(unewp); free(str); unum_close(fmt); } }
/* * Testing unum_getDoubleAttribute and unum_setDoubleAttribute() */ static void TestDoubleAttribute(void) { double mydata[] = { 1.11, 22.22, 333.33, 4444.44, 55555.55, 666666.66, 7777777.77, 88888888.88, 999999999.99}; double dvalue; int i; UErrorCode status=U_ZERO_ERROR; UNumberFormatAttribute attr; UNumberFormatStyle style= UNUM_DEFAULT; UNumberFormat *def; log_verbose("\nTesting get and set DoubleAttributes\n"); def=unum_open(style, NULL,0,NULL,NULL, &status); if (U_FAILURE(status)) { log_data_err("Fail: error creating a default number formatter -> %s (Are you missing data?)\n", u_errorName(status)); } else { attr=UNUM_ROUNDING_INCREMENT; dvalue=unum_getDoubleAttribute(def, attr); for (i = 0; i<9 ; i++) { dvalue = mydata[i]; unum_setDoubleAttribute(def, attr, dvalue); if(unum_getDoubleAttribute(def,attr)!=mydata[i]) log_err("Fail: error in setting and getting double attributes for UNUM_ROUNDING_INCREMENT\n"); else log_verbose("Pass: setting and getting double attributes for UNUM_ROUNDING_INCREMENT works fine\n"); } } unum_close(def); }
static void TestFractionDigitOverride(void) { UErrorCode status = U_ZERO_ERROR; UNumberFormat *fmt = unum_open(UNUM_CURRENCY, NULL, 0, "hu_HU", NULL, &status); UChar buffer[256]; UChar expectedBuf[256]; const char expectedFirst[] = "123\\u00A0Ft"; const char expectedSecond[] = "123,46\\u00A0Ft"; const char expectedThird[] = "123,456\\u00A0Ft"; if (U_FAILURE(status)) { log_data_err("Error: unum_open returned %s (Are you missing data?)\n", myErrorName(status)); return; } /* Make sure that you can format normal fraction digits. */ unum_formatDouble(fmt, 123.456, buffer, sizeof(buffer)/sizeof(buffer[0]), NULL, &status); u_unescape(expectedFirst, expectedBuf, strlen(expectedFirst)+1); if (u_strcmp(buffer, expectedBuf) != 0) { log_err("Error: unum_formatDouble didn't return %s\n", expectedFirst); } /* Make sure that you can format 2 fraction digits. */ unum_setAttribute(fmt, UNUM_FRACTION_DIGITS, 2); unum_formatDouble(fmt, 123.456, buffer, sizeof(buffer)/sizeof(buffer[0]), NULL, &status); u_unescape(expectedSecond, expectedBuf, strlen(expectedSecond)+1); if (u_strcmp(buffer, expectedBuf) != 0) { log_err("Error: unum_formatDouble didn't return %s\n", expectedSecond); } /* Make sure that you can format more fraction digits. */ unum_setAttribute(fmt, UNUM_FRACTION_DIGITS, 3); unum_formatDouble(fmt, 123.456, buffer, sizeof(buffer)/sizeof(buffer[0]), NULL, &status); u_unescape(expectedThird, expectedBuf, strlen(expectedThird)+1); if (u_strcmp(buffer, expectedBuf) != 0) { log_err("Error: unum_formatDouble didn't return %s\n", expectedThird); } unum_close(fmt); }
void ICULocale::initializeDecimalFormat() { if (m_didCreateDecimalFormat) return; m_didCreateDecimalFormat = true; UErrorCode status = U_ZERO_ERROR; m_numberFormat = unum_open(UNUM_DECIMAL, 0, 0, m_locale.data(), 0, &status); if (!U_SUCCESS(status)) return; setDecimalSymbol(0, UNUM_ZERO_DIGIT_SYMBOL); setDecimalSymbol(1, UNUM_ONE_DIGIT_SYMBOL); setDecimalSymbol(2, UNUM_TWO_DIGIT_SYMBOL); setDecimalSymbol(3, UNUM_THREE_DIGIT_SYMBOL); setDecimalSymbol(4, UNUM_FOUR_DIGIT_SYMBOL); setDecimalSymbol(5, UNUM_FIVE_DIGIT_SYMBOL); setDecimalSymbol(6, UNUM_SIX_DIGIT_SYMBOL); setDecimalSymbol(7, UNUM_SEVEN_DIGIT_SYMBOL); setDecimalSymbol(8, UNUM_EIGHT_DIGIT_SYMBOL); setDecimalSymbol(9, UNUM_NINE_DIGIT_SYMBOL); setDecimalSymbol(DecimalSeparatorIndex, UNUM_DECIMAL_SEPARATOR_SYMBOL); setDecimalSymbol(GroupSeparatorIndex, UNUM_GROUPING_SEPARATOR_SYMBOL); setDecimalTextAttribute(m_positivePrefix, UNUM_POSITIVE_PREFIX); setDecimalTextAttribute(m_positiveSuffix, UNUM_POSITIVE_SUFFIX); setDecimalTextAttribute(m_negativePrefix, UNUM_NEGATIVE_PREFIX); setDecimalTextAttribute(m_negativeSuffix, UNUM_NEGATIVE_SUFFIX); ASSERT(!m_positivePrefix.isEmpty() || !m_positiveSuffix.isEmpty() || !m_negativePrefix.isEmpty() || !m_negativeSuffix.isEmpty()); }
void capi() { UNumberFormat *fmt; UErrorCode status = U_ZERO_ERROR; /* The string "987654321.123" as UChars */ UChar str[] = { 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2E, 0x31, 0x32, 0x33, 0 }; UChar buf[256]; int32_t needed; double a; /* Create a formatter for the US locale */ fmt = unum_open( UNUM_DECIMAL, /* style */ 0, /* pattern */ 0, /* patternLength */ "en_US", /* locale */ 0, /* parseErr */ &status); if (U_FAILURE(status)) { printf("FAIL: unum_open\n"); exit(1); } /* Use the formatter to parse a number. When using the C API, we have to specify whether we want a double or a long in advance. We pass in NULL for the position pointer in order to get the default behavior which is to parse from the start. */ a = unum_parseDouble(fmt, str, u_strlen(str), NULL, &status); if (U_FAILURE(status)) { printf("FAIL: unum_parseDouble\n"); exit(1); } /* Show the result */ printf("unum_parseDouble(\""); uprintf(str); printf("\") => %g\n", a); /* Use the formatter to format the same number back into a string in the US locale. The return value is the buffer size needed. We're pretty sure we have enough space, but in a production application one would check this value. We pass in NULL for the UFieldPosition pointer because we don't care to receive that data. */ needed = unum_formatDouble(fmt, a, buf, 256, NULL, &status); if (U_FAILURE(status)) { printf("FAIL: format_parseDouble\n"); exit(1); } /* Show the result */ printf("unum_formatDouble(%g) => \"", a); uprintf(buf); printf("\"\n"); /* Release the storage used by the formatter */ unum_close(fmt); }
void LocaleICU::initializeLocaleData() { if (m_didCreateDecimalFormat) return; m_didCreateDecimalFormat = true; UErrorCode status = U_ZERO_ERROR; m_numberFormat = unum_open(UNUM_DECIMAL, 0, 0, m_locale.data(), 0, &status); if (!U_SUCCESS(status)) return; Vector<String, DecimalSymbolsSize> symbols; symbols.append(decimalSymbol(UNUM_ZERO_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_ONE_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_TWO_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_THREE_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_FOUR_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_FIVE_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_SIX_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_SEVEN_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_EIGHT_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_NINE_DIGIT_SYMBOL)); symbols.append(decimalSymbol(UNUM_DECIMAL_SEPARATOR_SYMBOL)); symbols.append(decimalSymbol(UNUM_GROUPING_SEPARATOR_SYMBOL)); ASSERT(symbols.size() == DecimalSymbolsSize); setLocaleData(symbols, decimalTextAttribute(UNUM_POSITIVE_PREFIX), decimalTextAttribute(UNUM_POSITIVE_SUFFIX), decimalTextAttribute(UNUM_NEGATIVE_PREFIX), decimalTextAttribute(UNUM_NEGATIVE_SUFFIX)); }
U_CAPI UNumberFormat * u_locbund_getNumberFormat(ULocaleBundle *bundle, UNumberFormatStyle style) { UNumberFormat *formatAlias = NULL; if (style > UNUM_IGNORE) { formatAlias = bundle->fNumberFormat[style-1]; if (formatAlias == NULL) { if (bundle->isInvariantLocale) { formatAlias = copyInvariantFormatter(bundle, style); } else { UErrorCode status = U_ZERO_ERROR; formatAlias = unum_open(style, NULL, 0, bundle->fLocale, NULL, &status); if (U_FAILURE(status)) { unum_close(formatAlias); formatAlias = NULL; } else { bundle->fNumberFormat[style-1] = formatAlias; } } } } return formatAlias; }
/* Function: GetLocaleInfoDecimalFormatSymbol Obtains the value of a DecimalFormatSymbols */ static UErrorCode GetLocaleInfoDecimalFormatSymbol(const char* locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); unum_getSymbol(pFormat, symbol, value, valueLength, &status); unum_close(pFormat); return status; }
/** * Test proper handling of rounding modes. */ static void TestRounding5350(void) { UNumberFormat *nnf; UErrorCode status = U_ZERO_ERROR; /* this is supposed to open default date format, but later on it treats it like it is "en_US" - very bad if you try to run the tests on machine where default locale is NOT "en_US" */ /* nnf = unum_open(UNUM_DEFAULT, NULL, &status); */ nnf = unum_open(UNUM_DEFAULT, NULL,0,"en_US",NULL, &status); if(U_FAILURE(status)){ log_data_err("FAIL: failure in the construction of number format: %s (Are you missing data?)\n", myErrorName(status)); return; } unum_setAttribute(nnf, UNUM_MAX_FRACTION_DIGITS, 2); roundingTest2(nnf, -0.125, UNUM_ROUND_CEILING, "-0.12"); roundingTest2(nnf, -0.125, UNUM_ROUND_FLOOR, "-0.13"); roundingTest2(nnf, -0.125, UNUM_ROUND_DOWN, "-0.12"); roundingTest2(nnf, -0.125, UNUM_ROUND_UP, "-0.13"); roundingTest2(nnf, 0.125, UNUM_FOUND_HALFEVEN, "0.12"); roundingTest2(nnf, 0.135, UNUM_ROUND_HALFDOWN, "0.13"); roundingTest2(nnf, 0.125, UNUM_ROUND_HALFUP, "0.13"); roundingTest2(nnf, 0.135, UNUM_FOUND_HALFEVEN, "0.14"); /* The following are exactly represented, and shouldn't round */ roundingTest2(nnf, 1.00, UNUM_ROUND_UP, "1"); roundingTest2(nnf, 24.25, UNUM_ROUND_UP, "24.25"); roundingTest2(nnf, 24.25, UNUM_ROUND_CEILING, "24.25"); roundingTest2(nnf, -24.25, UNUM_ROUND_UP, "-24.25"); /* Differences pretty far out there */ roundingTest2(nnf, 1.0000001, UNUM_ROUND_CEILING, "1.01"); roundingTest2(nnf, 1.0000001, UNUM_ROUND_FLOOR, "1"); roundingTest2(nnf, 1.0000001, UNUM_ROUND_DOWN, "1"); roundingTest2(nnf, 1.0000001, UNUM_ROUND_UP, "1.01"); roundingTest2(nnf, 1.0000001, UNUM_FOUND_HALFEVEN, "1"); roundingTest2(nnf, 1.0000001, UNUM_ROUND_HALFDOWN, "1"); roundingTest2(nnf, 1.0000001, UNUM_ROUND_HALFUP, "1"); roundingTest2(nnf, -1.0000001, UNUM_ROUND_CEILING, "-1"); roundingTest2(nnf, -1.0000001, UNUM_ROUND_FLOOR, "-1.01"); roundingTest2(nnf, -1.0000001, UNUM_ROUND_DOWN, "-1"); roundingTest2(nnf, -1.0000001, UNUM_ROUND_UP, "-1.01"); roundingTest2(nnf, -1.0000001, UNUM_FOUND_HALFEVEN, "-1"); roundingTest2(nnf, -1.0000001, UNUM_ROUND_HALFDOWN, "-1"); roundingTest2(nnf, -1.0000001, UNUM_ROUND_HALFUP, "-1"); unum_close(nnf); }
/* Function: GetLocaleInfoDecimalFormatSymbol Obtains the value of a DecimalFormatSymbols */ UErrorCode GetLocaleInfoDecimalFormatSymbol(const char* locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); if (U_FAILURE(status)) { return status; } unum_getSymbol(pFormat, symbol, value, valueLength, &status); return status; }
/* {{{ */ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor) { const char* locale; char* pattern = NULL; size_t locale_len = 0, pattern_len = 0; zend_long style; UChar* spattern = NULL; int32_t spattern_len = 0; int zpp_flags = is_constructor ? ZEND_PARSE_PARAMS_THROW : 0; FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ if( zend_parse_parameters_ex( zpp_flags, ZEND_NUM_ARGS(), "sl|s", &locale, &locale_len, &style, &pattern, &pattern_len ) == FAILURE ) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "numfmt_create: unable to parse input parameters", 0 ); return FAILURE; } INTL_CHECK_LOCALE_LEN_OR_FAILURE(locale_len); object = return_value; FORMATTER_METHOD_FETCH_OBJECT_NO_CHECK; /* Convert pattern (if specified) to UTF-16. */ if(pattern && pattern_len) { intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_CTOR_CHECK_STATUS(nfo, "numfmt_create: error converting pattern to UTF-16"); } if(locale_len == 0) { locale = intl_locale_get_default(); } /* Create an ICU number formatter. */ FORMATTER_OBJECT(nfo) = unum_open(style, spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(nfo)); if(spattern) { efree(spattern); } INTL_CTOR_CHECK_STATUS(nfo, "numfmt_create: number formatter creation failed"); return SUCCESS; }
/** * Test localized currency patterns. */ static void TestCurrency(void) { UNumberFormat *currencyFmt; UChar *str; int32_t lneed, i; UFieldPosition pos; UChar res[100]; UErrorCode status = U_ZERO_ERROR; const char* locale[]={"fr_CA", "de_DE_PREEURO", "fr_FR_PREEURO"}; const char* result[]={"1,50\\u00a0$", "1,50\\u00a0DM", "1,50\\u00a0F"}; log_verbose("\nTesting the number format with different currency patterns\n"); for(i=0; i < 3; i++) { str=NULL; currencyFmt = unum_open(UNUM_CURRENCY, NULL,0,locale[i],NULL, &status); if(U_FAILURE(status)){ log_data_err("Error in the construction of number format with style currency: %s (Are you missing data?)\n", myErrorName(status)); } else { lneed=0; lneed= unum_formatDouble(currencyFmt, 1.50, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); pos.field = 0; unum_formatDouble(currencyFmt, 1.50, str, lneed+1, &pos, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) ); } else { u_unescape(result[i], res, (int32_t)strlen(result[i])+1); if (u_strcmp(str, res) != 0){ log_err("FAIL: Expected %s Got: %s for locale: %s\n", result[i], aescstrdup(str, -1), locale[i]); } } } unum_close(currencyFmt); free(str); } }
/* {{{ */ static void numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS) { char* locale; char* pattern = NULL; int locale_len = 0, pattern_len = 0; long style; UChar* spattern = NULL; int spattern_len = 0; FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sl|s", &locale, &locale_len, &style, &pattern, &pattern_len ) == FAILURE ) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "numfmt_create: unable to parse input parameters", 0 TSRMLS_CC ); zval_dtor(return_value); RETURN_NULL(); } INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); object = return_value; FORMATTER_METHOD_FETCH_OBJECT; /* Convert pattern (if specified) to UTF-16. */ if(pattern && pattern_len) { intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_CTOR_CHECK_STATUS(nfo, "numfmt_create: error converting pattern to UTF-16"); } if(locale_len == 0) { locale = INTL_G(default_locale); } /* Create an ICU number formatter. */ FORMATTER_OBJECT(nfo) = unum_open(style, spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(nfo)); if(spattern) { efree(spattern); } INTL_CTOR_CHECK_STATUS(nfo, "numfmt_create: number formatter creation failed"); }
static inline UNumberFormat * copyInvariantFormatter(ULocaleBundle *result, UNumberFormatStyle style) { U_NAMESPACE_USE Mutex lock(&gLock); if (result->fNumberFormat[style-1] == NULL) { if (gPosixNumberFormat[style-1] == NULL) { UErrorCode status = U_ZERO_ERROR; UNumberFormat *formatAlias = unum_open(style, NULL, 0, "en_US_POSIX", NULL, &status); if (U_SUCCESS(status)) { gPosixNumberFormat[style-1] = formatAlias; ucln_io_registerCleanup(UCLN_IO_LOCBUND, locbund_cleanup); } } /* Copy the needed formatter. */ if (gPosixNumberFormat[style-1] != NULL) { UErrorCode status = U_ZERO_ERROR; result->fNumberFormat[style-1] = unum_clone(gPosixNumberFormat[style-1], &status); } } return result->fNumberFormat[style-1]; }
/* Function: GetPercentPositivePattern Implementation of NumberFormatInfo.PercentPositivePattern. Returns the pattern index. */ int GetPercentPositivePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"n %", "n%", "%n", "% n"}; UErrorCode status = U_ZERO_ERROR; UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); if (value >= 0) { return value; } } return DEFAULT_VALUE; }
int icu_format_number(lua_State *L) { double a = luaL_checknumber(L, 1); /* See http://www.unicode.org/repos/cldr/tags/latest/common/bcp47/number.xml for valid system names */ const char* system = luaL_checkstring(L, 2); char locale[18]; // "@numbers=12345678"; UChar buf[256]; char utf8[256]; int32_t needed; UErrorCode status = U_ZERO_ERROR; snprintf(locale, 18, "@numbers=%s", system); UNumberFormat* fmt = unum_open(UNUM_DECIMAL, 0, 0, locale, 0, &status); if(U_FAILURE(status)) { luaL_error(L, "Locale %s unavailable: %s", locale, u_errorName(status)); } needed = unum_formatDouble(fmt, a, buf, 256, NULL, &status); assert(!U_FAILURE(status)); u_austrncpy(utf8, buf, 256); lua_pushstring(L, utf8); return 1; }
/* Function: GetNumberNegativePattern Implementation of NumberFormatInfo.NumberNegativePattern. Returns the pattern index. */ int GetNumberNegativePattern(const char* locale) { const int DEFAULT_VALUE = 1; static const char* Patterns[] = {"(n)", "-n", "- n", "n-", "n -"}; UErrorCode status = U_ZERO_ERROR; UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); UNumberFormatHolder formatHolder(pFormat, status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); if (value >= 0) { return value; } } return DEFAULT_VALUE; }
/** * Test proper rounding by the format method. */ static void TestRounding487(void) { UNumberFormat *nnf; UErrorCode status = U_ZERO_ERROR; /* this is supposed to open default date format, but later on it treats it like it is "en_US" - very bad if you try to run the tests on machine where default locale is NOT "en_US" */ /* nnf = unum_open(UNUM_DEFAULT, NULL, &status); */ nnf = unum_open(UNUM_DEFAULT, NULL,0,"en_US",NULL, &status); if(U_FAILURE(status)){ log_data_err("FAIL: failure in the construction of number format: %s (Are you missing data?)\n", myErrorName(status)); } else { roundingTest(nnf, 0.00159999, 4, "0.0016"); roundingTest(nnf, 0.00995, 4, "0.01"); roundingTest(nnf, 12.3995, 3, "12.4"); roundingTest(nnf, 12.4999, 0, "12"); roundingTest(nnf, - 19.5, 0, "-20"); } unum_close(nnf); }
static void TestPrefixSuffix(void) { int32_t pos; UErrorCode status; double result1 = 0.0, result2 = 0.0; UNumberFormat* parser; UChar buffer[4]; static const UChar TEST_NUMBER[] = {0x0024,0x0031,0x0032,0x002E,0x0030,0x0030,0}; /* $12.00 */ static const UChar NEG_PREFIX[] = {0x005B,0}; /* "[" */ static const UChar NEG_SUFFIX[] = {0x005D,0}; /* "]" */ status = U_ZERO_ERROR; parser = unum_open(UNUM_CURRENCY, NULL, -1, "en_US", NULL, &status); if (U_FAILURE(status)) { log_data_err("Error: unum_open returned %s (Are you missing data?)\n", u_errorName(status)); return; } pos = 0; status = U_ZERO_ERROR; result1 = unum_parseDoubleCurrency(parser, TEST_NUMBER, -1, &pos, buffer, &status); unum_setTextAttribute(parser, UNUM_NEGATIVE_SUFFIX, NEG_SUFFIX, -1, &status); unum_setTextAttribute(parser, UNUM_NEGATIVE_PREFIX, NEG_PREFIX, -1, &status); if (U_FAILURE(status)) { log_err("Error: unum_setTextAttribute returned %s\n", u_errorName(status)); return; } pos = 0; result2 = unum_parseDoubleCurrency(parser, TEST_NUMBER, -1, &pos, buffer, &status); if (result1 != result2 || U_FAILURE(status)) { log_err("Error: unum_parseDoubleCurrency didn't return the same value for same string %f %f %s\n", result1, result2, u_errorName(status)); } unum_close(parser); }
void IntlTestNumberFormatAPI::testRegistration() { #if !UCONFIG_NO_SERVICE UErrorCode status = U_ZERO_ERROR; NumberFormat* f0 = NumberFormat::createInstance(SWAP_LOC, status); NumberFormat* f1 = NumberFormat::createInstance(SRC_LOC, status); NumberFormat* f2 = NumberFormat::createCurrencyInstance(SRC_LOC, status); URegistryKey key = NumberFormat::registerFactory(new NFTestFactory(), status); NumberFormat* f3 = NumberFormat::createCurrencyInstance(SRC_LOC, status); NumberFormat* f3a = NumberFormat::createCurrencyInstance(SRC_LOC, status); NumberFormat* f4 = NumberFormat::createInstance(SRC_LOC, status); StringEnumeration* locs = NumberFormat::getAvailableLocales(); UNumberFormat* uf3 = unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(),NULL, &status); UNumberFormat* uf4 = unum_open(UNUM_DEFAULT, NULL, 0, SRC_LOC.getName(), NULL, &status); const UnicodeString* res; for (res = locs->snext(status); res; res = locs->snext(status)) { logln(*res); // service is still in synch } NumberFormat::unregister(key, status); // restore for other tests NumberFormat* f5 = NumberFormat::createCurrencyInstance(SRC_LOC, status); UNumberFormat* uf5 = unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(),NULL, &status); if (U_FAILURE(status)) { dataerrln("Error creating instnaces."); return; } else { float n = 1234.567f; UnicodeString res0, res1, res2, res3, res4, res5; UChar ures3[50]; UChar ures4[50]; UChar ures5[50]; f0->format(n, res0); f1->format(n, res1); f2->format(n, res2); f3->format(n, res3); f4->format(n, res4); f5->format(n, res5); unum_formatDouble(uf3, n, ures3, 50, NULL, &status); unum_formatDouble(uf4, n, ures4, 50, NULL, &status); unum_formatDouble(uf5, n, ures5, 50, NULL, &status); logln((UnicodeString)"f0 swap int: " + res0); logln((UnicodeString)"f1 src int: " + res1); logln((UnicodeString)"f2 src cur: " + res2); logln((UnicodeString)"f3 reg cur: " + res3); logln((UnicodeString)"f4 reg int: " + res4); logln((UnicodeString)"f5 unreg cur: " + res5); log("uf3 reg cur: "); logln(ures3); log("uf4 reg int: "); logln(ures4); log("uf5 ureg cur: "); logln(ures5); if (f3 == f3a) { errln("did not get new instance from service"); } else { delete f3a; } if (res3 != res0) { errln("registered service did not match"); } if (res4 != res1) { errln("registered service did not inherit"); } if (res5 != res2) { errln("unregistered service did not match original"); } if (res0 != ures3) { errln("registered service did not match / unum"); } if (res1 != ures4) { errln("registered service did not inherit / unum"); } if (res2 != ures5) { errln("unregistered service did not match original / unum"); } } unum_close(uf5); delete f5; unum_close(uf4); unum_close(uf3); delete f4; delete f3; delete f2; delete f1; delete f0; for (res = locs->snext(status); res; res = locs->snext(status)) { errln(*res); // service should be out of synch } locs->reset(status); // now in synch again, we hope for (res = locs->snext(status); res; res = locs->snext(status)) { logln(*res); } delete locs; #endif }
void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales, JSValue optionsValue) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 11.1.2 InitializeNumberFormat (numberFormat, locales, options) (ECMA-402) // https://tc39.github.io/ecma402/#sec-initializenumberformat auto requestedLocales = canonicalizeLocaleList(state, locales); RETURN_IF_EXCEPTION(scope, void()); JSObject* options; if (optionsValue.isUndefined()) options = constructEmptyObject(&state, state.lexicalGlobalObject()->nullPrototypeObjectStructure()); else { options = optionsValue.toObject(&state); RETURN_IF_EXCEPTION(scope, void()); } HashMap<String, String> opt; String matcher = intlStringOption(state, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit"); RETURN_IF_EXCEPTION(scope, void()); opt.add("localeMatcher"_s, matcher); auto& availableLocales = state.jsCallee()->globalObject(vm)->intlNumberFormatAvailableLocales(); auto result = resolveLocale(state, availableLocales, requestedLocales, opt, relevantNumberExtensionKeys, WTF_ARRAY_LENGTH(relevantNumberExtensionKeys), IntlNFInternal::localeData); m_locale = result.get("locale"_s); if (m_locale.isEmpty()) { throwTypeError(&state, scope, "failed to initialize NumberFormat due to invalid locale"_s); return; } m_numberingSystem = result.get("nu"_s); String styleString = intlStringOption(state, options, Identifier::fromString(&vm, "style"), { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal"); RETURN_IF_EXCEPTION(scope, void()); if (styleString == "decimal") m_style = Style::Decimal; else if (styleString == "percent") m_style = Style::Percent; else if (styleString == "currency") m_style = Style::Currency; else ASSERT_NOT_REACHED(); String currency = intlStringOption(state, options, Identifier::fromString(&vm, "currency"), { }, nullptr, nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!currency.isNull()) { if (currency.length() != 3 || !currency.isAllSpecialCharacters<isASCIIAlpha>()) { throwException(&state, scope, createRangeError(&state, "currency is not a well-formed currency code"_s)); return; } } unsigned currencyDigits = 0; if (m_style == Style::Currency) { if (currency.isNull()) { throwTypeError(&state, scope, "currency must be a string"_s); return; } currency = currency.convertToASCIIUppercase(); m_currency = currency; currencyDigits = computeCurrencyDigits(currency); } String currencyDisplayString = intlStringOption(state, options, Identifier::fromString(&vm, "currencyDisplay"), { "code", "symbol", "name" }, "currencyDisplay must be either \"code\", \"symbol\", or \"name\"", "symbol"); RETURN_IF_EXCEPTION(scope, void()); if (m_style == Style::Currency) { if (currencyDisplayString == "code") m_currencyDisplay = CurrencyDisplay::Code; else if (currencyDisplayString == "symbol") m_currencyDisplay = CurrencyDisplay::Symbol; else if (currencyDisplayString == "name") m_currencyDisplay = CurrencyDisplay::Name; else ASSERT_NOT_REACHED(); } unsigned minimumIntegerDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumIntegerDigits"), 1, 21, 1); RETURN_IF_EXCEPTION(scope, void()); m_minimumIntegerDigits = minimumIntegerDigits; unsigned minimumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : 0; unsigned minimumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault); RETURN_IF_EXCEPTION(scope, void()); m_minimumFractionDigits = minimumFractionDigits; unsigned maximumFractionDigitsDefault; if (m_style == Style::Currency) maximumFractionDigitsDefault = std::max(minimumFractionDigits, currencyDigits); else if (m_style == Style::Percent) maximumFractionDigitsDefault = minimumFractionDigits; else maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u); unsigned maximumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault); RETURN_IF_EXCEPTION(scope, void()); m_maximumFractionDigits = maximumFractionDigits; JSValue minimumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "minimumSignificantDigits")); RETURN_IF_EXCEPTION(scope, void()); JSValue maximumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "maximumSignificantDigits")); RETURN_IF_EXCEPTION(scope, void()); if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) { unsigned minimumSignificantDigits = intlDefaultNumberOption(state, minimumSignificantDigitsValue, Identifier::fromString(&vm, "minimumSignificantDigits"), 1, 21, 1); RETURN_IF_EXCEPTION(scope, void()); unsigned maximumSignificantDigits = intlDefaultNumberOption(state, maximumSignificantDigitsValue, Identifier::fromString(&vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21); RETURN_IF_EXCEPTION(scope, void()); m_minimumSignificantDigits = minimumSignificantDigits; m_maximumSignificantDigits = maximumSignificantDigits; } bool usesFallback; bool useGrouping = intlBooleanOption(state, options, Identifier::fromString(&vm, "useGrouping"), usesFallback); if (usesFallback) useGrouping = true; RETURN_IF_EXCEPTION(scope, void()); m_useGrouping = useGrouping; UNumberFormatStyle style = UNUM_DEFAULT; switch (m_style) { case Style::Decimal: style = UNUM_DECIMAL; break; case Style::Percent: style = UNUM_PERCENT; break; case Style::Currency: switch (m_currencyDisplay) { case CurrencyDisplay::Code: style = UNUM_CURRENCY_ISO; break; case CurrencyDisplay::Symbol: style = UNUM_CURRENCY; break; case CurrencyDisplay::Name: style = UNUM_CURRENCY_PLURAL; break; default: ASSERT_NOT_REACHED(); } break; default: ASSERT_NOT_REACHED(); } UErrorCode status = U_ZERO_ERROR; m_numberFormat = std::unique_ptr<UNumberFormat, UNumberFormatDeleter>(unum_open(style, nullptr, 0, m_locale.utf8().data(), nullptr, &status)); if (U_FAILURE(status)) { throwTypeError(&state, scope, "failed to initialize NumberFormat"_s); return; } if (m_style == Style::Currency) { unum_setTextAttribute(m_numberFormat.get(), UNUM_CURRENCY_CODE, StringView(m_currency).upconvertedCharacters(), m_currency.length(), &status); if (U_FAILURE(status)) { throwTypeError(&state, scope, "failed to initialize NumberFormat"_s); return; } } if (!m_minimumSignificantDigits) { unum_setAttribute(m_numberFormat.get(), UNUM_MIN_INTEGER_DIGITS, m_minimumIntegerDigits); unum_setAttribute(m_numberFormat.get(), UNUM_MIN_FRACTION_DIGITS, m_minimumFractionDigits); unum_setAttribute(m_numberFormat.get(), UNUM_MAX_FRACTION_DIGITS, m_maximumFractionDigits); } else { unum_setAttribute(m_numberFormat.get(), UNUM_SIGNIFICANT_DIGITS_USED, true); unum_setAttribute(m_numberFormat.get(), UNUM_MIN_SIGNIFICANT_DIGITS, m_minimumSignificantDigits); unum_setAttribute(m_numberFormat.get(), UNUM_MAX_SIGNIFICANT_DIGITS, m_maximumSignificantDigits); } unum_setAttribute(m_numberFormat.get(), UNUM_GROUPING_USED, m_useGrouping); unum_setAttribute(m_numberFormat.get(), UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP); m_initializedNumberFormat = true; }
/* Test the handling of quotes*/ static void TestQuotes(void) { int32_t lneed; UErrorCode status=U_ZERO_ERROR; UChar pat[15]; UChar res[15]; UChar *str=NULL; UNumberFormat *fmt; char tempBuf[256]; log_verbose("\nTestting the handling of quotes in number format\n"); u_uastrcpy(pat, "a'fo''o'b#"); fmt =unum_open(UNUM_IGNORE,pat, u_strlen(pat), "en_US",NULL, &status); if(U_FAILURE(status)){ log_err_status(status, "Error in number format costruction using pattern \"a'fo''o'b#\" -> %s\n", u_errorName(status)); } lneed=0; lneed=unum_format(fmt, 123, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_format(fmt, 123, str, lneed+1, NULL, &status); } if(U_FAILURE(status) || !str) { log_err_status(status, "Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); return; } log_verbose("Pattern \"%s\" \n", u_austrcpy(tempBuf, pat) ); log_verbose("Format 123 -> %s\n", u_austrcpy(tempBuf, str) ); u_uastrcpy(res, "afo'ob123"); if(u_strcmp(str, res) != 0) log_err("FAIL: Expected afo'ob123"); free(str); unum_close(fmt); u_uastrcpy(pat, ""); u_uastrcpy(pat, "a''b#"); fmt =unum_open(UNUM_IGNORE,pat, u_strlen(pat), "en_US",NULL, &status); if(U_FAILURE(status)){ log_err("Error in number format costruction using pattern \"a''b#\"\n"); } lneed=0; lneed=unum_format(fmt, 123, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_format(fmt, 123, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } log_verbose("Pattern \"%s\" \n", u_austrcpy(tempBuf, pat) ); log_verbose("Format 123 -> %s\n", u_austrcpy(tempBuf, str) ); u_uastrcpy(res, ""); u_uastrcpy(res, "a'b123"); if(u_strcmp(str, res) != 0) log_err("FAIL: Expected a'b123\n"); free(str); unum_close(fmt); }
/** * Test the functioning of the secondary grouping value. */ static void TestSecondaryGrouping(void) { UErrorCode status = U_ZERO_ERROR; UNumberFormat *f = NULL, *g= NULL; UNumberFormat *us = unum_open(UNUM_DECIMAL,NULL,0, "en_US", NULL,&status); UFieldPosition pos; UChar resultBuffer[512]; int32_t l = 1876543210L; UBool ok = TRUE; UChar buffer[512]; int32_t i; UBool expectGroup = FALSE, isGroup = FALSE; u_uastrcpy(buffer, "#,##,###"); f = unum_open(UNUM_IGNORE,buffer, -1, "en_US",NULL, &status); if (U_FAILURE(status)) { log_data_err("Error DecimalFormat ct -> %s (Are you missing data?)\n", u_errorName(status)); return; } pos.field = 0; unum_format(f, (int32_t)123456789L, resultBuffer, 512 , &pos, &status); u_uastrcpy(buffer, "12,34,56,789"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: Formatting \"#,##,###\" pattern with 123456789 got %s, expected %s\n", austrdup(resultBuffer), "12,34,56,789"); } if (pos.beginIndex != 0 && pos.endIndex != 12) { log_err("Fail: Formatting \"#,##,###\" pattern pos = (%d, %d) expected pos = (0, 12)\n", pos.beginIndex, pos.endIndex); } memset(resultBuffer,0, sizeof(UChar)*512); unum_toPattern(f, FALSE, resultBuffer, 512, &status); u_uastrcpy(buffer, "#,##,##0"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: toPattern() got %s, expected %s\n", austrdup(resultBuffer), "#,##,##0"); } memset(resultBuffer,0, sizeof(UChar)*512); u_uastrcpy(buffer, "#,###"); unum_applyPattern(f, FALSE, buffer, -1,NULL,NULL); if (U_FAILURE(status)) { log_err("Fail: applyPattern call failed\n"); } unum_setAttribute(f, UNUM_SECONDARY_GROUPING_SIZE, 4); unum_format(f, (int32_t)123456789L, resultBuffer, 512 , &pos, &status); u_uastrcpy(buffer, "12,3456,789"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: Formatting \"#,###\" pattern with 123456789 got %s, expected %s\n", austrdup(resultBuffer), "12,3456,789"); } memset(resultBuffer,0, sizeof(UChar)*512); unum_toPattern(f, FALSE, resultBuffer, 512, &status); u_uastrcpy(buffer, "#,####,##0"); if ((u_strcmp(resultBuffer, buffer) != 0) || U_FAILURE(status)) { log_err("Fail: toPattern() got %s, expected %s\n", austrdup(resultBuffer), "#,####,##0"); } memset(resultBuffer,0, sizeof(UChar)*512); g = unum_open(UNUM_DECIMAL, NULL,0,"hi_IN",NULL, &status); if (U_FAILURE(status)) { log_err("Fail: Cannot create UNumberFormat for \"hi_IN\" locale.\n"); } unum_format(g, l, resultBuffer, 512, &pos, &status); unum_close(g); /* expect "1,87,65,43,210", but with Hindi digits */ /* 01234567890123 */ if (u_strlen(resultBuffer) != 14) { ok = FALSE; } else { for (i=0; i<u_strlen(resultBuffer); ++i) { expectGroup = FALSE; switch (i) { case 1: case 4: case 7: case 10: expectGroup = TRUE; break; } /* Later -- fix this to get the actual grouping */ /* character from the resource bundle. */ isGroup = (UBool)(resultBuffer[i] == 0x002C); if (isGroup != expectGroup) { ok = FALSE; break; } } } if (!ok) { log_err("FAIL Expected %s x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got %s\n", "1876543210L", resultBuffer); } unum_close(f); unum_close(us); }
/* Test exponential pattern*/ static void TestExponential(void) { int32_t pat_length, val_length, lval_length; int32_t ival, ilval, p, v, lneed; UNumberFormat *fmt; int32_t ppos; UChar *upat; UChar pattern[20]; UChar *str=NULL; UChar uvalfor[20], ulvalfor[20]; char tempMsgBug[256]; double a; UErrorCode status = U_ZERO_ERROR; #if U_PLATFORM == U_PF_OS390 static const double val[] = { 0.01234, 123456789, 1.23e75, -3.141592653e-78 }; #else static const double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 }; #endif static const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" }; static const int32_t lval[] = { 0, -1, 1, 123456789 }; static const char* valFormat[] = { "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271", "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272", "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273", "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" }; static const char* lvalFormat[] = { "0E0", "-1E0", "1E0", "1.2346E8", "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07", "0E000", "-1E000", "1E000", "123.4568E006", "0E0", "[1E0]", "1E0", "1.235E8" }; static const double valParse[] = { #if U_PLATFORM == U_PF_OS390 0.01234, 123460000, 1.23E75, -3.1416E-78, 0.01234, 123460000, 1.23E75, -3.1416E-78, 0.01234, 123456800, 1.23E75, -3.141593E-78, 0.01234, 123500000, 1.23E75, -3.142E-78 #else /* We define the whole IEEE 754 number in the 4th column because Visual Age 7 has a bug in rounding numbers. */ 0.01234, 123460000, 1.23E300, -3.1415999999999999E-271, 0.01234, 123460000, 1.23E300, -3.1415999999999999E-271, 0.01234, 123456800, 1.23E300, -3.1415929999999999E-271, 0.01234, 123500000, 1.23E300, -3.1420000000000001E-271 #endif }; static const int32_t lvalParse[] = { 0, -1, 1, 123460000, 0, -1, 1, 123460000, 0, -1, 1, 123456800, 0, -1, 1, 123500000 }; pat_length = UPRV_LENGTHOF(pat); val_length = UPRV_LENGTHOF(val); lval_length = UPRV_LENGTHOF(lval); ival = 0; ilval = 0; for (p=0; p < pat_length; ++p) { upat=(UChar*)malloc(sizeof(UChar) * (strlen(pat[p])+1) ); u_uastrcpy(upat, pat[p]); fmt=unum_open(UNUM_IGNORE,upat, u_strlen(upat), "en_US",NULL, &status); if (U_FAILURE(status)) { log_err_status(status, "FAIL: Bad status returned by Number format construction with pattern %s -> %s\n", pat[p], u_errorName(status)); continue; } lneed= u_strlen(upat) + 1; unum_toPattern(fmt, FALSE, pattern, lneed, &status); log_verbose("Pattern \" %s \" -toPattern-> \" %s \" \n", upat, u_austrcpy(tempMsgBug, pattern) ); for (v=0; v<val_length; ++v) { /*format*/ lneed=0; lneed=unum_formatDouble(fmt, val[v], NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, val[v], str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } u_uastrcpy(uvalfor, valFormat[v+ival]); if(u_strcmp(str, uvalfor) != 0) log_verbose("FAIL: Expected %s ( %s )\n", valFormat[v+ival], u_austrcpy(tempMsgBug, uvalfor) ); /*parsing*/ ppos=0; a=unum_parseDouble(fmt, str, u_strlen(str), &ppos, &status); if (ppos== u_strlen(str)) { if (a != valParse[v+ival]) log_err("FAIL: Expected: %e, Got: %g\n", valParse[v+ival], a); } else log_err(" FAIL: Partial parse ( %d chars ) -> %e\n", ppos, a); free(str); } for (v=0; v<lval_length; ++v) { /*format*/ lneed=0; lneed=unum_formatDouble(fmt, lval[v], NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, lval[v], str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } /*printf(" Format %e -> %s\n", lval[v], austrdup(str) );*/ u_uastrcpy(ulvalfor, lvalFormat[v+ilval]); if(u_strcmp(str, ulvalfor) != 0) log_err("FAIL: Expected %s ( %s )\n", valFormat[v+ilval], austrdup(ulvalfor) ); /*parsing*/ ppos=0; a=unum_parseDouble(fmt, str, u_strlen(str), &ppos, &status); if (ppos== u_strlen(str)) { /*printf(" Parse -> %e\n", a);*/ if (a != lvalParse[v+ilval]) log_err("FAIL: Expected : %e\n", valParse[v+ival]); } else log_err(" FAIL: Partial parse ( %d chars ) -> %e\n", ppos, a); free(str); } ival += val_length; ilval += lval_length; unum_close(fmt); free(upat); } }
/** * Test the handling of the currency symbol in patterns. */ static void TestCurrencySign(void) { int32_t lneed; UNumberFormat *fmt; UChar *pattern=NULL; UChar *str=NULL; UChar *pat=NULL; UChar *res=NULL; UErrorCode status = U_ZERO_ERROR; char tempBuf[256]; pattern=(UChar*)malloc(sizeof(UChar) * (strlen("*#,##0.00;-*#,##0.00") + 1) ); u_uastrcpy(pattern, "*#,##0.00;-*#,##0.00"); pattern[0]=pattern[11]=0xa4; /* insert latin-1 currency symbol */ fmt = unum_open(UNUM_IGNORE,pattern, u_strlen(pattern), "en_US",NULL, &status); if(U_FAILURE(status)){ log_err_status(status, "Error in number format construction with pattern \"\\xA4#,##0.00;-\\xA4#,##0.00\\\" -> %s\n", u_errorName(status)); } lneed=0; lneed=unum_formatDouble(fmt, 1234.56, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, 1234.56, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err_status(status, "Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } lneed=0; lneed=unum_toPattern(fmt, FALSE, NULL, lneed, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; pat=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, FALSE, pat, lneed+1, NULL, &status); } log_verbose("Pattern \" %s \" \n", u_austrcpy(tempBuf, pat)); log_verbose("Format 1234.56 -> %s\n", u_austrcpy(tempBuf, str) ); if(U_SUCCESS(status) && str) { res=(UChar*)malloc(sizeof(UChar) * (strlen("$1,234.56")+1) ); u_uastrcpy(res, "$1,234.56"); if (u_strcmp(str, res) !=0) log_data_err("FAIL: Expected $1,234.56\n"); } else { log_err_status(status, "Error formatting -> %s\n", u_errorName(status)); } free(str); free(res); free(pat); lneed=0; lneed=unum_formatDouble(fmt, -1234.56, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); unum_formatDouble(fmt, -1234.56, str, lneed+1, NULL, &status); } if(U_FAILURE(status)) { log_err_status(status, "Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); } if(str) { res=(UChar*)malloc(sizeof(UChar) * (strlen("-$1,234.56")+1) ); u_uastrcpy(res, "-$1,234.56"); if (u_strcmp(str, res) != 0) log_data_err("FAIL: Expected -$1,234.56\n"); free(str); free(res); } unum_close(fmt); free(pattern); }
/** * Test currency "object" (we use this name to match the other C++ * test name and the Jave name). Actually, test ISO currency code * support in the C API. */ static void TestCurrencyObject(void) { UNumberFormat *currencyFmt; UChar *str=NULL, *res=NULL; int32_t lneed, i; UFieldPosition pos; UErrorCode status = U_ZERO_ERROR; const char* locale[]={ "fr_FR", "fr_FR", }; const char* currency[]={ "", "JPY", }; const char* result[]={ "1\\u202F234,56\\u00A0\\u20AC", "1\\u202F235\\u00A0JPY", }; log_verbose("\nTesting the number format with different currency codes\n"); for(i=0; i < 2; i++) { char cStr[20]={0}; UChar isoCode[16]={0}; currencyFmt = unum_open(UNUM_CURRENCY, NULL,0,locale[i],NULL, &status); if(U_FAILURE(status)){ log_data_err("Error in the construction of number format with style currency: %s (Are you missing data?)\n", myErrorName(status)); } else { if (*currency[i]) { u_uastrcpy(isoCode, currency[i]); unum_setTextAttribute(currencyFmt, UNUM_CURRENCY_CODE, isoCode, u_strlen(isoCode), &status); if(U_FAILURE(status)) { log_err("FAIL: can't set currency code %s\n", myErrorName(status) ); } } unum_getTextAttribute(currencyFmt, UNUM_CURRENCY_CODE, isoCode, sizeof(isoCode), &status); if(U_FAILURE(status)) { log_err("FAIL: can't get currency code %s\n", myErrorName(status) ); } u_UCharsToChars(isoCode,cStr,u_strlen(isoCode)); log_verbose("ISO code %s\n", cStr); if (*currency[i] && uprv_strcmp(cStr, currency[i])) { log_err("FAIL: currency should be %s, but is %s\n", currency[i], cStr); } lneed=0; lneed= unum_formatDouble(currencyFmt, 1234.56, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); pos.field = 0; unum_formatDouble(currencyFmt, 1234.56, str, lneed+1, &pos, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) ); } else { res=(UChar*)malloc(sizeof(UChar) * (strlen(result[i])+1) ); u_unescape(result[i],res, (int32_t)(strlen(result[i])+1)); if (u_strcmp(str, res) != 0){ log_err("FAIL: Expected %s Got: %s for locale: %s\n", result[i],aescstrdup(str, -1),locale[i]); } } } unum_close(currencyFmt); free(str); free(res); } }
/** * Test localized currency patterns for PREEURO variants. */ static void TestCurrencyPreEuro(void) { UNumberFormat *currencyFmt; UChar *str=NULL, *res=NULL; int32_t lneed, i; UFieldPosition pos; UErrorCode status = U_ZERO_ERROR; const char* locale[]={ "ca_ES_PREEURO", "de_LU_PREEURO", "en_IE_PREEURO", "fi_FI_PREEURO", "fr_LU_PREEURO", "it_IT_PREEURO", "pt_PT_PREEURO", "de_AT_PREEURO", "el_GR_PREEURO", "es_ES_PREEURO", "fr_BE_PREEURO", "ga_IE_PREEURO", "nl_BE_PREEURO", "de_DE_PREEURO", "en_BE_PREEURO", "eu_ES_PREEURO", "fr_FR_PREEURO", "gl_ES_PREEURO", "nl_NL_PREEURO", }; const char* result[]={ "\\u20A7\\u00A02", "2\\u00A0F", "IEP\\u00A01.50", "1,50\\u00A0mk", "2\\u00A0F", "ITL\\u00A02", "1$50\\u00A0\\u200B", "\\u00F6S\\u00A01,50", "1,50\\u00A0\\u0394\\u03C1\\u03C7", "2\\u00A0\\u20A7", "1,50\\u00A0FB", "IEP\\u00A01.50", "BEF\\u00A01,50", "1,50\\u00A0DM", "1,50\\u00A0BEF", "\\u20A7\\u00A02", "1,50\\u00A0F", "2\\u00A0\\u20A7", "NLG\\u00A01,50" }; log_verbose("\nTesting the number format with different currency patterns\n"); for(i=0; i < 19; i++) { char curID[256] = {0}; uloc_canonicalize(locale[i], curID, 256, &status); if(U_FAILURE(status)){ log_data_err("Could not canonicalize %s. Error: %s (Are you missing data?)\n", locale[i], u_errorName(status)); continue; } currencyFmt = unum_open(UNUM_CURRENCY, NULL,0,curID,NULL, &status); if(U_FAILURE(status)){ log_data_err("Error in the construction of number format with style currency: %s (Are you missing data?)\n", myErrorName(status)); } else { lneed=0; lneed= unum_formatDouble(currencyFmt, 1.50, NULL, lneed, NULL, &status); if(status==U_BUFFER_OVERFLOW_ERROR){ status=U_ZERO_ERROR; str=(UChar*)malloc(sizeof(UChar) * (lneed+1) ); pos.field = 0; unum_formatDouble(currencyFmt, 1.50, str, lneed+1, &pos, &status); } if(U_FAILURE(status)) { log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status) ); } else { res=(UChar*)malloc(sizeof(UChar) * (strlen(result[i])+1) ); u_unescape(result[i],res,(int32_t)(strlen(result[i])+1)); if (u_strcmp(str, res) != 0){ log_err("FAIL: Expected %s Got: %s for locale: %s\n", result[i],aescstrdup(str, -1),locale[i]); } } } unum_close(currencyFmt); free(str); free(res); } }