mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
The guest fgets handed the size straight to the host. With a size of 0 glibc and the Windows runtime return NULL without setting errno or the stream error indicator, and a negative size goes to the Windows invalid-parameter path. FreeBSD's fgets checks n <= 0 before reading: it sets __SERR on the stream, sets errno to EINVAL and returns NULL, leaving the buffer and the file position untouched. fgets_nid_postfix now does the same before calling the host. The FileStream flag it uses was only set for encoding errors so far and is renamed from SetEncodingError/encodingError to SetError/guestError; it already stays set until clearerr like __SERR. guest_standard_streams checks sizes 0, -1 and INT_MIN (NULL, errno 22, error indicator set and cleared by clearerr, buffer and position untouched) and that a following read still returns the line; it fails without the change. Fixes #3084 AI-assisted: yes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
114 lines
3.9 KiB
C++
114 lines
3.9 KiB
C++
#include "prx/libc/include/FileStream.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cerrno>
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
namespace { FileStream input{stdin}; }
|
|
extern "C" {
|
|
FileStream* __stdinp_nid_postfix = &input;
|
|
FileStream* __stdoutp_nid_postfix = &_Stdout_nid_postfix;
|
|
FileStream* __stderrp_nid_postfix = &_Stderr_nid_postfix;
|
|
int __isthreaded_nid_postfix = 1;
|
|
|
|
int APS5_VABI fgetc_nid_postfix(FileStream* stream) {
|
|
const int result = std::fgetc(GetNativeStream(stream));
|
|
stream->SyncStatus();
|
|
return result;
|
|
}
|
|
std::int32_t APS5_VABI fgetwc_nid_postfix(FileStream* stream) {
|
|
return fgetc_nid_postfix(stream);
|
|
}
|
|
|
|
std::int32_t APS5_VABI ungetwc_nid_postfix(std::int32_t value, FileStream* stream) {
|
|
if (value == -1) return -1;
|
|
if (value < 0 || value > 255) {
|
|
errno = 86;
|
|
stream->SetError();
|
|
return -1;
|
|
}
|
|
const int result = std::ungetc(value, GetNativeStream(stream));
|
|
stream->SyncStatus();
|
|
return result;
|
|
}
|
|
int APS5_VABI getc_nid_postfix(FileStream* stream) { return fgetc_nid_postfix(stream); }
|
|
int APS5_VABI getc_unlocked_nid_postfix(FileStream* stream) {
|
|
#ifdef _WIN32
|
|
const int result = _fgetc_nolock(GetNativeStream(stream));
|
|
#else
|
|
const int result = ::getc_unlocked(GetNativeStream(stream));
|
|
#endif
|
|
stream->SyncUnlockedStatus();
|
|
return result;
|
|
}
|
|
int APS5_VABI __srget_nid_postfix(FileStream* stream) { return fgetc_nid_postfix(stream); }
|
|
int APS5_VABI getchar_nid_postfix() { return fgetc_nid_postfix(__stdinp_nid_postfix); }
|
|
int APS5_VABI fputc_nid_postfix(int value, FileStream* stream) {
|
|
const int result = std::fputc(value, GetNativeStream(stream));
|
|
stream->SyncStatus();
|
|
return result;
|
|
}
|
|
int APS5_VABI putc_nid_postfix(int value, FileStream* stream) { return fputc_nid_postfix(value, stream); }
|
|
int APS5_VABI putc_unlocked_nid_postfix(int value, FileStream* stream) {
|
|
#ifdef _WIN32
|
|
const int result = _fputc_nolock(value, GetNativeStream(stream));
|
|
#else
|
|
const int result = ::putc_unlocked(value, GetNativeStream(stream));
|
|
#endif
|
|
stream->SyncUnlockedStatus();
|
|
return result;
|
|
}
|
|
int APS5_VABI __swbuf_nid_postfix(int value, FileStream* stream) { return fputc_nid_postfix(value, stream); }
|
|
int APS5_VABI putchar_nid_postfix(int value) { return fputc_nid_postfix(value, __stdoutp_nid_postfix); }
|
|
int APS5_VABI ungetc_nid_postfix(int value, FileStream* stream) {
|
|
const int result = std::ungetc(value, GetNativeStream(stream));
|
|
stream->SyncStatus();
|
|
return result;
|
|
}
|
|
char* APS5_VABI fgets_nid_postfix(char* buffer, int size, FileStream* stream) {
|
|
if (size <= 0) {
|
|
stream->SetError();
|
|
errno = 22;
|
|
return nullptr;
|
|
}
|
|
auto* result = std::fgets(buffer, size, GetNativeStream(stream));
|
|
stream->SyncStatus();
|
|
return result;
|
|
}
|
|
int APS5_VABI feof_nid_postfix(FileStream* stream) {
|
|
stream->SyncStatus();
|
|
return (stream->GuestState().flags & 0x20) != 0;
|
|
}
|
|
int APS5_VABI ferror_nid_postfix(FileStream* stream) {
|
|
stream->SyncStatus();
|
|
return (stream->GuestState().flags & 0x40) != 0;
|
|
}
|
|
void APS5_VABI clearerr_nid_postfix(FileStream* stream) {
|
|
stream->ClearError();
|
|
}
|
|
int APS5_VABI fileno_nid_postfix(FileStream* stream) {
|
|
#ifdef _WIN32
|
|
const int descriptor = _fileno(GetNativeStream(stream));
|
|
#else
|
|
const int descriptor = ::fileno(GetNativeStream(stream));
|
|
#endif
|
|
stream->GuestState().descriptor = static_cast<std::int16_t>(descriptor);
|
|
return descriptor;
|
|
}
|
|
int APS5_VABI setvbuf_nid_postfix(FileStream* stream, char* buffer, int mode, std::size_t size) {
|
|
if (mode < 0 || mode > 2) return -1;
|
|
const int native = mode == 0 ? _IOFBF : mode == 1 ? _IOLBF : _IONBF;
|
|
if (native != _IONBF && size == 0) {
|
|
buffer = nullptr;
|
|
size = BUFSIZ;
|
|
}
|
|
return std::setvbuf(GetNativeStream(stream), buffer, native, size);
|
|
}
|
|
void APS5_VABI setbuf_nid_postfix(FileStream* stream, char* buffer) {
|
|
setvbuf_nid_postfix(stream, buffer, buffer ? 0 : 2, buffer ? 1024 : 0);
|
|
}
|
|
}
|