xref: /haiku/src/kits/locale/NumberFormat.cpp (revision e3db3bf84ea4934807e4104d20c3c39aeb8fe1df)
1 /*
2  * Copyright 2003, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
4  * Copyright 2012, John Scipione, jscipione@gmail.com
5  * Copyright 2017, Adrien Destugues, pulkomandy@pulkomandy.tk
6  * All rights reserved. Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include <unicode/uversion.h>
11 #include <NumberFormat.h>
12 
13 #include <AutoDeleter.h>
14 #include <Autolock.h>
15 #include <FormattingConventionsPrivate.h>
16 
17 #include <ICUWrapper.h>
18 
19 #include <unicode/dcfmtsym.h>
20 #include <unicode/decimfmt.h>
21 #include <unicode/numfmt.h>
22 
23 
24 class BNumberFormatImpl {
25 public:
26 					BNumberFormatImpl();
27 					~BNumberFormatImpl();
28 
29 	NumberFormat*	GetInteger(BFormattingConventions* convention);
30 	NumberFormat*	GetFloat(BFormattingConventions* convention);
31 	NumberFormat*	GetCurrency(BFormattingConventions* convention);
32 
33 private:
34 	NumberFormat*	fIntegerFormat;
35 	NumberFormat*	fFloatFormat;
36 	NumberFormat*	fCurrencyFormat;
37 };
38 
39 
40 BNumberFormatImpl::BNumberFormatImpl()
41 {
42 	// They are initialized lazily as needed
43 	fIntegerFormat = NULL;
44 	fFloatFormat = NULL;
45 	fCurrencyFormat = NULL;
46 }
47 
48 
49 BNumberFormatImpl::~BNumberFormatImpl()
50 {
51 	delete fIntegerFormat;
52 	delete fFloatFormat;
53 	delete fCurrencyFormat;
54 }
55 
56 
57 NumberFormat*
58 BNumberFormatImpl::GetInteger(BFormattingConventions* convention)
59 {
60 	if (fIntegerFormat == NULL) {
61 		UErrorCode err = U_ZERO_ERROR;
62 		fIntegerFormat = NumberFormat::createInstance(
63 			*BFormattingConventions::Private(convention).ICULocale(),
64 			UNUM_DECIMAL, err);
65 
66 		if (fIntegerFormat == NULL)
67 			return NULL;
68 		if (U_FAILURE(err)) {
69 			delete fIntegerFormat;
70 			fIntegerFormat = NULL;
71 			return NULL;
72 		}
73 	}
74 
75 	return fIntegerFormat;
76 }
77 
78 
79 NumberFormat*
80 BNumberFormatImpl::GetFloat(BFormattingConventions* convention)
81 {
82 	if (fFloatFormat == NULL) {
83 		UErrorCode err = U_ZERO_ERROR;
84 		fFloatFormat = NumberFormat::createInstance(
85 			*BFormattingConventions::Private(convention).ICULocale(),
86 			UNUM_DECIMAL, err);
87 
88 		if (fFloatFormat == NULL)
89 			return NULL;
90 		if (U_FAILURE(err)) {
91 			delete fFloatFormat;
92 			fFloatFormat = NULL;
93 			return NULL;
94 		}
95 	}
96 
97 	return fFloatFormat;
98 }
99 
100 
101 NumberFormat*
102 BNumberFormatImpl::GetCurrency(BFormattingConventions* convention)
103 {
104 	if (fCurrencyFormat == NULL) {
105 		UErrorCode err = U_ZERO_ERROR;
106 		fCurrencyFormat = NumberFormat::createCurrencyInstance(
107 			*BFormattingConventions::Private(convention).ICULocale(),
108 			err);
109 
110 		if (fCurrencyFormat == NULL)
111 			return NULL;
112 		if (U_FAILURE(err)) {
113 			delete fCurrencyFormat;
114 			fCurrencyFormat = NULL;
115 			return NULL;
116 		}
117 	}
118 
119 	return fCurrencyFormat;
120 }
121 
122 
123 BNumberFormat::BNumberFormat()
124 	: BFormat()
125 {
126 	fPrivateData = new BNumberFormatImpl();
127 }
128 
129 
130 BNumberFormat::BNumberFormat(const BNumberFormat &other)
131 	: BFormat(other)
132 {
133 	fPrivateData = new BNumberFormatImpl(*other.fPrivateData);
134 }
135 
136 
137 BNumberFormat::~BNumberFormat()
138 {
139 	delete fPrivateData;
140 }
141 
142 
143 // #pragma mark - Formatting
144 
145 
146 ssize_t
147 BNumberFormat::Format(char* string, size_t maxSize, const double value)
148 {
149 	BString fullString;
150 	status_t status = Format(fullString, value);
151 	if (status != B_OK)
152 		return status;
153 
154 	return strlcpy(string, fullString.String(), maxSize);
155 }
156 
157 
158 status_t
159 BNumberFormat::Format(BString& string, const double value)
160 {
161 	NumberFormat* formatter = fPrivateData->GetFloat(&fConventions);
162 
163 	if (formatter == NULL)
164 		return B_NO_MEMORY;
165 
166 	UnicodeString icuString;
167 	formatter->format(value, icuString);
168 
169 	string.Truncate(0);
170 	BStringByteSink stringConverter(&string);
171 	icuString.toUTF8(stringConverter);
172 
173 	return B_OK;
174 }
175 
176 
177 ssize_t
178 BNumberFormat::Format(char* string, size_t maxSize, const int32 value)
179 {
180 	BString fullString;
181 	status_t status = Format(fullString, value);
182 	if (status != B_OK)
183 		return status;
184 
185 	return strlcpy(string, fullString.String(), maxSize);
186 }
187 
188 
189 status_t
190 BNumberFormat::Format(BString& string, const int32 value)
191 {
192 	NumberFormat* formatter = fPrivateData->GetInteger(&fConventions);
193 
194 	if (formatter == NULL)
195 		return B_NO_MEMORY;
196 
197 	UnicodeString icuString;
198 	formatter->format((int32_t)value, icuString);
199 
200 	string.Truncate(0);
201 	BStringByteSink stringConverter(&string);
202 	icuString.toUTF8(stringConverter);
203 
204 	return B_OK;
205 }
206 
207 
208 ssize_t
209 BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value)
210 {
211 	BString fullString;
212 	status_t status = FormatMonetary(fullString, value);
213 	if (status != B_OK)
214 		return status;
215 
216 	return strlcpy(string, fullString.String(), maxSize);
217 }
218 
219 
220 status_t
221 BNumberFormat::FormatMonetary(BString& string, const double value)
222 {
223 	NumberFormat* formatter = fPrivateData->GetCurrency(&fConventions);
224 
225 	if (formatter == NULL)
226 		return B_NO_MEMORY;
227 
228 	UnicodeString icuString;
229 	formatter->format(value, icuString);
230 
231 	string.Truncate(0);
232 	BStringByteSink stringConverter(&string);
233 	icuString.toUTF8(stringConverter);
234 
235 	return B_OK;
236 }
237 
238 
239 status_t
240 BNumberFormat::Parse(const BString& string, double& value)
241 {
242 	NumberFormat* parser = fPrivateData->GetFloat(&fConventions);
243 
244 	if (parser == NULL)
245 		return B_NO_MEMORY;
246 
247 	UnicodeString unicode(string.String());
248 	Formattable result(0);
249 	UErrorCode err = U_ZERO_ERROR;
250 
251 	parser->parse(unicode, result, err);
252 
253 	if (err != U_ZERO_ERROR)
254 		return B_BAD_DATA;
255 
256 	value = result.getDouble();
257 
258 	return B_OK;
259 }
260 
261 
262 BString
263 BNumberFormat::GetSeparator(BNumberElement element)
264 {
265 	DecimalFormatSymbols::ENumberFormatSymbol symbol;
266 	BString result;
267 
268 	switch(element) {
269 		case B_DECIMAL_SEPARATOR:
270 			symbol = DecimalFormatSymbols::kDecimalSeparatorSymbol;
271 			break;
272 		case B_GROUPING_SEPARATOR:
273 			symbol = DecimalFormatSymbols::kGroupingSeparatorSymbol;
274 			break;
275 
276 		default:
277 			return result;
278 	}
279 
280 	NumberFormat* format = fPrivateData->GetFloat(&fConventions);
281 	DecimalFormat* decimal = dynamic_cast<DecimalFormat*>(format);
282 
283 	if (decimal == NULL)
284 		return result;
285 
286 	const DecimalFormatSymbols* symbols = decimal->getDecimalFormatSymbols();
287 	UnicodeString string = symbols->getSymbol(symbol);
288 
289 	BStringByteSink stringConverter(&result);
290 	string.toUTF8(stringConverter);
291 
292 	return result;
293 }
294