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