| /* |
| ******************************************************************************* |
| * |
| * Copyright (C) 2012, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * |
| ******************************************************************************* |
| * file name: listformatter.cpp |
| * encoding: US-ASCII |
| * tab size: 8 (not used) |
| * indentation:4 |
| * |
| * created on: 2012aug27 |
| * created by: Umesh P. Nair |
| */ |
| |
| #include "unicode/listformatter.h" |
| #include "mutex.h" |
| #include "hash.h" |
| #include "cstring.h" |
| #include "ulocimp.h" |
| #include "charstr.h" |
| #include "ucln_cmn.h" |
| #include "uresimp.h" |
| |
| U_NAMESPACE_BEGIN |
| |
| static Hashtable* listPatternHash = NULL; |
| static UMutex listFormatterMutex = U_MUTEX_INITIALIZER; |
| static UChar FIRST_PARAMETER[] = { 0x7b, 0x30, 0x7d }; // "{0}" |
| static UChar SECOND_PARAMETER[] = { 0x7b, 0x31, 0x7d }; // "{0}" |
| |
| U_CDECL_BEGIN |
| static UBool U_CALLCONV uprv_listformatter_cleanup() { |
| delete listPatternHash; |
| listPatternHash = NULL; |
| return TRUE; |
| } |
| |
| static void U_CALLCONV |
| uprv_deleteListFormatData(void *obj) { |
| delete static_cast<ListFormatData *>(obj); |
| } |
| |
| U_CDECL_END |
| |
| static ListFormatData* loadListFormatData(const Locale& locale, UErrorCode& errorCode); |
| static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode); |
| |
| void ListFormatter::initializeHash(UErrorCode& errorCode) { |
| if (U_FAILURE(errorCode)) { |
| return; |
| } |
| |
| listPatternHash = new Hashtable(); |
| if (listPatternHash == NULL) { |
| errorCode = U_MEMORY_ALLOCATION_ERROR; |
| return; |
| } |
| |
| listPatternHash->setValueDeleter(uprv_deleteListFormatData); |
| ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER, uprv_listformatter_cleanup); |
| |
| } |
| |
| const ListFormatData* ListFormatter::getListFormatData( |
| const Locale& locale, UErrorCode& errorCode) { |
| if (U_FAILURE(errorCode)) { |
| return NULL; |
| } |
| UnicodeString key(locale.getName(), -1, US_INV); |
| ListFormatData* result = NULL; |
| { |
| Mutex m(&listFormatterMutex); |
| if (listPatternHash == NULL) { |
| initializeHash(errorCode); |
| if (U_FAILURE(errorCode)) { |
| return NULL; |
| } |
| } |
| result = static_cast<ListFormatData*>(listPatternHash->get(key)); |
| } |
| if (result != NULL) { |
| return result; |
| } |
| result = loadListFormatData(locale, errorCode); |
| if (U_FAILURE(errorCode)) { |
| return NULL; |
| } |
| |
| { |
| Mutex m(&listFormatterMutex); |
| ListFormatData* temp = static_cast<ListFormatData*>(listPatternHash->get(key)); |
| if (temp != NULL) { |
| delete result; |
| result = temp; |
| } else { |
| listPatternHash->put(key, result, errorCode); |
| if (U_FAILURE(errorCode)) { |
| return NULL; |
| } |
| } |
| } |
| return result; |
| } |
| |
| static ListFormatData* loadListFormatData(const Locale& locale, UErrorCode& errorCode) { |
| UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode); |
| if (U_FAILURE(errorCode)) { |
| ures_close(rb); |
| return NULL; |
| } |
| rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode); |
| rb = ures_getByKeyWithFallback(rb, "standard", rb, &errorCode); |
| if (U_FAILURE(errorCode)) { |
| ures_close(rb); |
| return NULL; |
| } |
| UnicodeString two, start, middle, end; |
| getStringByKey(rb, "2", two, errorCode); |
| getStringByKey(rb, "start", start, errorCode); |
| getStringByKey(rb, "middle", middle, errorCode); |
| getStringByKey(rb, "end", end, errorCode); |
| ures_close(rb); |
| if (U_FAILURE(errorCode)) { |
| return NULL; |
| } |
| ListFormatData* result = new ListFormatData(two, start, middle, end); |
| if (result == NULL) { |
| errorCode = U_MEMORY_ALLOCATION_ERROR; |
| return NULL; |
| } |
| return result; |
| } |
| |
| static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode) { |
| int32_t len; |
| const UChar* ustr = ures_getStringByKeyWithFallback(rb, key, &len, &errorCode); |
| if (U_FAILURE(errorCode)) { |
| return; |
| } |
| result.setTo(ustr, len); |
| } |
| |
| ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) { |
| Locale locale; // The default locale. |
| return createInstance(locale, errorCode); |
| } |
| |
| ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) { |
| Locale tempLocale = locale; |
| const ListFormatData* listFormatData = getListFormatData(tempLocale, errorCode); |
| if (U_FAILURE(errorCode)) { |
| return NULL; |
| } |
| ListFormatter* p = new ListFormatter(*listFormatData); |
| if (p == NULL) { |
| errorCode = U_MEMORY_ALLOCATION_ERROR; |
| return NULL; |
| } |
| return p; |
| } |
| |
| ListFormatter::ListFormatter(const ListFormatData& listFormatterData) : data(listFormatterData) { |
| } |
| |
| ListFormatter::~ListFormatter() {} |
| |
| UnicodeString& ListFormatter::format(const UnicodeString items[], int32_t nItems, |
| UnicodeString& appendTo, UErrorCode& errorCode) const { |
| if (U_FAILURE(errorCode)) { |
| return appendTo; |
| } |
| |
| if (nItems > 0) { |
| UnicodeString newString = items[0]; |
| if (nItems == 2) { |
| addNewString(data.twoPattern, newString, items[1], errorCode); |
| } else if (nItems > 2) { |
| addNewString(data.startPattern, newString, items[1], errorCode); |
| int32_t i; |
| for (i = 2; i < nItems - 1; ++i) { |
| addNewString(data.middlePattern, newString, items[i], errorCode); |
| } |
| addNewString(data.endPattern, newString, items[nItems - 1], errorCode); |
| } |
| if (U_SUCCESS(errorCode)) { |
| appendTo += newString; |
| } |
| } |
| return appendTo; |
| } |
| |
| /** |
| * Joins originalString and nextString using the pattern pat and puts the result in |
| * originalString. |
| */ |
| void ListFormatter::addNewString(const UnicodeString& pat, UnicodeString& originalString, |
| const UnicodeString& nextString, UErrorCode& errorCode) const { |
| if (U_FAILURE(errorCode)) { |
| return; |
| } |
| |
| int32_t p0Offset = pat.indexOf(FIRST_PARAMETER, 3, 0); |
| if (p0Offset < 0) { |
| errorCode = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| int32_t p1Offset = pat.indexOf(SECOND_PARAMETER, 3, 0); |
| if (p1Offset < 0) { |
| errorCode = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| |
| int32_t i, j; |
| |
| const UnicodeString* firstString; |
| const UnicodeString* secondString; |
| if (p0Offset < p1Offset) { |
| i = p0Offset; |
| j = p1Offset; |
| firstString = &originalString; |
| secondString = &nextString; |
| } else { |
| i = p1Offset; |
| j = p0Offset; |
| firstString = &nextString; |
| secondString = &originalString; |
| } |
| |
| UnicodeString result = UnicodeString(pat, 0, i) + *firstString; |
| result += UnicodeString(pat, i+3, j-i-3); |
| result += *secondString; |
| result += UnicodeString(pat, j+3); |
| originalString = result; |
| } |
| |
| U_NAMESPACE_END |