ICU-12520 ucol_getKeywordValuesForLocale() resource data enumeration

X-SVN-Rev: 38674
This commit is contained in:
Markus Scherer 2016-04-29 23:04:00 +00:00
parent fef70d16f0
commit 3947687fcc
3 changed files with 117 additions and 126 deletions

View file

@ -1,6 +1,6 @@
/*
******************************************************************************
* Copyright (C) 2009-2014, International Business Machines
* Copyright (C) 2009-2016, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
*/
@ -63,18 +63,45 @@ static void ulist_addFirstItem(UList *list, UListNode *newItem) {
newItem->previous = NULL;
list->head = newItem;
list->tail = newItem;
}
static void ulist_removeItem(UList *list, UListNode *p) {
if (p->previous == NULL) {
// p is the list head.
list->head = p->next;
} else {
p->previous->next = p->next;
}
if (p->next == NULL) {
// p is the list tail.
list->tail = p->previous;
} else {
p->next->previous = p->previous;
}
list->curr = NULL;
list->currentIndex = 0;
--list->size;
if (p->forceDelete) {
uprv_free(p->data);
}
uprv_free(p);
}
U_CAPI void U_EXPORT2 ulist_addItemEndList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
UListNode *newItem = NULL;
if (U_FAILURE(*status) || list == NULL || data == NULL) {
if (forceDelete) {
uprv_free((void *)data);
}
return;
}
newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
if (newItem == NULL) {
if (forceDelete) {
uprv_free((void *)data);
}
*status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@ -97,11 +124,17 @@ U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBoo
UListNode *newItem = NULL;
if (U_FAILURE(*status) || list == NULL || data == NULL) {
if (forceDelete) {
uprv_free((void *)data);
}
return;
}
newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
if (newItem == NULL) {
if (forceDelete) {
uprv_free((void *)data);
}
*status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@ -122,25 +155,29 @@ U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBoo
}
U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data, int32_t length) {
UBool result = FALSE;
const UListNode *pointer = NULL;
if (list != NULL && list->size != 0) {
pointer = list->head;
while (pointer != NULL) {
if (list != NULL) {
for (const UListNode *pointer = list->head; pointer != NULL; pointer = pointer->next) {
if (length == uprv_strlen(pointer->data)) {
if (uprv_memcmp(data, pointer->data, length) == 0) {
result = TRUE;
break;
return TRUE;
}
}
pointer = pointer->next;
}
}
return result;
return FALSE;
}
U_CAPI UBool U_EXPORT2 ulist_removeString(UList *list, const char *data) {
if (list != NULL) {
for (UListNode *pointer = list->head; pointer != NULL; pointer = pointer->next) {
if (uprv_strcmp(data, pointer->data) == 0) {
ulist_removeItem(list, pointer);
// Remove only the first occurrence, like Java LinkedList.remove(Object).
return TRUE;
}
}
}
return FALSE;
}
U_CAPI void *U_EXPORT2 ulist_getNext(UList *list) {

View file

@ -1,6 +1,6 @@
/*
******************************************************************************
* Copyright (C) 2009, International Business Machines
* Copyright (C) 2009-2016, International Business Machines
* Corporation and others. All Rights Reserved.
******************************************************************************
*/
@ -22,6 +22,8 @@ U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBoo
U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data, int32_t length);
U_CAPI UBool U_EXPORT2 ulist_removeString(UList *list, const char *data);
U_CAPI void *U_EXPORT2 ulist_getNext(UList *list);
U_CAPI int32_t U_EXPORT2 ulist_getListSize(const UList *list);

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1996-2014, International Business Machines
* Copyright (C) 1996-2016, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: ucol_res.cpp
@ -34,11 +34,13 @@
#include "unicode/uloc.h"
#include "unicode/unistr.h"
#include "unicode/ures.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "collationdatareader.h"
#include "collationroot.h"
#include "collationtailoring.h"
#include "resource.h"
#include "putilimp.h"
#include "uassert.h"
#include "ucln_in.h"
@ -501,8 +503,6 @@ U_CAPI UCollator*
ucol_open(const char *loc,
UErrorCode *status)
{
U_NAMESPACE_USE
UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
UCollator *result = NULL;
@ -523,8 +523,6 @@ ucol_getDisplayName( const char *objLoc,
int32_t resultLength,
UErrorCode *status)
{
U_NAMESPACE_USE
if(U_FAILURE(*status)) return -1;
UnicodeString dst;
if(!(result==NULL && resultLength==0)) {
@ -558,8 +556,6 @@ ucol_countAvailable()
#if !UCONFIG_NO_SERVICE
U_CAPI UEnumeration* U_EXPORT2
ucol_openAvailableLocales(UErrorCode *status) {
U_NAMESPACE_USE
// This is a wrapper over Collator::getAvailableLocales()
if (U_FAILURE(*status)) {
return NULL;
@ -615,119 +611,75 @@ static const UEnumeration defaultKeywordValues = {
ulist_reset_keyword_values_iterator
};
#include <stdio.h>
namespace {
struct KeywordsSink : public ResourceSink {
public:
KeywordsSink(UErrorCode &errorCode) :
values(ulist_createEmptyList(&errorCode)), hasDefault(FALSE) {}
virtual ~KeywordsSink();
virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
ResourceTable collations = value.getTable(errorCode);
for (int32_t i = 0; collations.getKeyAndValue(i, key, value); ++i) {
UResType type = value.getType();
if (type == URES_STRING) {
if (!hasDefault && uprv_strcmp(key, "default") == 0) {
CharString defcoll;
defcoll.appendInvariantChars(value.getUnicodeString(errorCode), errorCode);
if (U_SUCCESS(errorCode) && !defcoll.isEmpty()) {
char *ownedDefault = uprv_strdup(defcoll.data());
if (ownedDefault == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return;
}
ulist_removeString(values, defcoll.data());
ulist_addItemBeginList(values, ownedDefault, TRUE, &errorCode);
hasDefault = TRUE;
}
}
} else if (type == URES_TABLE && uprv_strncmp(key, "private-", 8) != 0) {
if (!ulist_containsString(values, key, (int32_t)uprv_strlen(key))) {
ulist_addItemEndList(values, key, FALSE, &errorCode);
}
}
if (U_FAILURE(errorCode)) { return; }
}
}
UList *values;
UBool hasDefault;
};
KeywordsSink::~KeywordsSink() {
ulist_deleteList(values);
}
} // namespace
U_CAPI UEnumeration* U_EXPORT2
ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
UBool /*commonlyUsed*/, UErrorCode* status) {
/* Get the locale base name. */
char localeBuffer[ULOC_FULLNAME_CAPACITY] = "";
uloc_getBaseName(locale, localeBuffer, sizeof(localeBuffer), status);
// Note: The parameter commonlyUsed is not used.
// The switch is in the method signature for consistency
// with other locale services.
// Read available collation values from collation bundles.
LocalUResourceBundlePointer bundle(ures_open(U_ICUDATA_COLL, locale, status));
KeywordsSink sink(*status);
ures_getAllItemsWithFallback(bundle.getAlias(), RESOURCE_NAME, sink, *status);
if (U_FAILURE(*status)) { return NULL; }
/* Create the 2 lists
* -values is the temp location for the keyword values
* -results hold the actual list used by the UEnumeration object
*/
UList *values = ulist_createEmptyList(status);
UList *results = ulist_createEmptyList(status);
UEnumeration *en = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
if (U_FAILURE(*status) || en == NULL) {
if (en == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
} else {
uprv_free(en);
}
ulist_deleteList(values);
ulist_deleteList(results);
if (en == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
en->context = results;
/* Open the resource bundle for collation with the given locale. */
UResourceBundle bundle, collations, collres, defres;
ures_initStackObject(&bundle);
ures_initStackObject(&collations);
ures_initStackObject(&collres);
ures_initStackObject(&defres);
ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
while (U_SUCCESS(*status)) {
ures_getByKey(&bundle, RESOURCE_NAME, &collations, status);
ures_resetIterator(&collations);
while (U_SUCCESS(*status) && ures_hasNext(&collations)) {
ures_getNextResource(&collations, &collres, status);
const char *key = ures_getKey(&collres);
/* If the key is default, get the string and store it in results list only
* if results list is empty.
*/
if (uprv_strcmp(key, "default") == 0) {
if (ulist_getListSize(results) == 0) {
char *defcoll = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
int32_t defcollLength = ULOC_KEYWORDS_CAPACITY;
ures_getNextResource(&collres, &defres, status);
#if U_CHARSET_FAMILY==U_ASCII_FAMILY
/* optimize - use the utf-8 string */
ures_getUTF8String(&defres, defcoll, &defcollLength, TRUE, status);
#else
{
const UChar* defString = ures_getString(&defres, &defcollLength, status);
if(U_SUCCESS(*status)) {
if(defcollLength+1 > ULOC_KEYWORDS_CAPACITY) {
*status = U_BUFFER_OVERFLOW_ERROR;
} else {
u_UCharsToChars(defString, defcoll, defcollLength+1);
}
}
}
#endif
ulist_addItemBeginList(results, defcoll, TRUE, status);
}
} else if (uprv_strncmp(key, "private-", 8) != 0) {
ulist_addItemEndList(values, key, FALSE, status);
}
}
/* If the locale is "" this is root so exit. */
if (uprv_strlen(localeBuffer) == 0) {
break;
}
/* Get the parent locale and open a new resource bundle. */
uloc_getParent(localeBuffer, localeBuffer, sizeof(localeBuffer), status);
ures_openFillIn(&bundle, U_ICUDATA_COLL, localeBuffer, status);
}
ures_close(&defres);
ures_close(&collres);
ures_close(&collations);
ures_close(&bundle);
if (U_SUCCESS(*status)) {
char *value = NULL;
ulist_resetList(values);
while ((value = (char *)ulist_getNext(values)) != NULL) {
if (!ulist_containsString(results, value, (int32_t)uprv_strlen(value))) {
ulist_addItemEndList(results, value, FALSE, status);
if (U_FAILURE(*status)) {
break;
}
}
}
}
ulist_deleteList(values);
if (U_FAILURE(*status)){
uenum_close(en);
en = NULL;
} else {
ulist_resetList(results);
}
en->context = sink.values;
sink.values = NULL; // Avoid deletion in the sink destructor.
return en;
}