feat(libc): implement guest formatted stream output
This commit is contained in:
parent
b8c1097db4
commit
f49cace1ca
|
|
@ -4,6 +4,7 @@
|
|||
#include <cstdarg>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/VarArgsAbi.hpp"
|
||||
#include "prx/libc/include/FileStream.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "prx/libc/include/WindowsFormatting.hpp"
|
||||
|
|
@ -11,6 +12,37 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI vfprintf_nid_postfix(FileStream* stream, const char* format, VaList* args) {
|
||||
auto* native = GetNativeStream(stream);
|
||||
#ifdef _WIN32
|
||||
std::string buffer;
|
||||
const int count = LibcDetail::FormatWindows(nullptr, 0, format, args, &buffer);
|
||||
const int result = std::fwrite(buffer.data(), 1, static_cast<size_t>(count), native) ==
|
||||
static_cast<size_t>(count) ? count : -1;
|
||||
#else
|
||||
const int result = std::vfprintf(native, format, *reinterpret_cast<std::va_list*>(args));
|
||||
#endif
|
||||
stream->SyncStatus();
|
||||
return result;
|
||||
}
|
||||
|
||||
int APS5_VABI fprintf_nid_postfix(FileStream* stream, const char* format, ...) {
|
||||
#ifdef _WIN32
|
||||
__builtin_sysv_va_list args;
|
||||
__builtin_sysv_va_start(args, format);
|
||||
#else
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
#endif
|
||||
const int result = vfprintf_nid_postfix(stream, format, reinterpret_cast<VaList*>(args));
|
||||
#ifdef _WIN32
|
||||
__builtin_sysv_va_end(args);
|
||||
#else
|
||||
va_end(args);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int APS5_VABI printf_nid_postfix(const char* format, ...) {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
extern "C" {
|
||||
extern FileStream* __stdinp_nid_postfix;
|
||||
extern FileStream* __stdoutp_nid_postfix;
|
||||
extern FileStream* __stderrp_nid_postfix;
|
||||
extern int __isthreaded_nid_postfix;
|
||||
int APS5_VABI fprintf_nid_postfix(FileStream*, const char*, ...);
|
||||
int APS5_VABI vfprintf_nid_postfix(FileStream*, const char*, void*);
|
||||
int APS5_VABI fgetc_nid_postfix(FileStream*);
|
||||
int APS5_VABI fputc_nid_postfix(int, FileStream*);
|
||||
int APS5_VABI __srget_nid_postfix(FileStream*);
|
||||
|
|
@ -19,6 +23,22 @@ void APS5_VABI clearerr_nid_postfix(FileStream*);
|
|||
int APS5_VABI setvbuf_nid_postfix(FileStream*, char*, int, std::size_t);
|
||||
}
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
static int APS5_VABI WriteFormatted(FileStream* stream, const char* format, ...) {
|
||||
#ifdef _WIN32
|
||||
__builtin_sysv_va_list args;
|
||||
__builtin_sysv_va_start(args, format);
|
||||
#else
|
||||
std::va_list args;
|
||||
va_start(args, format);
|
||||
#endif
|
||||
const int result = vfprintf_nid_postfix(stream, format, args);
|
||||
#ifdef _WIN32
|
||||
__builtin_sysv_va_end(args);
|
||||
#else
|
||||
va_end(args);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
int main() {
|
||||
Require(__isthreaded_nid_postfix == 1);
|
||||
Require(__stdoutp_nid_postfix == &_Stdout_nid_postfix);
|
||||
|
|
@ -46,4 +66,17 @@ int main() {
|
|||
Require(!feof_nid_postfix(&stream) && !(guest.flags & 0x20));
|
||||
stream.Close();
|
||||
Require(guest.flags == 0 && guest.descriptor == -1);
|
||||
|
||||
FileStream formatted(std::tmpfile());
|
||||
const char expected[] = "guest 4294967297 1.25 1 2 3 4 5 6 7 8\n";
|
||||
Require(fprintf_nid_postfix(&formatted, "%s %ld %.2f %d %d %d %d %d %d %d %d\n",
|
||||
"guest", std::int64_t{4294967297}, 1.25, 1, 2, 3, 4, 5, 6, 7, 8) == sizeof(expected) - 1);
|
||||
Require(WriteFormatted(&formatted, "%*.*f:%s", 6, 2, 3.5, "end") == 10);
|
||||
std::rewind(formatted.GetHandle());
|
||||
char output[128]{};
|
||||
Require(fgets_nid_postfix(output, sizeof(output), &formatted) == output);
|
||||
Require(std::strcmp(output, expected) == 0);
|
||||
Require(fgets_nid_postfix(output, sizeof(output), &formatted) == output);
|
||||
Require(std::strcmp(output, " 3.50:end") == 0);
|
||||
formatted.Close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,3 +217,22 @@ and closure. All fourteen suites pass and the compatibility libraries rebuild.
|
|||
|
||||
Latest startup resolves the stream globals and stops at `8nY19bKoiZk` (`fcntl`).
|
||||
The game has not reached its entry point or displayed a frame.
|
||||
|
||||
## Follow-up: descriptor flags and formatted stream output
|
||||
|
||||
Added fcntl F_GETFL/F_SETFL for tracked UDP sockets. Nonblocking state is shared
|
||||
with FIONBIO ioctl and protected against concurrent mode updates. Unsupported
|
||||
flags are rejected; ordinary file descriptors and other fcntl commands are not
|
||||
implemented. The UDP test checks both APIs agree, mode transitions, and unchanged
|
||||
state after rejected flags.
|
||||
|
||||
Added fprintf and vfprintf using the guest FileStream wrapper and the existing
|
||||
SysV variadic formatter on Windows. Tests write and read back mixed strings,
|
||||
64-bit guest long integers, floating-point values, register-overflow arguments,
|
||||
and dynamic width/precision through an explicit guest va_list. Write failure
|
||||
returns a negative result and refreshes the guest stream status.
|
||||
|
||||
All fourteen CTest suites pass and patched compatibility libraries rebuild.
|
||||
The unchanged converted game now resolves fcntl and fprintf, and startup stops
|
||||
at `smbQukfxYJM` (`getenv`). This remains an import-resolution result: guest
|
||||
entry-point execution and a rendered frame are still unverified.
|
||||
|
|
|
|||
Loading…
Reference in New Issue