// Copyright (c) 2025 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "Console.hpp" #include "assert/Assert.hpp" using namespace Dawn; Console::Console(void) : commands(), variables(), buffer() { this->registerCommand("echo", [](auto console, auto args) { if(args.size() == 0) { console.print("Usage: echo "); return; } console.print("%s", args[0].c_str()); }); } void Console::registerCommand( const std::string &cmd, const std::function&)> &cb ) { assertTrue(cmd.length() > 0, "cmd length must be > 0"); assertTrue(cb != nullptr, "callback must not be null"); this->commands[cmd] = cb; } template void Console::registerVariable( const std::string &var, const std::function &getter, const std::function &setter ) { assertTrue(var.length() > 0, "var length must be > 0"); assertTrue(getter != nullptr, "getter must not be null"); assertTrue(setter != nullptr, "setter must not be null"); this->variables[var] = std::make_pair(getter, setter); } void Console::update() { enum class ParseState { FIND_CMD, FIND_ARG, COMMAND, ARG, ARG_QUOTED }; for (const auto &cmd : buffer) { std::string cmdName; std::vector args; ParseState state = ParseState::FIND_CMD; std::string buff; for(size_t i = 0; i < cmd.length(); i++) { char_t c = cmd[i]; switch(state) { case ParseState::FIND_CMD: if(isspace(c)) continue; state = ParseState::COMMAND; buff += c; break; case ParseState::FIND_ARG: if(isspace(c)) continue; if(c == '\"') { state = ParseState::ARG_QUOTED; break; } state = ParseState::ARG; buff += c; break; case ParseState::COMMAND: if(isspace(c)) { cmdName = buff; buff.clear(); state = ParseState::FIND_ARG; break; } buff += c; break; case ParseState::ARG: if(isspace(c)) { args.push_back(buff); buff.clear(); state = ParseState::FIND_ARG; break; } buff += c; break; case ParseState::ARG_QUOTED: if(c == '\"') { args.push_back(buff); buff.clear(); state = ParseState::FIND_ARG; break; } buff += c; break; } } if(buff.length() > 0) { if(state == ParseState::COMMAND) { cmdName = buff; } else { args.push_back(buff); } } // Find command auto itCmd = commands.find(cmdName); if(itCmd == commands.end()) { // Find variable auto itVar = variables.find(cmdName); if(itVar == variables.end()) { std::cout << "Console: Unknown command or variable '" << cmdName << "'" << std::endl; continue; } // Variable get/set printf("Console: Variable '%s' ", cmdName.c_str()); continue; } itCmd->second(*this, args); } buffer.clear(); } void Console::exec(const std::string &str) { // Split strings by command seperator std::istringstream iss(str); std::string token; while(std::getline(iss, token, COMMAND_SEPARATOR)) { // Seperate by newlines too std::istringstream lineIss(token); std::string lineToken; while(std::getline(lineIss, lineToken)) { if(lineToken.length() == 0) continue; buffer.push_back(lineToken); } } } void Console::print(const char_t *fmt, ...) { va_list args; va_start(args, fmt); vprintf(fmt, args); printf("\n"); va_end(args); } void Console::print(std::string str) { this->print("%s", str.c_str()); } Console::~Console(void) { }