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 ICULocaleBackend::ICULocaleBackend() 34 : 35 fThreadLocalStorageKey(_CreateThreadLocalStorageKey()), 36 fCollateData(fThreadLocalStorageKey), 37 fCtypeData(fThreadLocalStorageKey), 38 fMessagesData(fThreadLocalStorageKey), 39 fMonetaryData(fThreadLocalStorageKey, fLocaleConv), 40 fNumericData(fThreadLocalStorageKey, fLocaleConv), 41 fTimeData(fThreadLocalStorageKey, fLCTimeInfo, fMessagesData), 42 fTimeConversion(fTimeData) 43 { 44 } 45 46 47 ICULocaleBackend::~ICULocaleBackend() 48 { 49 pthread_key_delete(fThreadLocalStorageKey); 50 } 51 52 53 void 54 ICULocaleBackend::Initialize(LocaleDataBridge* dataBridge) 55 { 56 ErrnoMaintainer errnoMaintainer; 57 58 fCtypeData.Initialize(&dataBridge->ctypeDataBridge); 59 fMessagesData.Initialize(&dataBridge->messagesDataBridge); 60 fMonetaryData.Initialize(&dataBridge->monetaryDataBridge); 61 fNumericData.Initialize(&dataBridge->numericDataBridge); 62 fTimeData.Initialize(&dataBridge->timeDataBridge); 63 fTimeConversion.Initialize(&dataBridge->timeConversionDataBridge); 64 65 fPosixLanginfo = dataBridge->posixLanginfo; 66 67 _SetPosixLocale(LC_ALL); 68 } 69 70 71 const char* 72 ICULocaleBackend::SetLocale(int category, const char* posixLocaleName) 73 { 74 ErrnoMaintainer errnoMaintainer; 75 76 if (posixLocaleName == NULL) 77 return _QueryLocale(category); 78 79 if (strcasecmp(posixLocaleName, "POSIX") == 0 80 || strcasecmp(posixLocaleName, "C") == 0) 81 return _SetPosixLocale(category); 82 83 Locale locale = Locale::createCanonical(posixLocaleName); 84 switch (category) { 85 case LC_ALL: 86 if (fCollateData.SetTo(locale, posixLocaleName) != B_OK 87 || fCtypeData.SetTo(locale, posixLocaleName) != B_OK 88 || fMessagesData.SetTo(locale, posixLocaleName) != B_OK 89 || fMonetaryData.SetTo(locale, posixLocaleName) != B_OK 90 || fNumericData.SetTo(locale, posixLocaleName) != B_OK 91 || fTimeData.SetTo(locale, posixLocaleName) != B_OK) 92 return NULL; 93 break; 94 case LC_COLLATE: 95 if (fCollateData.SetTo(locale, posixLocaleName) != B_OK) 96 return NULL; 97 break; 98 case LC_CTYPE: 99 if (fCtypeData.SetTo(locale, posixLocaleName) != B_OK) 100 return NULL; 101 break; 102 case LC_MESSAGES: 103 if (fMessagesData.SetTo(locale, posixLocaleName) != B_OK) 104 return NULL; 105 break; 106 case LC_MONETARY: 107 if (fMonetaryData.SetTo(locale, posixLocaleName) != B_OK) 108 return NULL; 109 break; 110 case LC_NUMERIC: 111 if (fNumericData.SetTo(locale, posixLocaleName) != B_OK) 112 return NULL; 113 break; 114 case LC_TIME: 115 if (fTimeData.SetTo(locale, posixLocaleName) != B_OK) 116 return NULL; 117 break; 118 default: 119 // unsupported category 120 return NULL; 121 } 122 123 return posixLocaleName; 124 } 125 126 127 const struct lconv* 128 ICULocaleBackend::LocaleConv() 129 { 130 return &fLocaleConv; 131 } 132 133 134 const struct lc_time_t* 135 ICULocaleBackend::LCTimeInfo() 136 { 137 return &fLCTimeInfo; 138 } 139 140 141 int 142 ICULocaleBackend::IsWCType(wint_t wc, wctype_t charClass) 143 { 144 ErrnoMaintainer errnoMaintainer; 145 146 return fCtypeData.IsWCType(wc, charClass); 147 } 148 149 150 status_t 151 ICULocaleBackend::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result) 152 { 153 ErrnoMaintainer errnoMaintainer; 154 155 return fCtypeData.ToWCTrans(wc, transition, result); 156 } 157 158 159 status_t 160 ICULocaleBackend::MultibyteToWchar(wchar_t* wcOut, const char* mb, 161 size_t mbLength, mbstate_t* mbState, size_t& lengthOut) 162 { 163 ErrnoMaintainer errnoMaintainer; 164 165 return fCtypeData.MultibyteToWchar(wcOut, mb, mbLength, mbState, lengthOut); 166 } 167 168 169 status_t 170 ICULocaleBackend::MultibyteStringToWchar(wchar_t* wcDest, size_t wcDestLength, 171 const char** mbSource, size_t mbSourceLength, mbstate_t* mbState, 172 size_t& lengthOut) 173 { 174 ErrnoMaintainer errnoMaintainer; 175 176 return fCtypeData.MultibyteStringToWchar(wcDest, wcDestLength, mbSource, 177 mbSourceLength, mbState, lengthOut); 178 } 179 180 181 status_t 182 ICULocaleBackend::WcharToMultibyte(char* mbOut, wchar_t wc, mbstate_t* mbState, 183 size_t& lengthOut) 184 { 185 ErrnoMaintainer errnoMaintainer; 186 187 return fCtypeData.WcharToMultibyte(mbOut, wc, mbState, lengthOut); 188 } 189 190 191 status_t 192 ICULocaleBackend::WcharStringToMultibyte(char* mbDest, size_t mbDestLength, 193 const wchar_t** wcSource, size_t wcSourceLength, mbstate_t* mbState, 194 size_t& lengthOut) 195 { 196 ErrnoMaintainer errnoMaintainer; 197 198 return fCtypeData.WcharStringToMultibyte(mbDest, mbDestLength, wcSource, 199 wcSourceLength, mbState, lengthOut); 200 } 201 202 203 const char* 204 ICULocaleBackend::GetLanginfo(int index) 205 { 206 ErrnoMaintainer errnoMaintainer; 207 208 switch(index) { 209 case CODESET: 210 return fCtypeData.GetLanginfo(index); 211 212 case D_T_FMT: 213 case D_FMT: 214 case T_FMT: 215 case T_FMT_AMPM: 216 case AM_STR: 217 case PM_STR: 218 case DAY_1: 219 case DAY_2: 220 case DAY_3: 221 case DAY_4: 222 case DAY_5: 223 case DAY_6: 224 case DAY_7: 225 case ABDAY_1: 226 case ABDAY_2: 227 case ABDAY_3: 228 case ABDAY_4: 229 case ABDAY_5: 230 case ABDAY_6: 231 case ABDAY_7: 232 case MON_1: 233 case MON_2: 234 case MON_3: 235 case MON_4: 236 case MON_5: 237 case MON_6: 238 case MON_7: 239 case MON_8: 240 case MON_9: 241 case MON_10: 242 case MON_11: 243 case MON_12: 244 case ABMON_1: 245 case ABMON_2: 246 case ABMON_3: 247 case ABMON_4: 248 case ABMON_5: 249 case ABMON_6: 250 case ABMON_7: 251 case ABMON_8: 252 case ABMON_9: 253 case ABMON_10: 254 case ABMON_11: 255 case ABMON_12: 256 return fTimeData.GetLanginfo(index); 257 258 case ERA: 259 case ERA_D_FMT: 260 case ERA_D_T_FMT: 261 case ERA_T_FMT: 262 case ALT_DIGITS: 263 return fPosixLanginfo[index]; 264 265 case RADIXCHAR: 266 case THOUSEP: 267 return fNumericData.GetLanginfo(index); 268 269 case YESEXPR: 270 case NOEXPR: 271 return fMessagesData.GetLanginfo(index); 272 273 case CRNCYSTR: 274 return fMonetaryData.GetLanginfo(index); 275 276 default: 277 return ""; 278 } 279 } 280 281 282 status_t 283 ICULocaleBackend::Strcoll(const char* a, const char* b, int& result) 284 { 285 ErrnoMaintainer errnoMaintainer; 286 287 return fCollateData.Strcoll(a, b, result); 288 } 289 290 291 status_t 292 ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size, 293 size_t& outSize) 294 { 295 ErrnoMaintainer errnoMaintainer; 296 297 return fCollateData.Strxfrm(out, in, size, outSize); 298 } 299 300 301 status_t 302 ICULocaleBackend::Wcscoll(const wchar_t* a, const wchar_t* b, int& result) 303 { 304 ErrnoMaintainer errnoMaintainer; 305 306 return fCollateData.Wcscoll(a, b, result); 307 } 308 309 310 status_t 311 ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size, 312 size_t& outSize) 313 { 314 ErrnoMaintainer errnoMaintainer; 315 316 return fCollateData.Wcsxfrm(out, in, size, outSize); 317 } 318 319 320 status_t 321 ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz) 322 { 323 ErrnoMaintainer errnoMaintainer; 324 325 return fTimeConversion.TZSet(timeZoneID, tz); 326 } 327 328 329 status_t 330 ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut) 331 { 332 ErrnoMaintainer errnoMaintainer; 333 334 return fTimeConversion.Localtime(inTime, tmOut); 335 } 336 337 338 status_t 339 ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut) 340 { 341 ErrnoMaintainer errnoMaintainer; 342 343 return fTimeConversion.Gmtime(inTime, tmOut); 344 } 345 346 347 status_t 348 ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut) 349 { 350 ErrnoMaintainer errnoMaintainer; 351 352 return fTimeConversion.Mktime(inOutTm, timeOut); 353 } 354 355 356 status_t 357 ICULocaleBackend::Timegm(struct tm* inOutTm, time_t& timeOut) 358 { 359 ErrnoMaintainer errnoMaintainer; 360 361 return fTimeConversion.Timegm(inOutTm, timeOut); 362 } 363 364 365 const char* 366 ICULocaleBackend::_QueryLocale(int category) 367 { 368 switch (category) { 369 case LC_ALL: 370 { 371 // if all categories have the same locale, return that 372 const char* locale = fCollateData.PosixLocaleName(); 373 if (strcmp(locale, fCtypeData.PosixLocaleName()) == 0 374 && strcmp(locale, fMessagesData.PosixLocaleName()) == 0 375 && strcmp(locale, fMonetaryData.PosixLocaleName()) == 0 376 && strcmp(locale, fNumericData.PosixLocaleName()) == 0 377 && strcmp(locale, fTimeData.PosixLocaleName()) == 0) 378 return locale; 379 380 // build a string with all info (at least glibc does it, too) 381 snprintf(fLocaleDescription, sizeof(fLocaleDescription), 382 "LC_COLLATE=%s;LC_CTYPE=%s;LC_MESSAGES=%s;LC_MONETARY=%s;" 383 "LC_NUMERIC=%s;LC_TIME=%s", 384 fCollateData.PosixLocaleName(), fCtypeData.PosixLocaleName(), 385 fMessagesData.PosixLocaleName(), 386 fMonetaryData.PosixLocaleName(), fNumericData.PosixLocaleName(), 387 fTimeData.PosixLocaleName()); 388 return fLocaleDescription; 389 } 390 case LC_COLLATE: 391 return fCollateData.PosixLocaleName(); 392 case LC_CTYPE: 393 return fCtypeData.PosixLocaleName(); 394 case LC_MESSAGES: 395 return fMessagesData.PosixLocaleName(); 396 case LC_MONETARY: 397 return fMonetaryData.PosixLocaleName(); 398 case LC_NUMERIC: 399 return fNumericData.PosixLocaleName(); 400 case LC_TIME: 401 return fTimeData.PosixLocaleName(); 402 default: 403 // unsupported category 404 return NULL; 405 } 406 } 407 408 409 const char* 410 ICULocaleBackend::_SetPosixLocale(int category) 411 { 412 switch (category) { 413 case LC_ALL: 414 if (fCollateData.SetToPosix() != B_OK 415 || fCtypeData.SetToPosix() != B_OK 416 || fMessagesData.SetToPosix() != B_OK 417 || fMonetaryData.SetToPosix() != B_OK 418 || fNumericData.SetToPosix() != B_OK 419 || fTimeData.SetToPosix() != B_OK) 420 return NULL; 421 break; 422 case LC_COLLATE: 423 if (fCollateData.SetToPosix() != B_OK) 424 return NULL; 425 break; 426 case LC_CTYPE: 427 if (fCtypeData.SetToPosix() != B_OK) 428 return NULL; 429 break; 430 case LC_MESSAGES: 431 if (fMessagesData.SetToPosix() != B_OK) 432 return NULL; 433 break; 434 case LC_MONETARY: 435 if (fMonetaryData.SetToPosix() != B_OK) 436 return NULL; 437 break; 438 case LC_NUMERIC: 439 if (fNumericData.SetToPosix() != B_OK) 440 return NULL; 441 break; 442 case LC_TIME: 443 if (fTimeData.SetToPosix() != B_OK) 444 return NULL; 445 break; 446 default: 447 // unsupported category 448 return NULL; 449 } 450 451 return "POSIX"; 452 } 453 454 455 pthread_key_t 456 ICULocaleBackend::_CreateThreadLocalStorageKey() 457 { 458 pthread_key_t key; 459 460 pthread_key_create(&key, ICULocaleBackend::_DestroyThreadLocalStorageValue); 461 462 return key; 463 } 464 465 466 void 467 ICULocaleBackend::_DestroyThreadLocalStorageValue(void* value) 468 { 469 ICUThreadLocalStorageValue* tlsValue 470 = static_cast<ICUThreadLocalStorageValue*>(value); 471 472 delete tlsValue; 473 } 474 475 476 } // namespace Libroot 477 } // namespace BPrivate 478