Example #1
0
/* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
static void
u_sprintf_set_sign(UNumberFormat        *format,
                   const u_sprintf_spec_info     *info,
                   UErrorCode *status)
{
    if(info->fShowSign) {
        if (info->fSpace) {
            /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
            /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
            unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
        }
        else {
            UChar plusSymbol[USPRINTF_SYMBOL_BUFFER_SIZE];
            int32_t symbolLen;

            symbolLen = unum_getSymbol(format,
                UNUM_PLUS_SIGN_SYMBOL,
                plusSymbol,
                sizeof(plusSymbol)/sizeof(*plusSymbol),
                status);
            unum_setTextAttribute(format,
                UNUM_POSITIVE_PREFIX,
                plusSymbol,
                symbolLen,
                status);
        }
    }
}
static void NativeDecimalFormat_setTextAttribute(JNIEnv* env, jclass, jlong addr, jint javaAttr, jstring javaValue) {
    ScopedStringChars value(env, javaValue);
    if (value.get() == NULL) {
        return;
    }
    UErrorCode status = U_ZERO_ERROR;
    UNumberFormatTextAttribute attr = static_cast<UNumberFormatTextAttribute>(javaAttr);
    unum_setTextAttribute(toUNumberFormat(addr), attr, value.get(), value.size(), &status);
    maybeThrowIcuException(env, "unum_setTextAttribute", status);
}
Example #3
0
static bool HHVM_METHOD(NumberFormatter, setTextAttribute,
                        int64_t attr, const String& value) {
  NUMFMT_GET(obj, this_, false);
  UErrorCode error = U_ZERO_ERROR;
  icu::UnicodeString val(u16(value, error));
  NUMFMT_CHECK(obj, error, false);
  unum_setTextAttribute(obj->formatter(), (UNumberFormatTextAttribute)attr,
                        val.getBuffer(), val.length(), &error);
  NUMFMT_CHECK(obj, error, false);
  return true;
}
Example #4
0
//static void NativeDecimalFormat_setTextAttribute(JNIEnv* env, jclass, jint addr, jint javaAttr, jstring javaValue) {
JNIEXPORT void JNICALL
Java_com_ibm_icu4jni_text_NativeDecimalFormat_setTextAttribute(JNIEnv* env,
        jclass, jint addr, jint javaAttr, jstring javaValue) {
    ScopedJavaUnicodeString value(env, javaValue);
    UnicodeString& s(value.unicodeString());
    UErrorCode status = U_ZERO_ERROR;
    UNumberFormatTextAttribute attr =
        static_cast<UNumberFormatTextAttribute> (javaAttr);
    unum_setTextAttribute(toUNumberFormat(addr), attr, s.getBuffer(),
                          s.length(), &status);
    icu4jni_error(env, status);
}
Example #5
0
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);
}
static void
u_printf_reset_sign(UNumberFormat        *format,
                   const u_printf_spec_info     *info,
                   UChar *prefixBuffer,
                   int32_t *prefixBufLen,
                   UErrorCode *status)
{
    if(info->fShowSign) {
        unum_setTextAttribute(format,
                              UNUM_POSITIVE_PREFIX,
                              prefixBuffer,
                              *prefixBufLen,
                              status);
    }
}
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;
}
Example #8
0
/**
 * 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);
    }
}
Example #9
0
/**
 *  call-seq:
 *     23874.localize(:decimal, 'es_ES') => 23.874
 */
