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