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