* Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
* Distributed under the terms of the MIT License.
*/
#include "ICUTimeData.h"
#include <langinfo.h>
#include <string.h>
#include <strings.h>
#include <unicode/dtfmtsym.h>
#include <unicode/gregocal.h>
#include <unicode/smpdtfmt.h>
#include <AutoDeleter.h>
#include "ICUMessagesData.h"
U_NAMESPACE_USE
namespace BPrivate {
namespace Libroot {
ICUTimeData::ICUTimeData(pthread_key_t tlsKey, struct lc_time_t& lcTimeInfo,
const ICUMessagesData& messagesData)
:
inherited(tlsKey),
fLCTimeInfo(lcTimeInfo),
fDataBridge(NULL),
fMessagesData(messagesData)
{
for (int i = 0; i < 12; ++i) {
fLCTimeInfo.mon[i] = fMon[i];
fLCTimeInfo.month[i] = fMonth[i];
fLCTimeInfo.alt_month[i] = fAltMonth[i];
}
for (int i = 0; i < 7; ++i) {
fLCTimeInfo.wday[i] = fWday[i];
fLCTimeInfo.weekday[i] = fWeekday[i];
}
fLCTimeInfo.X_fmt = fTimeFormat;
fLCTimeInfo.x_fmt = fDateFormat;
fLCTimeInfo.c_fmt = fDateTimeFormat;
fLCTimeInfo.am = fAm;
fLCTimeInfo.pm = fPm;
fLCTimeInfo.date_fmt = fDateTimeZoneFormat;
fLCTimeInfo.md_order = fMonthDayOrder;
fLCTimeInfo.ampm_fmt = fAmPmFormat;
}
ICUTimeData::~ICUTimeData()
{
}
void
ICUTimeData::Initialize(LocaleTimeDataBridge* dataBridge)
{
fDataBridge = dataBridge;
}
status_t
ICUTimeData::SetTo(const Locale& locale, const char* posixLocaleName)
{
status_t result = inherited::SetTo(locale, posixLocaleName);
if (result != B_OK)
return result;
UErrorCode icuStatus = U_ZERO_ERROR;
DateFormatSymbols formatSymbols(ICULocaleForStrings(), icuStatus);
if (!U_SUCCESS(icuStatus))
return B_UNSUPPORTED;
int count = 0;
const UnicodeString* strings = formatSymbols.getShortMonths(count);
result = _SetLCTimeEntries(strings, fMon[0], sizeof(fMon[0]), count, 12);
if (result == B_OK) {
strings = formatSymbols.getMonths(count);
result = _SetLCTimeEntries(strings, fMonth[0], sizeof(fMonth[0]), count,
12);
}
if (result == B_OK) {
strings = formatSymbols.getShortWeekdays(count);
if (count == 8 && strings[0].length() == 0) {
strings++;
count = 7;
}
result
= _SetLCTimeEntries(strings, fWday[0], sizeof(fWday[0]), count, 7);
}
if (result == B_OK) {
strings = formatSymbols.getWeekdays(count);
if (count == 8 && strings[0].length() == 0) {
strings++;
count = 7;
}
result = _SetLCTimeEntries(strings, fWeekday[0], sizeof(fWeekday[0]),
count, 7);
}
if (result == B_OK) {
try {
DateFormat* format = DateFormat::createTimeInstance(
DateFormat::kDefault, fLocale);
result = _SetLCTimePattern(format, fTimeFormat, sizeof(fTimeFormat));
delete format;
} catch(...) {
result = B_NO_MEMORY;
}
}
if (result == B_OK) {
try {
DateFormat* format = DateFormat::createDateInstance(
DateFormat::kDefault, fLocale);
result = _SetLCTimePattern(format, fDateFormat, sizeof(fDateFormat));
delete format;
} catch(...) {
result = B_NO_MEMORY;
}
}
if (result == B_OK) {
try {
DateFormat* format = DateFormat::createDateTimeInstance(
DateFormat::kDefault, DateFormat::kDefault, fLocale);
result = _SetLCTimePattern(format, fDateTimeFormat,
sizeof(fDateTimeFormat));
delete format;
} catch(...) {
result = B_NO_MEMORY;
}
}
if (result == B_OK) {
strings = formatSymbols.getAmPmStrings(count);
result = _SetLCTimeEntries(strings, fAm, sizeof(fAm), 1, 1);
if (result == B_OK)
result = _SetLCTimeEntries(&strings[1], fPm, sizeof(fPm), 1, 1);
}
if (result == B_OK) {
strings = formatSymbols.getMonths(count, DateFormatSymbols::STANDALONE,
DateFormatSymbols::WIDE);
result = _SetLCTimeEntries(strings, fAltMonth[0], sizeof(fAltMonth[0]),
count, 12);
}
strcpy(fAmPmFormat, fDataBridge->posixLCTimeInfo->ampm_fmt);
return result;
}
status_t
ICUTimeData::SetToPosix()
{
status_t result = inherited::SetToPosix();
if (result == B_OK) {
for (int i = 0; i < 12; ++i) {
strcpy(fMon[i], fDataBridge->posixLCTimeInfo->mon[i]);
strcpy(fMonth[i], fDataBridge->posixLCTimeInfo->month[i]);
strcpy(fAltMonth[i], fDataBridge->posixLCTimeInfo->alt_month[i]);
}
for (int i = 0; i < 7; ++i) {
strcpy(fWday[i], fDataBridge->posixLCTimeInfo->wday[i]);
strcpy(fWeekday[i], fDataBridge->posixLCTimeInfo->weekday[i]);
}
strcpy(fTimeFormat, fDataBridge->posixLCTimeInfo->X_fmt);
strcpy(fDateFormat, fDataBridge->posixLCTimeInfo->x_fmt);
strcpy(fDateTimeFormat, fDataBridge->posixLCTimeInfo->c_fmt);
strcpy(fAm, fDataBridge->posixLCTimeInfo->am);
strcpy(fPm, fDataBridge->posixLCTimeInfo->pm);
strcpy(fDateTimeZoneFormat, fDataBridge->posixLCTimeInfo->date_fmt);
strcpy(fMonthDayOrder, fDataBridge->posixLCTimeInfo->md_order);
strcpy(fAmPmFormat, fDataBridge->posixLCTimeInfo->ampm_fmt);
}
return result;
}
const char*
ICUTimeData::GetLanginfo(int index)
{
switch(index) {
case D_T_FMT:
return fDateTimeFormat;
case D_FMT:
return fDateFormat;
case T_FMT:
return fTimeFormat;
case T_FMT_AMPM:
return fAmPmFormat;
case AM_STR:
return fAm;
case PM_STR:
return fPm;
case DAY_1:
case DAY_2:
case DAY_3:
case DAY_4:
case DAY_5:
case DAY_6:
case DAY_7:
return fWeekday[index - DAY_1];
case ABDAY_1:
case ABDAY_2:
case ABDAY_3:
case ABDAY_4:
case ABDAY_5:
case ABDAY_6:
case ABDAY_7:
return fWday[index - ABDAY_1];
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:
return fMonth[index - MON_1];
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 fMon[index - ABMON_1];
default:
return "";
}
}
const Locale&
ICUTimeData::ICULocaleForStrings() const
{
UErrorCode icuStatus = U_ZERO_ERROR;
char stringsValue[16];
fLocale.getKeywordValue("strings", stringsValue, sizeof(stringsValue),
icuStatus);
if (U_SUCCESS(icuStatus) && strcasecmp(stringsValue, "messages") == 0)
return fMessagesData.ICULocale();
else
return fLocale;
}
status_t
ICUTimeData::_SetLCTimeEntries(const UnicodeString* strings, char* destination,
int entrySize, int count, int maxCount)
{
if (strings == NULL)
return B_ERROR;
status_t result = B_OK;
if (count > maxCount)
count = maxCount;
for (int32 i = 0; result == B_OK && i < count; ++i) {
result = _ConvertUnicodeStringToLocaleconvEntry(strings[i], destination,
entrySize);
destination += entrySize;
}
return result;
}
status_t
ICUTimeData::_SetLCTimePattern(DateFormat* format, char* destination,
int destinationSize)
{
SimpleDateFormat* simpleFormat = dynamic_cast<SimpleDateFormat*>(format);
if (!simpleFormat)
return B_BAD_TYPE;
UnicodeString icuPattern;
simpleFormat->toPattern(icuPattern);
UnicodeString posixPattern;
if (icuPattern.length() > 0) {
UChar lastCharSeen = 0;
int lastCharCount = 1;
bool inSingleQuotes = false;
bool inDoubleQuotes = false;
for (int i = 0; i <= icuPattern.length(); ++i) {
UChar currChar = icuPattern.charAt(i);
if (u_isspace(currChar))
currChar = ' ';
if (lastCharSeen != 0 && currChar == lastCharSeen) {
lastCharCount++;
continue;
}
if (!inSingleQuotes && !inDoubleQuotes) {
switch (lastCharSeen) {
case L'a':
posixPattern.append(UnicodeString("%p", ""));
break;
case L'd':
if (lastCharCount == 2)
posixPattern.append(UnicodeString("%d", ""));
else
posixPattern.append(UnicodeString("%e", ""));
break;
case L'D':
posixPattern.append(UnicodeString("%j", ""));
break;
case L'c':
case L'e':
if (lastCharCount == 4)
posixPattern.append(UnicodeString("%A", ""));
else if (lastCharCount <= 2)
posixPattern.append(UnicodeString("%u", ""));
else
posixPattern.append(UnicodeString("%a", ""));
break;
case L'E':
if (lastCharCount == 4)
posixPattern.append(UnicodeString("%A", ""));
else
posixPattern.append(UnicodeString("%a", ""));
break;
case L'k':
case L'h':
if (lastCharCount == 2)
posixPattern.append(UnicodeString("%I", ""));
else
posixPattern.append(UnicodeString("%l", ""));
break;
case L'H':
if (lastCharCount == 2)
posixPattern.append(UnicodeString("%H", ""));
else
posixPattern.append(UnicodeString("%k", ""));
break;
case L'm':
posixPattern.append(UnicodeString("%M", ""));
break;
case L'L':
case L'M':
if (lastCharCount == 4)
posixPattern.append(UnicodeString("%B", ""));
else if (lastCharCount == 3)
posixPattern.append(UnicodeString("%b", ""));
else
posixPattern.append(UnicodeString("%m", ""));
break;
case L's':
posixPattern.append(UnicodeString("%S", ""));
break;
case L'w':
posixPattern.append(UnicodeString("%V", ""));
break;
case L'y':
if (lastCharCount == 2)
posixPattern.append(UnicodeString("%y", ""));
else
posixPattern.append(UnicodeString("%Y", ""));
break;
case L'Y':
posixPattern.append(UnicodeString("%G", ""));
break;
case L'z':
posixPattern.append(UnicodeString("%Z", ""));
break;
case L'Z':
posixPattern.append(UnicodeString("%z", ""));
break;
default:
if (lastCharSeen != 0)
posixPattern.append(lastCharSeen);
}
} else {
if (lastCharSeen != 0)
posixPattern.append(lastCharSeen);
}
if (currChar == L'"') {
inDoubleQuotes = !inDoubleQuotes;
lastCharSeen = 0;
} else if (currChar == L'\'') {
inSingleQuotes = !inSingleQuotes;
lastCharSeen = 0;
} else
lastCharSeen = currChar;
lastCharCount = 1;
}
}
return _ConvertUnicodeStringToLocaleconvEntry(posixPattern, destination,
destinationSize);
}
}
}