From 59e3518dd802e8532b89d6272e2fae81b2fac53c Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Sun, 28 Sep 2014 02:11:26 +1000 Subject: [PATCH] Implemented command line config overrides You can set the file to read as the config file via the command line, like this, assuming the program supports it: prog -config=file.cfg You can also override indevidual key-value pairs in the config system using this syntax: prog -Ckey=value Both commands can be used together, and you can override multiple key-value pairs at once. To use this feature of the ConfigUtility, it must receive argc and argv as parameters to the Load() method. --- client/client_application.cpp | 4 +- client/client_application.hpp | 2 +- client/main.cpp | 2 +- client/scenes/lobby_menu.cpp | 6 +-- common/utilities/config_utility.cpp | 77 +++++++++++++++++++++++------ common/utilities/config_utility.hpp | 2 +- server/main.cpp | 2 +- server/server_application.hpp | 2 +- server/server_logic.cpp | 4 +- todo.txt | 3 -- 10 files changed, 74 insertions(+), 30 deletions(-) diff --git a/client/client_application.cpp b/client/client_application.cpp index 62e4d25..4ae481b 100644 --- a/client/client_application.cpp +++ b/client/client_application.cpp @@ -45,12 +45,12 @@ //Public access members //------------------------- -void ClientApplication::Init(int argc, char** argv) { +void ClientApplication::Init(int argc, char* argv[]) { std::cout << "Beginning " << argv[0] << std::endl; //load the prerequisites ConfigUtility& config = ConfigUtility::GetSingleton(); - config.Load("rsc\\config.cfg"); + config.Load("rsc\\config.cfg", argc, argv); //------------------------- //Initialize the APIs diff --git a/client/client_application.hpp b/client/client_application.hpp index 773243f..dbbc785 100644 --- a/client/client_application.hpp +++ b/client/client_application.hpp @@ -35,7 +35,7 @@ class ClientApplication: public Singleton { public: //public methods - void Init(int argc, char** argv); + void Init(int argc, char* argv[]); void Proc(); void Quit(); diff --git a/client/main.cpp b/client/main.cpp index 0903053..c8584e5 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -30,7 +30,7 @@ using namespace std; -int main(int argc, char** argv) { +int main(int argc, char* argv[]) { try { //create the singletons ConfigUtility::Create(); diff --git a/client/scenes/lobby_menu.cpp b/client/scenes/lobby_menu.cpp index 92ce5d1..7346f45 100644 --- a/client/scenes/lobby_menu.cpp +++ b/client/scenes/lobby_menu.cpp @@ -25,7 +25,6 @@ #include "utility.hpp" #include -#include //------------------------- //Public access members @@ -113,7 +112,7 @@ void LobbyMenu::Render(SDL_Surface* const screen) { (Uint16)listBox.w, (Uint16)listBox.h }; r.y += i * listBox.h; - SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 255, 127, 39)); + SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 49, 150, 5)); } //draw the server name @@ -226,8 +225,7 @@ void LobbyMenu::HandleJoinResponse(ClientPacket* const argPacket) { } void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) { - //TODO: Better output - std::cerr << "Error: " << argPacket->text << std::endl; + //TODO: Better output for join rejection } //------------------------- diff --git a/common/utilities/config_utility.cpp b/common/utilities/config_utility.cpp index f761570..93187b4 100644 --- a/common/utilities/config_utility.cpp +++ b/common/utilities/config_utility.cpp @@ -22,14 +22,56 @@ #include "config_utility.hpp" #include +#include #include +#include #include -void ConfigUtility::Load(std::string fname) { +void ConfigUtility::Load(std::string fname, int argc, char* argv[]) { //clear the stored configuration configMap.clear(); - //pass to the recursive method - configMap = Read(fname); + + //use the default file + if (argc < 2) { + configMap = Read(fname); + return; + } + + //some variables to use + table_t redirectedFile; + table_t cmdLineParams; + char key[256], val[256]; + + //reading from the command line + for (int i = 1; i < argc; ++i) { + //read from a specified config file + if (!strncmp(argv[i], "-config=", 8)) { + redirectedFile = Read(argv[i] + 8); + continue; + } + + //set some specific values + if (!strncmp(argv[i], "-C", 2)) { + //wipe the variables + memset(key, 0, 256); + memset(key, 0, 256); + + //read the key-value pair + if (sscanf(argv[i], "-C%[^=]=%[^\0]", key, val) != 2) { + std::ostringstream os; + os << "Failed to read a command line config argument (expected -C%s=%s):" << std::endl; + os << "\targv[" << i << "]: " << argv[i] << std::endl; + os << "\tkey: " << key << std::endl; + os << "\tval: " << val << std::endl; + throw(std::runtime_error( os.str() )); + } + cmdLineParams[key] = val; + } + } + + //finally, construct the final config table + configMap.insert(cmdLineParams.begin(), cmdLineParams.end()); + configMap.insert(redirectedFile.begin(), redirectedFile.end()); } ConfigUtility::table_t ConfigUtility::Read(std::string fname) { @@ -38,10 +80,9 @@ ConfigUtility::table_t ConfigUtility::Read(std::string fname) { std::ifstream is(fname); if (!is.is_open()) { - std::string msg; - msg += "Failed to open a config file: "; - msg += fname; - throw(std::runtime_error(msg)); + std::ostringstream os; + os << "Failed to open a config file: " << fname; + throw(std::runtime_error( os.str() )); } std::string key, val; @@ -69,15 +110,23 @@ ConfigUtility::table_t ConfigUtility::Read(std::string fname) { getline(is, key,'='); getline(is, val); - //trim the strings at the start & end - while(key.size() && isspace(*key.begin())) key.erase(0, 1); - while(val.size() && isspace(*val.begin())) val.erase(0, 1); + //eat the whitespace at the start & end + while(key.size() && isspace( *key.begin() )) { + key.erase(0, 1); + } + while(val.size() && isspace( *val.begin() )) { + val.erase(0, 1); + } - while(key.size() && isspace(*(key.end()-1))) key.erase(key.end() - 1); - while(val.size() && isspace(*(val.end()-1))) val.erase(val.end() - 1); + while(key.size() && isspace( *(key.end()-1) )) { + key.erase(key.end() - 1); + } + while(val.size() && isspace( *(val.end()-1) )) { + val.erase(val.end() - 1); + } - //disallow empty/wiped values - if (key.size() == 0) { + //disallow empty/wiped pairs + if (key.size() == 0 || val.size() == 0) { continue; } diff --git a/common/utilities/config_utility.hpp b/common/utilities/config_utility.hpp index 8b85528..fd6fb99 100644 --- a/common/utilities/config_utility.hpp +++ b/common/utilities/config_utility.hpp @@ -29,7 +29,7 @@ class ConfigUtility : public Singleton { public: - void Load(std::string fname); + void Load(std::string fname, int argc = 0, char* argv[] = nullptr); //convert to a type std::string& String(std::string); diff --git a/server/main.cpp b/server/main.cpp index 8987d26..4cca4da 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -30,7 +30,7 @@ using namespace std; -int main(int argc, char** argv) { +int main(int argc, char* argv[]) { try { //create the singletons AccountManager::Create(); diff --git a/server/server_application.hpp b/server/server_application.hpp index 105cffe..3337588 100644 --- a/server/server_application.hpp +++ b/server/server_application.hpp @@ -47,7 +47,7 @@ class ServerApplication: public Singleton { public: //public methods - void Init(int argc, char** argv); + void Init(int argc, char* argv[]); void Proc(); void Quit(); diff --git a/server/server_logic.cpp b/server/server_logic.cpp index b770cdf..48fd153 100644 --- a/server/server_logic.cpp +++ b/server/server_logic.cpp @@ -34,12 +34,12 @@ //public methods //------------------------- -void ServerApplication::Init(int argc, char** argv) { +void ServerApplication::Init(int argc, char* argv[]) { //NOTE: I might need to rearrange the init process so that lua & SQL can interact with the map system as needed. std::cout << "Beginning " << argv[0] << std::endl; //load the prerequisites - config.Load("rsc\\config.cfg"); + config.Load("rsc\\config.cfg", argc, argv); //------------------------- //Initialize the APIs diff --git a/todo.txt b/todo.txt index 2098c57..bef95f3 100644 --- a/todo.txt +++ b/todo.txt @@ -1,6 +1,3 @@ -TODO: Config switch for the debug output -TODO: A better way of handling the disconnection message -TODO: LobbyMenu::HandleJoinRejection() TODO: Get the rooms working, even if only via hotkeys TODO: Fix shoddy movement TODO: Move the statistics into their own SQL table, instead of duplicating the structure a dozen times