#include "commands.h" #include "error.h" #include #include #include #include #include #include #include #include using std::cout, std::endl, std::string, std::vector, std::tolower; const void CommandsModule::printHello(const CommandArg* argv) { cout << "Hello" << endl; } const void CommandsModule::echo(const CommandArg* argv) { cout << "Echo: '" << argv[0].str << '\'' << endl; } CommandsModule::CommandsModule() { addCommand("printHello", &CommandsModule::printHello, 0, {}, this); CommandArgType* args0 = new CommandArgType[1]; args0[0] = STR_REST; addCommand("echo", &CommandsModule::echo, 1, args0, this); } CommandsModule::~CommandsModule() { for(Command c : commandList) { // This is probably needed but its not working //if(c.argc > 0) //delete[] c.argTypes; } } void CommandsModule::addCommand(Command c) { if(lookupCommand(c.name) != nullptr) { cout << "Duplicate command: " << c.name << endl; } commandList.push_back(c); } void CommandsModule::addCommand(std::string name, const void (*func)(const CommandArg *), const int argc, CommandArgType *argTypes) { Command c = {name, nullptr, func, argc, argTypes, nullptr}; addCommand(c); } void CommandsModule::addCommand(std::string name, const void(*func)(const CommandArg*), const int argc, std::vector argTypes) { CommandArgType* argTypesArr = new CommandArgType[argc]; for(int i = 0; i < argc; i++) { argTypesArr[i] = argTypes[i]; } addCommand(name, func, argc, argTypesArr); } struct NameMatches { NameMatches(string s): s_{s} {} bool operator()(Command c) { return (c.name == s_); } string s_; }; Command* CommandsModule::lookupCommand(string name) { auto elem = std::find_if(commandList.begin(), commandList.end(), NameMatches(name)); if (elem != commandList.end()) { int i = elem - commandList.begin(); return &(commandList[i]); } else { return nullptr; } } vector CommandsModule::splitCommand(string command) { vector v; string regexString = "((?:\"[^\"\n]+\")|(?:'[^'\n]+')|(?:[^ \n]+))+"; std::regex regex(regexString, std::regex_constants::_S_icase); auto begin = std::sregex_iterator(command.begin(), command.end(), regex); auto end = std::sregex_iterator(); for (std::sregex_iterator i = begin; i != end; i++) { std::smatch match = *i; std::string str = match.str(); if(str[0] == '\'' || str[0] == '"') str = str.substr(1, str.size() - 2); v.push_back(str); } return v; } template std::basic_string lowercase(const std::basic_string& s) { std::basic_string s2 = s; std::transform(s2.begin(), s2.end(), s2.begin(), [](unsigned char c){ return std::tolower(c); }); return s2; } CommandArg* CommandsModule::getCommandArgs(vector& split, const CommandArgType* argTypes, const int argc) { CommandArg* args = new CommandArg[argc]; for(int i = 1; i < argc + 1; i++) { switch(argTypes[i-1]) { case STR: args[i-1].str = (char*)split[i].c_str(); break; case NUM: args[i-1].num = std::stoi(split[i]); break; case MOVDIR: args[i-1].dir = LEFT; break; case STR_REST: { string rest = ""; for(int j = i; j < split.size(); j++) { rest += split[j]; if(j != split.size() - 1) rest += " "; } args[i-1].str = new char[rest.size()]; strcpy(args[i-1].str, rest.c_str()); return args; } case NUM_ARR_REST: { int* rest = new int[split.size() - i]; for(int j = 0; j < split.size() - i; j++) { rest[j] = std::stoi(split[j + i]); } args[i-1].numArr = {rest, (int) split.size() - i}; return args; } default: cout << "UH OH SOMETHING IS VERY WRONG" << endl; } } return args; } void CommandsModule::runCommand(string command) { cout << command << endl; vector split = splitCommand(command); Command* cmd = lookupCommand(split[0]); if(cmd == nullptr) throw Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); if(cmd->argc > split.size() - 1) throw Err(CMD_ERR_WRONG_ARGS, command + " is the wrong args"); CommandArg* args = getCommandArgs(split, cmd->argTypes, cmd->argc); try { if(cmd->module == nullptr) cmd->staticFunc(args); else cmd->func(*cmd->module, args); } catch (Err e) { for(int i = 0; i < cmd->argc; i++) { if(cmd->argTypes[i] == STR_REST) delete[] args[i].str; } delete[] args; throw e; } for(int i = 0; i < cmd->argc; i++) { if(cmd->argTypes[i] == STR_REST) delete[] args[i].str; } delete[] args; } Err CommandsModule::checkCommand(string command) { vector split = splitCommand(command); Command* cmd = lookupCommand(split[0]); if(cmd == nullptr) return Err(CMD_ERR_NOT_FOUND, split[0] + " is not a valid command name"); if(cmd->argc > split.size()) return Err(CMD_ERR_WRONG_ARGS, command + " is the wrong args"); CommandArg* args = getCommandArgs(split, cmd->argTypes, cmd->argc); for(int i = 0; i < cmd->argc; i++) { if(cmd->argTypes[i] == STR_REST || cmd->argTypes[i] == NUM_ARR_REST) delete[] args[i].str; } delete[] args; return Err(NOERR, ""); }