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