From: Fredrik Roubert Date: Thu, 13 Sep 2018 23:08:29 +0000 (-0700) Subject: ICU-13417 Add the Locale::createUnicodeKeywords() function. X-Git-Tag: release-63-rc~70 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6eb53e0884492c365a2da234b433a7daaaf0a2d6;p=icu ICU-13417 Add the Locale::createUnicodeKeywords() function. This is a wrapper of Locale::createKeywords() that under the hood calls uloc_toUnicodeLocaleKey() for each key before returning it, so that the caller won't have to do this. --- diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp index fe52afc9f31..784193f2511 100644 --- a/icu4c/source/common/locid.cpp +++ b/icu4c/source/common/locid.cpp @@ -1174,6 +1174,29 @@ KeywordEnumeration::~KeywordEnumeration() { uprv_free(keywords); } +// A wrapper around KeywordEnumeration that calls uloc_toUnicodeLocaleKey() in +// the next() method for each keyword before returning it. +class UnicodeKeywordEnumeration : public KeywordEnumeration { +public: + using KeywordEnumeration::KeywordEnumeration; + virtual ~UnicodeKeywordEnumeration() = default; + + virtual const char* next(int32_t* resultLength, UErrorCode& status) { + const char* legacy_key = KeywordEnumeration::next(nullptr, status); + if (U_SUCCESS(status) && legacy_key != nullptr) { + const char* key = uloc_toUnicodeLocaleKey(legacy_key); + if (key == nullptr) { + status = U_ILLEGAL_ARGUMENT_ERROR; + } else { + if (resultLength != nullptr) *resultLength = uprv_strlen(key); + return key; + } + } + if (resultLength != nullptr) *resultLength = 0; + return nullptr; + } +}; + StringEnumeration * Locale::createKeywords(UErrorCode &status) const { @@ -1196,6 +1219,28 @@ Locale::createKeywords(UErrorCode &status) const return result; } +StringEnumeration * +Locale::createUnicodeKeywords(UErrorCode &status) const +{ + char keywords[256]; + int32_t keywordCapacity = 256; + StringEnumeration *result = NULL; + + const char* variantStart = uprv_strchr(fullName, '@'); + const char* assignment = uprv_strchr(fullName, '='); + if(variantStart) { + if(assignment > variantStart) { + int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status); + if(keyLen) { + result = new UnicodeKeywordEnumeration(keywords, keyLen, 0, status); + } + } else { + status = U_INVALID_FORMAT_ERROR; + } + } + return result; +} + int32_t Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const { diff --git a/icu4c/source/common/unicode/locid.h b/icu4c/source/common/unicode/locid.h index ef8df739a00..962e6ddb269 100644 --- a/icu4c/source/common/unicode/locid.h +++ b/icu4c/source/common/unicode/locid.h @@ -494,6 +494,20 @@ public: */ StringEnumeration * createKeywords(UErrorCode &status) const; +#ifndef U_HIDE_DRAFT_API + + /** + * Gets the list of Unicode keywords for the specified locale. + * + * @param status the status code + * @return pointer to StringEnumeration class, or NULL if there are no keywords. + * Client must dispose of it by calling delete. + * @draft ICU 63 + */ + StringEnumeration * createUnicodeKeywords(UErrorCode &status) const; + +#endif // U_HIDE_DRAFT_API + /** * Gets the value for a keyword. * diff --git a/icu4c/source/test/intltest/loctest.cpp b/icu4c/source/test/intltest/loctest.cpp index cd75670cff6..33174cba05c 100644 --- a/icu4c/source/test/intltest/loctest.cpp +++ b/icu4c/source/test/intltest/loctest.cpp @@ -7,6 +7,7 @@ ********************************************************************/ #include "loctest.h" +#include "unicode/localpointer.h" #include "unicode/decimfmt.h" #include "unicode/ucurr.h" #include "unicode/smpdtfmt.h" @@ -221,6 +222,7 @@ void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, c TESTCASE_AUTO(TestSetIsBogus); TESTCASE_AUTO(TestParallelAPIValues); TESTCASE_AUTO(TestKeywordVariants); + TESTCASE_AUTO(TestCreateUnicodeKeywords); TESTCASE_AUTO(TestKeywordVariantParsing); TESTCASE_AUTO(TestSetKeywordValue); TESTCASE_AUTO(TestGetBaseName); @@ -1708,6 +1710,55 @@ LocaleTest::TestKeywordVariants(void) { } + +void +LocaleTest::TestCreateUnicodeKeywords(void) { + IcuTestErrorCode status(*this, "TestCreateUnicodeKeywords()"); + + static const Locale l("de@calendar=buddhist;collation=phonebook"); + + LocalPointer keys(l.createUnicodeKeywords(status)); + status.errIfFailureAndReset("\"%s\"", l.getName()); + + const char* key; + int32_t resultLength; + + key = keys->next(&resultLength, status); + status.errIfFailureAndReset("key #1"); + assertEquals("resultLength", 2, resultLength); + assertTrue("key != nullptr", key != nullptr); + assertEquals("calendar", "ca", key); + + key = keys->next(&resultLength, status); + status.errIfFailureAndReset("key #2"); + assertEquals("resultLength", 2, resultLength); + assertTrue("key != nullptr", key != nullptr); + assertEquals("collation", "co", key); + + key = keys->next(&resultLength, status); + status.errIfFailureAndReset("end of keys"); + assertEquals("resultLength", 0, resultLength); + assertTrue("key == nullptr", key == nullptr); + + const UnicodeString* skey; + keys->reset(status); // KeywordEnumeration::reset() never touches status. + + skey = keys->snext(status); + status.errIfFailureAndReset("skey #1"); + assertTrue("skey != nullptr", skey != nullptr); + assertEquals("calendar", "ca", *skey); + + skey = keys->snext(status); + status.errIfFailureAndReset("skey #2"); + assertTrue("skey != nullptr", skey != nullptr); + assertEquals("collation", "co", *skey); + + skey = keys->snext(status); + status.errIfFailureAndReset("end of keys"); + assertTrue("skey == nullptr", skey == nullptr); +} + + void LocaleTest::TestKeywordVariantParsing(void) { static const struct { diff --git a/icu4c/source/test/intltest/loctest.h b/icu4c/source/test/intltest/loctest.h index 529df214df8..7bb52f47a9f 100644 --- a/icu4c/source/test/intltest/loctest.h +++ b/icu4c/source/test/intltest/loctest.h @@ -72,8 +72,9 @@ public: void TestVariantParsing(void); - /* Test getting keyword enumeratin */ + /* Test getting keyword enumeration */ void TestKeywordVariants(void); + void TestCreateUnicodeKeywords(void); /* Test getting keyword values */ void TestKeywordVariantParsing(void);