2 *******************************************************************************
4 * Copyright (C) 2012, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: listformatter.cpp
10 * tab size: 8 (not used)
13 * created on: 2012aug27
14 * created by: Umesh P. Nair
17 #include "unicode/listformatter.h"
28 static Hashtable
* listPatternHash
= NULL
;
29 static UMutex listFormatterMutex
= U_MUTEX_INITIALIZER
;
30 static UChar FIRST_PARAMETER
[] = { 0x7b, 0x30, 0x7d }; // "{0}"
31 static UChar SECOND_PARAMETER
[] = { 0x7b, 0x31, 0x7d }; // "{0}"
34 static UBool U_CALLCONV
uprv_listformatter_cleanup() {
35 delete listPatternHash
;
36 listPatternHash
= NULL
;
40 static void U_CALLCONV
41 uprv_deleteListFormatData(void *obj
) {
42 delete static_cast<ListFormatData
*>(obj
);
47 static ListFormatData
* loadListFormatData(const Locale
& locale
, UErrorCode
& errorCode
);
48 static void getStringByKey(const UResourceBundle
* rb
, const char* key
, UnicodeString
& result
, UErrorCode
& errorCode
);
50 void ListFormatter::initializeHash(UErrorCode
& errorCode
) {
51 if (U_FAILURE(errorCode
)) {
55 listPatternHash
= new Hashtable();
56 if (listPatternHash
== NULL
) {
57 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
61 listPatternHash
->setValueDeleter(uprv_deleteListFormatData
);
62 ucln_common_registerCleanup(UCLN_COMMON_LIST_FORMATTER
, uprv_listformatter_cleanup
);
66 const ListFormatData
* ListFormatter::getListFormatData(
67 const Locale
& locale
, UErrorCode
& errorCode
) {
68 if (U_FAILURE(errorCode
)) {
71 UnicodeString
key(locale
.getName(), -1, US_INV
);
72 ListFormatData
* result
= NULL
;
74 Mutex
m(&listFormatterMutex
);
75 if (listPatternHash
== NULL
) {
76 initializeHash(errorCode
);
77 if (U_FAILURE(errorCode
)) {
81 result
= static_cast<ListFormatData
*>(listPatternHash
->get(key
));
86 result
= loadListFormatData(locale
, errorCode
);
87 if (U_FAILURE(errorCode
)) {
92 Mutex
m(&listFormatterMutex
);
93 ListFormatData
* temp
= static_cast<ListFormatData
*>(listPatternHash
->get(key
));
98 listPatternHash
->put(key
, result
, errorCode
);
99 if (U_FAILURE(errorCode
)) {
107 static ListFormatData
* loadListFormatData(const Locale
& locale
, UErrorCode
& errorCode
) {
108 UResourceBundle
* rb
= ures_open(NULL
, locale
.getName(), &errorCode
);
109 if (U_FAILURE(errorCode
)) {
113 rb
= ures_getByKeyWithFallback(rb
, "listPattern", rb
, &errorCode
);
114 rb
= ures_getByKeyWithFallback(rb
, "standard", rb
, &errorCode
);
115 if (U_FAILURE(errorCode
)) {
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
);
125 if (U_FAILURE(errorCode
)) {
128 ListFormatData
* result
= new ListFormatData(two
, start
, middle
, end
);
129 if (result
== NULL
) {
130 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
136 static void getStringByKey(const UResourceBundle
* rb
, const char* key
, UnicodeString
& result
, UErrorCode
& errorCode
) {
138 const UChar
* ustr
= ures_getStringByKeyWithFallback(rb
, key
, &len
, &errorCode
);
139 if (U_FAILURE(errorCode
)) {
142 result
.setTo(ustr
, len
);
145 ListFormatter
* ListFormatter::createInstance(UErrorCode
& errorCode
) {
146 Locale locale
; // The default locale.
147 return createInstance(locale
, errorCode
);
150 ListFormatter
* ListFormatter::createInstance(const Locale
& locale
, UErrorCode
& errorCode
) {
151 Locale tempLocale
= locale
;
152 const ListFormatData
* listFormatData
= getListFormatData(tempLocale
, errorCode
);
153 if (U_FAILURE(errorCode
)) {
156 ListFormatter
* p
= new ListFormatter(*listFormatData
);
158 errorCode
= U_MEMORY_ALLOCATION_ERROR
;
164 ListFormatter::ListFormatter(const ListFormatData
& listFormatterData
) : data(listFormatterData
) {
167 ListFormatter::~ListFormatter() {}
169 UnicodeString
& ListFormatter::format(const UnicodeString items
[], int32_t nItems
,
170 UnicodeString
& appendTo
, UErrorCode
& errorCode
) const {
171 if (U_FAILURE(errorCode
)) {
176 UnicodeString newString
= items
[0];
178 addNewString(data
.twoPattern
, newString
, items
[1], errorCode
);
179 } else if (nItems
> 2) {
180 addNewString(data
.startPattern
, newString
, items
[1], errorCode
);
182 for (i
= 2; i
< nItems
- 1; ++i
) {
183 addNewString(data
.middlePattern
, newString
, items
[i
], errorCode
);
185 addNewString(data
.endPattern
, newString
, items
[nItems
- 1], errorCode
);
187 if (U_SUCCESS(errorCode
)) {
188 appendTo
+= newString
;
195 * Joins originalString and nextString using the pattern pat and puts the result in
198 void ListFormatter::addNewString(const UnicodeString
& pat
, UnicodeString
& originalString
,
199 const UnicodeString
& nextString
, UErrorCode
& errorCode
) const {
200 if (U_FAILURE(errorCode
)) {
204 int32_t p0Offset
= pat
.indexOf(FIRST_PARAMETER
, 3, 0);
206 errorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
209 int32_t p1Offset
= pat
.indexOf(SECOND_PARAMETER
, 3, 0);
211 errorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
217 const UnicodeString
* firstString
;
218 const UnicodeString
* secondString
;
219 if (p0Offset
< p1Offset
) {
222 firstString
= &originalString
;
223 secondString
= &nextString
;
227 firstString
= &nextString
;
228 secondString
= &originalString
;
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
;