2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
7 #include "ICUMonetaryData.h"
19 ICUMonetaryData::ICUMonetaryData(pthread_key_t tlsKey
, struct lconv
& localeConv
)
22 fLocaleConv(localeConv
),
23 fPosixLocaleConv(NULL
)
25 fLocaleConv
.int_curr_symbol
= fIntCurrSymbol
;
26 fLocaleConv
.currency_symbol
= fCurrencySymbol
;
27 fLocaleConv
.mon_decimal_point
= fDecimalPoint
;
28 fLocaleConv
.mon_thousands_sep
= fThousandsSep
;
29 fLocaleConv
.mon_grouping
= fGrouping
;
30 fLocaleConv
.positive_sign
= fPositiveSign
;
31 fLocaleConv
.negative_sign
= fNegativeSign
;
36 ICUMonetaryData::Initialize(LocaleMonetaryDataBridge
* dataBridge
)
38 fPosixLocaleConv
= dataBridge
->posixLocaleConv
;
43 ICUMonetaryData::SetTo(const Locale
& locale
, const char* posixLocaleName
)
45 status_t result
= inherited::SetTo(locale
, posixLocaleName
);
48 UErrorCode icuStatus
= U_ZERO_ERROR
;
49 UChar intlCurrencySeparatorChar
= CHAR_MAX
;
50 DecimalFormat
* currencyFormat
= dynamic_cast<DecimalFormat
*>(
51 NumberFormat::createCurrencyInstance(locale
, icuStatus
));
52 if (!U_SUCCESS(icuStatus
))
57 const DecimalFormatSymbols
* formatSymbols
58 = currencyFormat
->getDecimalFormatSymbols();
63 result
= _SetLocaleconvEntry(formatSymbols
, fDecimalPoint
,
64 DecimalFormatSymbols::kMonetarySeparatorSymbol
);
67 result
= _SetLocaleconvEntry(formatSymbols
, fThousandsSep
,
68 DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol
);
71 int32 groupingSize
= currencyFormat
->getGroupingSize();
75 fGrouping
[0] = groupingSize
;
76 int32 secondaryGroupingSize
77 = currencyFormat
->getSecondaryGroupingSize();
78 if (secondaryGroupingSize
< 1)
81 fGrouping
[1] = secondaryGroupingSize
;
87 fLocaleConv
.int_frac_digits
88 = currencyFormat
->getMinimumFractionDigits();
89 fLocaleConv
.frac_digits
90 = currencyFormat
->getMinimumFractionDigits();
93 UnicodeString positivePrefix
, positiveSuffix
, negativePrefix
,
95 currencyFormat
->getPositivePrefix(positivePrefix
);
96 currencyFormat
->getPositiveSuffix(positiveSuffix
);
97 currencyFormat
->getNegativePrefix(negativePrefix
);
98 currencyFormat
->getNegativeSuffix(negativeSuffix
);
99 UnicodeString currencySymbol
= formatSymbols
->getSymbol(
100 DecimalFormatSymbols::kCurrencySymbol
);
101 UnicodeString plusSymbol
= formatSymbols
->getSymbol(
102 DecimalFormatSymbols::kPlusSignSymbol
);
103 UnicodeString minusSymbol
= formatSymbols
->getSymbol(
104 DecimalFormatSymbols::kMinusSignSymbol
);
106 // fill national values
107 int32 positiveCurrencyFlags
= _DetermineCurrencyPosAndSeparator(
108 positivePrefix
, positiveSuffix
, plusSymbol
, currencySymbol
,
109 intlCurrencySeparatorChar
);
110 fLocaleConv
.p_cs_precedes
111 = (positiveCurrencyFlags
& kCsPrecedesFlag
) ? 1 : 0;
112 fLocaleConv
.p_sep_by_space
113 = (positiveCurrencyFlags
& kSepBySpaceFlag
) ? 1 : 0;
115 int32 negativeCurrencyFlags
= _DetermineCurrencyPosAndSeparator(
116 negativePrefix
, negativeSuffix
, minusSymbol
, currencySymbol
,
117 intlCurrencySeparatorChar
);
118 fLocaleConv
.n_cs_precedes
119 = (negativeCurrencyFlags
& kCsPrecedesFlag
) ? 1 : 0;
120 fLocaleConv
.n_sep_by_space
121 = (negativeCurrencyFlags
& kSepBySpaceFlag
) ? 1 : 0;
123 fLocaleConv
.p_sign_posn
= _DetermineSignPos(positivePrefix
,
124 positiveSuffix
, plusSymbol
, currencySymbol
);
125 fLocaleConv
.n_sign_posn
= _DetermineSignPos(negativePrefix
,
126 negativeSuffix
, minusSymbol
, currencySymbol
);
127 if (fLocaleConv
.p_sign_posn
== CHAR_MAX
) {
128 // usually there is no positive sign indicator, so we
129 // adopt the sign pos of the negative sign symbol
130 fLocaleConv
.p_sign_posn
= fLocaleConv
.n_sign_posn
;
133 // copy national to international values, as ICU does not seem
134 // to have separate info for those
135 fLocaleConv
.int_p_cs_precedes
= fLocaleConv
.p_cs_precedes
;
136 fLocaleConv
.int_p_sep_by_space
= fLocaleConv
.p_sep_by_space
;
137 fLocaleConv
.int_n_cs_precedes
= fLocaleConv
.n_cs_precedes
;
138 fLocaleConv
.int_n_sep_by_space
= fLocaleConv
.n_sep_by_space
;
139 fLocaleConv
.int_p_sign_posn
= fLocaleConv
.p_sign_posn
;
140 fLocaleConv
.int_n_sign_posn
= fLocaleConv
.n_sign_posn
;
142 // only set sign symbols if they are actually used in any pattern
143 if (positivePrefix
.indexOf(plusSymbol
) > -1
144 || positiveSuffix
.indexOf(plusSymbol
) > -1) {
145 result
= _SetLocaleconvEntry(formatSymbols
, fPositiveSign
,
146 DecimalFormatSymbols::kPlusSignSymbol
);
148 fPositiveSign
[0] = '\0';
149 if (negativePrefix
.indexOf(minusSymbol
) > -1
150 || negativeSuffix
.indexOf(minusSymbol
) > -1) {
151 result
= _SetLocaleconvEntry(formatSymbols
, fNegativeSign
,
152 DecimalFormatSymbols::kMinusSignSymbol
);
154 fNegativeSign
[0] = '\0';
156 if (result
== B_OK
) {
157 UnicodeString intlCurrencySymbol
= formatSymbols
->getSymbol(
158 DecimalFormatSymbols::kIntlCurrencySymbol
);
159 if (intlCurrencySeparatorChar
!= CHAR_MAX
)
160 intlCurrencySymbol
+= intlCurrencySeparatorChar
;
162 intlCurrencySymbol
+= ' ';
163 result
= _ConvertUnicodeStringToLocaleconvEntry(intlCurrencySymbol
,
164 fIntCurrSymbol
, skLCBufSize
);
166 if (result
== B_OK
) {
167 result
= _SetLocaleconvEntry(formatSymbols
, fCurrencySymbol
,
168 DecimalFormatSymbols::kCurrencySymbol
);
169 if (fCurrencySymbol
[0] == '\0') {
170 // fall back to the international currency symbol
171 result
= _SetLocaleconvEntry(formatSymbols
, fCurrencySymbol
,
172 DecimalFormatSymbols::kIntlCurrencySymbol
);
173 fCurrencySymbol
[3] = '\0';
174 // drop separator char that's contained in int-curr-symbol
178 delete currencyFormat
;
186 ICUMonetaryData::SetToPosix()
188 status_t result
= inherited::SetToPosix();
190 if (result
== B_OK
) {
191 strcpy(fDecimalPoint
, fPosixLocaleConv
->mon_decimal_point
);
192 strcpy(fThousandsSep
, fPosixLocaleConv
->mon_thousands_sep
);
193 strcpy(fGrouping
, fPosixLocaleConv
->mon_grouping
);
194 strcpy(fCurrencySymbol
, fPosixLocaleConv
->currency_symbol
);
195 strcpy(fIntCurrSymbol
, fPosixLocaleConv
->int_curr_symbol
);
196 strcpy(fPositiveSign
, fPosixLocaleConv
->positive_sign
);
197 strcpy(fNegativeSign
, fPosixLocaleConv
->negative_sign
);
198 fLocaleConv
.int_frac_digits
= fPosixLocaleConv
->int_frac_digits
;
199 fLocaleConv
.frac_digits
= fPosixLocaleConv
->frac_digits
;
200 fLocaleConv
.p_cs_precedes
= fPosixLocaleConv
->p_cs_precedes
;
201 fLocaleConv
.p_sep_by_space
= fPosixLocaleConv
->p_sep_by_space
;
202 fLocaleConv
.n_cs_precedes
= fPosixLocaleConv
->n_cs_precedes
;
203 fLocaleConv
.n_sep_by_space
= fPosixLocaleConv
->n_sep_by_space
;
204 fLocaleConv
.p_sign_posn
= fPosixLocaleConv
->p_sign_posn
;
205 fLocaleConv
.n_sign_posn
= fPosixLocaleConv
->n_sign_posn
;
206 fLocaleConv
.int_p_cs_precedes
= fPosixLocaleConv
->int_p_cs_precedes
;
207 fLocaleConv
.int_p_sep_by_space
= fPosixLocaleConv
->int_p_sep_by_space
;
208 fLocaleConv
.int_n_cs_precedes
= fPosixLocaleConv
->int_n_cs_precedes
;
209 fLocaleConv
.int_n_sep_by_space
= fPosixLocaleConv
->int_n_sep_by_space
;
210 fLocaleConv
.int_p_sign_posn
= fPosixLocaleConv
->int_p_sign_posn
;
211 fLocaleConv
.int_n_sign_posn
= fPosixLocaleConv
->int_n_sign_posn
;
219 ICUMonetaryData::GetLanginfo(int index
)
223 return fCurrencySymbol
;
231 ICUMonetaryData::_DetermineCurrencyPosAndSeparator(const UnicodeString
& prefix
,
232 const UnicodeString
& suffix
, const UnicodeString
& signSymbol
,
233 const UnicodeString
& currencySymbol
, UChar
& currencySeparatorChar
)
237 int32 currencySymbolPos
= prefix
.indexOf(currencySymbol
);
238 if (currencySymbolPos
> -1) {
239 result
|= kCsPrecedesFlag
;
240 int32 signSymbolPos
= prefix
.indexOf(signSymbol
);
241 // if a char is following the currency symbol, we assume it's
242 // the separator (usually space), but we need to take care to
243 // skip over the sign symbol, if found
244 int32 potentialSeparatorPos
245 = currencySymbolPos
+ currencySymbol
.length();
246 if (potentialSeparatorPos
== signSymbolPos
)
247 potentialSeparatorPos
++;
248 if (prefix
.charAt(potentialSeparatorPos
) != 0xFFFF) {
249 // We can't use the actual separator char since this is usually
250 // 'c2a0' (non-breakable space), which is not available in the
251 // ASCII charset used/assumed by POSIX lconv. So we use space
253 currencySeparatorChar
= ' ';
254 result
|= kSepBySpaceFlag
;
257 currencySymbolPos
= suffix
.indexOf(currencySymbol
);
258 if (currencySymbolPos
> -1) {
259 int32 signSymbolPos
= suffix
.indexOf(signSymbol
);
260 // if a char is preceding the currency symbol, we assume
261 // it's the separator (usually space), but we need to take
262 // care to skip the sign symbol, if found
263 int32 potentialSeparatorPos
= currencySymbolPos
- 1;
264 if (potentialSeparatorPos
== signSymbolPos
)
265 potentialSeparatorPos
--;
266 if (suffix
.charAt(potentialSeparatorPos
) != 0xFFFF) {
267 // We can't use the actual separator char since this is usually
268 // 'c2a0' (non-breakable space), which is not available in the
269 // ASCII charset used/assumed by POSIX lconv. So we use space
271 currencySeparatorChar
= ' ';
272 result
|= kSepBySpaceFlag
;
282 * This method determines the positive/negative sign position value according to
283 * the following map (where '$' indicated the currency symbol, '#' the number
284 * value, and '-' or parantheses the sign symbol):
295 ICUMonetaryData::_DetermineSignPos(const UnicodeString
& prefix
,
296 const UnicodeString
& suffix
, const UnicodeString
& signSymbol
,
297 const UnicodeString
& currencySymbol
)
299 if (prefix
.indexOf(UnicodeString("(", "")) >= 0
300 && suffix
.indexOf(UnicodeString(")", "")) >= 0)
301 return kParenthesesAroundCurrencyAndValue
;
303 UnicodeString
value("#", "");
304 UnicodeString prefixNumberSuffixString
= prefix
+ value
+ suffix
;
305 int32 signSymbolPos
= prefixNumberSuffixString
.indexOf(signSymbol
);
306 if (signSymbolPos
>= 0) {
307 int32 valuePos
= prefixNumberSuffixString
.indexOf(value
);
308 int32 currencySymbolPos
309 = prefixNumberSuffixString
.indexOf(currencySymbol
);
311 if (signSymbolPos
< valuePos
&& signSymbolPos
< currencySymbolPos
)
312 return kSignPrecedesCurrencyAndValue
;
313 if (signSymbolPos
> valuePos
&& signSymbolPos
> currencySymbolPos
)
314 return kSignSucceedsCurrencyAndValue
;
315 if (signSymbolPos
== currencySymbolPos
- 1)
316 return kSignImmediatelyPrecedesCurrency
;
317 if (signSymbolPos
== currencySymbolPos
+ currencySymbol
.length())
318 return kSignImmediatelySucceedsCurrency
;
325 } // namespace Libroot
326 } // namespace BPrivate