167 lines
3.8 KiB
C++
167 lines
3.8 KiB
C++
// 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 <message>");
|
|
return;
|
|
}
|
|
console.print("%s", args[0].c_str());
|
|
});
|
|
}
|
|
|
|
void Console::registerCommand(
|
|
const std::string &cmd,
|
|
const std::function<void(Console&, const std::vector<std::string>&)> &cb
|
|
) {
|
|
assertTrue(cmd.length() > 0, "cmd length must be > 0");
|
|
assertTrue(cb != nullptr, "callback must not be null");
|
|
|
|
this->commands[cmd] = cb;
|
|
}
|
|
|
|
template<typename T>
|
|
void Console::registerVariable(
|
|
const std::string &var,
|
|
const std::function<T()> &getter,
|
|
const std::function<void(const T &)> &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<std::string> 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) {
|
|
|
|
} |