From c1e6e51a05d569622330492ffcaa50494d31737c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sun, 21 Feb 2021 12:10:47 +0100 Subject: [PATCH] libroot: implement timegm calling the ICU backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib4de4288e061670acbc2edea3671cee029305d33 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3748 Reviewed-by: Axel Dörfler --- .../private/libroot/locale/ICULocaleBackend.h | 2 + .../libroot/locale/ICUTimeConversion.h | 6 +++ .../private/libroot/locale/LocaleBackend.h | 2 + .../libroot/add-ons/icu/ICULocaleBackend.cpp | 9 ++++ .../libroot/add-ons/icu/ICUTimeConversion.cpp | 50 ++++++++++++------- src/system/libroot/posix/time/localtime.cpp | 29 ++++++++++- .../libroot/posix/time/localtime_fading_out.c | 6 +-- 7 files changed, 82 insertions(+), 22 deletions(-) diff --git a/headers/private/libroot/locale/ICULocaleBackend.h b/headers/private/libroot/locale/ICULocaleBackend.h index 72e3ef96b6..1d5f5f4807 100644 --- a/headers/private/libroot/locale/ICULocaleBackend.h +++ b/headers/private/libroot/locale/ICULocaleBackend.h @@ -73,6 +73,8 @@ public: virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut); + virtual status_t Timegm(struct tm* inOutTm, time_t& timeOut); + private: const char* _QueryLocale(int category); const char* _SetPosixLocale(int category); diff --git a/headers/private/libroot/locale/ICUTimeConversion.h b/headers/private/libroot/locale/ICUTimeConversion.h index c7b2b38315..8fb9b4f862 100644 --- a/headers/private/libroot/locale/ICUTimeConversion.h +++ b/headers/private/libroot/locale/ICUTimeConversion.h @@ -34,11 +34,17 @@ public: status_t Mktime(struct tm* inOutTm, time_t& timeOut); + status_t Timegm(struct tm* inOutTm, time_t& timeOut); + private: status_t _FillTmValues(const U_NAMESPACE_QUALIFIER TimeZone* icuTimeZone, const time_t* inTime, struct tm* tmOut); + status_t _Mktime(const U_NAMESPACE_QUALIFIER + TimeZone* icuTimeZone, + struct tm* inOutTm, time_t& timeOut); + const ICUTimeData& fTimeData; TimeConversionDataBridge* fDataBridge; diff --git a/headers/private/libroot/locale/LocaleBackend.h b/headers/private/libroot/locale/LocaleBackend.h index 670253c4b7..eb4fc8e8eb 100644 --- a/headers/private/libroot/locale/LocaleBackend.h +++ b/headers/private/libroot/locale/LocaleBackend.h @@ -157,6 +157,8 @@ public: struct tm* tmOut) = 0; virtual status_t Mktime(struct tm* inOutTm, time_t& timeOut) = 0; + virtual status_t Timegm(struct tm* inOutTm, time_t& timeOut) = 0; + virtual void Initialize(LocaleDataBridge* dataBridge) = 0; static status_t LoadBackend(); diff --git a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp index 3f226f29a6..a1c45b705a 100644 --- a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp +++ b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp @@ -353,6 +353,15 @@ ICULocaleBackend::Mktime(struct tm* inOutTm, time_t& timeOut) } +status_t +ICULocaleBackend::Timegm(struct tm* inOutTm, time_t& timeOut) +{ + ErrnoMaintainer errnoMaintainer; + + return fTimeConversion.Timegm(inOutTm, timeOut); +} + + const char* ICULocaleBackend::_QueryLocale(int category) { diff --git a/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp b/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp index 1a2d749e2b..5951b6c50b 100644 --- a/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp +++ b/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp @@ -166,25 +166,15 @@ ICUTimeConversion::Gmtime(const time_t* inTime, struct tm* tmOut) status_t ICUTimeConversion::Mktime(struct tm* inOutTm, time_t& timeOut) { - if (fTimeZone == NULL) - return B_NO_INIT; + return _Mktime(fTimeZone, inOutTm, timeOut); +} - UErrorCode icuStatus = U_ZERO_ERROR; - GregorianCalendar calendar(*fTimeZone, fTimeData.ICULocale(), - icuStatus); - if (!U_SUCCESS(icuStatus)) - return B_ERROR; - calendar.setLenient(TRUE); - calendar.set(inOutTm->tm_year + 1900, inOutTm->tm_mon, inOutTm->tm_mday, - inOutTm->tm_hour, inOutTm->tm_min, inOutTm->tm_sec); - - UDate timeInMillis = calendar.getTime(icuStatus); - if (!U_SUCCESS(icuStatus)) - return B_ERROR; - timeOut = (time_t)((int64_t)timeInMillis / 1000); - - return _FillTmValues(fTimeZone, &timeOut, inOutTm); +status_t +ICUTimeConversion::Timegm(struct tm* inOutTm, time_t& timeOut) +{ + const TimeZone* icuTimeZone = TimeZone::getGMT(); + return _Mktime(icuTimeZone, inOutTm, timeOut); } @@ -238,5 +228,31 @@ ICUTimeConversion::_FillTmValues(const TimeZone* icuTimeZone, } +status_t +ICUTimeConversion::_Mktime(const TimeZone* icuTimeZone, + struct tm* inOutTm, time_t& timeOut) +{ + if (icuTimeZone == NULL) + return B_NO_INIT; + + UErrorCode icuStatus = U_ZERO_ERROR; + GregorianCalendar calendar(*icuTimeZone, fTimeData.ICULocale(), + icuStatus); + if (!U_SUCCESS(icuStatus)) + return B_ERROR; + + calendar.setLenient(TRUE); + calendar.set(inOutTm->tm_year + 1900, inOutTm->tm_mon, inOutTm->tm_mday, + inOutTm->tm_hour, inOutTm->tm_min, inOutTm->tm_sec); + + UDate timeInMillis = calendar.getTime(icuStatus); + if (!U_SUCCESS(icuStatus)) + return B_ERROR; + timeOut = (time_t)((int64_t)timeInMillis / 1000); + + return _FillTmValues(icuTimeZone, &timeOut, inOutTm); +} + + } // namespace Libroot } // namespace BPrivate diff --git a/src/system/libroot/posix/time/localtime.cpp b/src/system/libroot/posix/time/localtime.cpp index cc4a2b49e2..739712fb81 100644 --- a/src/system/libroot/posix/time/localtime.cpp +++ b/src/system/libroot/posix/time/localtime.cpp @@ -33,10 +33,11 @@ long timezone = 0; int daylight = 0; -// These two functions are used as a fallback when the locale backend could not +// These three functions are used as a fallback when the locale backend could not // be loaded. They are implemented in localtime_fading_out.c. extern "C" struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp); extern "C" time_t __mktime_fallback(struct tm* tmp); +extern "C" time_t __timegm_fallback(struct tm* tmp); extern "C" void @@ -143,3 +144,29 @@ mktime(struct tm* inTm) // implementation. return __mktime_fallback(inTm); } + + +extern "C" time_t +timegm(struct tm* inTm) +{ + if (inTm == NULL) { + __set_errno(EINVAL); + return -1; + } + tzset(); + if (gLocaleBackend != NULL) { + time_t timeOut; + status_t status = gLocaleBackend->Timegm(inTm, timeOut); + + if (status != B_OK) { + __set_errno(EOVERFLOW); + return -1; + } + + return timeOut; + } + + // without a locale backend, we fall back to using a basic timegm + // implementation. + return __timegm_fallback(inTm); +} diff --git a/src/system/libroot/posix/time/localtime_fading_out.c b/src/system/libroot/posix/time/localtime_fading_out.c index 081254a401..5d0a690f94 100644 --- a/src/system/libroot/posix/time/localtime_fading_out.c +++ b/src/system/libroot/posix/time/localtime_fading_out.c @@ -169,7 +169,7 @@ static int tmcomp P((const struct tm * atmp, */ struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp); time_t __mktime_fallback(struct tm* tmp); -time_t timegm(struct tm* const tmp); +time_t __timegm_fallback(struct tm* const tmp); static struct state lclmem; static struct state gmtmem; @@ -831,10 +831,8 @@ __mktime_fallback(struct tm* tmp) } - time_t -timegm(tmp) -struct tm * const tmp; +__timegm_fallback(struct tm* const tmp) { tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L);