#include #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(&m_ram[args.GetNext()]); output += text; paramDone = true; } else if(type == 'c') { char character = static_cast(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(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(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(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(m_ram + stringPtr); m_ioman.Write(CIoman::FID_STDOUT, strlen(string), string); return 0; }