intl/icu/source/common/listformatter.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 2013, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 *******************************************************************************
michael@0 8 * file name: listformatter.cpp
michael@0 9 * encoding: US-ASCII
michael@0 10 * tab size: 8 (not used)
michael@0 11 * indentation:4
michael@0 12 *
michael@0 13 * created on: 2012aug27
michael@0 14 * created by: Umesh P. Nair
michael@0 15 */
michael@0 16
michael@0 17 #include "unicode/listformatter.h"
michael@0 18 #include "mutex.h"
michael@0 19 #include "hash.h"
michael@0 20 #include "cstring.h"
michael@0 21 #include "ulocimp.h"
michael@0 22 #include "charstr.h"
michael@0 23 #include "ucln_cmn.h"
michael@0 24 #include "uresimp.h"
michael@0 25
michael@0 26 U_NAMESPACE_BEGIN
michael@0 27
michael@0 28 static Hashtable* listPatternHash = NULL;
michael@0 29 static UMutex listFormatterMutex = U_MUTEX_INITIALIZER;
michael@0 30 static UChar FIRST_PARAMETER[] = { 0x7b, 0x30, 0x7d }; // "{0}"
michael@0 31 static UChar SECOND_PARAMETER[] = { 0x7b, 0x31, 0x7d }; // "{0}"
michael@0 32 static const char *STANDARD_STYLE = "standard";
michael@0 33
michael@0 34 U_CDECL_BEGIN
michael@0 35 static UBool U_CALLCONV uprv_listformatter_cleanup() {
michael@0 36 delete listPatternHash;
michael@0 37 listPatternHash = NULL;
michael@0 38 return TRUE;
michael@0 39 }
michael@0 40
michael@0 41 static void U_CALLCONV
michael@0 42 uprv_deleteListFormatData(void *obj) {
michael@0 43 delete static_cast<ListFormatData *>(obj);
michael@0 44 }
michael@0 45
michael@0 46 U_CDECL_END
michael@0 47
michael@0 48 static ListFormatData* loadListFormatData(const Locale& locale, const char* style, UErrorCode& errorCode);
michael@0 49 static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode);
michael@0 50
michael@0 51 ListFormatter::ListFormatter(const ListFormatter& other) : data(other.data) {
michael@0 52 }
michael@0 53
michael@0 54 ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
michael@0 55 data = other.data;
michael@0 56 return *this;
michael@0 57 }
michael@0 58
michael@0 59 void ListFormatter::initializeHash(UErrorCode& errorCode) {
michael@0 60 if (U_FAILURE(errorCode)) {
michael@0 61 return;
michael@0 62 }
michael@0 63
michael@0 64 listPatternHash = new Hashtable();
michael@0 65 if (listPatternHash == NULL) {
michael@0 66 errorCode = U_MEMORY_ALLOCATION_ERROR;
michael@0 67 return;
michael@0 68 }
michael@0 69
michael@0 70 listPatternHash->setValueDeleter(uprv_deleteListFormatData);
michael@0 71 ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER, uprv_listformatter_cleanup);
michael@0 72
michael@0 73 }
michael@0 74
michael@0 75 const ListFormatData* ListFormatter::getListFormatData(
michael@0 76 const Locale& locale, const char *style, UErrorCode& errorCode) {
michael@0 77 if (U_FAILURE(errorCode)) {
michael@0 78 return NULL;
michael@0 79 }
michael@0 80 CharString keyBuffer(locale.getName(), errorCode);
michael@0 81 keyBuffer.append(':', errorCode).append(style, errorCode);
michael@0 82 UnicodeString key(keyBuffer.data(), -1, US_INV);
michael@0 83 ListFormatData* result = NULL;
michael@0 84 {
michael@0 85 Mutex m(&listFormatterMutex);
michael@0 86 if (listPatternHash == NULL) {
michael@0 87 initializeHash(errorCode);
michael@0 88 if (U_FAILURE(errorCode)) {
michael@0 89 return NULL;
michael@0 90 }
michael@0 91 }
michael@0 92 result = static_cast<ListFormatData*>(listPatternHash->get(key));
michael@0 93 }
michael@0 94 if (result != NULL) {
michael@0 95 return result;
michael@0 96 }
michael@0 97 result = loadListFormatData(locale, style, errorCode);
michael@0 98 if (U_FAILURE(errorCode)) {
michael@0 99 return NULL;
michael@0 100 }
michael@0 101
michael@0 102 {
michael@0 103 Mutex m(&listFormatterMutex);
michael@0 104 ListFormatData* temp = static_cast<ListFormatData*>(listPatternHash->get(key));
michael@0 105 if (temp != NULL) {
michael@0 106 delete result;
michael@0 107 result = temp;
michael@0 108 } else {
michael@0 109 listPatternHash->put(key, result, errorCode);
michael@0 110 if (U_FAILURE(errorCode)) {
michael@0 111 return NULL;
michael@0 112 }
michael@0 113 }
michael@0 114 }
michael@0 115 return result;
michael@0 116 }
michael@0 117
michael@0 118 static ListFormatData* loadListFormatData(
michael@0 119 const Locale& locale, const char * style, UErrorCode& errorCode) {
michael@0 120 UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode);
michael@0 121 if (U_FAILURE(errorCode)) {
michael@0 122 ures_close(rb);
michael@0 123 return NULL;
michael@0 124 }
michael@0 125 rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
michael@0 126 rb = ures_getByKeyWithFallback(rb, style, rb, &errorCode);
michael@0 127
michael@0 128 // TODO(Travis Keep): This is a hack until fallbacks can be added for
michael@0 129 // listPattern/duration and listPattern/duration-narrow in CLDR.
michael@0 130 if (errorCode == U_MISSING_RESOURCE_ERROR) {
michael@0 131 errorCode = U_ZERO_ERROR;
michael@0 132 rb = ures_getByKeyWithFallback(rb, "standard", rb, &errorCode);
michael@0 133 }
michael@0 134 if (U_FAILURE(errorCode)) {
michael@0 135 ures_close(rb);
michael@0 136 return NULL;
michael@0 137 }
michael@0 138 UnicodeString two, start, middle, end;
michael@0 139 getStringByKey(rb, "2", two, errorCode);
michael@0 140 getStringByKey(rb, "start", start, errorCode);
michael@0 141 getStringByKey(rb, "middle", middle, errorCode);
michael@0 142 getStringByKey(rb, "end", end, errorCode);
michael@0 143 ures_close(rb);
michael@0 144 if (U_FAILURE(errorCode)) {
michael@0 145 return NULL;
michael@0 146 }
michael@0 147 ListFormatData* result = new ListFormatData(two, start, middle, end);
michael@0 148 if (result == NULL) {
michael@0 149 errorCode = U_MEMORY_ALLOCATION_ERROR;
michael@0 150 return NULL;
michael@0 151 }
michael@0 152 return result;
michael@0 153 }
michael@0 154
michael@0 155 static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode) {
michael@0 156 int32_t len;
michael@0 157 const UChar* ustr = ures_getStringByKeyWithFallback(rb, key, &len, &errorCode);
michael@0 158 if (U_FAILURE(errorCode)) {
michael@0 159 return;
michael@0 160 }
michael@0 161 result.setTo(ustr, len);
michael@0 162 }
michael@0 163
michael@0 164 ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
michael@0 165 Locale locale; // The default locale.
michael@0 166 return createInstance(locale, errorCode);
michael@0 167 }
michael@0 168
michael@0 169 ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
michael@0 170 return createInstance(locale, STANDARD_STYLE, errorCode);
michael@0 171 }
michael@0 172
michael@0 173 ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
michael@0 174 Locale tempLocale = locale;
michael@0 175 const ListFormatData* listFormatData = getListFormatData(tempLocale, style, errorCode);
michael@0 176 if (U_FAILURE(errorCode)) {
michael@0 177 return NULL;
michael@0 178 }
michael@0 179 ListFormatter* p = new ListFormatter(listFormatData);
michael@0 180 if (p == NULL) {
michael@0 181 errorCode = U_MEMORY_ALLOCATION_ERROR;
michael@0 182 return NULL;
michael@0 183 }
michael@0 184 return p;
michael@0 185 }
michael@0 186
michael@0 187
michael@0 188 ListFormatter::ListFormatter(const ListFormatData* listFormatterData) : data(listFormatterData) {
michael@0 189 }
michael@0 190
michael@0 191 ListFormatter::~ListFormatter() {}
michael@0 192
michael@0 193 UnicodeString& ListFormatter::format(const UnicodeString items[], int32_t nItems,
michael@0 194 UnicodeString& appendTo, UErrorCode& errorCode) const {
michael@0 195 if (U_FAILURE(errorCode)) {
michael@0 196 return appendTo;
michael@0 197 }
michael@0 198 if (data == NULL) {
michael@0 199 errorCode = U_INVALID_STATE_ERROR;
michael@0 200 return appendTo;
michael@0 201 }
michael@0 202
michael@0 203 if (nItems > 0) {
michael@0 204 UnicodeString newString = items[0];
michael@0 205 if (nItems == 2) {
michael@0 206 addNewString(data->twoPattern, newString, items[1], errorCode);
michael@0 207 } else if (nItems > 2) {
michael@0 208 addNewString(data->startPattern, newString, items[1], errorCode);
michael@0 209 int32_t i;
michael@0 210 for (i = 2; i < nItems - 1; ++i) {
michael@0 211 addNewString(data->middlePattern, newString, items[i], errorCode);
michael@0 212 }
michael@0 213 addNewString(data->endPattern, newString, items[nItems - 1], errorCode);
michael@0 214 }
michael@0 215 if (U_SUCCESS(errorCode)) {
michael@0 216 appendTo += newString;
michael@0 217 }
michael@0 218 }
michael@0 219 return appendTo;
michael@0 220 }
michael@0 221
michael@0 222 /**
michael@0 223 * Joins originalString and nextString using the pattern pat and puts the result in
michael@0 224 * originalString.
michael@0 225 */
michael@0 226 void ListFormatter::addNewString(const UnicodeString& pat, UnicodeString& originalString,
michael@0 227 const UnicodeString& nextString, UErrorCode& errorCode) const {
michael@0 228 if (U_FAILURE(errorCode)) {
michael@0 229 return;
michael@0 230 }
michael@0 231
michael@0 232 int32_t p0Offset = pat.indexOf(FIRST_PARAMETER, 3, 0);
michael@0 233 if (p0Offset < 0) {
michael@0 234 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 235 return;
michael@0 236 }
michael@0 237 int32_t p1Offset = pat.indexOf(SECOND_PARAMETER, 3, 0);
michael@0 238 if (p1Offset < 0) {
michael@0 239 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 240 return;
michael@0 241 }
michael@0 242
michael@0 243 int32_t i, j;
michael@0 244
michael@0 245 const UnicodeString* firstString;
michael@0 246 const UnicodeString* secondString;
michael@0 247 if (p0Offset < p1Offset) {
michael@0 248 i = p0Offset;
michael@0 249 j = p1Offset;
michael@0 250 firstString = &originalString;
michael@0 251 secondString = &nextString;
michael@0 252 } else {
michael@0 253 i = p1Offset;
michael@0 254 j = p0Offset;
michael@0 255 firstString = &nextString;
michael@0 256 secondString = &originalString;
michael@0 257 }
michael@0 258
michael@0 259 UnicodeString result = UnicodeString(pat, 0, i) + *firstString;
michael@0 260 result += UnicodeString(pat, i+3, j-i-3);
michael@0 261 result += *secondString;
michael@0 262 result += UnicodeString(pat, j+3);
michael@0 263 originalString = result;
michael@0 264 }
michael@0 265
michael@0 266 U_NAMESPACE_END

mercurial