#include #include #include #include #include #include #include #include "commander.h" #define DEFAULT_MESSAGE_MAX_LEN (30) #define DEFAULT_ERROR_EXIT_CODE (1) class CommandImpl; class OptionImpl; class ArgumentImpl; using namespace commander; void assert(bool condition, const char *fmt, ...) { if (!condition) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); exit(DEFAULT_ERROR_EXIT_CODE); } } class CastClass { public: void *m_ptr; }; #define CMD (static_cast(m_ptr)) #define OPT (static_cast(m_ptr)) #define ARG (static_cast(m_ptr)) #define CAST_TO(clazz, ptr) (static_cast(((CastClass *)(ptr))->m_ptr)) inline CommandImpl *CMD_EX(Command &cmd) { return CAST_TO(CommandImpl, &cmd); } inline CommandImpl *CMD_EX(Command *cmd) { return CAST_TO(CommandImpl, cmd); } inline OptionImpl *OPT_EX(Option &opt) { return CAST_TO(OptionImpl, &opt); } inline OptionImpl *OPT_EX(Option *opt) { return CAST_TO(OptionImpl, opt); } inline ArgumentImpl *ARG_EX(Argument &arg) { return CAST_TO(ArgumentImpl, &arg); } inline ArgumentImpl *ARG_EX(Argument *arg) { return CAST_TO(ArgumentImpl, arg); } class OptionImpl { public: OptionImpl(const std::string &name) : m_name(name) {} inline const std::string &name() const { return m_name; } inline void shortcut(const std::string &shortcut) { m_shortcut = shortcut; } inline const std::string &shortcut() const { return m_shortcut; } inline void description(const std::string &description) { m_description = description; } inline const std::string &description() const { return m_description; } inline void required(bool required) { m_required = required; } inline bool required() const { return m_required; } void boolean(bool boolean) { m_boolean = boolean; } bool boolean() const { return m_boolean; } void valueName(const std::string &valueName) { m_valueName = valueName; } const std::string &valueName() const { return m_valueName; } std::string helpMessage(int maxlen = DEFAULT_MESSAGE_MAX_LEN) { std::stringstream ss; if (m_shortcut.size()) ss << "-" << m_shortcut << ","; ss << "--" << m_name; if (!m_boolean) { ss << " "; if (m_required) ss << "<"; else ss << "["; if (m_valueName.size()) ss << m_valueName; else ss << m_name; if (m_required) ss << ">"; else ss << "]"; } std::string result = ss.str(); if (m_description.size()) { std::stringstream pad; for (size_t i = result.size(); i < maxlen; i++) pad << " "; pad << m_description; result += pad.str(); } return result; } private: std::string m_name; std::string m_shortcut; std::string m_description; std::string m_valueName; bool m_required = false; bool m_boolean = false; }; class ArgumentImpl { public: inline ArgumentImpl(const std::string &name) : m_name(name) {} inline const std::string &name() const { return m_name; } inline void description(const std::string &description) { m_description = description; } inline const std::string &description() const { return m_description; } inline void required(bool required) { m_required = required; } inline bool required() const { return m_required; } std::string helpMessage(int maxlen = DEFAULT_MESSAGE_MAX_LEN) { std::string result = m_name; if (m_description.size()) { std::stringstream pad; for (size_t i = result.size(); i < maxlen; i++) pad << " "; pad << m_description; result += pad.str(); } return result; } private: std::string m_name; std::string m_description; bool m_required = false; }; class CommandImpl { public: CommandImpl(const std::string &name) : m_name(name) { option("help").shortcut("h").boolean().description("Print this help message"); } const std::string &name() const { return m_name; } inline void execute(ExecuteCallback callback) { m_excute = callback; } inline ExecuteCallback execute() const { return m_excute; } inline void description(const std::string &description) { m_description = description; } inline const std::string &description() const { return m_description; } Command &command(const std::string &name) { if (m_commands.find(name) == m_commands.end()) { m_commands.emplace(name, std::make_shared(name)); } return *m_commands[name]; } Option &option(const std::string &name) { if (m_options.find(name) == m_options.end()) m_options.emplace(name, std::make_shared