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