Play-/Source/iop/Iop_Stdio.cpp

176 lines
3.8 KiB
C++
Raw Permalink Normal View History

2019-08-17 13:51:31 -04:00
#include <cstring>
#include "Iop_Stdio.h"
#include "Iop_Ioman.h"
#include "lexical_cast_ex.h"
#include "string_format.h"
2025-03-11 12:48:26 -04:00
#include "Log.h"
2018-04-30 21:01:23 +01:00
#define LOG_NAME "iop_stdio"
2018-04-30 21:01:23 +01:00
#define FUNCTION_PRINTF "printf"
2018-05-27 15:11:48 -04:00
#define FUNCTION_PUTS "puts"
using namespace Iop;
CStdio::CStdio(uint8* ram, CIoman& ioman)
2018-04-30 21:01:23 +01:00
: 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;
2018-05-27 15:11:48 -04:00
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;
2018-05-27 15:11:48 -04:00
case 7:
context.m_State.nGPR[CMIPS::V0].nD0 = __puts(
2018-05-28 12:39:50 -04:00
context.m_State.nGPR[CMIPS::A0].nV0);
break;
default:
2018-05-24 12:59:15 -04:00
CLog::GetInstance().Warn(LOG_NAME, "Unknown function (%d) called. PC = (%08X).\r\n",
functionId, context.m_State.nPC);
break;
}
}
2016-05-27 16:46:31 +01:00
std::string CStdio::PrintFormatted(const char* format, CArgumentIterator& args)
{
2016-05-29 16:41:31 -04:00
std::string output;
while(*format != 0)
{
char character = *(format++);
if(character == '%')
{
bool paramDone = false;
bool inPrecision = false;
2016-10-15 21:26:01 -04:00
bool showSign = false;
char fillChar = ' ';
std::string precision;
2018-04-30 21:01:23 +01:00
while(!paramDone && *format != 0)
{
char type = *(format++);
2014-05-31 04:46:45 -04:00
if(type == '%')
{
2014-05-30 12:49:40 +01:00
output += type;
paramDone = true;
}
2016-10-15 21:26:01 -04:00
else if(type == '+')
{
showSign = true;
}
2014-05-30 12:49:40 +01:00
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;
2016-10-15 21:26:01 -04:00
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
{
2019-10-31 18:57:44 -04:00
fillChar = '0';
inPrecision = true;
}
}
}
}
else
{
output += character;
}
}
return output;
}
void CStdio::__printf(CMIPS& context)
{
2016-05-29 16:41:31 -04:00
CCallArgumentIterator args(context);
auto format = reinterpret_cast<const char*>(m_ram + args.GetNext());
2016-05-27 16:46:31 +01:00
auto output = PrintFormatted(format, args);
m_ioman.Write(CIoman::FID_STDOUT, output.length(), output.c_str());
}
2018-05-27 15:11:48 -04:00
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;
}