#include "SceTypes.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include "prx/libc/include/SonyCrt.hpp" #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { SonyLconv* APS5_VABI sceAmprLocaleconv(void); double APS5_VABI sceAmprSinh(double x, double y); char* APS5_VABI sceAmprStrtokS(char* str, const char* delim, char** context); int APS5_VABI sceAmprCtimeS(char* buffer, std::size_t size, const std::int64_t* time); int APS5_VABI sceAmprWcscpyS(std::uint16_t* dest, std::size_t size, const std::uint16_t* src); void* APS5_VABI sceAmprSetConstraintHandlerS(void* handler); int APS5_VABI sceAmprFltrounds(void); void APS5_VABI sceAmprIgnoreHandlerS(const char* message, void* pointer, int error); std::size_t APS5_VABI sceAmprMbstowcs(std::uint16_t* dest, const char* src, std::size_t size); int APS5_VABI sceAmprAsctimeS(char* buffer, std::size_t size, const GuestTm* time); int APS5_VABI ctime_s_nid_postfix(char* buffer, std::size_t size, const std::int64_t* time); int APS5_VABI asctime_s_nid_postfix(char* buffer, std::size_t size, const GuestTm* time); std::size_t APS5_VABI mbstowcs_nid_postfix(std::uint16_t* dest, const char* src, std::size_t size); char* APS5_VABI strtok_s_nid_postfix(char* str, const char* delim, char** context); int APS5_VABI __fpclassifyd_nid_postfix(double value); unsigned __int128 APS5_VABI __udivti3_nid_postfix(unsigned __int128 dividend, unsigned __int128 divisor); __int128 APS5_VABI __divti3_nid_postfix(__int128 dividend, __int128 divisor); unsigned __int128 APS5_VABI __umodti3_nid_postfix(unsigned __int128 dividend, unsigned __int128 divisor); SonyLconv* APS5_VABI localeconv_nid_postfix(void); int APS5_VABI sceAmprFpclassifyd(double value); unsigned int APS5_VABI _ZSt14_Random_devicev_nid_postfix(); } #define Require(condition) do { if (!(condition)) { std::fprintf(stderr, "guest_crt: line %d: %s\n", __LINE__, #condition); std::abort(); } } while (0) static int g_handlerCalls = 0; static void CountingHandler(const char* message, void* pointer, int error) { (void)message; (void)pointer; (void)error; ++g_handlerCalls; } int main() { Require(sceAmprFpclassifyd(std::numeric_limits::quiet_NaN()) == 2); Require(sceAmprFpclassifyd(std::numeric_limits::infinity()) == 1); Require(sceAmprFpclassifyd(0.0) == 0); Require(sceAmprFpclassifyd(std::numeric_limits::denorm_min()) == -2); Require(sceAmprFpclassifyd(1.5) == -1); Require(__fpclassifyd_nid_postfix(0.0) == 0); Require(sceAmprFltrounds() == 1); Require(std::fesetround(FE_DOWNWARD) == 0); Require(sceAmprFltrounds() == 3); Require(std::fesetround(FE_TONEAREST) == 0); Require(sceAmprFltrounds() == 1); Require(sceAmprSinh(1.0, 2.0) == 2.0 * std::sinh(1.0)); Require(sceAmprSinh(0.0, 5.0) == 0.0); SonyLconv* locale = sceAmprLocaleconv(); Require(reinterpret_cast(&locale->decimal_point) - reinterpret_cast(locale) == 0x48); Require(std::strcmp(locale->decimal_point, ".") == 0); Require(std::memcmp(localeconv_nid_postfix()->chars, locale->chars, sizeof(locale->chars)) == 0); Require(std::strcmp(localeconv_nid_postfix()->decimal_point, ".") == 0); for (const char* text : locale->monetary) Require(text != nullptr && text[0] == '\0'); for (char value : locale->chars) Require(value == CHAR_MAX); Require(std::strcmp(locale->false_text, "false") == 0 && std::strcmp(locale->true_text, "true") == 0); Require(locale->grouping[0] == '\0' && locale->thousands_sep[0] == '\0'); Require(__udivti3_nid_postfix(100, 3) == 33); Require(SonyUdivti3(100, 3) == 33); Require(SonyUdivti3(0, 5) == 0); Require(SonyUdivti3((unsigned __int128)1 << 100, 3) == (((unsigned __int128)1 << 100) / 3)); bool trapped = false; try { SonyUdivti3(1, 0); } catch (const std::exception&) { trapped = true; } Require(trapped); Require(__divti3_nid_postfix(100, 3) == 33); Require(__divti3_nid_postfix(-100, 3) == -33); Require(__divti3_nid_postfix(100, -3) == -33); Require(__divti3_nid_postfix(-100, -3) == 33); Require(SonyDivti3(0, 5) == 0); const __int128 large = (__int128)1 << 100; Require(SonyDivti3(large, 3) == large / 3); Require(SonyDivti3(-large, 3) == -(large / 3)); Require(SonyDivti3(large, -3) == -(large / 3)); Require(SonyDivti3(-large, -3) == large / 3); const __int128 minimum = (__int128)((unsigned __int128)1 << 127); const __int128 maximum = (__int128)(((unsigned __int128)1 << 127) - 1); Require(SonyDivti3(minimum, 1) == minimum); Require(SonyDivti3(minimum, -1) == minimum); Require(SonyDivti3(maximum, -1) == -maximum); trapped = false; try { SonyDivti3(1, 0); } catch (const std::exception&) { trapped = true; } Require(trapped); const unsigned __int128 unsignedMaximum = ~(unsigned __int128)0; const unsigned __int128 largeDivisor = ((unsigned __int128)1 << 64) + 3; Require(__umodti3_nid_postfix(100, 3) == 1); Require(__umodti3_nid_postfix(0, 5) == 0); Require(__umodti3_nid_postfix(3, 100) == 3); Require(__umodti3_nid_postfix(unsignedMaximum, 1) == 0); Require(__umodti3_nid_postfix(unsignedMaximum, unsignedMaximum) == 0); Require(__umodti3_nid_postfix(largeDivisor, largeDivisor) == 0); Require(__umodti3_nid_postfix(unsignedMaximum, 10) == 5); Require(__umodti3_nid_postfix((unsigned __int128)1 << 100, 3) == 1); Require(__umodti3_nid_postfix(unsignedMaximum, (unsigned __int128)1 << 64) == 0xFFFFFFFFFFFFFFFFull); Require(__umodti3_nid_postfix(unsignedMaximum, largeDivisor) == 8); Require(__umodti3_nid_postfix((unsigned __int128)1 << 127, largeDivisor) == 0x8000000000000006ull); Require(__umodti3_nid_postfix(unsignedMaximum - 1, unsignedMaximum) == unsignedMaximum - 1); Require(__umodti3_nid_postfix(unsignedMaximum, (unsigned __int128)1 << 127) == ((unsigned __int128)1 << 127) - 1); trapped = false; try { __umodti3_nid_postfix(((unsigned __int128)0x1234 << 64) | 0x5678, 0); } catch (const std::runtime_error& error) { trapped = std::strcmp(error.what(), "__umodti3: integer divide by zero (0x00000000000012340000000000005678 % 0)") == 0; } Require(trapped); void* previous = sceAmprSetConstraintHandlerS(reinterpret_cast(&CountingHandler)); Require(previous != nullptr); Require(previous != reinterpret_cast(&CountingHandler)); const std::uint16_t hello[] = {'h', 'i', 0}; std::uint16_t buffer[8] = {}; Require(sceAmprWcscpyS(buffer, 8, hello) == 0); Require(buffer[0] == 'h' && buffer[1] == 'i' && buffer[2] == 0); const std::uint16_t longText[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 0}; g_handlerCalls = 0; Require(sceAmprWcscpyS(buffer, 4, longText) == ERANGE); Require(g_handlerCalls == 1); Require(sceAmprWcscpyS(nullptr, 4, longText) == EINVAL); previous = sceAmprSetConstraintHandlerS(nullptr); Require(previous == reinterpret_cast(&CountingHandler)); previous = sceAmprSetConstraintHandlerS(reinterpret_cast(&CountingHandler)); Require(previous != nullptr && previous != reinterpret_cast(&CountingHandler)); sceAmprIgnoreHandlerS("msg", nullptr, 0); char text[64]; GuestTm known{}; known.tm_year = 70; known.tm_mon = 0; known.tm_mday = 1; known.tm_wday = 4; Require(sceAmprAsctimeS(text, sizeof(text), &known) == 0); Require(std::strcmp(text, "Thu Jan 1 00:00:00 1970\n") == 0); std::memset(text, 0, sizeof(text)); Require(asctime_s_nid_postfix(text, sizeof(text), &known) == 0); Require(std::strcmp(text, "Thu Jan 1 00:00:00 1970\n") == 0); known.tm_wday = 7; Require(sceAmprAsctimeS(text, sizeof(text), &known) == EINVAL); known.tm_wday = 4; Require(sceAmprAsctimeS(nullptr, sizeof(text), &known) == EINVAL); Require(sceAmprAsctimeS(text, sizeof(text), nullptr) == EINVAL); Require(sceAmprAsctimeS(text, 25, &known) == EINVAL); const std::int64_t epoch = 0; Require(sceAmprCtimeS(text, sizeof(text), &epoch) == 0); Require(std::strlen(text) == 25 && text[24] == '\n'); char libcText[64]; Require(ctime_s_nid_postfix(libcText, sizeof(libcText), &epoch) == 0); Require(std::strcmp(libcText, text) == 0); Require(sceAmprCtimeS(text, 25, &epoch) == EINVAL); Require(sceAmprCtimeS(text, sizeof(text), nullptr) == EINVAL); char line[] = "a,b,,c"; char* context = nullptr; Require(std::strcmp(sceAmprStrtokS(line, ",", &context), "a") == 0); Require(std::strcmp(sceAmprStrtokS(nullptr, ",", &context), "b") == 0); Require(std::strcmp(sceAmprStrtokS(nullptr, ",", &context), "c") == 0); Require(sceAmprStrtokS(nullptr, ",", &context) == nullptr); Require(sceAmprStrtokS(line, nullptr, &context) == nullptr); char again[] = "x y"; char* again_context = nullptr; Require(std::strcmp(strtok_s_nid_postfix(again, " ", &again_context), "x") == 0); std::uint16_t wide[8] = {}; Require(sceAmprMbstowcs(wide, "ABC", 8) == 3); Require(wide[0] == 65 && wide[1] == 66 && wide[2] == 67 && wide[3] == 0); Require(sceAmprMbstowcs(nullptr, "ABC", 8) == 3); Require(sceAmprMbstowcs(nullptr, "ABC", 0) == 3 && sceAmprMbstowcs(nullptr, "ABC", 1) == 3); Require(mbstowcs_nid_postfix(nullptr, "ABC", 0) == 3 && mbstowcs_nid_postfix(nullptr, "ABC", 1) == 3); Require(sceAmprMbstowcs(wide, "ABC", 2) == 2); Require(mbstowcs_nid_postfix(wide, "ABC", 8) == 3); const unsigned int firstRandom = _ZSt14_Random_devicev_nid_postfix(); bool randomChanged = false; for (int draw = 0; draw < 8; ++draw) randomChanged |= _ZSt14_Random_devicev_nid_postfix() != firstRandom; Require(randomChanged); }