Play-/Source/iop/Iop_Stdio.cpp
Jean-Philip Desjardins 30568a057d
Some checks failed
Build macOS / build_macos (push) Has been cancelled
Build Android / build_android (apk) (push) Has been cancelled
Build Android / build_android (libretro) (push) Has been cancelled
Build Linux ARM32 / build_linux_arm32 (push) Has been cancelled
Build Linux ARM64 / build_linux_arm64 (push) Has been cancelled
Build Windows Psf / build_windows_psf (off, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows Psf / build_windows_psf (on, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows / build_windows (x86_32, Visual Studio 16 2019, installer32.nsi, win32_msvc2019, Win32) (push) Has been cancelled
Build Windows / build_windows (x86_64, Visual Studio 16 2019, installer64.nsi, win64_msvc2019_64, x64) (push) Has been cancelled
Check Format / run_clangformat (push) Has been cancelled
Build iOS / build_ios (push) Has been cancelled
Build JavaScript / build_js (push) Has been cancelled
Build Linux / build_linux (push) Has been cancelled
Use app_config module.
2025-03-11 16:18:58 -04:00

175 lines
3.8 KiB
C++

#include <cstring>
#include "Iop_Stdio.h"
#include "Iop_Ioman.h"
#include "lexical_cast_ex.h"
#include "string_format.h"
#include "Log.h"
#define LOG_NAME "iop_stdio"
#define FUNCTION_PRINTF "printf"
#define FUNCTION_PUTS "puts"
using namespace Iop;
CStdio::CStdio(uint8* ram, CIoman& ioman)
: m_ram(ram)
, m_ioman(ioman)
{
}
std::string CStdio::GetId() const
{
return "stdio";
}
std::string CStdio::GetFunctionName(unsigned int functionId) const
{
switch(functionId)
{
case 4:
return FUNCTION_PRINTF;
break;
case 7:
return FUNCTION_PUTS;
break;
default:
return "unknown";
break;
}
}
void CStdio::Invoke(CMIPS& context, unsigned int functionId)
{
switch(functionId)
{
case 4:
__printf(context);
break;
case 7:
context.m_State.nGPR[CMIPS::V0].nD0 = __puts(
context.m_State.nGPR[CMIPS::A0].nV0);
break;
default:
CLog::GetInstance().Warn(LOG_NAME, "Unknown function (%d) called. PC = (%08X).\r\n",
functionId, context.m_State.nPC);
break;
}
}
std::string CStdio::PrintFormatted(const char* format, CArgumentIterator& args)
{
std::string output;
while(*format != 0)
{
char character = *(format++);
if(character == '%')
{
bool paramDone = false;
bool inPrecision = false;
bool showSign = false;
char fillChar = ' ';
std::string precision;
while(!paramDone && *format != 0)
{
char type = *(format++);
if(type == '%')
{
output += type;
paramDone = true;
}
else if(type == '+')
{
showSign = true;
}
else if(type == 's')
{
const char* text = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
output += text;
paramDone = true;
}
else if(type == 'c')
{
char character = static_cast<char>(args.GetNext());
output += character;
paramDone = true;
}
else if(type == 'd' || type == 'i')
{
int number = args.GetNext();
unsigned int precisionValue = precision.length() ? std::stoul(precision) : 1;
if(showSign && (number >= 0))
{
output += "+";
}
output += lexical_cast_int<std::string>(number, precisionValue, fillChar);
paramDone = true;
}
else if(type == 'u')
{
unsigned int number = args.GetNext();
unsigned int precisionValue = precision.length() ? std::stoul(precision) : 1;
output += lexical_cast_uint<std::string>(number, precisionValue);
paramDone = true;
}
else if(type == 'x' || type == 'X' || type == 'p')
{
uint32 number = args.GetNext();
std::string format;
if(precision.empty())
{
format = string_format("%%%c", type);
}
else
{
unsigned int precisionValue = atoi(precision.c_str());
format = string_format("%%0%d%c", precisionValue, type);
}
output += string_format(format.c_str(), number);
paramDone = true;
}
else if(type == 'l')
{
//Length specifier, don't bother about it.
}
else if(type == '.')
{
inPrecision = true;
}
else
{
assert(isdigit(type));
if(inPrecision)
{
precision += type;
}
else
{
fillChar = '0';
inPrecision = true;
}
}
}
}
else
{
output += character;
}
}
return output;
}
void CStdio::__printf(CMIPS& context)
{
CCallArgumentIterator args(context);
auto format = reinterpret_cast<const char*>(m_ram + args.GetNext());
auto output = PrintFormatted(format, args);
m_ioman.Write(CIoman::FID_STDOUT, output.length(), output.c_str());
}
int32 CStdio::__puts(uint32 stringPtr)
{
auto string = reinterpret_cast<const char*>(m_ram + stringPtr);
m_ioman.Write(CIoman::FID_STDOUT, strlen(string), string);
return 0;
}