fysxasteroids/engine/Commands.cc

285 lines
6.6 KiB
C++

#include "Commands.h"
#include <boost/filesystem.hpp>
namespace Engine {
static Commands *CommandsInstance = NULL;
void trim_command_str (std::string &command_str) {
std::string::size_type start = command_str.find_first_not_of (" \t");
if (start != std::string::npos)
command_str = command_str.substr (start);
std::string::size_type end = command_str.find_first_of ("#;\n\r\0");
if (end != std::string::npos)
command_str = command_str.substr (0, end);
}
/*
* Inherited Module functions
*/
int Commands::OnInit (int argc, char* argv[]) {
LogDebug ("Commands Init");
mErrorString = "";
if (CommandsInstance) {
LogError ("Commands module already initialized!");
return -1;
}
CommandsInstance = this;
return 0;
}
void Commands::OnDestroy () {
LogDebug ("Commands Destroy");
if (CommandsInstance)
CommandsInstance = NULL;
}
/*
* Module specific functions
*/
std::string Commands::GetCommandName (const std::string &command) {
return command.substr (0, command.find_first_of (" ;\n\0"));
}
std::vector<std::string> Commands::ParseArgs (std::string &argument_str) {
std::vector<std::string> args;
std::string::size_type pos = argument_str.find_first_not_of (" ");
std::string::size_type next_token = 0;
while ( argument_str.length ()> pos && argument_str.find_first_of (" \"", pos) != std::string::npos) {
next_token = argument_str.find_first_of (" \"", pos);
if (next_token != std::string::npos && argument_str[next_token] =='"') {
pos = next_token;
next_token = argument_str.find_first_of ('"', pos + 1);
if (next_token != std::string::npos) {
args.push_back (argument_str.substr (pos + 1, next_token - pos - 1));
}
pos = argument_str.find_first_not_of (" ", next_token + 1);
} else {
args.push_back (argument_str.substr (pos, next_token - pos));
pos = argument_str.find_first_not_of (" ", next_token + 1);
}
}
if (pos != std::string::npos)
args.push_back (argument_str.substr (pos, argument_str.length ()));
return args;
}
void Commands::AddCommand (const std::string &name, command_cb callback){
LogDebug ("Adding Command '%s' at %x", name.c_str(), (void *) callback);
mCommandsCallbacks[name] = callback;
return;
}
bool Commands::RunCommand (const std::string &command){
LogDebug ("Running Command: %s", command.c_str());
std::string cmd_name = GetCommandName (command);
std::string args;
if (command.length () > cmd_name.length () + 1)
args = command.substr (cmd_name.length () + 1, command.length ());
if (mCommandsCallbacks.find (cmd_name) != mCommandsCallbacks.end()) {
std::vector<std::string> argv = ParseArgs (args);
if (mCommandsCallbacks[cmd_name] (argv)) {
mErrorString = "";
return true;
} else {
return false;
}
} else {
LogWarning ("Command '%s' not registered!", cmd_name.c_str ());
}
SetErrorString ("Command '" + cmd_name + "' does not exist!");
return false;
}
void Commands::QueueCommand (const std::string &command){
mCommandQueue.push (command);
}
bool Commands::QueueExecute (){
bool result = true;
while (mCommandQueue.size() > 0) {
result = RunCommand (mCommandQueue.front());
if (!result) {
while (!mCommandQueue.empty())
mCommandQueue.pop();
return false;
}
mCommandQueue.pop();
}
return true;
}
void Commands::SetErrorString (const std::string &error_str){
mErrorString = error_str;
LogWarning ("Command Error: %s", error_str.c_str ());
}
std::string Commands::GetErrorString (){
return mErrorString;
}
/*
* Global functions
*/
bool CommandsInitialized () {
if (!CommandsInstance) {
LogError ("Commands System not yet initialized!");
return false;
}
return true;
}
void AddCommand (const std::string &name, command_cb callback){
if (!CommandsInitialized ())
return;
CommandsInstance->AddCommand (name, callback);
}
bool RunCommand (const std::string &command){
if (!CommandsInitialized ())
return false;
return CommandsInstance->RunCommand (command);
}
void QueueCommand (const std::string &command){
if (!CommandsInitialized ())
return;
CommandsInstance->QueueCommand (command);
}
bool CommandQueueExecute (){
if (!CommandsInitialized ())
return false;
return CommandsInstance->QueueExecute ();
}
void CommandSetErrorString (const std::string &error_str){
if (!CommandsInitialized ())
return;
CommandsInstance->SetErrorString (error_str);
}
std::string CommandGetErrorString (){
if (!CommandsInitialized ())
return false;
return CommandsInstance->GetErrorString();
}
/** \brief Searches for possible candidates at reasonable places
*
* In that order:
* 1. current directory
* 2. user data directory
* 3. game data directory
*
* \returns full path to the file, otherwise only the filename (which will
* \returns then cause an error because the file cannot be opened)
*/
std::string find_exec_file_full_path (const std::string &exec_file) {
std::string full_path = exec_file;
boost::filesystem::path exec_file_path (full_path);
if(boost::filesystem::is_regular_file(exec_file_path)) {
return full_path;
}
full_path = GetUserDirFullPath(std::string("/") + exec_file);
exec_file_path = full_path;
if(boost::filesystem::is_regular_file(exec_file_path)) {
return full_path;
}
full_path = GetResourceFullPath(std::string("/") + exec_file);
exec_file_path = full_path;
if(boost::filesystem::is_regular_file(exec_file_path)) {
return full_path;
}
// otherwise just return the normal path which will fail anyway
return exec_file;
}
/*
* Commands of the Command system
*/
bool Cmd_Exec (const std::vector<std::string> args) {
if (!CommandsInitialized())
return false;
if (args.size() != 1) {
CommandsInstance->SetErrorString("usage: exec <path_to_file>");
return false;
}
std::string full_path = find_exec_file_full_path(args[0]);
LogDebug ("Trying to exec file %s", full_path.c_str());
std::ifstream exec_file;
exec_file.open(full_path.c_str(), std::ios_base::in);
if (!exec_file) {
std::ostringstream error_msg;
error_msg << "exec failed: could not open file '"
<< full_path.c_str() << "'";
CommandsInstance->SetErrorString(error_msg.str());
return false;
}
int linecounter = 0;
while (!exec_file.eof()) {
std::string line;
getline (exec_file, line);
linecounter++;
trim_command_str (line);
if (line.size() == 0)
continue;
if (!CommandsInstance->RunCommand (line)) {
std::ostringstream error_msg;
error_msg << "exec failed running command '" << line
<< "' in file " << args[0] << ":" << linecounter << ".";
CommandsInstance->SetErrorString (error_msg.str());
return false;
}
}
exec_file.close();
LogDebug ("exec success for file %s", full_path.c_str());
return true;
}
void Commands::OnRegisterCommands () {
AddCommand ("exec", Cmd_Exec);
}
}