232 lines
7.4 KiB
C++
232 lines
7.4 KiB
C++
#ifndef CORE_LIBS_PRX_LIBC_INCLUDE_SONYCRT_HPP
|
|
#define CORE_LIBS_PRX_LIBC_INCLUDE_SONYCRT_HPP
|
|
|
|
#include <cfenv>
|
|
#include <cerrno>
|
|
#include <climits>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <ctime>
|
|
#include <mutex>
|
|
#include <stdexcept>
|
|
|
|
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/GuestTime.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
|
|
extern "C" GuestTm* APS5_VABI localtime_s_nid_postfix(const std::int64_t* timer, GuestTm* result);
|
|
|
|
namespace {
|
|
|
|
using SonyConstraintHandler = void (*)(const char* message, void* pointer, int error);
|
|
|
|
inline void SonyDefaultConstraintHandler(const char* message, void* pointer, int error) {
|
|
(void)message;
|
|
(void)pointer;
|
|
(void)error;
|
|
std::abort();
|
|
}
|
|
|
|
inline std::mutex& SonyConstraintMutex() {
|
|
static std::mutex mutex;
|
|
return mutex;
|
|
}
|
|
|
|
inline SonyConstraintHandler& SonyConstraintHandlerSlot() {
|
|
static SonyConstraintHandler handler = SonyDefaultConstraintHandler;
|
|
return handler;
|
|
}
|
|
|
|
inline void SonyInvokeConstraintHandler(const char* message, void* pointer, int error) {
|
|
SonyConstraintHandler handler = nullptr;
|
|
{
|
|
std::lock_guard<std::mutex> lock(SonyConstraintMutex());
|
|
handler = SonyConstraintHandlerSlot();
|
|
}
|
|
if (handler) handler(message, pointer, error);
|
|
}
|
|
|
|
inline char* SonyStrtokS(char* str, const char* delim, char** context) {
|
|
if (!delim || !context) return nullptr;
|
|
char* cursor = str ? str : *context;
|
|
if (!cursor) return nullptr;
|
|
cursor += std::strspn(cursor, delim);
|
|
if (*cursor == '\0') {
|
|
*context = cursor;
|
|
return nullptr;
|
|
}
|
|
char* token = cursor;
|
|
cursor += std::strcspn(cursor, delim);
|
|
if (*cursor != '\0') {
|
|
*cursor = '\0';
|
|
*context = cursor + 1;
|
|
} else {
|
|
*context = cursor;
|
|
}
|
|
return token;
|
|
}
|
|
|
|
inline int SonyFormatAsctime(char* buffer, std::size_t size, const GuestTm& time) {
|
|
static const char* const days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
|
static const char* const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
|
if (!buffer || size < 26) return EINVAL;
|
|
if (time.tm_wday < 0 || time.tm_wday > 6 || time.tm_mon < 0 || time.tm_mon > 11) return EINVAL;
|
|
std::snprintf(buffer, size, "%.3s %.3s %2d %.2d:%.2d:%.2d %4d\n", days[time.tm_wday], months[time.tm_mon],
|
|
time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, 1900 + time.tm_year);
|
|
return 0;
|
|
}
|
|
|
|
inline int SonyCtimeS(char* buffer, std::size_t size, const std::int64_t* time) {
|
|
if (!buffer || size < 26 || !time) return EINVAL;
|
|
GuestTm parts{};
|
|
if (!localtime_s_nid_postfix(time, &parts)) return EINVAL;
|
|
return SonyFormatAsctime(buffer, size, parts);
|
|
}
|
|
|
|
inline int SonyAsctimeS(char* buffer, std::size_t size, const GuestTm* time) {
|
|
if (!buffer || size < 26 || !time) return EINVAL;
|
|
return SonyFormatAsctime(buffer, size, *time);
|
|
}
|
|
|
|
inline void SonyIgnoreHandlerS(const char* message, void* pointer, int error) {
|
|
(void)message;
|
|
(void)pointer;
|
|
(void)error;
|
|
}
|
|
|
|
inline void* SonySetConstraintHandlerS(void* handler) {
|
|
std::lock_guard<std::mutex> lock(SonyConstraintMutex());
|
|
void* previous = reinterpret_cast<void*>(SonyConstraintHandlerSlot());
|
|
SonyConstraintHandlerSlot() = handler ? reinterpret_cast<SonyConstraintHandler>(handler) : SonyDefaultConstraintHandler;
|
|
return previous;
|
|
}
|
|
|
|
inline int SonyWcscpyS(std::uint16_t* dest, std::size_t size, const std::uint16_t* src) {
|
|
if (!dest || !src || size == 0) {
|
|
SonyInvokeConstraintHandler("wcscpy_s", dest, EINVAL);
|
|
return EINVAL;
|
|
}
|
|
std::size_t i = 0;
|
|
while (i + 1 < size && src[i] != 0) {
|
|
dest[i] = src[i];
|
|
++i;
|
|
}
|
|
dest[i] = 0;
|
|
if (src[i] != 0) {
|
|
SonyInvokeConstraintHandler("wcscpy_s", dest, ERANGE);
|
|
return ERANGE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
inline std::size_t SonyMbstowcs(std::uint16_t* dest, const char* src, std::size_t size) {
|
|
if (!src) return 0;
|
|
if (!dest) return std::strlen(src);
|
|
std::size_t converted = 0;
|
|
while (converted < size) {
|
|
const auto value = static_cast<unsigned char>(src[converted]);
|
|
dest[converted] = value;
|
|
if (value == 0) return converted;
|
|
++converted;
|
|
}
|
|
return converted;
|
|
}
|
|
|
|
inline SonyLconv* SonyLocaleconv(void) {
|
|
static char empty[] = "";
|
|
static char point[] = ".";
|
|
static char falseText[] = "false";
|
|
static char trueText[] = "true";
|
|
static SonyLconv value = [] {
|
|
SonyLconv init{};
|
|
for (auto& pointer : init.monetary) pointer = empty;
|
|
for (auto& byte : init.chars) byte = CHAR_MAX;
|
|
init.decimal_point = point;
|
|
init.grouping = empty;
|
|
init.thousands_sep = empty;
|
|
init.frac_grouping = empty;
|
|
init.frac_sep = empty;
|
|
init.false_text = falseText;
|
|
init.true_text = trueText;
|
|
init.no_text = empty;
|
|
init.yes_text = empty;
|
|
return init;
|
|
}();
|
|
return &value;
|
|
}
|
|
|
|
inline int SonyFpclassifyd(double value) {
|
|
if (std::isnan(value)) return 2;
|
|
if (std::isinf(value)) return 1;
|
|
if (value == 0.0) return 0;
|
|
if (std::fpclassify(value) == FP_SUBNORMAL) return -2;
|
|
return -1;
|
|
}
|
|
|
|
inline double SonySinh(double x, double y) {
|
|
return y * std::sinh(x);
|
|
}
|
|
|
|
inline int SonyFltrounds(void) {
|
|
switch (std::fegetround()) {
|
|
case FE_TONEAREST: return 1;
|
|
case FE_DOWNWARD: return 3;
|
|
case FE_UPWARD: return 2;
|
|
case FE_TOWARDZERO: return 0;
|
|
default: return 1;
|
|
}
|
|
}
|
|
|
|
inline unsigned __int128 SonyUdivmod128(unsigned __int128 dividend, unsigned __int128 divisor, unsigned __int128* remainderOut) {
|
|
unsigned __int128 quotient = 0;
|
|
unsigned __int128 remainder = 0;
|
|
for (int i = 127; i >= 0; --i) {
|
|
remainder = (remainder << 1) | ((dividend >> i) & 1);
|
|
if (remainder >= divisor) {
|
|
remainder -= divisor;
|
|
quotient |= (unsigned __int128)1 << i;
|
|
}
|
|
}
|
|
*remainderOut = remainder;
|
|
return quotient;
|
|
}
|
|
|
|
inline unsigned __int128 SonyUdivti3(unsigned __int128 dividend, unsigned __int128 divisor) {
|
|
if (divisor == 0) throw std::runtime_error("__udivti3: integer divide by zero");
|
|
unsigned __int128 remainder = 0;
|
|
return SonyUdivmod128(dividend, divisor, &remainder);
|
|
}
|
|
|
|
inline unsigned __int128 SonyUmodti3(unsigned __int128 dividend, unsigned __int128 divisor) {
|
|
if (divisor == 0) {
|
|
char message[96];
|
|
std::snprintf(message, sizeof(message), "__umodti3: integer divide by zero (0x%016llx%016llx %% 0)",
|
|
(unsigned long long)(dividend >> 64), (unsigned long long)dividend);
|
|
throw std::runtime_error(message);
|
|
}
|
|
unsigned __int128 remainder = 0;
|
|
SonyUdivmod128(dividend, divisor, &remainder);
|
|
return remainder;
|
|
}
|
|
|
|
inline __int128 SonyDivti3(__int128 dividend, __int128 divisor) {
|
|
if (divisor == 0) throw std::runtime_error("__divti3: integer divide by zero");
|
|
const bool negative = (dividend < 0) != (divisor < 0);
|
|
const unsigned __int128 magnitudeDividend = dividend < 0
|
|
? (unsigned __int128)0 - (unsigned __int128)dividend
|
|
: (unsigned __int128)dividend;
|
|
const unsigned __int128 magnitudeDivisor = divisor < 0
|
|
? (unsigned __int128)0 - (unsigned __int128)divisor
|
|
: (unsigned __int128)divisor;
|
|
const unsigned __int128 magnitude = SonyUdivti3(magnitudeDividend, magnitudeDivisor);
|
|
return (__int128)(negative ? (unsigned __int128)0 - magnitude : magnitude);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|