Author: zooey Date: 2010-04-07 23:54:50 +0200 (Wed, 07 Apr 2010) New Revision: 36076 Changeset: http://dev.haiku-os.org/changeset/36076/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 Log: * implement filling of many lconv-members in SetLocale(), the positional arguments and some other bits are still missing, though 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-07 21:52:28 UTC (rev 36075) +++ haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.cpp 2010-04-07 21:54:50 UTC (rev 36076) @@ -12,27 +12,39 @@ #include <locale.h> #include <string.h> +#include <unicode/decimfmt.h> + namespace BPrivate { /* - * the values below initialize the struct to the "C"/"POSIX" locale, but it + * the values below initialize the struct to let each member point to a static + * buffer, which will be initialized to match the "C"/"POSIX" locale, but it * will be changed according to any locale requested via SetLocale() */ +static const uint16 skLCBufSize = 10; +static char sDecimalPoint[skLCBufSize] = "."; +static char sThousandsSep[skLCBufSize] = ""; +static char sGrouping[skLCBufSize] = ""; +static char sIntCurrSymbol[skLCBufSize] = ""; +static char sCurrencySymbol[skLCBufSize] = ""; +static char sMonDecimalPoint[skLCBufSize] = ""; +static char sMonThousandsSep[skLCBufSize] = ""; +static char sMonGrouping[skLCBufSize] = ""; +static char sPositiveSign[skLCBufSize] = ""; +static char sNegativeSign[skLCBufSize] = ""; static struct lconv sLocaleConv = { - ".", // decimal point - - "", // thousands separator - "", // grouping - "", // international currency symbol - "", // local currency symbol - "", // monetary decimal point - "", // monetary thousands separator - "", // monetary grouping - "", // positive sign - "", // negative sign - + sDecimalPoint, + sThousandsSep, + sGrouping, + sIntCurrSymbol, + sCurrencySymbol, + sMonDecimalPoint, + sMonThousandsSep, + sMonGrouping, + sPositiveSign, + sNegativeSign, CHAR_MAX, // int_frac_digits CHAR_MAX, // frac_digits CHAR_MAX, // p_cs_precedes @@ -45,6 +57,8 @@ CategoryData::CategoryData() + : + fConverter(NULL) { *fPosixLocaleName = '\0'; *fGivenCharset = '\0'; @@ -53,6 +67,8 @@ CategoryData::~CategoryData() { + if (fConverter) + ucnv_close(fConverter); } @@ -81,12 +97,54 @@ snprintf(fGivenCharset, UCNV_MAX_CONVERTER_NAME_LENGTH, "%.*s", l, charsetStart); } + if (!strlen(fGivenCharset)) + strcpy(fGivenCharset, "utf-8"); + UErrorCode icuStatus = U_ZERO_ERROR; + fConverter = ucnv_open(fGivenCharset, &icuStatus); + if (fConverter == NULL) + return B_NAME_NOT_FOUND; + + ucnv_setFromUCallBack(fConverter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, + NULL, &icuStatus); + if (!U_SUCCESS(icuStatus)) + return B_ERROR; + return B_OK; } status_t +CategoryData::_ConvertUnicodeStringToLocaleconvEntry(UnicodeString& string, + char* destination, char* defaultValue) +{ + status_t result = B_OK; + UErrorCode icuStatus = U_ZERO_ERROR; + + ucnv_fromUChars(fConverter, destination, skLCBufSize, string.getBuffer(), + string.length(), &icuStatus); + if (!U_SUCCESS(icuStatus)) { + switch (icuStatus) { + case U_BUFFER_OVERFLOW_ERROR: + result = B_NAME_TOO_LONG; + break; + case U_INVALID_CHAR_FOUND: + case U_TRUNCATED_CHAR_FOUND: + case U_ILLEGAL_CHAR_FOUND: + result = B_BAD_DATA; + break; + default: + result = B_ERROR; + break; + } + strcpy(destination, defaultValue); + } + + return result; +} + + +status_t CollateData::SetTo(const Locale& locale, const char* posixLocaleName) { status_t result = CategoryData::SetTo(locale, posixLocaleName); @@ -96,16 +154,12 @@ CtypeData::CtypeData() - : - fConverter(NULL) { } CtypeData::~CtypeData() { - if (fConverter) - ucnv_close(fConverter); } @@ -113,12 +167,6 @@ CtypeData::SetTo(const Locale& locale, const char* posixLocaleName) { status_t result = CategoryData::SetTo(locale, posixLocaleName); - if (result == B_OK && *fGivenCharset != '\0') { - UErrorCode icuStatus = U_ZERO_ERROR; - fConverter = ucnv_open(fGivenCharset, &icuStatus); - if (fConverter == NULL) - result = B_BAD_VALUE; - } return result; } @@ -134,10 +182,96 @@ status_t +LocaleconvData::_SetLocaleconvEntry(const DecimalFormatSymbols* formatSymbols, + char* destination, FormatSymbol symbol, char* defaultValue) +{ + status_t result = B_OK; + + UnicodeString symbolString = formatSymbols->getSymbol(symbol); + if (!symbolString.isEmpty()) { + result = _ConvertUnicodeStringToLocaleconvEntry(symbolString, + destination, defaultValue); + } else + destination[0] = '\0'; + + return result; +} + + +status_t MonetaryData::SetTo(const Locale& locale, const char* posixLocaleName) { status_t result = CategoryData::SetTo(locale, posixLocaleName); + if (result == B_OK) { + UErrorCode icuStatus = U_ZERO_ERROR; + DecimalFormat* currencyFormat = dynamic_cast<DecimalFormat*>( + NumberFormat::createInstance(locale, DecimalFormat::kCurrencyStyle, + icuStatus)); + if (!U_SUCCESS(icuStatus)) + return B_UNSUPPORTED; + if (!currencyFormat) + return B_BAD_TYPE; + const DecimalFormatSymbols* formatSymbols + = currencyFormat->getDecimalFormatSymbols(); + if (!formatSymbols) + result = B_BAD_DATA; + + if (result == B_OK) { + result = _SetLocaleconvEntry(formatSymbols, sMonDecimalPoint, + DecimalFormatSymbols::kMonetarySeparatorSymbol); + } + if (result == B_OK) { + result = _SetLocaleconvEntry(formatSymbols, sMonThousandsSep, + DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); + } + if (result == B_OK) { + int32 groupingSize = currencyFormat->getGroupingSize(); + if (groupingSize < 1) + sMonGrouping[0] = '\0'; + else { + sMonGrouping[0] = groupingSize; + int32 secondaryGroupingSize + = currencyFormat->getSecondaryGroupingSize(); + if (secondaryGroupingSize < 1) + sMonGrouping[1] = '\0'; + else { + sMonGrouping[1] = secondaryGroupingSize; + sMonGrouping[2] = '\0'; + } + } + } + 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); + } + if (result == B_OK) { + result = _SetLocaleconvEntry(formatSymbols, sNegativeSign, + DecimalFormatSymbols::kMinusSignSymbol); + } + if (result == B_OK) { + sLocaleConv.int_frac_digits + = currencyFormat->getMinimumFractionDigits(); + sLocaleConv.frac_digits + = currencyFormat->getMinimumFractionDigits(); + } + + delete currencyFormat; + } + return result; } @@ -147,6 +281,48 @@ { status_t result = CategoryData::SetTo(locale, posixLocaleName); + if (result == B_OK) { + UErrorCode icuStatus = U_ZERO_ERROR; + DecimalFormat* numberFormat = dynamic_cast<DecimalFormat*>( + NumberFormat::createInstance(locale, DecimalFormat::kNumberStyle, + icuStatus)); + if (!U_SUCCESS(icuStatus)) + return B_UNSUPPORTED; + if (!numberFormat) + return B_BAD_TYPE; + const DecimalFormatSymbols* formatSymbols + = numberFormat->getDecimalFormatSymbols(); + if (!formatSymbols) + result = B_BAD_DATA; + + if (result == B_OK) { + result = _SetLocaleconvEntry(formatSymbols, sDecimalPoint, + DecimalFormatSymbols::kDecimalSeparatorSymbol); + } + if (result == B_OK) { + result = _SetLocaleconvEntry(formatSymbols, sThousandsSep, + DecimalFormatSymbols::kGroupingSeparatorSymbol); + } + if (result == B_OK) { + int32 groupingSize = numberFormat->getGroupingSize(); + if (groupingSize < 1) + sGrouping[0] = '\0'; + else { + sGrouping[0] = groupingSize; + int32 secondaryGroupingSize + = numberFormat->getSecondaryGroupingSize(); + if (secondaryGroupingSize < 1) + sGrouping[1] = '\0'; + else { + sGrouping[1] = secondaryGroupingSize; + sGrouping[2] = '\0'; + } + } + } + + delete numberFormat; + } + return result; } 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-07 21:52:28 UTC (rev 36075) +++ haiku/branches/developer/zooey/posix-locale/src/system/libroot/posix/locale/ICULocaleBackend.h 2010-04-07 21:54:50 UTC (rev 36076) @@ -6,8 +6,10 @@ #define _ICU_LOCALE_BACKEND_H +#include <unicode/dcfmtsym.h> #include <unicode/locid.h> #include <unicode/ucnv.h> +#include <unicode/unistr.h> #include "LocaleBackend.h" @@ -15,6 +17,9 @@ namespace BPrivate { +typedef DecimalFormatSymbols::ENumberFormatSymbol FormatSymbol; + + class CategoryData { public: CategoryData(); @@ -27,8 +32,14 @@ { return fPosixLocaleName; } protected: + status_t _ConvertUnicodeStringToLocaleconvEntry( + UnicodeString& string, char* destination, + char* defaultValue = ""); + static const uint16 skMaxPosixLocaleNameLen = 128; + Locale fLocale; + UConverter* fConverter; char fPosixLocaleName[skMaxPosixLocaleNameLen]; char fGivenCharset[UCNV_MAX_CONVERTER_NAME_LENGTH]; }; @@ -50,7 +61,6 @@ const char* posixLocaleName); private: - UConverter* fConverter; }; @@ -61,14 +71,23 @@ }; -class MonetaryData : public CategoryData { +class LocaleconvData : public CategoryData { +protected: + status_t _SetLocaleconvEntry( + const DecimalFormatSymbols* formatSymbols, + char* destination, FormatSymbol symbol, + char* defaultValue = ""); +}; + + +class MonetaryData : public LocaleconvData { public: virtual status_t SetTo(const Locale& locale, const char* posixLocaleName); }; -class NumericData : public CategoryData { +class NumericData : public LocaleconvData { public: virtual status_t SetTo(const Locale& locale, const char* posixLocaleName);