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