Files
AnyPS5/core/libs/tests/GuestCharacter.cpp
T
JJenkxandClaude Opus 5.5 d2e18d53b3 fix(libc): return the console's class bits from the ctype functions
isalpha, isdigit, isspace and the other ctype classifiers returned 1 for
a match. The libc.prx bundled with eleven titles returns the matching
bits of its classification table instead, for example 0x20 from isdigit,
0x04 from isspace(' ') and 0x40 from isspace('\t'), and its table marks
tab with 0x400, which isblank returns. The classifiers now return the
exported table's bits under the console's masks, and the table gains the
tab bit; which characters match is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-23 16:18:56 -04:00

91 lines
5.0 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cctype>
#include <clocale>
#include <cstdio>
#include <cstdlib>
#include <cstring>
extern "C" {
int APS5_VABI isupper_nid_postfix(int);
int APS5_VABI islower_nid_postfix(int);
int APS5_VABI isalpha_nid_postfix(int);
int APS5_VABI isdigit_nid_postfix(int);
int APS5_VABI isalnum_nid_postfix(int);
int APS5_VABI isspace_nid_postfix(int);
int APS5_VABI isblank_nid_postfix(int);
int APS5_VABI iscntrl_nid_postfix(int);
int APS5_VABI isprint_nid_postfix(int);
int APS5_VABI isgraph_nid_postfix(int);
int APS5_VABI ispunct_nid_postfix(int);
int APS5_VABI isxdigit_nid_postfix(int);
int APS5_VABI toupper_nid_postfix(int);
int APS5_VABI tolower_nid_postfix(int);
const short* APS5_VABI _Getptolower_nid_postfix();
const short* APS5_VABI _Getptoupper_nid_postfix();
const char* APS5_VABI setlocale_nid_postfix(int, const char*);
}
static void Require(bool value) { if (!value) std::abort(); }
static int ConsoleClass(int c) {
if (c < 0 || c > 255) return 0;
int bits = 0;
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) bits |= 0x01;
if (c >= 'A' && c <= 'Z') bits |= 0x02;
if (c == ' ') bits |= 0x04;
if (c >= 33 && c <= 126 && !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z')) bits |= 0x08;
if (c >= 'a' && c <= 'z') bits |= 0x10;
if (c >= '0' && c <= '9') bits |= 0x20;
if (c >= '\t' && c <= '\r') bits |= 0x40;
if (c < 32 || c == 127) bits |= 0x80;
if (c == '\t') bits |= 0x400;
return bits;
}
static void CheckConsoleClassValues() {
Require(isspace_nid_postfix(' ') == 0x04 && isspace_nid_postfix('\t') == 0x40 && isspace_nid_postfix('\n') == 0x40);
Require(isblank_nid_postfix(' ') == 0x04 && isblank_nid_postfix('\t') == 0x400 && iscntrl_nid_postfix('\t') == 0x80);
Require(isdigit_nid_postfix('0') == 0x20 && isalnum_nid_postfix('0') == 0x20 && isxdigit_nid_postfix('0') == 0x01);
Require(isupper_nid_postfix('A') == 0x02 && isalpha_nid_postfix('A') == 0x02 && isxdigit_nid_postfix('F') == 0x01 && isxdigit_nid_postfix('G') == 0);
Require(islower_nid_postfix('a') == 0x10 && isalpha_nid_postfix('a') == 0x10 && isprint_nid_postfix(' ') == 0x04 && isgraph_nid_postfix(' ') == 0);
Require(ispunct_nid_postfix('_') == 0x08 && isgraph_nid_postfix('_') == 0x08 && isprint_nid_postfix('_') == 0x08 && iscntrl_nid_postfix(127) == 0x80);
for (int c = EOF; c <= 255; ++c) {
const int bits = ConsoleClass(c);
Require(isupper_nid_postfix(c) == (bits & 0x02) && islower_nid_postfix(c) == (bits & 0x10) && isalpha_nid_postfix(c) == (bits & 0x12));
Require(isdigit_nid_postfix(c) == (bits & 0x20) && isalnum_nid_postfix(c) == (bits & 0x32) && isxdigit_nid_postfix(c) == (bits & 0x01));
Require(isspace_nid_postfix(c) == (bits & 0x44) && isblank_nid_postfix(c) == (bits & 0x404) && iscntrl_nid_postfix(c) == (bits & 0x80));
Require(isprint_nid_postfix(c) == (bits & 0x3e) && isgraph_nid_postfix(c) == (bits & 0x3a) && ispunct_nid_postfix(c) == (bits & 0x08));
}
}
int main() {
CheckConsoleClassValues();
Require(std::setlocale(LC_CTYPE, "C") != nullptr);
for (int category = 0; category <= 6; ++category) {
const char* result = setlocale_nid_postfix(category, "C");
Require(result != nullptr && std::strcmp(result, "C") == 0);
result = setlocale_nid_postfix(category, "POSIX");
Require(result != nullptr && std::strcmp(result, "C") == 0);
result = setlocale_nid_postfix(category, nullptr);
Require(result != nullptr && std::strcmp(result, "C") == 0);
result = setlocale_nid_postfix(category, "");
Require(result != nullptr && std::strcmp(result, "C") == 0);
Require(setlocale_nid_postfix(category, "en_US.UTF-8") == nullptr);
}
Require(setlocale_nid_postfix(-1, "C") == nullptr);
Require(setlocale_nid_postfix(7, "C") == nullptr);
for (int c = EOF; c <= 255; ++c) {
Require(bool(isupper_nid_postfix(c)) == bool(std::isupper(c)));
Require(bool(islower_nid_postfix(c)) == bool(std::islower(c)));
Require(bool(isalpha_nid_postfix(c)) == bool(std::isalpha(c)));
Require(bool(isdigit_nid_postfix(c)) == bool(std::isdigit(c)));
Require(bool(isalnum_nid_postfix(c)) == bool(std::isalnum(c)));
Require(bool(isspace_nid_postfix(c)) == bool(std::isspace(c)));
Require(bool(isblank_nid_postfix(c)) == bool(std::isblank(c)));
Require(bool(iscntrl_nid_postfix(c)) == bool(std::iscntrl(c)));
Require(bool(isprint_nid_postfix(c)) == bool(std::isprint(c)));
Require(bool(isgraph_nid_postfix(c)) == bool(std::isgraph(c)));
Require(bool(ispunct_nid_postfix(c)) == bool(std::ispunct(c)));
Require(bool(isxdigit_nid_postfix(c)) == bool(std::isxdigit(c)));
Require(toupper_nid_postfix(c) == std::toupper(c));
Require(tolower_nid_postfix(c) == std::tolower(c));
Require(toupper_nid_postfix(c) == _Getptoupper_nid_postfix()[c]);
Require(tolower_nid_postfix(c) == _Getptolower_nid_postfix()[c]);
}
}