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
19U_NAMESPACE_USE
20
21
22namespace BPrivate {
23namespace Libroot {
24
25
26extern "C" LocaleBackend*
27CreateInstance()
28{
29	return new(std::nothrow) ICULocaleBackend();
30}
31
32
33extern "C" void
34DestroyInstance(LocaleBackend* instance)
35{
36	delete instance;
37}
38
39
40ICULocaleBackend::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
54ICULocaleBackend::~ICULocaleBackend()
55{
56	pthread_key_delete(fThreadLocalStorageKey);
57}
58
59
60void
61ICULocaleBackend::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
78const char*
79ICULocaleBackend::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
134const struct lconv*
135ICULocaleBackend::LocaleConv()
136{
137	return &fLocaleConv;
138}
139
140
141const struct lc_time_t*
142ICULocaleBackend::LCTimeInfo()
143{
144	return &fLCTimeInfo;
145}
146
147
148int
149ICULocaleBackend::IsWCType(wint_t wc, wctype_t charClass)
150{
151	ErrnoMaintainer errnoMaintainer;
152
153	return fCtypeData.IsWCType(wc, charClass);
154}
155
156
157status_t
158ICULocaleBackend::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
166status_t
167ICULocaleBackend::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
176status_t
177ICULocaleBackend::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
188status_t
189ICULocaleBackend::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
198status_t
199ICULocaleBackend::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
210const char*
211ICULocaleBackend::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
289status_t
290ICULocaleBackend::Strcoll(const char* a, const char* b, int& result)
291{
292	ErrnoMaintainer errnoMaintainer;
293
294	return fCollateData.Strcoll(a, b, result);
295}
296
297
298status_t
299ICULocaleBackend::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
308status_t
309ICULocaleBackend::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
317status_t
318ICULocaleBackend::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
327status_t
328ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz)
329{
330	ErrnoMaintainer errnoMaintainer;
331
332	return fTimeConversion.TZSet(timeZoneID, tz);
333}
334
335
336status_t
337ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut)
338{
339	ErrnoMaintainer errnoMaintainer;
340
341	return fTimeConversion.Localtime(inTime, tmOut);
342}
343
344
345status_t
346ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut)
347{
348	ErrnoMaintainer errnoMaintainer;
349
350	return fTimeConversion.Gmtime(inTime, tmOut);
351}
352
353
354status_t
355ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut)
356{
357	ErrnoMaintainer errnoMaintainer;
358
359	return fTimeConversion.Mktime(inOutTm, timeOut);
360}
361
362
363status_t
364ICULocaleBackend::Timegm(struct tm* inOutTm, time_t& timeOut)
365{
366	ErrnoMaintainer errnoMaintainer;
367
368	return fTimeConversion.Timegm(inOutTm, timeOut);
369}
370
371
372const char*
373ICULocaleBackend::_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
416const char*
417ICULocaleBackend::_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
462pthread_key_t
463ICULocaleBackend::_CreateThreadLocalStorageKey()
464{
465	pthread_key_t key;
466
467	pthread_key_create(&key, ICULocaleBackend::_DestroyThreadLocalStorageValue);
468
469	return key;
470}
471
472
473void
474ICULocaleBackend::_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