mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
feat(libc): sscanf_s on linux
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01ButHENCbXXt8h4EZuWUabJ
This commit is contained in:
1 parent
7656458121
commit
20cc23438f
3 files changed
+133
-5
No files matched your search
@@ -81,11 +81,6 @@ int APS5_VABI fscanf_nid_postfix() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sscanf_s_nid_postfix() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI vswprintf_nid_postfix() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/VarArgsAbi.hpp"
|
||||
#include "prx/libc/include/FileStream.hpp"
|
||||
@@ -143,6 +147,117 @@ int APS5_VABI sscanf_nid_postfix(VA_ARGS) {
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int APS5_VABI sscanf_s_nid_postfix(const char* buffer, const char* format, ...) {
|
||||
(void)buffer;
|
||||
(void)format;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int APS5_VABI sscanf_s_nid_postfix(const char* buffer, const char* format, ...) {
|
||||
if (buffer == nullptr || format == nullptr) return EOF;
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
const char* input = buffer;
|
||||
int assigned = 0;
|
||||
bool converted = false;
|
||||
const char* cursor = format;
|
||||
const auto finish = [&](int result) {
|
||||
va_end(args);
|
||||
return result;
|
||||
};
|
||||
while (*cursor != '\0') {
|
||||
if (std::isspace(static_cast<unsigned char>(*cursor))) {
|
||||
while (std::isspace(static_cast<unsigned char>(*cursor))) ++cursor;
|
||||
while (std::isspace(static_cast<unsigned char>(*input))) ++input;
|
||||
continue;
|
||||
}
|
||||
if (*cursor != '%' || cursor[1] == '%') {
|
||||
const char expected = *cursor == '%' ? '%' : *cursor;
|
||||
cursor += *cursor == '%' ? 2 : 1;
|
||||
if (expected == '%') while (std::isspace(static_cast<unsigned char>(*input))) ++input;
|
||||
if (*input != expected) return finish(!converted && *input == '\0' ? EOF : assigned);
|
||||
++input;
|
||||
continue;
|
||||
}
|
||||
++cursor;
|
||||
const bool suppress = *cursor == '*';
|
||||
if (suppress) ++cursor;
|
||||
unsigned long width = 0;
|
||||
while (std::isdigit(static_cast<unsigned char>(*cursor))) width = width * 10 + static_cast<unsigned long>(*cursor++ - '0');
|
||||
const char* lengthStart = cursor;
|
||||
while (std::strchr("hljztL", *cursor) != nullptr && *cursor != '\0') ++cursor;
|
||||
const std::string length(lengthStart, cursor);
|
||||
const char conversion = *cursor;
|
||||
if (conversion == '\0') return finish(assigned);
|
||||
std::string specifier(1, conversion);
|
||||
if (conversion == '[') {
|
||||
const char* setStart = cursor++;
|
||||
if (*cursor == '^') ++cursor;
|
||||
if (*cursor == ']') ++cursor;
|
||||
while (*cursor != '\0' && *cursor != ']') ++cursor;
|
||||
if (*cursor != ']') return finish(assigned);
|
||||
specifier.assign(setStart, cursor + 1);
|
||||
}
|
||||
++cursor;
|
||||
if (conversion == 'n') {
|
||||
if (!suppress) *va_arg(args, int*) = static_cast<int>(input - buffer);
|
||||
continue;
|
||||
}
|
||||
if (conversion != 'c' && conversion != '[') {
|
||||
const char* probe = input;
|
||||
while (std::isspace(static_cast<unsigned char>(*probe))) ++probe;
|
||||
if (*probe == '\0') return finish(converted ? assigned : EOF);
|
||||
}
|
||||
const bool sized = conversion == 's' || conversion == 'c' || conversion == '[';
|
||||
std::string directive = "%";
|
||||
void* target = nullptr;
|
||||
if (suppress) directive += '*';
|
||||
else target = va_arg(args, void*);
|
||||
if (sized && !suppress) {
|
||||
const auto capacity = static_cast<unsigned long>(va_arg(args, unsigned int));
|
||||
const unsigned long limit = conversion == 'c' ? capacity : (capacity == 0 ? 0 : capacity - 1);
|
||||
const unsigned long wanted = conversion == 'c' ? (width == 0 ? 1 : width) : width;
|
||||
if (limit == 0 || (conversion == 'c' && wanted > limit)) {
|
||||
if (capacity != 0) static_cast<char*>(target)[0] = '\0';
|
||||
return finish(assigned);
|
||||
}
|
||||
width = wanted == 0 ? limit : std::min(wanted, limit);
|
||||
}
|
||||
if (width != 0) directive += std::to_string(width);
|
||||
directive += length;
|
||||
directive += specifier;
|
||||
directive += "%n";
|
||||
int consumed = -1;
|
||||
const int matched = suppress ? std::sscanf(input, directive.c_str(), &consumed) : std::sscanf(input, directive.c_str(), target, &consumed);
|
||||
if (consumed < 0 || (!suppress && matched != 1)) return finish(!converted && *input == '\0' ? EOF : assigned);
|
||||
if (sized && !suppress && conversion != 'c') {
|
||||
const char next = input[consumed];
|
||||
bool overflow = false;
|
||||
if (conversion == 's') overflow = next != '\0' && !std::isspace(static_cast<unsigned char>(next));
|
||||
else if (next != '\0') {
|
||||
char probe[2];
|
||||
const std::string test = "%1" + specifier;
|
||||
overflow = std::sscanf(input + consumed, test.c_str(), probe) == 1;
|
||||
}
|
||||
if (overflow) {
|
||||
static_cast<char*>(target)[0] = '\0';
|
||||
return finish(assigned);
|
||||
}
|
||||
}
|
||||
input += consumed;
|
||||
converted = true;
|
||||
if (!suppress) ++assigned;
|
||||
}
|
||||
return finish(assigned);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int APS5_VABI vprintf_nid_postfix(const char* str, VaList* c) {
|
||||
#ifdef _WIN32
|
||||
return LibcDetail::PrintWindows(str, c);
|
||||
|
||||
@@ -15,6 +15,7 @@ std::size_t APS5_VABI strlcat_nid_postfix(char*, const char*, std::size_t);
|
||||
char* APS5_VABI strtok_r_nid_postfix(char*, const char*, char**);
|
||||
char* APS5_VABI strtok_nid_postfix(char*, const char*);
|
||||
char* APS5_VABI strcasestr_nid_postfix(const char*, const char*);
|
||||
int APS5_VABI sscanf_s_nid_postfix(const char*, const char*, ...);
|
||||
}
|
||||
|
||||
static void Require(bool condition) {
|
||||
@@ -24,7 +25,24 @@ static void Require(bool condition) {
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckSscanfS() {
|
||||
#ifndef _WIN32
|
||||
int number = 0;
|
||||
char word[4] = "zz";
|
||||
char letter = 0;
|
||||
char value[8] = {};
|
||||
Require(sscanf_s_nid_postfix(" 12 abc x", "%d %s %c", &number, word, 4u, &letter, 1u) == 3 && number == 12 && std::strcmp(word, "abc") == 0 && letter == 'x');
|
||||
Require(sscanf_s_nid_postfix("12 abcd", "%d %s", &number, word, 4u) == 1 && word[0] == '\0');
|
||||
Require(sscanf_s_nid_postfix("key=val", "%3[a-z]=%3s", word, 4u, value, 8u) == 2 && std::strcmp(word, "key") == 0 && std::strcmp(value, "val") == 0);
|
||||
int position = 0;
|
||||
Require(sscanf_s_nid_postfix("7 %", "%d %%%n", &number, &position) == 1 && position == 3);
|
||||
Require(sscanf_s_nid_postfix(" ", "%d", &number) == EOF);
|
||||
Require(sscanf_s_nid_postfix("x", "%d", &number) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main() {
|
||||
CheckSscanfS();
|
||||
Require(std::strcmp(basename_nid_postfix(nullptr), ".") == 0);
|
||||
Require(std::strcmp(basename_nid_postfix(""), ".") == 0);
|
||||
Require(std::strcmp(basename_nid_postfix("////"), "/") == 0);
|
||||
|
||||
Reference in new issue
Block a user