1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru********************************************************************************
383a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius*   Copyright (C) 2005-2011, International Business Machines
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru********************************************************************************
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru* File WINNMFMT.CPP
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru********************************************************************************
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*/
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/utypes.h"
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1483a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius#if U_PLATFORM_USES_ONLY_WIN32_API
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "winnmfmt.h"
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/format.h"
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/numfmt.h"
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/locid.h"
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/ustring.h"
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "cmemory.h"
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "uassert.h"
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "locmap.h"
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#   define WIN32_LEAN_AND_MEAN
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#   define VC_EXTRALEAN
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#   define NOUSER
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#   define NOSERVICE
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#   define NOIME
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#   define NOMCX
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <windows.h>
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <stdio.h>
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruunion FormatInfo
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    NUMBERFMTW   number;
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    CURRENCYFMTW currency;
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat)
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define DELETE_ARRAY(array) uprv_free((void *) (array))
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define STACK_BUFFER_SIZE 32
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Turns a string of the form "3;2;0" into the grouping UINT
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * needed for NUMBERFMT and CURRENCYFMT. If the string does not
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * end in ";0" then the return value should be multiplied by 10.
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * (e.g. "3" => 30, "3;2" => 320)
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UINT getGrouping(const char *grouping)
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UINT g = 0;
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	const char *s;
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (s = grouping; *s != '\0'; s += 1) {
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (*s > '0' && *s < '9') {
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            g = g * 10 + (*s - '0');
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (*s != ';') {
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (*s != '0') {
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        g *= 10;
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return g;
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void getNumberFormat(NUMBERFMTW *fmt, int32_t lcid)
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    char buf[10];
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO,  (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoA(lcid, LOCALE_SGROUPING, buf, 10);
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->Grouping = getGrouping(buf);
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->lpDecimalSep = NEW_ARRAY(UChar, 6);
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_SDECIMAL,  fmt->lpDecimalSep,  6);
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->lpThousandSep = NEW_ARRAY(UChar, 6);
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_STHOUSAND, fmt->lpThousandSep, 6);
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void freeNumberFormat(NUMBERFMTW *fmt)
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fmt != NULL) {
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(fmt->lpThousandSep);
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(fmt->lpDecimalSep);
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void getCurrencyFormat(CURRENCYFMTW *fmt, int32_t lcid)
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    char buf[10];
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoA(lcid, LOCALE_SMONGROUPING, buf, sizeof(buf));
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->Grouping = getGrouping(buf);
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->lpDecimalSep = NEW_ARRAY(UChar, 6);
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_SMONDECIMALSEP,  fmt->lpDecimalSep,  6);
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->lpThousandSep = NEW_ARRAY(UChar, 6);
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6);
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR,  (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT));
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fmt->lpCurrencySymbol = NEW_ARRAY(UChar, 8);
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    GetLocaleInfoW(lcid, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8);
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void freeCurrencyFormat(CURRENCYFMTW *fmt)
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fmt != NULL) {
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(fmt->lpCurrencySymbol);
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(fmt->lpThousandSep);
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(fmt->lpDecimalSep);
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// TODO: keep locale too?
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruWin32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status)
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  : NumberFormat(), fCurrency(currency), fFractionDigitsSet(FALSE), fFormatInfo(NULL)
141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!U_FAILURE(status)) {
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        fLCID = locale.getLCID();
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        fFormatInfo = (FormatInfo*)uprv_malloc(sizeof(FormatInfo));
146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (fCurrency) {
148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            getCurrencyFormat(&fFormatInfo->currency, fLCID);
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            getNumberFormat(&fFormatInfo->number, fLCID);
151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruWin32NumberFormat::Win32NumberFormat(const Win32NumberFormat &other)
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru  : NumberFormat(other), fFormatInfo((FormatInfo*)uprv_malloc(sizeof(FormatInfo)))
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fFormatInfo != NULL) {
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        uprv_memset(fFormatInfo, 0, sizeof(*fFormatInfo));
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    *this = other;
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruWin32NumberFormat::~Win32NumberFormat()
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fFormatInfo != NULL) {
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (fCurrency) {
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            freeCurrencyFormat(&fFormatInfo->currency);
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            freeNumberFormat(&fFormatInfo->number);
171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        uprv_free(fFormatInfo);
174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruWin32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    NumberFormat::operator=(other);
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    this->fCurrency          = other.fCurrency;
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    this->fLCID              = other.fLCID;
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    this->fFractionDigitsSet = other.fFractionDigitsSet;
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fCurrency) {
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        freeCurrencyFormat(&fFormatInfo->currency);
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        getCurrencyFormat(&fFormatInfo->currency, fLCID);
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        freeNumberFormat(&fFormatInfo->number);
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        getNumberFormat(&fFormatInfo->number, fLCID);
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return *this;
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruFormat *Win32NumberFormat::clone(void) const
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return new Win32NumberFormat(*this);
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString& Win32NumberFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return format(getMaximumFractionDigits(), appendTo, L"%.16f", number);
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString& Win32NumberFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return format(getMinimumFractionDigits(), appendTo, L"%I32d", number);
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString& Win32NumberFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const
212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return format(getMinimumFractionDigits(), appendTo, L"%I64d", number);
214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// TODO: cache Locale and NumberFormat? Could keep locale passed to constructor...
217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid Win32NumberFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const
218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    Locale loc(uprv_convertToPosix(fLCID, &status));
221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    NumberFormat *nf = fCurrency? NumberFormat::createCurrencyInstance(loc, status) : NumberFormat::createInstance(loc, status);
222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    nf->parse(text, result, parsePosition);
224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    delete nf;
225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid Win32NumberFormat::setMaximumFractionDigits(int32_t newValue)
227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fFractionDigitsSet = TRUE;
229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    NumberFormat::setMaximumFractionDigits(newValue);
230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid Win32NumberFormat::setMinimumFractionDigits(int32_t newValue)
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    fFractionDigitsSet = TRUE;
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    NumberFormat::setMinimumFractionDigits(newValue);
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appendTo, wchar_t *fmt, ...) const
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    wchar_t nStackBuffer[STACK_BUFFER_SIZE];
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    wchar_t *nBuffer = nStackBuffer;
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    va_list args;
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int result;
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    nBuffer[0] = 0x0000;
246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /* Due to the arguments causing a result to be <= 23 characters (+2 for NULL and minus),
248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    we don't need to reallocate the buffer. */
249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    va_start(args, fmt);
250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    result = _vsnwprintf(nBuffer, STACK_BUFFER_SIZE, fmt, args);
251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    va_end(args);
252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /* Just to make sure of the above statement, we add this assert */
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    U_ASSERT(result >=0);
255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // The following code is not used because _vscwprintf isn't available on MinGW at the moment.
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /*if (result < 0) {
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int newLength;
258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        va_start(args, fmt);
260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        newLength = _vscwprintf(fmt, args);
261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        va_end(args);
262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        nBuffer = NEW_ARRAY(UChar, newLength + 1);
264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        va_start(args, fmt);
266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        va_end(args);
268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }*/
269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // vswprintf is sensitive to the locale set by setlocale. For some locales
271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // it doesn't use "." as the decimal separator, which is what GetNumberFormatW
272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // and GetCurrencyFormatW both expect to see.
273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    //
274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // To fix this, we scan over the string and replace the first non-digits, except
275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // for a leading "-", with a "."
276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    //
277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Note: (nBuffer[0] == L'-') will evaluate to 1 if there is a leading '-' in the
278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // number, and 0 otherwise.
279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (wchar_t *p = &nBuffer[nBuffer[0] == L'-']; *p != L'\0'; p += 1) {
280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (*p < L'0' || *p > L'9') {
281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            *p = L'.';
282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UChar stackBuffer[STACK_BUFFER_SIZE];
287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UChar *buffer = stackBuffer;
288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    FormatInfo formatInfo;
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    formatInfo = *fFormatInfo;
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    buffer[0] = 0x0000;
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (fCurrency) {
294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (fFractionDigitsSet) {
295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            formatInfo.currency.NumDigits = (UINT) numDigits;
296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (!isGroupingUsed()) {
299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            formatInfo.currency.Grouping = 0;
300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE);
303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (result == 0) {
305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            DWORD lastError = GetLastError();
306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (lastError == ERROR_INSUFFICIENT_BUFFER) {
308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int newLength = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, NULL, 0);
309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                buffer = NEW_ARRAY(UChar, newLength);
311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                buffer[0] = 0x0000;
312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                GetCurrencyFormatW(fLCID, 0, nBuffer,  &formatInfo.currency, buffer, newLength);
313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (fFractionDigitsSet) {
317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            formatInfo.number.NumDigits = (UINT) numDigits;
318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (!isGroupingUsed()) {
321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            formatInfo.number.Grouping = 0;
322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE);
325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (result == 0) {
327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int newLength = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, NULL, 0);
329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                buffer = NEW_ARRAY(UChar, newLength);
331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                buffer[0] = 0x0000;
332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, newLength);
333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendTo.append(buffer, (int32_t) wcslen(buffer));
338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (buffer != stackBuffer) {
340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(buffer);
341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    /*if (nBuffer != nStackBuffer) {
344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        DELETE_ARRAY(nBuffer);
345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }*/
346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return appendTo;
348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
35483a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius#endif // U_PLATFORM_USES_ONLY_WIN32_API
355