typedef void (* FUNC0)();
+template <typename F>
class FUNC0_ACTION : public ACTION
{
public:
- FUNC0_ACTION(FUNC0 func) : m_func(func) {}
+ FUNC0_ACTION(const F & func) : m_func(func) {}
+
+ virtual ACTION * Clone() const { return new FUNC0_ACTION<F>(*this); }
virtual std::string ParamDescription() const { return ""; }
virtual std::string DefaultDescription() const { return ""; }
virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
- virtual PARSER_STATE Parse(int argc, char ** argv);
+ virtual PARSER_STATE Parse(int argc, char ** argv)
+ {
+ m_func();
+ return PARSER_STATE(true, argc, argv);
+ }
private:
- FUNC0 m_func;
+ F m_func;
OPTION_BLOCK m_suboptions;
};
+template <typename F>
inline
-FUNC0_ACTION * MakeFunc0Action(FUNC0 func)
+FUNC0_ACTION<F> * MakeFunc0Action(F func)
{
-return new FUNC0_ACTION(func);
+return new FUNC0_ACTION<F>(func);
}
template <typename T>
-class PARAM_ACTION: public ACTION
+class PARAM_ACTION : public ACTION
{
public:
PARAM_ACTION(RESETABLE<T> & param,
m_hasDefault(false)
{}
+ virtual ACTION * Clone() const { return new PARAM_ACTION<T>(*this); }
+
virtual std::string ParamDescription() const { return m_description; }
virtual std::string DefaultDescription() const;
virtual OPTION_BLOCK & Suboptions() { return m_suboptions; }
typedef T type;
};
+template <typename T>
+struct nullary_function
+{
+typedef T result_type;
+};
+
+template <typename F>
+class binder0 : public nullary_function<typename F::result_type>
+{
+ 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 <typename F>
+inline
+binder0<F> bind0(const F & func, const typename F::argument_type & arg)
+{
+return binder0<F>(func, arg);
+}
+
+template <typename C, typename A, typename R>
+class METHOD1_ADAPTER : public std::unary_function<A, R>
+{
+ 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 <typename C, typename A, typename R>
+class CONST_METHOD1_ADAPTER : public std::unary_function<A, R>
+{
+ 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 <typename C, typename A, typename R>
+METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A), C & obj)
+{
+return METHOD1_ADAPTER<C, A, R>(func, obj);
+}
+
+template <typename C, typename A, typename R>
+CONST_METHOD1_ADAPTER<C, A, R> Method1Adapt(R (C::* func)(A) const, C & obj)
+{
+return CONST_METHOD1_ADAPTER<C, A, R>(func, obj);
+}
+
template <typename T>
bool SetArrayItem(T & array, const char * index, const typename ARRAY_TYPE<T>::type & value)
{
namespace SGCONF
{
-class CONFIG_ACTION: public ACTION
+class CONFIG_ACTION : public ACTION
{
public:
CONFIG_ACTION(CONFIG & config,
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; }
//-----------------------------------------------------------------------------
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"), "<config file>"), "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"), "<address>"), "host to connect");
-connOptions.Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "port to connect");
-connOptions.Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "administrative login");
-connOptions.Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "password for the administrative login");
-connOptions.Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
+SGCONF::OPTION_BLOCKS blocks;
+blocks.Add("General options")
+ .Add("c", "config", SGCONF::MakeParamAction(config.configFile, std::string("~/.config/stg/sgconf.conf"), "<config file>"), "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");
+blocks.Add("Connection options")
+ .Add("s", "server", SGCONF::MakeParamAction(config.server, std::string("localhost"), "<address>"), "\t\thost to connect")
+ .Add("p", "port", SGCONF::MakeParamAction(config.port, uint16_t(5555), "<port>"), "\t\tport to connect")
+ .Add("u", "username", SGCONF::MakeParamAction(config.userName, std::string("admin"), "<username>"), "\tadministrative login")
+ .Add("w", "userpass", SGCONF::MakeParamAction(config.userPass, "<password>"), "\tpassword for the administrative login")
+ .Add("a", "address", SGCONF::MakeParamAction(config, "<connection string>"), "connection params as a single string in format: <login>:<password>@<host>:<port>");
+
+SGCONF::PARSER_STATE state(blocks.Parse(--argc, ++argv)); // Skipping self name
+
+if (state.stop)
+ return 0;
+
+if (state.argc > 0)
+ {
+ std::cerr << "Unknown option: '" << *state.argv << "'\n";
+ return -1;
+ }
+
+return 0;
if (argc < 2)
{
using SGCONF::OPTION;
using SGCONF::OPTION_BLOCK;
+using SGCONF::OPTION_BLOCKS;
using SGCONF::ACTION;
using SGCONF::PARSER_STATE;
OPTION::OPTION(const OPTION & rhs)
: m_shortName(rhs.m_shortName),
m_longName(rhs.m_longName),
- m_action(rhs.m_action),
+ m_action(rhs.m_action->Clone()),
m_description(rhs.m_description)
{
}
}
}
-void OPTION_BLOCK::Add(const std::string & shortName,
- const std::string & longName,
- ACTION * action,
- const std::string & description)
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & shortName,
+ const std::string & longName,
+ ACTION * action,
+ const std::string & description)
{
m_options.push_back(OPTION(shortName, longName, action, description));
+return *this;
}
-void OPTION_BLOCK::Add(const std::string & longName,
- ACTION * action,
- const std::string & description)
+OPTION_BLOCK & OPTION_BLOCK::Add(const std::string & longName,
+ ACTION * action,
+ const std::string & description)
{
m_options.push_back(OPTION(longName, action, description));
+return *this;
}
void OPTION_BLOCK::Help(size_t level) const
{
+if (m_options.empty())
+ return;
+std::cout << m_description << ":\n";
std::for_each(m_options.begin(),
m_options.end(),
- std::bind2nd(std::mem_fun_ref(&OPTION::Help), level));
+ std::bind2nd(std::mem_fun_ref(&OPTION::Help), level + 1));
}
PARSER_STATE OPTION_BLOCK::Parse(int argc, char ** argv)
state = it->Parse(--state.argc, ++state.argv);
else
break;
+ ++it;
+ }
+return state;
+}
+
+void OPTION_BLOCKS::Help(size_t level) const
+{
+std::list<OPTION_BLOCK>::const_iterator it(m_blocks.begin());
+while (it != m_blocks.end())
+ {
+ it->Help(level);
+ std::cout << "\n";
+ ++it;
+ }
+}
+
+PARSER_STATE OPTION_BLOCKS::Parse(int argc, char ** argv)
+{
+PARSER_STATE state(false, argc, argv);
+std::list<OPTION_BLOCK>::iterator it(m_blocks.begin());
+while (!state.stop && it != m_blocks.end())
+ {
+ state = it->Parse(state.argc, state.argv);
+ ++it;
}
return state;
}
#include <string>
#include <vector>
+#include <list>
#include <stdexcept>
#include <cstddef> // size_t
class OPTION_BLOCK
{
public:
- void Add(const std::string & shortName,
- const std::string & longName,
- ACTION * action,
- const std::string & description);
- void Add(const std::string & longName,
- ACTION * action,
- const std::string & description);
+ OPTION_BLOCK() {}
+ OPTION_BLOCK(const std::string & description)
+ : m_description(description) {}
+ OPTION_BLOCK & Add(const std::string & shortName,
+ const std::string & longName,
+ ACTION * action,
+ const std::string & description);
+ OPTION_BLOCK & Add(const std::string & longName,
+ ACTION * action,
+ const std::string & description);
void Help(size_t level) const;
private:
std::vector<OPTION> m_options;
+ std::string m_description;
+};
+
+class OPTION_BLOCKS
+{
+ public:
+ OPTION_BLOCK & Add(const std::string & description)
+ { m_blocks.push_back(OPTION_BLOCK(description)); return m_blocks.back(); }
+ void Help(size_t level) const;
+ PARSER_STATE Parse(int argc, char ** argv);
+
+ private:
+ std::list<OPTION_BLOCK> m_blocks;
};
} // namespace SGCONF