X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/df2bb45e41303b5132feb6b264caaa01c31b8bb5..a3d92499a8c10b231db452e86a0a71900910fa4f:/projects/sgconf/main.cpp diff --git a/projects/sgconf/main.cpp b/projects/sgconf/main.cpp index 8644e690..a0ef89a1 100644 --- a/projects/sgconf/main.cpp +++ b/projects/sgconf/main.cpp @@ -65,6 +65,65 @@ struct ARRAY_TYPE typedef T type; }; +template +struct nullary_function +{ +typedef T result_type; +}; + +template +class binder0 : public nullary_function +{ + public: + binder0(const F & func, const typename F::argument_type & arg) + : m_func(func), m_arg(arg) {} + typename F::result_type operator()() const { return m_func(m_arg); } + private: + F m_func; + typename F::argument_type m_arg; +}; + +template +inline +binder0 bind0(const F & func, const typename F::argument_type & arg) +{ +return binder0(func, arg); +} + +template +class METHOD1_ADAPTER : public std::unary_function +{ + public: + METHOD1_ADAPTER(R (C::* func)(A), C & obj) : m_func(func), m_obj(obj) {} + R operator()(A arg) { return (m_obj.*m_func)(arg); } + private: + R (C::* m_func)(A); + C & m_obj; +}; + +template +class CONST_METHOD1_ADAPTER : public std::unary_function +{ + public: + CONST_METHOD1_ADAPTER(R (C::* func)(A) const, C & obj) : m_func(func), m_obj(obj) {} + R operator()(A arg) const { return (m_obj.*m_func)(arg); } + private: + R (C::* m_func)(A) const; + C & m_obj; +}; + +template +METHOD1_ADAPTER Method1Adapt(R (C::* func)(A), C & obj) +{ +return METHOD1_ADAPTER(func, obj); +} + +template +CONST_METHOD1_ADAPTER Method1Adapt(R (C::* func)(A) const, C & obj) +{ +return CONST_METHOD1_ADAPTER(func, obj); +} + template bool SetArrayItem(T & array, const char * index, const typename ARRAY_TYPE::type & value) { @@ -87,12 +146,34 @@ void UsageCorporations(bool full); void Version(); +void ReadUserConfigFile(SGCONF::OPTION_BLOCK & block) +{ +std::vector paths; +const char * configHome = getenv("XDG_CONFIG_HOME"); +if (configHome == NULL) + { + const char * home = getenv("HOME"); + if (home == NULL) + return; + paths.push_back(std::string(home) + "/.config/sgconf/sgconf.conf"); + paths.push_back(std::string(home) + "/.sgconf/sgconf.conf"); + } +else + paths.push_back(std::string(configHome) + "/sgconf/sgconf.conf"); +for (std::vector::const_iterator it = paths.begin(); it != paths.end(); ++it) + if (access(it->c_str(), R_OK) == 0) + { + block.ParseFile(*it); + return; + } +} + } // namespace anonymous namespace SGCONF { -class CONFIG_ACTION: public ACTION +class CONFIG_ACTION : public ACTION { public: CONFIG_ACTION(CONFIG & config, @@ -101,6 +182,8 @@ class CONFIG_ACTION: public ACTION m_description(paramDescription) {} + virtual ACTION * Clone() const { return new CONFIG_ACTION(*this); } + virtual std::string ParamDescription() const { return m_description; } virtual std::string DefaultDescription() const { return ""; } virtual OPTION_BLOCK & Suboptions() { return m_suboptions; } @@ -117,6 +200,10 @@ class CONFIG_ACTION: public ACTION PARSER_STATE CONFIG_ACTION::Parse(int argc, char ** argv) { +if (argc == 0 || + argv == NULL || + *argv == NULL) + throw ERROR("Missing argument."); char * pos = strchr(*argv, '@'); if (pos != NULL) { @@ -1138,23 +1225,70 @@ return ProcessSetUser(req.server.data(), req.port.data(), req.admLogin.data(), r //----------------------------------------------------------------------------- int main(int argc, char **argv) { -UsageAll(); -exit(0); - SGCONF::CONFIG config; -SGCONF::OPTION_BLOCK generalOptions; -generalOptions.Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), ""), "override default config file"); -generalOptions.Add("h", "help", SGCONF::MakeFunc0Action(Usage), "show this help and exit"); -generalOptions.Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "show full help and exit"); -generalOptions.Add("v", "version", SGCONF::MakeFunc0Action(Version), "show version information and exit"); - -SGCONF::OPTION_BLOCK connOptions; -connOptions.Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "
"), "host to connect"); -connOptions.Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), ""), "port to connect"); -connOptions.Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), ""), "administrative login"); -connOptions.Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, ""), "password for the administrative login"); -connOptions.Add("a", "address", SGCONF::MakeParamAction(config, ""), "connection params as a single string in format: :@:"); +SGCONF::OPTION_BLOCKS blocks; +blocks.Add("General options") + .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), ""), "override default config file") + .Add("h", "help", SGCONF::MakeFunc0Action(bind0(Method1Adapt(&SGCONF::OPTION_BLOCKS::Help, blocks), 0)), "\t\tshow this help and exit") + .Add("help-all", SGCONF::MakeFunc0Action(UsageAll), "\t\tshow full help and exit") + .Add("v", "version", SGCONF::MakeFunc0Action(Version), "\t\tshow version information and exit"); +SGCONF::OPTION_BLOCK & block = blocks.Add("Connection options") + .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "
"), "\t\thost to connect") + .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), ""), "\t\tport to connect") + .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), ""), "\tadministrative login") + .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, ""), "\tpassword for the administrative login") + .Add("a", "address", SGCONF::MakeParamAction(config, ""), "connection params as a single string in format: :@:"); + + +SGCONF::PARSER_STATE state(false, argc, argv); + +try +{ +state = blocks.Parse(--argc, ++argv); // Skipping self name +} +catch (const SGCONF::OPTION::ERROR& ex) +{ +std::cerr << ex.what() << "\n"; +return -1; +} + +if (state.stop) + return 0; + +if (state.argc > 0) + { + std::cerr << "Unknown option: '" << *state.argv << "'\n"; + return -1; + } + +try +{ +SGCONF::CONFIG configOverride(config); + +if (config.configFile.empty()) + { + const char * mainConfigFile = "/etc/sgconf/sgconf.conf"; + if (access(mainConfigFile, R_OK) == 0) + block.ParseFile(mainConfigFile); + ReadUserConfigFile(block); + } +else + { + block.ParseFile(config.configFile.data()); + } + +config = configOverride; +} +catch (const std::exception& ex) +{ +std::cerr << ex.what() << "\n"; +return -1; +} + +std::cerr << "Config: " << config.Serialize() << std::endl; + +return 0; if (argc < 2) {