xref: /haiku/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*
2  * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ICULocaleBackend.h"
8 
9 #include <new>
10 
11 #include <langinfo.h>
12 #include <locale.h>
13 #include <string.h>
14 #include <strings.h>
15 
16 #include <ErrnoMaintainer.h>
17 
18 
19 U_NAMESPACE_USE
20 
21 
22 namespace BPrivate {
23 namespace Libroot {
24 
25 
26 extern "C" LocaleBackend*
27 CreateInstance()
28 {
29 	return new(std::nothrow) ICULocaleBackend();
30 }
31 
32 
33 extern "C" void
34 DestroyInstance(LocaleBackend* instance)
35 {
36 	delete instance;
37 }
38 
39 
40 ICULocaleBackend::ICULocaleBackend()
41 	:
42 	fThreadLocalStorageKey(_CreateThreadLocalStorageKey()),
43 	fCollateData(fThreadLocalStorageKey),
44 	fCtypeData(fThreadLocalStorageKey),
45 	fMessagesData(fThreadLocalStorageKey),
46 	fMonetaryData(fThreadLocalStorageKey, fLocaleConv),
47 	fNumericData(fThreadLocalStorageKey, fLocaleConv),
48 	fTimeData(fThreadLocalStorageKey, fLCTimeInfo, fMessagesData),
49 	fTimeConversion(fTimeData)
50 {
51 }
52 
53 
54 ICULocaleBackend::~ICULocaleBackend()
55 {
56 	pthread_key_delete(fThreadLocalStorageKey);
57 }
58 
59 
60 void
61 ICULocaleBackend::Initialize(LocaleDataBridge* dataBridge)
62 {
63 	ErrnoMaintainer errnoMaintainer;
64 
65 	fCtypeData.Initialize(&dataBridge->ctypeDataBridge);
66 	fMessagesData.Initialize(&dataBridge->messagesDataBridge);
67 	fMonetaryData.Initialize(&dataBridge->monetaryDataBridge);
68 	fNumericData.Initialize(&dataBridge->numericDataBridge);
69 	fTimeData.Initialize(&dataBridge->timeDataBridge);
70 	fTimeConversion.Initialize(&dataBridge->timeConversionDataBridge);
71 
72 	fPosixLanginfo = dataBridge->posixLanginfo;
73 
74 	_SetPosixLocale(LC_ALL);
75 }
76 
77 
78 const char*
79 ICULocaleBackend::SetLocale(int category, const char* posixLocaleName)
80 {
81 	ErrnoMaintainer errnoMaintainer;
82 
83 	if (posixLocaleName == NULL)
84 		return _QueryLocale(category);
85 
86 	if (strcasecmp(posixLocaleName, "POSIX") == 0
87 		|| strcasecmp(posixLocaleName, "C") == 0)
88 		return _SetPosixLocale(category);
89 
90 	Locale locale = Locale::createCanonical(posixLocaleName);
91 	switch (category) {
92 		case LC_ALL:
93 			if (fCollateData.SetTo(locale, posixLocaleName) != B_OK
94 				|| fCtypeData.SetTo(locale, posixLocaleName) != B_OK
95 				|| fMessagesData.SetTo(locale, posixLocaleName) != B_OK
96 				|| fMonetaryData.SetTo(locale, posixLocaleName) != B_OK
97 				|| fNumericData.SetTo(locale, posixLocaleName) != B_OK
98 				|| fTimeData.SetTo(locale, posixLocaleName) != B_OK)
99 				return NULL;
100 			break;
101 		case LC_COLLATE:
102 			if (fCollateData.SetTo(locale, posixLocaleName) != B_OK)
103 				return NULL;
104 			break;
105 		case LC_CTYPE:
106 			if (fCtypeData.SetTo(locale, posixLocaleName) != B_OK)
107 				return NULL;
108 			break;
109 		case LC_MESSAGES:
110 			if (fMessagesData.SetTo(locale, posixLocaleName) != B_OK)
111 				return NULL;
112 			break;
113 		case LC_MONETARY:
114 			if (fMonetaryData.SetTo(locale, posixLocaleName) != B_OK)
115 				return NULL;
116 			break;
117 		case LC_NUMERIC:
118 			if (fNumericData.SetTo(locale, posixLocaleName) != B_OK)
119 				return NULL;
120 			break;
121 		case LC_TIME:
122 			if (fTimeData.SetTo(locale, posixLocaleName) != B_OK)
123 				return NULL;
124 			break;
125 		default:
126 			// unsupported category
127 			return NULL;
128 	}
129 
130 	return posixLocaleName;
131 }
132 
133 
134 const struct lconv*
135 ICULocaleBackend::LocaleConv()
136 {
137 	return &fLocaleConv;
138 }
139 
140 
141 const struct lc_time_t*
142 ICULocaleBackend::LCTimeInfo()
143 {
144 	return &fLCTimeInfo;
145 }
146 
147 
148 int
149 ICULocaleBackend::IsWCType(wint_t wc, wctype_t charClass)
150 {
151 	ErrnoMaintainer errnoMaintainer;
152 
153 	return fCtypeData.IsWCType(wc, charClass);
154 }
155 
156 
157 status_t
158 ICULocaleBackend::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result)
159 {
160 	ErrnoMaintainer errnoMaintainer;
161 
162 	return fCtypeData.ToWCTrans(wc, transition, result);
163 }
164 
165 
166 status_t
167 ICULocaleBackend::MultibyteToWchar(wchar_t* wcOut, const char* mb,
168 	size_t mbLength, mbstate_t* mbState, size_t& lengthOut)
169 {
170 	ErrnoMaintainer errnoMaintainer;
171 
172 	return fCtypeData.MultibyteToWchar(wcOut, mb, mbLength, mbState, lengthOut);
173 }
174 
175 
176 status_t
177 ICULocaleBackend::MultibyteStringToWchar(wchar_t* wcDest, size_t wcDestLength,
178 	const char** mbSource, size_t mbSourceLength, mbstate_t* mbState,
179 	size_t& lengthOut)
180 {
181 	ErrnoMaintainer errnoMaintainer;
182 
183 	return fCtypeData.MultibyteStringToWchar(wcDest, wcDestLength, mbSource,
184 		mbSourceLength, mbState, lengthOut);
185 }
186 
187 
188 status_t
189 ICULocaleBackend::WcharToMultibyte(char* mbOut, wchar_t wc, mbstate_t* mbState,
190 	size_t& lengthOut)
191 {
192 	ErrnoMaintainer errnoMaintainer;
193 
194 	return fCtypeData.WcharToMultibyte(mbOut, wc, mbState, lengthOut);
195 }
196 
197 
198 status_t
199 ICULocaleBackend::WcharStringToMultibyte(char* mbDest, size_t mbDestLength,
200 	const wchar_t** wcSource, size_t wcSourceLength, mbstate_t* mbState,
201 	size_t& lengthOut)
202 {
203 	ErrnoMaintainer errnoMaintainer;
204 
205 	return fCtypeData.WcharStringToMultibyte(mbDest, mbDestLength, wcSource,
206 		wcSourceLength, mbState, lengthOut);
207 }
208 
209 
210 const char*
211 ICULocaleBackend::GetLanginfo(int index)
212 {
213 	ErrnoMaintainer errnoMaintainer;
214 
215 	switch(index) {
216 		case CODESET:
217 			return fCtypeData.GetLanginfo(index);
218 
219 		case D_T_FMT:
220 		case D_FMT:
221 		case T_FMT:
222 		case T_FMT_AMPM:
223 		case AM_STR:
224 		case PM_STR:
225 		case DAY_1:
226 		case DAY_2:
227 		case DAY_3:
228 		case DAY_4:
229 		case DAY_5:
230 		case DAY_6:
231 		case DAY_7:
232 		case ABDAY_1:
233 		case ABDAY_2:
234 		case ABDAY_3:
235 		case ABDAY_4:
236 		case ABDAY_5:
237 		case ABDAY_6:
238 		case ABDAY_7:
239 		case MON_1:
240 		case MON_2:
241 		case MON_3:
242 		case MON_4:
243 		case MON_5:
244 		case MON_6:
245 		case MON_7:
246 		case MON_8:
247 		case MON_9:
248 		case MON_10:
249 		case MON_11:
250 		case MON_12:
251 		case ABMON_1:
252 		case ABMON_2:
253 		case ABMON_3:
254 		case ABMON_4:
255 		case ABMON_5:
256 		case ABMON_6:
257 		case ABMON_7:
258 		case ABMON_8:
259 		case ABMON_9:
260 		case ABMON_10:
261 		case ABMON_11:
262 		case ABMON_12:
263 			return fTimeData.GetLanginfo(index);
264 
265 		case ERA:
266 		case ERA_D_FMT:
267 		case ERA_D_T_FMT:
268 		case ERA_T_FMT:
269 		case ALT_DIGITS:
270 			return fPosixLanginfo[index];
271 
272 		case RADIXCHAR:
273 		case THOUSEP:
274 			return fNumericData.GetLanginfo(index);
275 
276 		case YESEXPR:
277 		case NOEXPR:
278 			return fMessagesData.GetLanginfo(index);
279 
280 		case CRNCYSTR:
281 			return fMonetaryData.GetLanginfo(index);
282 
283 		default:
284 			return "";
285 	}
286 }
287 
288 
289 status_t
290 ICULocaleBackend::Strcoll(const char* a, const char* b, int& result)
291 {
292 	ErrnoMaintainer errnoMaintainer;
293 
294 	return fCollateData.Strcoll(a, b, result);
295 }
296 
297 
298 status_t
299 ICULocaleBackend::Strxfrm(char* out, const char* in,
300 	size_t outSize, size_t& requiredSize)
301 {
302 	ErrnoMaintainer errnoMaintainer;
303 
304 	return fCollateData.Strxfrm(out, in, outSize, requiredSize);
305 }
306 
307 
308 status_t
309 ICULocaleBackend::Wcscoll(const wchar_t* a, const wchar_t* b, int& result)
310 {
311 	ErrnoMaintainer errnoMaintainer;
312 
313 	return fCollateData.Wcscoll(a, b, result);
314 }
315 
316 
317 status_t
318 ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t outSize,
319 	size_t& requiredSize)
320 {
321 	ErrnoMaintainer errnoMaintainer;
322 
323 	return fCollateData.Wcsxfrm(out, in, outSize, requiredSize);
324 }
325 
326 
327 status_t
328 ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz)
329 {
330 	ErrnoMaintainer errnoMaintainer;
331 
332 	return fTimeConversion.TZSet(timeZoneID, tz);
333 }
334 
335 
336 status_t
337 ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut)
338 {
339 	ErrnoMaintainer errnoMaintainer;
340 
341 	return fTimeConversion.Localtime(inTime, tmOut);
342 }
343 
344 
345 status_t
346 ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut)
347 {
348 	ErrnoMaintainer errnoMaintainer;
349 
350 	return fTimeConversion.Gmtime(inTime, tmOut);
351 }
352 
353 
354 status_t
355 ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut)
356 {
357 	ErrnoMaintainer errnoMaintainer;
358 
359 	return fTimeConversion.Mktime(inOutTm, timeOut);
360 }
361 
362 
363 status_t
364 ICULocaleBackend::Timegm(struct tm* inOutTm, time_t& timeOut)
365 {
366 	ErrnoMaintainer errnoMaintainer;
367 
368 	return fTimeConversion.Timegm(inOutTm, timeOut);
369 }
370 
371 
372 const char*
373 ICULocaleBackend::_QueryLocale(int category)
374 {
375 	switch (category) {
376 		case LC_ALL:
377 		{
378 			// if all categories have the same locale, return that
379 			const char* locale = fCollateData.PosixLocaleName();
380 			if (strcmp(locale, fCtypeData.PosixLocaleName()) == 0
381 				&& strcmp(locale, fMessagesData.PosixLocaleName()) == 0
382 				&& strcmp(locale, fMonetaryData.PosixLocaleName()) == 0
383 				&& strcmp(locale, fNumericData.PosixLocaleName()) == 0
384 				&& strcmp(locale, fTimeData.PosixLocaleName()) == 0)
385 				return locale;
386 
387 			// build a string with all info (at least glibc does it, too)
388 			snprintf(fLocaleDescription, sizeof(fLocaleDescription),
389 				"LC_COLLATE=%s;LC_CTYPE=%s;LC_MESSAGES=%s;LC_MONETARY=%s;"
390 				"LC_NUMERIC=%s;LC_TIME=%s",
391 				fCollateData.PosixLocaleName(), fCtypeData.PosixLocaleName(),
392 				fMessagesData.PosixLocaleName(),
393 				fMonetaryData.PosixLocaleName(), fNumericData.PosixLocaleName(),
394 				fTimeData.PosixLocaleName());
395 			return fLocaleDescription;
396 		}
397 		case LC_COLLATE:
398 			return fCollateData.PosixLocaleName();
399 		case LC_CTYPE:
400 			return fCtypeData.PosixLocaleName();
401 		case LC_MESSAGES:
402 			return fMessagesData.PosixLocaleName();
403 		case LC_MONETARY:
404 			return fMonetaryData.PosixLocaleName();
405 		case LC_NUMERIC:
406 			return fNumericData.PosixLocaleName();
407 		case LC_TIME:
408 			return fTimeData.PosixLocaleName();
409 		default:
410 			// unsupported category
411 			return NULL;
412 	}
413 }
414 
415 
416 const char*
417 ICULocaleBackend::_SetPosixLocale(int category)
418 {
419 	switch (category) {
420 		case LC_ALL:
421 			if (fCollateData.SetToPosix() != B_OK
422 				|| fCtypeData.SetToPosix() != B_OK
423 				|| fMessagesData.SetToPosix() != B_OK
424 				|| fMonetaryData.SetToPosix() != B_OK
425 				|| fNumericData.SetToPosix() != B_OK
426 				|| fTimeData.SetToPosix() != B_OK)
427 				return NULL;
428 			break;
429 		case LC_COLLATE:
430 			if (fCollateData.SetToPosix() != B_OK)
431 				return NULL;
432 			break;
433 		case LC_CTYPE:
434 			if (fCtypeData.SetToPosix() != B_OK)
435 				return NULL;
436 			break;
437 		case LC_MESSAGES:
438 			if (fMessagesData.SetToPosix() != B_OK)
439 				return NULL;
440 			break;
441 		case LC_MONETARY:
442 			if (fMonetaryData.SetToPosix() != B_OK)
443 				return NULL;
444 			break;
445 		case LC_NUMERIC:
446 			if (fNumericData.SetToPosix() != B_OK)
447 				return NULL;
448 			break;
449 		case LC_TIME:
450 			if (fTimeData.SetToPosix() != B_OK)
451 				return NULL;
452 			break;
453 		default:
454 			// unsupported category
455 			return NULL;
456 	}
457 
458 	return "POSIX";
459 }
460 
461 
462 pthread_key_t
463 ICULocaleBackend::_CreateThreadLocalStorageKey()
464 {
465 	pthread_key_t key;
466 
467 	pthread_key_create(&key, ICULocaleBackend::_DestroyThreadLocalStorageValue);
468 
469 	return key;
470 }
471 
472 
473 void
474 ICULocaleBackend::_DestroyThreadLocalStorageValue(void* value)
475 {
476 	ICUThreadLocalStorageValue* tlsValue
477 		= static_cast<ICUThreadLocalStorageValue*>(value);
478 
479 	delete tlsValue;
480 }
481 
482 
483 }	// namespace Libroot
484 }	// namespace BPrivate
485