Author: zooey Date: 2010-04-12 01:56:02 +0200 (Mon, 12 Apr 2010) New Revision: 36176 Changeset: http://dev.haiku-os.org/changeset/36176/haiku Modified: haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.cpp haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.h haiku/branches/developer/zooey/posix-locale/src/tests/system/libroot/posix/locale_test.cpp Log: * finished implementation of monetary locale data fetching Modified: haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.cpp =================================================================== --- haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.cpp 2010-04-11 23:00:25 UTC (rev 36175) +++ haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.cpp 2010-04-11 23:56:02 UTC (rev 36176) @@ -205,9 +205,9 @@ if (result == B_OK) { UErrorCode icuStatus = U_ZERO_ERROR; + UChar currencySeparatorChar = CHAR_MAX; DecimalFormat* currencyFormat = dynamic_cast<DecimalFormat*>( - NumberFormat::createInstance(locale, DecimalFormat::kCurrencyStyle, - icuStatus)); + NumberFormat::createCurrencyInstance(locale, icuStatus)); if (!U_SUCCESS(icuStatus)) return B_UNSUPPORTED; if (!currencyFormat) @@ -242,19 +242,6 @@ } } if (result == B_OK) { - result = _SetLocaleconvEntry(formatSymbols, sIntCurrSymbol, - DecimalFormatSymbols::kIntlCurrencySymbol); - } - if (result == B_OK) { - result = _SetLocaleconvEntry(formatSymbols, sCurrencySymbol, - DecimalFormatSymbols::kCurrencySymbol); - if (sCurrencySymbol[0] == '\0') { - // fall back to the international currency symbol - result = _SetLocaleconvEntry(formatSymbols, sCurrencySymbol, - DecimalFormatSymbols::kIntlCurrencySymbol); - } - } - if (result == B_OK) { result = _SetLocaleconvEntry(formatSymbols, sPositiveSign, DecimalFormatSymbols::kPlusSignSymbol); } @@ -268,7 +255,70 @@ sLocaleConv.frac_digits = currencyFormat->getMinimumFractionDigits(); } + if (result == B_OK) { + UnicodeString positivePrefix, positiveSuffix, negativePrefix, + negativeSuffix; + currencyFormat->getPositivePrefix(positivePrefix); + currencyFormat->getPositiveSuffix(positiveSuffix); + currencyFormat->getNegativePrefix(negativePrefix); + currencyFormat->getNegativeSuffix(negativeSuffix); + UnicodeString currencySymbol = formatSymbols->getSymbol( + DecimalFormatSymbols::kCurrencySymbol); + UnicodeString plusSymbol = formatSymbols->getSymbol( + DecimalFormatSymbols::kPlusSignSymbol); + UnicodeString minusSymbol = formatSymbols->getSymbol( + DecimalFormatSymbols::kMinusSignSymbol); + int32 positiveCurrencyFlags = _DetermineCurrencyPosAndSeparator( + positivePrefix, positiveSuffix, plusSymbol, currencySymbol, + currencySeparatorChar + ); + sLocaleConv.p_cs_precedes + = (positiveCurrencyFlags & kCsPrecedesFlag) ? 1 : 0; + sLocaleConv.p_sep_by_space + = (positiveCurrencyFlags & kSepBySpaceFlag) ? 1 : 0; + + int32 negativeCurrencyFlags = _DetermineCurrencyPosAndSeparator( + negativePrefix, negativeSuffix, minusSymbol, currencySymbol, + currencySeparatorChar + ); + sLocaleConv.n_cs_precedes + = (negativeCurrencyFlags & kCsPrecedesFlag) ? 1 : 0; + sLocaleConv.n_sep_by_space + = (negativeCurrencyFlags & kSepBySpaceFlag) ? 1 : 0; + + sLocaleConv.p_sign_posn = _DetermineSignPos(positivePrefix, + positiveSuffix, plusSymbol, currencySymbol); + sLocaleConv.n_sign_posn = _DetermineSignPos(negativePrefix, + negativeSuffix, minusSymbol, currencySymbol); + if (sLocaleConv.p_sign_posn == CHAR_MAX) { + // usually there is no positive sign indicator, so we + // remove the character ... + sPositiveSign[0] = '\0'; + // ... and adopt the sign pos of the negative sign symbol + sLocaleConv.p_sign_posn = sLocaleConv.n_sign_posn; + } + } + if (result == B_OK) { + UnicodeString intCurrencySymbol = formatSymbols->getSymbol( + DecimalFormatSymbols::kIntlCurrencySymbol); + if (currencySeparatorChar != CHAR_MAX) + intCurrencySymbol += currencySeparatorChar; + result = _ConvertUnicodeStringToLocaleconvEntry(intCurrencySymbol, + sIntCurrSymbol); + } + if (result == B_OK) { + result = _SetLocaleconvEntry(formatSymbols, sCurrencySymbol, + DecimalFormatSymbols::kCurrencySymbol); + if (sCurrencySymbol[0] == '\0') { + // fall back to the international currency symbol + result = _SetLocaleconvEntry(formatSymbols, sCurrencySymbol, + DecimalFormatSymbols::kIntlCurrencySymbol); + sCurrencySymbol[3] = '\0'; + // drop separator char that's contained in int-curr-symbol + } + } + delete currencyFormat; } @@ -276,6 +326,91 @@ } +int32 +MonetaryData::_DetermineCurrencyPosAndSeparator(const UnicodeString& prefix, + const UnicodeString& suffix, const UnicodeString& signSymbol, + const UnicodeString& currencySymbol, UChar& currencySeparatorChar) +{ + int32 result = 0; + + int32 currencySymbolPos = prefix.indexOf(currencySymbol); + if (currencySymbolPos > -1) { + int32 signSymbolPos = prefix.indexOf(signSymbol); + result |= kCsPrecedesFlag; + // if a char is following the currency symbol, we assume it's + // the separator (usually space), but we need to take care to + // skip over the sign symbol, if found + int32 potentialSeparatorPos + = currencySymbolPos + currencySymbol.length(); + if (potentialSeparatorPos == signSymbolPos) + potentialSeparatorPos++; + currencySeparatorChar = prefix.charAt(potentialSeparatorPos); + if (currencySeparatorChar != 0xFFFF) + result |= kSepBySpaceFlag; + } else { + currencySymbolPos = suffix.indexOf(currencySymbol); + if (currencySymbolPos > -1) { + int32 signSymbolPos = suffix.indexOf(signSymbol); + // if a char is preceding the currency symbol, we assume + // it's the separator (usually space), but we need to take + // care to skip the sign symbol, if found + int32 potentialSeparatorPos = currencySymbolPos - 1; + if (potentialSeparatorPos == signSymbolPos) + potentialSeparatorPos--; + currencySeparatorChar = suffix.charAt(potentialSeparatorPos); + if (currencySeparatorChar != 0xFFFF) + result |= kSepBySpaceFlag; + } + } + + return result; +} + + +/* + * This method determines the <>_sign_posn value according to the following + * map (where '$' indicated the currency symbol, '#' the number value, and + * '-' the sign symbol [or alternatively the paranthesis]): + * ($#) -> 0 + * (#$) -> 0 + * -$# -> 1 + * -#$ -> 1 + * $-# -> 4 + * $#- -> 2 + * #$- -> 2 + * #-$ -> 3 + */ +int32 +MonetaryData::_DetermineSignPos(const UnicodeString& prefix, + const UnicodeString& suffix, const UnicodeString& signSymbol, + const UnicodeString& currencySymbol) +{ + if (prefix.indexOf(UnicodeString("(", "")) >= 0 + && suffix.indexOf(UnicodeString(")", "")) >= 0) + return 0; // parentheses around currency and value + + UnicodeString value("#", ""); + UnicodeString prefixNumberSuffixString = prefix + value + suffix; + int32 signSymbolPos = prefixNumberSuffixString.indexOf(signSymbol); + if (signSymbolPos >= 0) { + int32 valuePos = prefixNumberSuffixString.indexOf(value); + int32 currencySymbolPos + = prefixNumberSuffixString.indexOf(currencySymbol); + + if (signSymbolPos < valuePos && signSymbolPos < currencySymbolPos) + return 1; // sign precedes currency and value + if (signSymbolPos > valuePos && signSymbolPos > currencySymbolPos) + return 2; // sign succeeds currency and value + if (signSymbolPos == currencySymbolPos - 1) + return 3; // sign immediately precedes currency + if (signSymbolPos == currencySymbolPos + currencySymbol.length()) + return 4; // sign immediately succeeds currency + } + + return CHAR_MAX; +} + + status_t NumericData::SetTo(const Locale& locale, const char* posixLocaleName) { Modified: haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.h =================================================================== --- haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.h 2010-04-11 23:00:25 UTC (rev 36175) +++ haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.h 2010-04-11 23:56:02 UTC (rev 36176) @@ -84,6 +84,21 @@ public: virtual status_t SetTo(const Locale& locale, const char* posixLocaleName); + +private: +static const int32 kCsPrecedesFlag = 1 << 0; +static const int32 kSepBySpaceFlag = 1 << 1; + + int32 _DetermineCurrencyPosAndSeparator( + const UnicodeString& prefix, + const UnicodeString& suffix, + const UnicodeString& signSymbol, + const UnicodeString& currencySymbol, + UChar& currencySeparatorChar); + int32 _DetermineSignPos(const UnicodeString& prefix, + const UnicodeString& suffix, + const UnicodeString& signSymbol, + const UnicodeString& currencySymbol); }; Modified: haiku/branches/developer/zooey/posix-locale/src/tests/system/libroot/posix/locale_test.cpp =================================================================== --- haiku/branches/developer/zooey/posix-locale/src/tests/system/libroot/posix/locale_test.cpp 2010-04-11 23:00:25 UTC (rev 36175) +++ haiku/branches/developer/zooey/posix-locale/src/tests/system/libroot/posix/locale_test.cpp 2010-04-11 23:56:02 UTC (rev 36176) @@ -58,9 +58,11 @@ "de_DE.iso8859-1", "hr_HR.ISO-8859-2", "de_CH", + "gu_IN", "it_IT", "nl_NL", "nb_NO", + "nb_NO.utf-8", "POSIX", NULL }; @@ -85,6 +87,14 @@ printf("\n"); printf("\tlc.positive_sign: '%s'\n", lc->positive_sign); printf("\tlc.negative_sign: '%s'\n", lc->negative_sign); + printf("\tlc.frac_digits: '%x'\n", lc->frac_digits); + printf("\tlc.int_frac_digits: '%x'\n", lc->int_frac_digits); + printf("\tlc.p_cs_precedes: '%x'\n", lc->p_cs_precedes); + printf("\tlc.p_sep_by_space: '%x'\n", lc->p_sep_by_space); + printf("\tlc.n_cs_precedes: '%x'\n", lc->n_cs_precedes); + printf("\tlc.n_sep_by_space: '%x'\n", lc->n_sep_by_space); + printf("\tlc.p_sign_posn: '%x'\n", lc->p_sign_posn); + printf("\tlc.n_sign_posn: '%x'\n", lc->n_sign_posn); } } }