diff --git a/external/libwolv b/external/libwolv index 1063613e..25907ccf 160000 --- a/external/libwolv +++ b/external/libwolv @@ -1 +1 @@ -Subproject commit 1063613e87100910dfae254ae9af0111203c768b +Subproject commit 25907ccf6459658b1f610eec0aaee155730d1459 diff --git a/lib/include/pl/pattern_language.hpp b/lib/include/pl/pattern_language.hpp index 2cffb219..0e5e1027 100644 --- a/lib/include/pl/pattern_language.hpp +++ b/lib/include/pl/pattern_language.hpp @@ -23,6 +23,7 @@ #include #include +#include namespace pl { @@ -134,6 +135,16 @@ namespace pl { */ void abort(); + /** + * @brief Get locale (currently only used for date/time formatting) + */ + const wolv::util::Locale& getLocale() const; + + /** + * @brief Set locale (currently only used for date/time formatting) + */ + void setLocale(const wolv::util::Locale &lc); + /** * @brief Sets the data source for the pattern language * @param baseAddress Base address of the data source @@ -416,6 +427,7 @@ namespace pl { private: Internals m_internals; + wolv::util::Locale m_locale; std::vector m_compileErrors; std::optional m_currError; std::map m_defines; diff --git a/lib/source/pl/lib/std/time.cpp b/lib/source/pl/lib/std/time.cpp index 11a05b70..559553c4 100644 --- a/lib/source/pl/lib/std/time.cpp +++ b/lib/source/pl/lib/std/time.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -11,6 +12,9 @@ namespace pl::lib::libstd::time { + const std::string s_invalid = "Invalid"; + const std::string s_canNotFormat = "Can not format"; + static u128 packTMValue(const std::tm &tm, pl::PatternLanguage &runtime) { auto endian = runtime.getInternals().evaluator->getDefaultEndian(); std::tm tmCopy = tm; @@ -65,29 +69,21 @@ namespace pl::lib::libstd::time { /* to_local(time) */ runtime.addFunction(nsStdTime, "to_local", FunctionParameterCount::exactly(1), [&runtime](Evaluator *, auto params) -> std::optional { auto time = time_t(params[0].toUnsigned()); + auto localTime = std::localtime(&time); - try { - auto localTime = std::localtime(&time); - if (localTime == nullptr) return u128(0); + if (localTime == nullptr) return u128(0); - return { packTMValue(*localTime, runtime) }; - } catch (const fmt::format_error&) { - return u128(0); - } + return { packTMValue(*localTime, runtime) }; }); /* to_utc(time) */ runtime.addFunction(nsStdTime, "to_utc", FunctionParameterCount::exactly(1), [&runtime](Evaluator *, auto params) -> std::optional { auto time = time_t(params[0].toUnsigned()); + auto gmTime = std::gmtime(&time); - try { - auto gmTime = std::gmtime(&time); - if (gmTime == nullptr) return u128(0); + if (gmTime == nullptr) return u128(0); - return { packTMValue(*gmTime, runtime) }; - } catch (const fmt::format_error&) { - return u128(0); - } + return { packTMValue(*gmTime, runtime) }; }); /* to_epoch(structured_time) */ @@ -117,6 +113,94 @@ namespace pl::lib::libstd::time { return { fmt::format(fmt::runtime(fmt::format("{{:{}}}", formatString)), time) }; }); + + /* format_tt(time_t) */ + runtime.addFunction(nsStdTime, "format_tt", FunctionParameterCount::exactly(1), [&runtime](Evaluator *, auto params) -> std::optional { + auto tt = params[0].toUnsigned(); + const wolv::util::Locale &lc = runtime.getLocale(); + + using wolv::util::DTOpts; + auto optval = wolv::util::formatTT(lc, tt, DTOpts::TT64 | DTOpts::DandT); + if (!optval) { + return s_canNotFormat; + } + + return optval; + }); + + /* format_dos_date(time_t) */ + runtime.addFunction(nsStdTime, "format_dos_date", FunctionParameterCount::exactly(1), [&runtime](Evaluator *, auto params) -> std::optional { + auto p = params[0].toUnsigned(); + + struct DOSDate { + u16 day : 5; + u16 month : 4; + u16 year : 7; + }; + + DOSDate dd; + std::memcpy(&dd, &p, sizeof(dd)); + if ( (dd.day<1 || dd.day>31) || (dd.month<1 || dd.month>12) ) { + return s_invalid; + } + + std::tm tm{}; + tm.tm_year = dd.year + 80; + tm.tm_mon = dd.month - 1; + tm.tm_mday = dd.day; + +#if defined(OS_WINDOWS) + time_t tt = _mkgmtime(&tm); +#else + time_t tt = timegm(&tm); +#endif + if (tt == -1) { + return s_canNotFormat; + } + + const wolv::util::Locale &lc = runtime.getLocale(); + + using wolv::util::DTOpts; + auto optval = wolv::util::formatTT(lc, tt, DTOpts::TT64 | DTOpts::D); + if (!optval) { + return s_canNotFormat; + } + + return *optval; + }); + + /* format_dos_time(time_t) */ + runtime.addFunction(nsStdTime, "format_dos_time", FunctionParameterCount::exactly(1), [&runtime](Evaluator *, auto params) -> std::optional { + auto p = params[0].toUnsigned(); + + struct DOSTime { + u16 seconds : 5; + u16 minutes : 6; + u16 hours : 5; + }; + + DOSTime dt; + std::memcpy(&dt, &p, sizeof(dt)); + + if ( (dt.hours<0 || dt.hours>23) || + (dt.minutes<0 || dt.minutes>59) || + (dt.seconds<0 || dt.seconds>29) ) + { + return s_invalid; + } + + time_t tt = dt.hours*60*60 + dt.minutes*60 + dt.seconds*2; + + const wolv::util::Locale &lc = runtime.getLocale(); + + using wolv::util::DTOpts; + auto optval = wolv::util::formatTT(lc, tt, DTOpts::TT64 | DTOpts::T); + if (!optval) { + return s_canNotFormat; + } + + return *optval; + }); } } diff --git a/lib/source/pl/pattern_language.cpp b/lib/source/pl/pattern_language.cpp index 54c4e24c..2a2116de 100644 --- a/lib/source/pl/pattern_language.cpp +++ b/lib/source/pl/pattern_language.cpp @@ -380,6 +380,14 @@ namespace pl { this->m_aborted = true; } + const wolv::util::Locale& PatternLanguage::getLocale() const { + return m_locale; + } + + void PatternLanguage::setLocale(const wolv::util::Locale &lc) { + m_locale = lc; + } + void PatternLanguage::setIncludePaths(const std::vector& paths) { this->m_fileResolver.setIncludePaths(paths); }