1 /* 2 * Copyright 2010, 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 fMonetaryData(fLocaleConv), 32 fNumericData(fLocaleConv), 33 fTimeData(fLCTimeInfo), 34 fTimeConversion(fTimeData) 35 { 36 } 37 38 39 ICULocaleBackend::~ICULocaleBackend() 40 { 41 } 42 43 44 void 45 ICULocaleBackend::Initialize(LocaleDataBridge* dataBridge) 46 { 47 ErrnoMaintainer errnoMaintainer; 48 49 fCtypeData.Initialize(&dataBridge->ctypeDataBridge); 50 fMessagesData.Initialize(&dataBridge->messagesDataBridge); 51 fMonetaryData.Initialize(&dataBridge->monetaryDataBridge); 52 fNumericData.Initialize(&dataBridge->numericDataBridge); 53 fTimeData.Initialize(&dataBridge->timeDataBridge); 54 fTimeConversion.Initialize(&dataBridge->timeConversionDataBridge); 55 56 fPosixLanginfo = dataBridge->posixLanginfo; 57 58 _SetPosixLocale(LC_ALL); 59 } 60 61 62 const char* 63 ICULocaleBackend::SetLocale(int category, const char* posixLocaleName) 64 { 65 ErrnoMaintainer errnoMaintainer; 66 67 if (posixLocaleName == NULL) 68 return _QueryLocale(category); 69 70 if (strcasecmp(posixLocaleName, "POSIX") == 0 71 || strcasecmp(posixLocaleName, "C") == 0) 72 return _SetPosixLocale(category); 73 74 Locale locale = Locale::createCanonical(posixLocaleName); 75 switch (category) { 76 case LC_ALL: 77 if (fCollateData.SetTo(locale, posixLocaleName) != B_OK 78 || fCtypeData.SetTo(locale, posixLocaleName) != B_OK 79 || fMessagesData.SetTo(locale, posixLocaleName) != B_OK 80 || fMonetaryData.SetTo(locale, posixLocaleName) != B_OK 81 || fNumericData.SetTo(locale, posixLocaleName) != B_OK 82 || fTimeData.SetTo(locale, posixLocaleName) != B_OK) 83 return NULL; 84 break; 85 case LC_COLLATE: 86 if (fCollateData.SetTo(locale, posixLocaleName) != B_OK) 87 return NULL; 88 break; 89 case LC_CTYPE: 90 if (fCtypeData.SetTo(locale, posixLocaleName) != B_OK) 91 return NULL; 92 break; 93 case LC_MESSAGES: 94 if (fMessagesData.SetTo(locale, posixLocaleName) != B_OK) 95 return NULL; 96 break; 97 case LC_MONETARY: 98 if (fMonetaryData.SetTo(locale, posixLocaleName) != B_OK) 99 return NULL; 100 break; 101 case LC_NUMERIC: 102 if (fNumericData.SetTo(locale, posixLocaleName) != B_OK) 103 return NULL; 104 break; 105 case LC_TIME: 106 if (fTimeData.SetTo(locale, posixLocaleName) != B_OK) 107 return NULL; 108 break; 109 default: 110 // unsupported category 111 return NULL; 112 } 113 114 return posixLocaleName; 115 } 116 117 118 const struct lconv* 119 ICULocaleBackend::LocaleConv() 120 { 121 return &fLocaleConv; 122 } 123 124 125 const struct lc_time_t* 126 ICULocaleBackend::LCTimeInfo() 127 { 128 return &fLCTimeInfo; 129 } 130 131 132 int 133 ICULocaleBackend::IsWCType(wint_t wc, wctype_t charClass) 134 { 135 ErrnoMaintainer errnoMaintainer; 136 137 return fCtypeData.IsWCType(wc, charClass); 138 } 139 140 141 status_t 142 ICULocaleBackend::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result) 143 { 144 ErrnoMaintainer errnoMaintainer; 145 146 return fCtypeData.ToWCTrans(wc, transition, result); 147 } 148 149 150 const char* 151 ICULocaleBackend::GetLanginfo(int index) 152 { 153 ErrnoMaintainer errnoMaintainer; 154 155 switch(index) { 156 case CODESET: 157 return fCtypeData.GetLanginfo(index); 158 159 case D_T_FMT: 160 case D_FMT: 161 case T_FMT: 162 case T_FMT_AMPM: 163 case AM_STR: 164 case PM_STR: 165 case DAY_1: 166 case DAY_2: 167 case DAY_3: 168 case DAY_4: 169 case DAY_5: 170 case DAY_6: 171 case DAY_7: 172 case ABDAY_1: 173 case ABDAY_2: 174 case ABDAY_3: 175 case ABDAY_4: 176 case ABDAY_5: 177 case ABDAY_6: 178 case ABDAY_7: 179 case MON_1: 180 case MON_2: 181 case MON_3: 182 case MON_4: 183 case MON_5: 184 case MON_6: 185 case MON_7: 186 case MON_8: 187 case MON_9: 188 case MON_10: 189 case MON_11: 190 case MON_12: 191 case ABMON_1: 192 case ABMON_2: 193 case ABMON_3: 194 case ABMON_4: 195 case ABMON_5: 196 case ABMON_6: 197 case ABMON_7: 198 case ABMON_8: 199 case ABMON_9: 200 case ABMON_10: 201 case ABMON_11: 202 case ABMON_12: 203 return fTimeData.GetLanginfo(index); 204 205 case ERA: 206 case ERA_D_FMT: 207 case ERA_D_T_FMT: 208 case ERA_T_FMT: 209 case ALT_DIGITS: 210 return fPosixLanginfo[index]; 211 212 case RADIXCHAR: 213 case THOUSEP: 214 return fNumericData.GetLanginfo(index); 215 216 case YESEXPR: 217 case NOEXPR: 218 return fMessagesData.GetLanginfo(index); 219 220 case CRNCYSTR: 221 return fMonetaryData.GetLanginfo(index); 222 223 default: 224 return ""; 225 } 226 } 227 228 229 status_t 230 ICULocaleBackend::Strcoll(const char* a, const char* b, int& result) 231 { 232 ErrnoMaintainer errnoMaintainer; 233 234 return fCollateData.Strcoll(a, b, result); 235 } 236 237 238 status_t 239 ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size, 240 size_t& outSize) 241 { 242 ErrnoMaintainer errnoMaintainer; 243 244 return fCollateData.Strxfrm(out, in, size, outSize); 245 } 246 247 248 status_t 249 ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz) 250 { 251 ErrnoMaintainer errnoMaintainer; 252 253 return fTimeConversion.TZSet(timeZoneID, tz); 254 } 255 256 257 status_t 258 ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut) 259 { 260 ErrnoMaintainer errnoMaintainer; 261 262 return fTimeConversion.Localtime(inTime, tmOut); 263 } 264 265 266 status_t 267 ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut) 268 { 269 ErrnoMaintainer errnoMaintainer; 270 271 return fTimeConversion.Gmtime(inTime, tmOut); 272 } 273 274 275 status_t 276 ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut) 277 { 278 ErrnoMaintainer errnoMaintainer; 279 280 return fTimeConversion.Mktime(inOutTm, timeOut); 281 } 282 283 284 const char* 285 ICULocaleBackend::_QueryLocale(int category) 286 { 287 switch (category) { 288 case LC_ALL: 289 { 290 // if all categories have the same locale, return that 291 const char* locale = fCollateData.PosixLocaleName(); 292 if (strcmp(locale, fCtypeData.PosixLocaleName()) == 0 293 && strcmp(locale, fMessagesData.PosixLocaleName()) == 0 294 && strcmp(locale, fMonetaryData.PosixLocaleName()) == 0 295 && strcmp(locale, fNumericData.PosixLocaleName()) == 0 296 && strcmp(locale, fTimeData.PosixLocaleName()) == 0) 297 return locale; 298 299 // build a string with all info (at least glibc does it, too) 300 snprintf(fLocaleDescription, sizeof(fLocaleDescription), 301 "LC_COLLATE=%s;LC_CTYPE=%s;LC_MESSAGES=%s;LC_MONETARY=%s;" 302 "LC_NUMERIC=%s;LC_TIME=%s", 303 fCollateData.PosixLocaleName(), fCtypeData.PosixLocaleName(), 304 fMessagesData.PosixLocaleName(), 305 fMonetaryData.PosixLocaleName(), fNumericData.PosixLocaleName(), 306 fTimeData.PosixLocaleName()); 307 return fLocaleDescription; 308 } 309 case LC_COLLATE: 310 return fCollateData.PosixLocaleName(); 311 case LC_CTYPE: 312 return fCtypeData.PosixLocaleName(); 313 case LC_MESSAGES: 314 return fMessagesData.PosixLocaleName(); 315 case LC_MONETARY: 316 return fMonetaryData.PosixLocaleName(); 317 case LC_NUMERIC: 318 return fNumericData.PosixLocaleName(); 319 case LC_TIME: 320 return fTimeData.PosixLocaleName(); 321 default: 322 // unsupported category 323 return NULL; 324 } 325 } 326 327 328 const char* 329 ICULocaleBackend::_SetPosixLocale(int category) 330 { 331 switch (category) { 332 case LC_ALL: 333 if (fCollateData.SetToPosix() != B_OK 334 || fCtypeData.SetToPosix() != B_OK 335 || fMessagesData.SetToPosix() != B_OK 336 || fMonetaryData.SetToPosix() != B_OK 337 || fNumericData.SetToPosix() != B_OK 338 || fTimeData.SetToPosix() != B_OK) 339 return NULL; 340 break; 341 case LC_COLLATE: 342 if (fCollateData.SetToPosix() != B_OK) 343 return NULL; 344 break; 345 case LC_CTYPE: 346 if (fCtypeData.SetToPosix() != B_OK) 347 return NULL; 348 break; 349 case LC_MESSAGES: 350 if (fMessagesData.SetToPosix() != B_OK) 351 return NULL; 352 break; 353 case LC_MONETARY: 354 if (fMonetaryData.SetToPosix() != B_OK) 355 return NULL; 356 break; 357 case LC_NUMERIC: 358 if (fNumericData.SetToPosix() != B_OK) 359 return NULL; 360 break; 361 case LC_TIME: 362 if (fTimeData.SetToPosix() != B_OK) 363 return NULL; 364 break; 365 default: 366 // unsupported category 367 return NULL; 368 } 369 370 return "POSIX"; 371 } 372 373 374 } // namespace Libroot 375 } // namespace BPrivate 376