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