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