2 ********************************************************************************
3 * Copyright (C) 2005-2013, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
9 ********************************************************************************
12 #include "unicode/utypes.h"
14 #if U_PLATFORM_USES_ONLY_WIN32_API
16 #if !UCONFIG_NO_FORMATTING
20 #include "unicode/format.h"
21 #include "unicode/numfmt.h"
22 #include "unicode/locid.h"
23 #include "unicode/ustring.h"
29 # define WIN32_LEAN_AND_MEAN
43 CURRENCYFMTW currency
;
46 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat
)
48 #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
49 #define DELETE_ARRAY(array) uprv_free((void *) (array))
51 #define STACK_BUFFER_SIZE 32
54 * Turns a string of the form "3;2;0" into the grouping UINT
55 * needed for NUMBERFMT and CURRENCYFMT. If the string does not
56 * end in ";0" then the return value should be multiplied by 10.
57 * (e.g. "3" => 30, "3;2" => 320)
59 static UINT
getGrouping(const char *grouping
)
64 for (s
= grouping
; *s
!= '\0'; s
+= 1) {
65 if (*s
> '0' && *s
< '9') {
66 g
= g
* 10 + (*s
- '0');
67 } else if (*s
!= ';') {
79 static void getNumberFormat(NUMBERFMTW
*fmt
, int32_t lcid
)
83 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_IDIGITS
, (LPWSTR
) &fmt
->NumDigits
, sizeof(UINT
));
84 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_ILZERO
, (LPWSTR
) &fmt
->LeadingZero
, sizeof(UINT
));
86 GetLocaleInfoA(lcid
, LOCALE_SGROUPING
, buf
, 10);
87 fmt
->Grouping
= getGrouping(buf
);
89 fmt
->lpDecimalSep
= NEW_ARRAY(UChar
, 6);
90 GetLocaleInfoW(lcid
, LOCALE_SDECIMAL
, fmt
->lpDecimalSep
, 6);
92 fmt
->lpThousandSep
= NEW_ARRAY(UChar
, 6);
93 GetLocaleInfoW(lcid
, LOCALE_STHOUSAND
, fmt
->lpThousandSep
, 6);
95 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_INEGNUMBER
, (LPWSTR
) &fmt
->NegativeOrder
, sizeof(UINT
));
98 static void freeNumberFormat(NUMBERFMTW
*fmt
)
101 DELETE_ARRAY(fmt
->lpThousandSep
);
102 DELETE_ARRAY(fmt
->lpDecimalSep
);
106 static void getCurrencyFormat(CURRENCYFMTW
*fmt
, int32_t lcid
)
110 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_ICURRDIGITS
, (LPWSTR
) &fmt
->NumDigits
, sizeof(UINT
));
111 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_ILZERO
, (LPWSTR
) &fmt
->LeadingZero
, sizeof(UINT
));
113 GetLocaleInfoA(lcid
, LOCALE_SMONGROUPING
, buf
, sizeof(buf
));
114 fmt
->Grouping
= getGrouping(buf
);
116 fmt
->lpDecimalSep
= NEW_ARRAY(UChar
, 6);
117 GetLocaleInfoW(lcid
, LOCALE_SMONDECIMALSEP
, fmt
->lpDecimalSep
, 6);
119 fmt
->lpThousandSep
= NEW_ARRAY(UChar
, 6);
120 GetLocaleInfoW(lcid
, LOCALE_SMONTHOUSANDSEP
, fmt
->lpThousandSep
, 6);
122 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_INEGCURR
, (LPWSTR
) &fmt
->NegativeOrder
, sizeof(UINT
));
123 GetLocaleInfoW(lcid
, LOCALE_RETURN_NUMBER
|LOCALE_ICURRENCY
, (LPWSTR
) &fmt
->PositiveOrder
, sizeof(UINT
));
125 fmt
->lpCurrencySymbol
= NEW_ARRAY(UChar
, 8);
126 GetLocaleInfoW(lcid
, LOCALE_SCURRENCY
, (LPWSTR
) fmt
->lpCurrencySymbol
, 8);
129 static void freeCurrencyFormat(CURRENCYFMTW
*fmt
)
132 DELETE_ARRAY(fmt
->lpCurrencySymbol
);
133 DELETE_ARRAY(fmt
->lpThousandSep
);
134 DELETE_ARRAY(fmt
->lpDecimalSep
);
138 Win32NumberFormat::Win32NumberFormat(const Locale
&locale
, UBool currency
, UErrorCode
&status
)
139 : NumberFormat(), fCurrency(currency
), fFractionDigitsSet(FALSE
), fFormatInfo(NULL
)
141 if (!U_FAILURE(status
)) {
142 fLCID
= locale
.getLCID();
144 // Resolve actual locale to be used later
145 UErrorCode tmpsts
= U_ZERO_ERROR
;
146 char tmpLocID
[ULOC_FULLNAME_CAPACITY
];
147 int32_t len
= uloc_getLocaleForLCID(fLCID
, tmpLocID
, sizeof(tmpLocID
)/sizeof(tmpLocID
[0]) - 1, &tmpsts
);
148 if (U_SUCCESS(tmpsts
)) {
150 fLocale
= Locale((const char*)tmpLocID
);
153 fFormatInfo
= (FormatInfo
*)uprv_malloc(sizeof(FormatInfo
));
156 getCurrencyFormat(&fFormatInfo
->currency
, fLCID
);
158 getNumberFormat(&fFormatInfo
->number
, fLCID
);
163 Win32NumberFormat::Win32NumberFormat(const Win32NumberFormat
&other
)
164 : NumberFormat(other
), fFormatInfo((FormatInfo
*)uprv_malloc(sizeof(FormatInfo
)))
166 if (fFormatInfo
!= NULL
) {
167 uprv_memset(fFormatInfo
, 0, sizeof(*fFormatInfo
));
172 Win32NumberFormat::~Win32NumberFormat()
174 if (fFormatInfo
!= NULL
) {
176 freeCurrencyFormat(&fFormatInfo
->currency
);
178 freeNumberFormat(&fFormatInfo
->number
);
181 uprv_free(fFormatInfo
);
185 Win32NumberFormat
&Win32NumberFormat::operator=(const Win32NumberFormat
&other
)
187 NumberFormat::operator=(other
);
189 this->fCurrency
= other
.fCurrency
;
190 this->fLocale
= other
.fLocale
;
191 this->fLCID
= other
.fLCID
;
192 this->fFractionDigitsSet
= other
.fFractionDigitsSet
;
195 freeCurrencyFormat(&fFormatInfo
->currency
);
196 getCurrencyFormat(&fFormatInfo
->currency
, fLCID
);
198 freeNumberFormat(&fFormatInfo
->number
);
199 getNumberFormat(&fFormatInfo
->number
, fLCID
);
205 Format
*Win32NumberFormat::clone(void) const
207 return new Win32NumberFormat(*this);
210 UnicodeString
& Win32NumberFormat::format(double number
, UnicodeString
& appendTo
, FieldPosition
& pos
) const
212 return format(getMaximumFractionDigits(), appendTo
, L
"%.16f", number
);
215 UnicodeString
& Win32NumberFormat::format(int32_t number
, UnicodeString
& appendTo
, FieldPosition
& pos
) const
217 return format(getMinimumFractionDigits(), appendTo
, L
"%I32d", number
);
220 UnicodeString
& Win32NumberFormat::format(int64_t number
, UnicodeString
& appendTo
, FieldPosition
& pos
) const
222 return format(getMinimumFractionDigits(), appendTo
, L
"%I64d", number
);
225 void Win32NumberFormat::parse(const UnicodeString
& text
, Formattable
& result
, ParsePosition
& parsePosition
) const
227 UErrorCode status
= U_ZERO_ERROR
;
228 NumberFormat
*nf
= fCurrency
? NumberFormat::createCurrencyInstance(fLocale
, status
) : NumberFormat::createInstance(fLocale
, status
);
230 nf
->parse(text
, result
, parsePosition
);
233 void Win32NumberFormat::setMaximumFractionDigits(int32_t newValue
)
235 fFractionDigitsSet
= TRUE
;
236 NumberFormat::setMaximumFractionDigits(newValue
);
239 void Win32NumberFormat::setMinimumFractionDigits(int32_t newValue
)
241 fFractionDigitsSet
= TRUE
;
242 NumberFormat::setMinimumFractionDigits(newValue
);
245 UnicodeString
&Win32NumberFormat::format(int32_t numDigits
, UnicodeString
&appendTo
, wchar_t *fmt
, ...) const
247 wchar_t nStackBuffer
[STACK_BUFFER_SIZE
];
248 wchar_t *nBuffer
= nStackBuffer
;
254 /* Due to the arguments causing a result to be <= 23 characters (+2 for NULL and minus),
255 we don't need to reallocate the buffer. */
257 result
= _vsnwprintf(nBuffer
, STACK_BUFFER_SIZE
, fmt
, args
);
260 /* Just to make sure of the above statement, we add this assert */
261 U_ASSERT(result
>=0);
262 // The following code is not used because _vscwprintf isn't available on MinGW at the moment.
267 newLength = _vscwprintf(fmt, args);
270 nBuffer = NEW_ARRAY(UChar, newLength + 1);
273 result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
277 // vswprintf is sensitive to the locale set by setlocale. For some locales
278 // it doesn't use "." as the decimal separator, which is what GetNumberFormatW
279 // and GetCurrencyFormatW both expect to see.
281 // To fix this, we scan over the string and replace the first non-digits, except
282 // for a leading "-", with a "."
284 // Note: (nBuffer[0] == L'-') will evaluate to 1 if there is a leading '-' in the
285 // number, and 0 otherwise.
286 for (wchar_t *p
= &nBuffer
[nBuffer
[0] == L
'-']; *p
!= L
'\0'; p
+= 1) {
287 if (*p
< L
'0' || *p
> L
'9') {
293 UChar stackBuffer
[STACK_BUFFER_SIZE
];
294 UChar
*buffer
= stackBuffer
;
295 FormatInfo formatInfo
;
297 formatInfo
= *fFormatInfo
;
301 if (fFractionDigitsSet
) {
302 formatInfo
.currency
.NumDigits
= (UINT
) numDigits
;
305 if (!isGroupingUsed()) {
306 formatInfo
.currency
.Grouping
= 0;
309 result
= GetCurrencyFormatW(fLCID
, 0, nBuffer
, &formatInfo
.currency
, buffer
, STACK_BUFFER_SIZE
);
312 DWORD lastError
= GetLastError();
314 if (lastError
== ERROR_INSUFFICIENT_BUFFER
) {
315 int newLength
= GetCurrencyFormatW(fLCID
, 0, nBuffer
, &formatInfo
.currency
, NULL
, 0);
317 buffer
= NEW_ARRAY(UChar
, newLength
);
319 GetCurrencyFormatW(fLCID
, 0, nBuffer
, &formatInfo
.currency
, buffer
, newLength
);
323 if (fFractionDigitsSet
) {
324 formatInfo
.number
.NumDigits
= (UINT
) numDigits
;
327 if (!isGroupingUsed()) {
328 formatInfo
.number
.Grouping
= 0;
331 result
= GetNumberFormatW(fLCID
, 0, nBuffer
, &formatInfo
.number
, buffer
, STACK_BUFFER_SIZE
);
334 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
335 int newLength
= GetNumberFormatW(fLCID
, 0, nBuffer
, &formatInfo
.number
, NULL
, 0);
337 buffer
= NEW_ARRAY(UChar
, newLength
);
339 GetNumberFormatW(fLCID
, 0, nBuffer
, &formatInfo
.number
, buffer
, newLength
);
344 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
346 if (buffer
!= stackBuffer
) {
347 DELETE_ARRAY(buffer
);
350 /*if (nBuffer != nStackBuffer) {
351 DELETE_ARRAY(nBuffer);
359 #endif /* #if !UCONFIG_NO_FORMATTING */
361 #endif // U_PLATFORM_USES_ONLY_WIN32_API