xref: /haiku/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp (revision a906d0a031e721e2f2ec9d95274103e74a3a774f)
1 /*
2  * Copyright 2010, 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 	fMonetaryData(fLocaleConv),
32 	fNumericData(fLocaleConv),
33 	fTimeData(fLCTimeInfo),
34 	fTimeConversion(fTimeData)
35 {
36 }
37 
38 
39 ICULocaleBackend::~ICULocaleBackend()
40 {
41 }
42 
43 
44 void
45 ICULocaleBackend::Initialize(LocaleDataBridge* dataBridge)
46 {
47 	ErrnoMaintainer errnoMaintainer;
48 
49 	fCtypeData.Initialize(&dataBridge->ctypeDataBridge);
50 	fMessagesData.Initialize(&dataBridge->messagesDataBridge);
51 	fMonetaryData.Initialize(&dataBridge->monetaryDataBridge);
52 	fNumericData.Initialize(&dataBridge->numericDataBridge);
53 	fTimeData.Initialize(&dataBridge->timeDataBridge);
54 	fTimeConversion.Initialize(&dataBridge->timeConversionDataBridge);
55 
56 	fPosixLanginfo = dataBridge->posixLanginfo;
57 
58 	_SetPosixLocale(LC_ALL);
59 }
60 
61 
62 const char*
63 ICULocaleBackend::SetLocale(int category, const char* posixLocaleName)
64 {
65 	ErrnoMaintainer errnoMaintainer;
66 
67 	if (posixLocaleName == NULL)
68 		return _QueryLocale(category);
69 
70 	if (strcasecmp(posixLocaleName, "POSIX") == 0
71 		|| strcasecmp(posixLocaleName, "C") == 0)
72 		return _SetPosixLocale(category);
73 
74 	Locale locale = Locale::createCanonical(posixLocaleName);
75 	switch (category) {
76 		case LC_ALL:
77 			if (fCollateData.SetTo(locale, posixLocaleName) != B_OK
78 				|| fCtypeData.SetTo(locale, posixLocaleName) != B_OK
79 				|| fMessagesData.SetTo(locale, posixLocaleName) != B_OK
80 				|| fMonetaryData.SetTo(locale, posixLocaleName) != B_OK
81 				|| fNumericData.SetTo(locale, posixLocaleName) != B_OK
82 				|| fTimeData.SetTo(locale, posixLocaleName) != B_OK)
83 				return NULL;
84 			break;
85 		case LC_COLLATE:
86 			if (fCollateData.SetTo(locale, posixLocaleName) != B_OK)
87 				return NULL;
88 			break;
89 		case LC_CTYPE:
90 			if (fCtypeData.SetTo(locale, posixLocaleName) != B_OK)
91 				return NULL;
92 			break;
93 		case LC_MESSAGES:
94 			if (fMessagesData.SetTo(locale, posixLocaleName) != B_OK)
95 				return NULL;
96 			break;
97 		case LC_MONETARY:
98 			if (fMonetaryData.SetTo(locale, posixLocaleName) != B_OK)
99 				return NULL;
100 			break;
101 		case LC_NUMERIC:
102 			if (fNumericData.SetTo(locale, posixLocaleName) != B_OK)
103 				return NULL;
104 			break;
105 		case LC_TIME:
106 			if (fTimeData.SetTo(locale, posixLocaleName) != B_OK)
107 				return NULL;
108 			break;
109 		default:
110 			// unsupported category
111 			return NULL;
112 	}
113 
114 	return posixLocaleName;
115 }
116 
117 
118 const struct lconv*
119 ICULocaleBackend::LocaleConv()
120 {
121 	return &fLocaleConv;
122 }
123 
124 
125 const struct lc_time_t*
126 ICULocaleBackend::LCTimeInfo()
127 {
128 	return &fLCTimeInfo;
129 }
130 
131 
132 int
133 ICULocaleBackend::IsWCType(wint_t wc, wctype_t charClass)
134 {
135 	ErrnoMaintainer errnoMaintainer;
136 
137 	return fCtypeData.IsWCType(wc, charClass);
138 }
139 
140 
141 status_t
142 ICULocaleBackend::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result)
143 {
144 	ErrnoMaintainer errnoMaintainer;
145 
146 	return fCtypeData.ToWCTrans(wc, transition, result);
147 }
148 
149 
150 const char*
151 ICULocaleBackend::GetLanginfo(int index)
152 {
153 	ErrnoMaintainer errnoMaintainer;
154 
155 	switch(index) {
156 		case CODESET:
157 			return fCtypeData.GetLanginfo(index);
158 
159 		case D_T_FMT:
160 		case D_FMT:
161 		case T_FMT:
162 		case T_FMT_AMPM:
163 		case AM_STR:
164 		case PM_STR:
165 		case DAY_1:
166 		case DAY_2:
167 		case DAY_3:
168 		case DAY_4:
169 		case DAY_5:
170 		case DAY_6:
171 		case DAY_7:
172 		case ABDAY_1:
173 		case ABDAY_2:
174 		case ABDAY_3:
175 		case ABDAY_4:
176 		case ABDAY_5:
177 		case ABDAY_6:
178 		case ABDAY_7:
179 		case MON_1:
180 		case MON_2:
181 		case MON_3:
182 		case MON_4:
183 		case MON_5:
184 		case MON_6:
185 		case MON_7:
186 		case MON_8:
187 		case MON_9:
188 		case MON_10:
189 		case MON_11:
190 		case MON_12:
191 		case ABMON_1:
192 		case ABMON_2:
193 		case ABMON_3:
194 		case ABMON_4:
195 		case ABMON_5:
196 		case ABMON_6:
197 		case ABMON_7:
198 		case ABMON_8:
199 		case ABMON_9:
200 		case ABMON_10:
201 		case ABMON_11:
202 		case ABMON_12:
203 			return fTimeData.GetLanginfo(index);
204 
205 		case ERA:
206 		case ERA_D_FMT:
207 		case ERA_D_T_FMT:
208 		case ERA_T_FMT:
209 		case ALT_DIGITS:
210 			return fPosixLanginfo[index];
211 
212 		case RADIXCHAR:
213 		case THOUSEP:
214 			return fNumericData.GetLanginfo(index);
215 
216 		case YESEXPR:
217 		case NOEXPR:
218 			return fMessagesData.GetLanginfo(index);
219 
220 		case CRNCYSTR:
221 			return fMonetaryData.GetLanginfo(index);
222 
223 		default:
224 			return "";
225 	}
226 }
227 
228 
229 status_t
230 ICULocaleBackend::Strcoll(const char* a, const char* b, int& result)
231 {
232 	ErrnoMaintainer errnoMaintainer;
233 
234 	return fCollateData.Strcoll(a, b, result);
235 }
236 
237 
238 status_t
239 ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size,
240 	size_t& outSize)
241 {
242 	ErrnoMaintainer errnoMaintainer;
243 
244 	return fCollateData.Strxfrm(out, in, size, outSize);
245 }
246 
247 
248 status_t
249 ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz)
250 {
251 	ErrnoMaintainer errnoMaintainer;
252 
253 	return fTimeConversion.TZSet(timeZoneID, tz);
254 }
255 
256 
257 status_t
258 ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut)
259 {
260 	ErrnoMaintainer errnoMaintainer;
261 
262 	return fTimeConversion.Localtime(inTime, tmOut);
263 }
264 
265 
266 status_t
267 ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut)
268 {
269 	ErrnoMaintainer errnoMaintainer;
270 
271 	return fTimeConversion.Gmtime(inTime, tmOut);
272 }
273 
274 
275 status_t
276 ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut)
277 {
278 	ErrnoMaintainer errnoMaintainer;
279 
280 	return fTimeConversion.Mktime(inOutTm, timeOut);
281 }
282 
283 
284 const char*
285 ICULocaleBackend::_QueryLocale(int category)
286 {
287 	switch (category) {
288 		case LC_ALL:
289 		{
290 			// if all categories have the same locale, return that
291 			const char* locale = fCollateData.PosixLocaleName();
292 			if (strcmp(locale, fCtypeData.PosixLocaleName()) == 0
293 				&& strcmp(locale, fMessagesData.PosixLocaleName()) == 0
294 				&& strcmp(locale, fMonetaryData.PosixLocaleName()) == 0
295 				&& strcmp(locale, fNumericData.PosixLocaleName()) == 0
296 				&& strcmp(locale, fTimeData.PosixLocaleName()) == 0)
297 				return locale;
298 
299 			// build a string with all info (at least glibc does it, too)
300 			snprintf(fLocaleDescription, sizeof(fLocaleDescription),
301 				"LC_COLLATE=%s;LC_CTYPE=%s;LC_MESSAGES=%s;LC_MONETARY=%s;"
302 				"LC_NUMERIC=%s;LC_TIME=%s",
303 				fCollateData.PosixLocaleName(), fCtypeData.PosixLocaleName(),
304 				fMessagesData.PosixLocaleName(),
305 				fMonetaryData.PosixLocaleName(), fNumericData.PosixLocaleName(),
306 				fTimeData.PosixLocaleName());
307 			return fLocaleDescription;
308 		}
309 		case LC_COLLATE:
310 			return fCollateData.PosixLocaleName();
311 		case LC_CTYPE:
312 			return fCtypeData.PosixLocaleName();
313 		case LC_MESSAGES:
314 			return fMessagesData.PosixLocaleName();
315 		case LC_MONETARY:
316 			return fMonetaryData.PosixLocaleName();
317 		case LC_NUMERIC:
318 			return fNumericData.PosixLocaleName();
319 		case LC_TIME:
320 			return fTimeData.PosixLocaleName();
321 		default:
322 			// unsupported category
323 			return NULL;
324 	}
325 }
326 
327 
328 const char*
329 ICULocaleBackend::_SetPosixLocale(int category)
330 {
331 	switch (category) {
332 		case LC_ALL:
333 			if (fCollateData.SetToPosix() != B_OK
334 				|| fCtypeData.SetToPosix() != B_OK
335 				|| fMessagesData.SetToPosix() != B_OK
336 				|| fMonetaryData.SetToPosix() != B_OK
337 				|| fNumericData.SetToPosix() != B_OK
338 				|| fTimeData.SetToPosix() != B_OK)
339 				return NULL;
340 			break;
341 		case LC_COLLATE:
342 			if (fCollateData.SetToPosix() != B_OK)
343 				return NULL;
344 			break;
345 		case LC_CTYPE:
346 			if (fCtypeData.SetToPosix() != B_OK)
347 				return NULL;
348 			break;
349 		case LC_MESSAGES:
350 			if (fMessagesData.SetToPosix() != B_OK)
351 				return NULL;
352 			break;
353 		case LC_MONETARY:
354 			if (fMonetaryData.SetToPosix() != B_OK)
355 				return NULL;
356 			break;
357 		case LC_NUMERIC:
358 			if (fNumericData.SetToPosix() != B_OK)
359 				return NULL;
360 			break;
361 		case LC_TIME:
362 			if (fTimeData.SetToPosix() != B_OK)
363 				return NULL;
364 			break;
365 		default:
366 			// unsupported category
367 			return NULL;
368 	}
369 
370 	return "POSIX";
371 }
372 
373 
374 }	// namespace Libroot
375 }	// namespace BPrivate
376