From c93625a460b7d296dc3ebdf61d1769e05d9524a8 Mon Sep 17 00:00:00 2001 From: Ram Viswanadha Date: Fri, 7 Nov 2003 02:38:19 +0000 Subject: [PATCH] ICU-2938 add uloc_getDisplayKeywords, uloc_getDisplayKeywordValue, uset_applyPattern X-SVN-Rev: 13615 --- icu4c/source/common/uloc.c | 188 ++++++++++++++++++++++++--- icu4c/source/common/unicode/uloc.h | 75 ++++++++++- icu4c/source/common/unicode/uniset.h | 3 + icu4c/source/common/unicode/uset.h | 27 ++++ icu4c/source/common/uset.cpp | 30 +++++ 5 files changed, 306 insertions(+), 17 deletions(-) diff --git a/icu4c/source/common/uloc.c b/icu4c/source/common/uloc.c index 860031db3db..b133ec3d393 100644 --- a/icu4c/source/common/uloc.c +++ b/icu4c/source/common/uloc.c @@ -52,14 +52,16 @@ U_CFUNC const char *locale_get_default(void); /* These strings describe the resources we attempt to load from the locale ResourceBundle data file.*/ -static const char _kLanguages[] = "Languages"; -static const char _kScripts[] = "Scripts"; -static const char _kCountries[] = "Countries"; -static const char _kVariants[] = "Variants"; -static const char _kKeys[] = "Keys"; +static const char _kLanguages[] = "Languages"; +static const char _kScripts[] = "Scripts"; +static const char _kCountries[] = "Countries"; +static const char _kVariants[] = "Variants"; +static const char _kKeys[] = "Keys"; +static const char _kTypes[] = "Types"; static const char _kIndexLocaleName[] = "res_index"; -static const char _kIndexTag[] = "InstalledLocales"; - +static const char _kIndexTag[] = "InstalledLocales"; +static const char _kCurrency[] = "currency"; +static const char _kCurrencies[] = "Currencies"; static char** _installedLocales = NULL; static int32_t _installedLocalesCount = 0; @@ -1334,7 +1336,8 @@ uloc_getLCID(const char* localeID) */ static const UChar * _res_getTableStringWithFallback(const char *path, const char *locale, - const char *tableKey, const char *itemKey, + const char *tableKey, const char *subTableKey, + const char *itemKey, int32_t *pLength, UErrorCode *pErrorCode) { @@ -1400,7 +1403,14 @@ _res_getTableStringWithFallback(const char *path, const char *locale, /* try to open the requested item in the table */ errorCode=U_ZERO_ERROR; - item=ures_getStringByKey(&table, itemKey, pLength, &errorCode); + if(subTableKey == NULL){ + item=ures_getStringByKey(&table, itemKey, pLength, &errorCode); + }else{ + UResourceBundle subTable; + ures_initStackObject(&subTable); + ures_getByKey(&table, subTableKey, &subTable, &errorCode); + item = ures_getStringByKey(&subTable, itemKey, pLength, &errorCode); + } if(U_SUCCESS(errorCode)) { /* if the item for the key is empty ... override the explicit fall back set */ if(item[0]==0 && efnLen > 0){ @@ -1476,7 +1486,9 @@ _res_getTableStringWithFallback(const char *path, const char *locale, static int32_t _getStringOrCopyKey(const char *path, const char *locale, - const char *tableKey, const char *itemKey, + const char *tableKey, + const char* subTableKey, + const char *itemKey, const char *substitute, UChar *dest, int32_t destCapacity, UErrorCode *pErrorCode) { @@ -1496,7 +1508,9 @@ _getStringOrCopyKey(const char *path, const char *locale, } else { /* second-level item, use special fallback */ s=_res_getTableStringWithFallback(path, locale, - tableKey, itemKey, + tableKey, + subTableKey, + itemKey, &length, pErrorCode); } @@ -1544,8 +1558,8 @@ uloc_getDisplayLanguage(const char *locale, } return _getStringOrCopyKey(NULL, displayLocale, - _kLanguages, localeBuffer, - localeBuffer, + _kLanguages, NULL, localeBuffer, + localeBuffer, dest, destCapacity, pErrorCode); } @@ -1580,12 +1594,15 @@ uloc_getDisplayScript(const char* locale, } return _getStringOrCopyKey(NULL, displayLocale, - _kScripts, localeBuffer, + _kScripts, NULL, + localeBuffer, localeBuffer, dest, destCapacity, pErrorCode); } + + U_CAPI int32_t U_EXPORT2 uloc_getDisplayCountry(const char *locale, const char *displayLocale, @@ -1615,7 +1632,8 @@ uloc_getDisplayCountry(const char *locale, } return _getStringOrCopyKey(NULL, displayLocale, - _kCountries, localeBuffer, + _kCountries, NULL, + localeBuffer, localeBuffer, dest, destCapacity, pErrorCode); @@ -1660,7 +1678,8 @@ uloc_getDisplayVariant(const char *locale, /* pass itemKey=NULL to look for a top-level item */ return _getStringOrCopyKey(NULL, displayLocale, - _kVariants, localeBuffer, + _kVariants, NULL, + localeBuffer, localeBuffer, dest, destCapacity, pErrorCode); @@ -1809,6 +1828,143 @@ uloc_getDisplayName(const char *locale, return u_terminateUChars(dest, destCapacity, length, pErrorCode); } +U_CAPI int32_t U_EXPORT2 +uloc_getDisplayKeyword(const char* keyword, + const char* displayLocale, + UChar* dest, + int32_t destCapacity, + UErrorCode* status){ + + /* argument checking */ + if(status==NULL || U_FAILURE(*status)) { + return 0; + } + + if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { + *status=U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + + /* pass itemKey=NULL to look for a top-level item */ + return _getStringOrCopyKey(NULL, displayLocale, + _kKeys, NULL, + keyword, + keyword, + dest, destCapacity, + status); + +} +/** + * Modify the given locale name by removing the rightmost _-delimited + * element. If there is none, empty the string ("" == root). + * NOTE: The string "root" is not recognized; do not use it. + * @return TRUE if the fallback happened; FALSE if locale is already + * root (""). + */ +static UBool fallback(char *loc) { + UErrorCode status = U_ZERO_ERROR; + + if (!*loc) { + return FALSE; + } + uloc_getParent(loc, loc, uprv_strlen(loc), &status); + + return TRUE; +} + +#define UCURRENCY_DISPLAY_NAME_INDEX 1 + +U_CAPI int32_t U_EXPORT2 +uloc_getDisplayKeywordValue( const char* locale, + const char* keyword, + const char* displayLocale, + UChar* dest, + int32_t destCapacity, + UErrorCode* status){ + + char loc[ULOC_FULLNAME_CAPACITY*4]; + int32_t locLen = 0; + char keywordValue[ULOC_FULLNAME_CAPACITY*4]; + int32_t capacity = ULOC_FULLNAME_CAPACITY*4; + int32_t keywordValueLen =0; + + /* argument checking */ + if(status==NULL || U_FAILURE(*status)) { + return 0; + } + + if(destCapacity<0 || (destCapacity>0 && dest==NULL)) { + *status=U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + /* get the keyword value */ + keywordValueLen = uloc_getKeywordValue(locale, keyword, keywordValue, capacity, status); + + /* + * if the keyword is equal to currency .. then to get the display name + * we need to do the fallback ourselves + */ + if(uprv_stricmp(keyword, _kCurrency)==0){ + + UErrorCode ec2 = U_ZERO_ERROR; + int32_t dispNameLen = 0; + const UChar *dispName = NULL; + + for (;;) { + UResourceBundle* rb = ures_open(NULL, displayLocale, &ec2); + UResourceBundle* curr = ures_getByKey(rb, _kCurrencies, NULL, &ec2); + UResourceBundle* names = ures_getByKey(curr, keywordValue, NULL, &ec2); + + dispName = ures_getStringByIndex(names, UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, &ec2); + ures_close(names); + ures_close(curr); + ures_close(rb); + + /* If we've succeeded we're done. Otherwise, try to fallback. + * If that fails (because we are already at root) then exit. + */ + if (U_SUCCESS(ec2) || !fallback(loc)) { + break; + } + } + if(U_FAILURE(ec2)){ + *status = ec2; + return 0; + } + /* now copy the dispName over if not NULL */ + if(dispName != NULL){ + if(dispNameLen <= destCapacity){ + uprv_memcpy(dest, dispName, dispNameLen * U_SIZEOF_UCHAR); + return u_terminateUChars(dest, destCapacity, dispNameLen, status); + }else{ + *status = U_BUFFER_OVERFLOW_ERROR; + return dispNameLen; + } + }else{ + /* we have not found the display name for the value .. just copy over */ + if(keywordValueLen <= destCapacity){ + u_charsToUChars(keywordValue, dest, keywordValueLen); + return u_terminateUChars(dest, destCapacity, keywordValueLen, status); + }else{ + *status = U_BUFFER_OVERFLOW_ERROR; + return keywordValueLen; + } + } + + + }else{ + + return _getStringOrCopyKey(NULL, displayLocale, + _kTypes, keyword, + keywordValue, + keywordValue, + dest, destCapacity, + status); + } +} + static void _load_installedLocales() { UBool localesLoaded; diff --git a/icu4c/source/common/unicode/uloc.h b/icu4c/source/common/unicode/uloc.h index db1fb0f00b2..3b459acbf0e 100644 --- a/icu4c/source/common/unicode/uloc.h +++ b/icu4c/source/common/unicode/uloc.h @@ -557,7 +557,7 @@ uloc_getDisplayCountry(const char* locale, /** - * Gets the variant code suitable for display for the specified locale. + * Gets the variant name suitable for display for the specified locale. * * @param locale the locale to get the displayable variant code with. NULL may be used to specify the default. * @param displayLocale Specifies the locale to be used to display the name. In other words, @@ -579,6 +579,79 @@ uloc_getDisplayVariant(const char* locale, int32_t variantCapacity, UErrorCode* status); +/** + * Gets the keyword name suitable for display for the specified locale. + * E.g: for the locale string de_DE@collation=PHONEBOOK, this API gets the display + * string for the keyword collation. + * Usage: + * + * UErrorCode status = U_ZERO_ERROR; + * const char* keyword =NULL; + * int32_t keywordLen = 0; + * int32_t keywordCount = 0; + * UChar displayKeyword[256]; + * int32_t displayKeywordLen = 0; + * UEnumeration* keywordEnum = uloc_getKeywords("de_DE@collation=PHONEBOOK;calendar=TRADITIONAL", &status); + * for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){ + * if(U_FAILURE(status)){ + * ...something went wrong so handle the error... + * break; + * } + * // the uenum_next returns NUL terminated string + * keyword = uenum_next(keywordEnum, &keywordLen, &status); + * displayKeywordLen = uloc_getDisplayKeyword(keyword, "en_US", displayKeyword, 256); + * ... do something interesting ..... + * } + * uenum_close(keywordEnum); + * + * @param keyword The keyword whose display string needs to be returned. + * @param displayLocale Specifies the locale to be used to display the name. In other words, + * if the locale's language code is "en", passing Locale::getFrench() for + * inLocale would result in "Anglais", while passing Locale::getGerman() + * for inLocale would result in "Englisch". NULL may be used to specify the default. + * @param dest the buffer to which the displayable keyword should be written. + * @param destCapacity The size of the buffer (number of UChars). If it is 0, then + * dest may be NULL and the function will only return the length of the + * result without writing any of the result string (pre-flighting). + * @param status error information if retrieving the displayable string failed. + * Should not be NULL and should not indicate failure on entry. + * @return the actual buffer size needed for the displayable variant code. + * @see #uloc_getKeywords + * @draft ICU 2.8 + */ +U_CAPI int32_t U_EXPORT2 +uloc_getDisplayKeyword(const char* keyword, + const char* displayLocale, + UChar* dest, + int32_t destCapacity, + UErrorCode* status); +/** + * Gets the value of the keyword suitable for display for the specified locale. + * E.g: for the locale string de_DE@collation=PHONEBOOK, this API gets the display + * string for PHONEBOOK, in the display locale, when "collation" is specified as the keyword. + * + * @param locale The locale to get the displayable variant code with. NULL may be used to specify the default. + * @param keyword The keyword for whose value should be used. + * @param displayLocale Specifies the locale to be used to display the name. In other words, + * if the locale's language code is "en", passing Locale::getFrench() for + * inLocale would result in "Anglais", while passing Locale::getGerman() + * for inLocale would result in "Englisch". NULL may be used to specify the default. + * @param dest the buffer to which the displayable keyword should be written. + * @param destCapacity The size of the buffer (number of UChars). If it is 0, then + * dest may be NULL and the function will only return the length of the + * result without writing any of the result string (pre-flighting). + * @param status error information if retrieving the displayable string failed. + * Should not be NULL and must not indicate failure on entry. + * @return the actual buffer size needed for the displayable variant code. + * @draft ICU 2.8 + */ +U_CAPI int32_t U_EXPORT2 +uloc_getDisplayKeywordValue( const char* locale, + const char* keyword, + const char* displayLocale, + UChar* dest, + int32_t destCapacity, + UErrorCode* status); /** * Gets the full name suitable for display for the specified locale. * diff --git a/icu4c/source/common/unicode/uniset.h b/icu4c/source/common/unicode/uniset.h index fdf56f6badd..a246123f013 100644 --- a/icu4c/source/common/unicode/uniset.h +++ b/icu4c/source/common/unicode/uniset.h @@ -451,6 +451,7 @@ public: * @param pattern a string specifying what characters are in the set * @param status returns U_ILLEGAL_ARGUMENT_ERROR if the pattern * contains a syntax error. + * Empties the set passed before applying the pattern. * @return a reference to this * @stable ICU 2.0 */ @@ -468,6 +469,7 @@ public: * values and stand-ins to UnicodeSets; may be NULL * @param status returns U_ILLEGAL_ARGUMENT_ERROR if the pattern * contains a syntax error. + * Empties the set passed before applying the pattern. * @return a reference to this * @internal */ @@ -486,6 +488,7 @@ public: * following the closing ']', and a StringBuffer containing a * pairs list for the parsed pattern is returned. This method calls * itself recursively to parse embedded subpatterns. + * Empties the set passed before applying the pattern. * * @param pattern the string containing the pattern to be parsed. * The portion of the string from pos.getIndex(), which must be a diff --git a/icu4c/source/common/unicode/uset.h b/icu4c/source/common/unicode/uset.h index 28f2fec02f7..93d1a0e35d7 100644 --- a/icu4c/source/common/unicode/uset.h +++ b/icu4c/source/common/unicode/uset.h @@ -28,6 +28,7 @@ #define __USET_H__ #include "unicode/utypes.h" +#include "unicode/umisc.h" #ifndef UCNV_H struct USet; @@ -154,6 +155,32 @@ uset_openPatternOptions(const UChar* pattern, int32_t patternLength, U_CAPI void U_EXPORT2 uset_close(USet* set); +/** + * Modifies the set to represent the set specified by the given + * pattern. See the UnicodeSet class description for the syntax of + * the pattern language. See also the User Guide chapter about UnicodeSet. + * Empties the set passed before applying the pattern. + * @param set The set to which the pattern is to be applied. + * @param pattern A pointer to UChar string specifying what characters are in the set. + * The character at pattern[0] must be a '['. + * @param patternLength The length of the UChar string. -1 if NUL terminated. + * @param options A bitmask for options to apply to the pattern. + * Valid options are USET_IGNORE_SPACE and USET_CASE_INSENSITIVE. + * @param status Returns an error if the pattern cannot be parsed. + * @return Upon successful parse, the value is either + * the index of the character after the closing ']' + * of the parsed pattern. + * If the status code indicates failure, then the return value + * is the index of the error in the source. + * + * @draft ICU 2.8 + */ +U_CAPI int32_t U_EXPORT2 +uset_applyPattern(USet *set, + const UChar *pattern, int32_t patternLength, + uint32_t options, + UErrorCode *status); + /** * Returns a string representation of this set. If the result of * calling this function is passed to a uset_openPattern(), it diff --git a/icu4c/source/common/uset.cpp b/icu4c/source/common/uset.cpp index 2f614dd6566..7c7d0346089 100644 --- a/icu4c/source/common/uset.cpp +++ b/icu4c/source/common/uset.cpp @@ -27,6 +27,7 @@ #include "unicode/uniset.h" #include "cmemory.h" #include "unicode/ustring.h" +#include "unicode/parsepos.h" U_CAPI USet* U_EXPORT2 uset_open(UChar32 start, UChar32 end) { @@ -78,6 +79,35 @@ uset_close(USet* set) { delete (UnicodeSet*) set; } +U_CAPI int32_t U_EXPORT2 +uset_applyPattern(USet *set, + const UChar *pattern, int32_t patternLength, + uint32_t options, + UErrorCode *status){ + + // status code needs to be checked since we + // dereference it + if(status == NULL || U_FAILURE(*status)){ + return 0; + } + + // check only the set paramenter + // if pattern is NULL or null terminate + // UnicodeString constructor takes care of it + if(set == NULL){ + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + UnicodeString pat(pattern, patternLength); + + ParsePosition pos; + + ((UnicodeSet*) set)->applyPattern(pat, pos, options, NULL, *status); + + return pos.getIndex(); +} + U_CAPI int32_t U_EXPORT2 uset_toPattern(const USet* set, UChar* result, int32_t resultCapacity,