VALUE rb_numeric_localize(int argc, VALUE *argv, VALUE self)
{
	VALUE style, options;
	UNumberFormatStyle formatStyle;
	char *locale = NULL;

	UNumberFormat *format;
	UErrorCode status;

	UChar result[256];
	/* arguments */
	rb_scan_args(argc, argv, "02", &style, &options);
	if (style == Qnil) {
		formatStyle = UNUM_DECIMAL;
	} else {
		ID style_ID;

		Check_Type(style, T_SYMBOL);
		style_ID = SYM2ID(style);
		if (style_ID == rb_intern("decimal")) {
			formatStyle = UNUM_DECIMAL;
		} else if (style_ID == rb_intern("currency")) {
			formatStyle = UNUM_CURRENCY;
		} else if (style_ID == rb_intern("percent")) {
			formatStyle = UNUM_PERCENT;
		} else if (style_ID == rb_intern("scientific")) {
			formatStyle = UNUM_SCIENTIFIC;
		} else if (style_ID == rb_intern("spellout")) {
			formatStyle = UNUM_SPELLOUT;
		} else {
			rb_raise(rb_eArgError, "unsupported format style %s", rb_id2name(style_ID));
		}
	}
	if (options != Qnil) {
		VALUE rb_locale;

		Check_Type(options, T_HASH);
		rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale")));
		if (rb_locale != Qnil) {
			locale = StringValuePtr(rb_locale);
		}
	}
	/* formatter */
	status = U_ZERO_ERROR;
    format = unum_open(formatStyle, NULL, 0, locale, NULL, &status);
    RAISE_ON_ERROR(status);
    /* set format attributes */
	if (options != Qnil) {
		VALUE currency, precision, round_mode, round_increment;

		switch (formatStyle) {
			case UNUM_CURRENCY:
				currency = rb_hash_aref(options, ID2SYM(rb_intern("currency")));
				if (currency != Qnil) {
					UChar *uStr;
					int32_t uStrLen;

					uStr = u_strFromRString(currency, &uStrLen);
					status = U_ZERO_ERROR;
					unum_setTextAttribute(format, UNUM_CURRENCY_CODE, uStr, uStrLen, &status);
					RAISE_ON_ERROR(status);
				}
			case UNUM_DECIMAL:
				/* precision */
				precision = rb_hash_aref(options, ID2SYM(rb_intern("precision")));
				if (precision != Qnil) {
					Check_Type(precision, T_FIXNUM);
					status = U_ZERO_ERROR;
					unum_setAttribute(format, UNUM_FRACTION_DIGITS, NUM2INT(precision));
					RAISE_ON_ERROR(status);
				}

				round_mode = rb_hash_aref(options, ID2SYM(rb_intern("round_mode")));
				if (round_mode != Qnil) {
					ID round_mode_ID;
					UNumberFormatRoundingMode rounding_mode;

					Check_Type(round_mode, T_SYMBOL);
					round_mode_ID = SYM2ID(round_mode);
					if (round_mode_ID == rb_intern("ceil")) {
						rounding_mode = UNUM_ROUND_CEILING;
					} else if (round_mode_ID == rb_intern("floor")) {
						rounding_mode = UNUM_ROUND_FLOOR;
					} else if (round_mode_ID == rb_intern("down")) {
						rounding_mode = UNUM_ROUND_DOWN;
					} else if (round_mode_ID == rb_intern("up")) {
						rounding_mode = UNUM_ROUND_UP;
					} else if (round_mode_ID == rb_intern("halfeven")) {
						rounding_mode = UNUM_FOUND_HALFEVEN;
					} else if (round_mode_ID == rb_intern("halfdown")) {
						rounding_mode = UNUM_ROUND_HALFDOWN;
					} else if (round_mode_ID == rb_intern("halfup")) {
						rounding_mode = UNUM_ROUND_HALFUP;
					} else {
						rb_raise(rb_eArgError, "unsupported rounding mode '%s'", rb_id2name(round_mode_ID));
					}
					status = U_ZERO_ERROR;
					unum_setAttribute(format, UNUM_ROUNDING_MODE, rounding_mode);
					RAISE_ON_ERROR(status);
				}
				round_increment = rb_hash_aref(options, ID2SYM(rb_intern("round_increment")));
				if (round_increment != Qnil) {
					Check_Type(round_increment, T_FLOAT);
					status = U_ZERO_ERROR;
					unum_setDoubleAttribute(format, UNUM_ROUNDING_INCREMENT, NUM2DBL(round_increment));
					RAISE_ON_ERROR(status);
				}
		}
	}
	/* format */
	status = U_ZERO_ERROR;
    switch (TYPE(self)) {
    	case T_FIXNUM:
    		unum_format(format, NUM2INT(self), result, 256, NULL, &status);
    		break;
    	case T_FLOAT:
    		unum_formatDouble(format, NUM2DBL(self), result, 256, NULL, &status);
    		break;
    	case T_BIGNUM:
			unum_formatInt64(format, rb_big2ll(self), result, 256, NULL, &status);
    		break;

    }
    RAISE_ON_ERROR(status);
    /* free resources */
    unum_close(format);

    return u_strToRString(result, -1);
}