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