/*
* Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
* Distributed under the terms of the MIT License.
*/
#include "ICULocaleBackend.h"
#include <new>
#include <langinfo.h>
#include <locale.h>
#include <string.h>
#include <strings.h>
#include <ErrnoMaintainer.h>
namespace BPrivate {
namespace Libroot {
extern "C" LocaleBackend*
CreateInstance()
{
return new(std::nothrow) ICULocaleBackend();
}
ICULocaleBackend::ICULocaleBackend()
:
fThreadLocalStorageKey(_CreateThreadLocalStorageKey()),
fCollateData(fThreadLocalStorageKey),
fCtypeData(fThreadLocalStorageKey),
fMessagesData(fThreadLocalStorageKey),
fMonetaryData(fThreadLocalStorageKey, fLocaleConv),
fNumericData(fThreadLocalStorageKey, fLocaleConv),
fTimeData(fThreadLocalStorageKey, fLCTimeInfo, fMessagesData),
fTimeConversion(fTimeData)
{
}
ICULocaleBackend::~ICULocaleBackend()
{
pthread_key_delete(fThreadLocalStorageKey);
}
void
ICULocaleBackend::Initialize(LocaleDataBridge* dataBridge)
{
ErrnoMaintainer errnoMaintainer;
fCtypeData.Initialize(&dataBridge->ctypeDataBridge);
fMessagesData.Initialize(&dataBridge->messagesDataBridge);
fMonetaryData.Initialize(&dataBridge->monetaryDataBridge);
fNumericData.Initialize(&dataBridge->numericDataBridge);
fTimeData.Initialize(&dataBridge->timeDataBridge);
fTimeConversion.Initialize(&dataBridge->timeConversionDataBridge);
fPosixLanginfo = dataBridge->posixLanginfo;
_SetPosixLocale(LC_ALL);
}
const char*
ICULocaleBackend::SetLocale(int category, const char* posixLocaleName)
{
ErrnoMaintainer errnoMaintainer;
if (posixLocaleName == NULL)
return _QueryLocale(category);
if (strcasecmp(posixLocaleName, "POSIX") == 0
|| strcasecmp(posixLocaleName, "C") == 0)
return _SetPosixLocale(category);
Locale locale = Locale::createCanonical(posixLocaleName);
switch (category) {
case LC_ALL:
if (fCollateData.SetTo(locale, posixLocaleName) != B_OK
|| fCtypeData.SetTo(locale, posixLocaleName) != B_OK
|| fMessagesData.SetTo(locale, posixLocaleName) != B_OK
|| fMonetaryData.SetTo(locale, posixLocaleName) != B_OK
|| fNumericData.SetTo(locale, posixLocaleName) != B_OK
|| fTimeData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
case LC_COLLATE:
if (fCollateData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
case LC_CTYPE:
if (fCtypeData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
case LC_MESSAGES:
if (fMessagesData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
case LC_MONETARY:
if (fMonetaryData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
case LC_NUMERIC:
if (fNumericData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
case LC_TIME:
if (fTimeData.SetTo(locale, posixLocaleName) != B_OK)
return NULL;
break;
default:
// unsupported category
return NULL;
}
return posixLocaleName;
}
const struct lconv*
ICULocaleBackend::LocaleConv()
{
return &fLocaleConv;
}
const struct lc_time_t*
ICULocaleBackend::LCTimeInfo()
{
return &fLCTimeInfo;
}
int
ICULocaleBackend::IsWCType(wint_t wc, wctype_t charClass)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.IsWCType(wc, charClass);
}
status_t
ICULocaleBackend::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.ToWCTrans(wc, transition, result);
}
status_t
ICULocaleBackend::MultibyteToWchar(wchar_t* wcOut, const char* mb,
size_t mbLength, mbstate_t* mbState, size_t& lengthOut)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.MultibyteToWchar(wcOut, mb, mbLength, mbState, lengthOut);
}
status_t
ICULocaleBackend::MultibyteStringToWchar(wchar_t* wcDest, size_t wcDestLength,
const char** mbSource, size_t mbSourceLength, mbstate_t* mbState,
size_t& lengthOut)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.MultibyteStringToWchar(wcDest, wcDestLength, mbSource,
mbSourceLength, mbState, lengthOut);
}
status_t
ICULocaleBackend::WcharToMultibyte(char* mbOut, wchar_t wc, mbstate_t* mbState,
size_t& lengthOut)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.WcharToMultibyte(mbOut, wc, mbState, lengthOut);
}
status_t
ICULocaleBackend::WcharStringToMultibyte(char* mbDest, size_t mbDestLength,
const wchar_t** wcSource, size_t wcSourceLength, mbstate_t* mbState,
size_t& lengthOut)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.WcharStringToMultibyte(mbDest, mbDestLength, wcSource,
wcSourceLength, mbState, lengthOut);
}
const char*
ICULocaleBackend::GetLanginfo(int index)
{
ErrnoMaintainer errnoMaintainer;
switch(index) {
case CODESET:
return fCtypeData.GetLanginfo(index);
case D_T_FMT:
case D_FMT:
case T_FMT:
case T_FMT_AMPM:
case AM_STR:
case PM_STR:
case DAY_1:
case DAY_2:
case DAY_3:
case DAY_4:
case DAY_5:
case DAY_6:
case DAY_7:
case ABDAY_1:
case ABDAY_2:
case ABDAY_3:
case ABDAY_4:
case ABDAY_5:
case ABDAY_6:
case ABDAY_7:
case MON_1:
case MON_2:
case MON_3:
case MON_4:
case MON_5:
case MON_6:
case MON_7:
case MON_8:
case MON_9:
case MON_10:
case MON_11:
case MON_12:
case ABMON_1:
case ABMON_2:
case ABMON_3:
case ABMON_4:
case ABMON_5:
case ABMON_6:
case ABMON_7:
case ABMON_8:
case ABMON_9:
case ABMON_10:
case ABMON_11:
case ABMON_12:
return fTimeData.GetLanginfo(index);
case ERA:
case ERA_D_FMT:
case ERA_D_T_FMT:
case ERA_T_FMT:
case ALT_DIGITS:
return fPosixLanginfo[index];
case RADIXCHAR:
case THOUSEP:
return fNumericData.GetLanginfo(index);
case YESEXPR:
case NOEXPR:
return fMessagesData.GetLanginfo(index);
case CRNCYSTR:
return fMonetaryData.GetLanginfo(index);
default:
return "";
}
}
status_t
ICULocaleBackend::Strcoll(const char* a, const char* b, int& result)
{
ErrnoMaintainer errnoMaintainer;
return fCollateData.Strcoll(a, b, result);
}
status_t
ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size,
size_t& outSize)
{
ErrnoMaintainer errnoMaintainer;
return fCollateData.Strxfrm(out, in, size, outSize);
}
status_t
ICULocaleBackend::Wcscoll(const wchar_t* a, const wchar_t* b, int& result)
{
ErrnoMaintainer errnoMaintainer;
return fCollateData.Wcscoll(a, b, result);
}
status_t
ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size,
size_t& outSize)
{
ErrnoMaintainer errnoMaintainer;
return fCollateData.Wcsxfrm(out, in, size, outSize);
}
status_t
ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.TZSet(timeZoneID, tz);
}
status_t
ICULocaleBackend::Localtime(const time_t* inTime, struct tm* tmOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Localtime(inTime, tmOut);
}
status_t
ICULocaleBackend::Gmtime(const time_t* inTime, struct tm* tmOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Gmtime(inTime, tmOut);
}
status_t
ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut)
{
ErrnoMaintainer errnoMaintainer;
return fTimeConversion.Mktime(inOutTm, timeOut);
}
const char*
ICULocaleBackend::_QueryLocale(int category)
{
switch (category) {
case LC_ALL:
{
// if all categories have the same locale, return that
const char* locale = fCollateData.PosixLocaleName();
if (strcmp(locale, fCtypeData.PosixLocaleName()) == 0
&& strcmp(locale, fMessagesData.PosixLocaleName()) == 0
&& strcmp(locale, fMonetaryData.PosixLocaleName()) == 0
&& strcmp(locale, fNumericData.PosixLocaleName()) == 0
&& strcmp(locale, fTimeData.PosixLocaleName()) == 0)
return locale;
// build a string with all info (at least glibc does it, too)
snprintf(fLocaleDescription, sizeof(fLocaleDescription),
"LC_COLLATE=%s;LC_CTYPE=%s;LC_MESSAGES=%s;LC_MONETARY=%s;"
"LC_NUMERIC=%s;LC_TIME=%s",
fCollateData.PosixLocaleName(), fCtypeData.PosixLocaleName(),
fMessagesData.PosixLocaleName(),
fMonetaryData.PosixLocaleName(), fNumericData.PosixLocaleName(),
fTimeData.PosixLocaleName());
return fLocaleDescription;
}
case LC_COLLATE:
return fCollateData.PosixLocaleName();
case LC_CTYPE:
return fCtypeData.PosixLocaleName();
case LC_MESSAGES:
return fMessagesData.PosixLocaleName();
case LC_MONETARY:
return fMonetaryData.PosixLocaleName();
case LC_NUMERIC:
return fNumericData.PosixLocaleName();
case LC_TIME:
return fTimeData.PosixLocaleName();
default:
// unsupported category
return NULL;
}
}
const char*
ICULocaleBackend::_SetPosixLocale(int category)
{
switch (category) {
case LC_ALL:
if (fCollateData.SetToPosix() != B_OK
|| fCtypeData.SetToPosix() != B_OK
|| fMessagesData.SetToPosix() != B_OK
|| fMonetaryData.SetToPosix() != B_OK
|| fNumericData.SetToPosix() != B_OK
|| fTimeData.SetToPosix() != B_OK)
return NULL;
break;
case LC_COLLATE:
if (fCollateData.SetToPosix() != B_OK)
return NULL;
break;
case LC_CTYPE:
if (fCtypeData.SetToPosix() != B_OK)
return NULL;
break;
case LC_MESSAGES:
if (fMessagesData.SetToPosix() != B_OK)
return NULL;
break;
case LC_MONETARY:
if (fMonetaryData.SetToPosix() != B_OK)
return NULL;
break;
case LC_NUMERIC:
if (fNumericData.SetToPosix() != B_OK)
return NULL;
break;
case LC_TIME:
if (fTimeData.SetToPosix() != B_OK)
return NULL;
break;
default:
// unsupported category
return NULL;
}
return "POSIX";
}
pthread_key_t
ICULocaleBackend::_CreateThreadLocalStorageKey()
{
pthread_key_t key;
pthread_key_create(&key, ICULocaleBackend::_DestroyThreadLocalStorageValue);
return key;
}
void
ICULocaleBackend::_DestroyThreadLocalStorageValue(void* value)
{
ICUThreadLocalStorageValue* tlsValue
= static_cast<ICUThreadLocalStorageValue*>(value);
delete tlsValue;
}
} // namespace Libroot
} // namespace BPrivate
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fLocaleDescription, fLocaleConv, fLCTimeInfo, fPosixLanginfo.