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