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