#ifndef SHAREDDATALAYER_CLI_COMMANDMAP_HPP #define SHAREDDATALAYER_CLI_COMMANDMAP_HPP #include #include #include #include #include #include #include #include namespace shareddatalayer { namespace cli { class CommandMap { public: class CommandNameAlreadyRegistered; class UnknownCommandName; class CategoryOffsetAlreadyRegistered; enum class Category { UNDEFINED, UTIL, }; CommandMap(); ~CommandMap(); using CommandFunction = std::function; boost::program_options::options_description& registerCommand(const std::string& commandName, const std::string& shortHelp, const std::string& longHelp, const CommandFunction& commandFunction, Category category, int categoryOffset); std::vector getCommandNames() const; const boost::program_options::options_description& getCommandOptions(const std::string& commandName) const; int execute(const std::string& commandName, std::ostream& out, std::ostream& err, const boost::program_options::variables_map& params, size_t count); void shortHelp(std::ostream& out) const; void longHelp(std::ostream& out, const std::string& commandName) const; static CommandMap& getCommandMap() noexcept; CommandMap(const CommandMap&) = delete; CommandMap(CommandMap&&) = delete; CommandMap& operator = (const CommandMap&) = delete; CommandMap& operator = (CommandMap&&) = delete; private: struct Info; std::map map; using CategoryKey = std::pair; std::map categoryMap; }; class CommandMap::CommandNameAlreadyRegistered: public Exception { public: explicit CommandNameAlreadyRegistered(const std::string& commandName); }; class CommandMap::UnknownCommandName: public Exception { public: explicit UnknownCommandName(const std::string& commandName); }; class CommandMap::CategoryOffsetAlreadyRegistered: public Exception { public: CategoryOffsetAlreadyRegistered(const std::string& commandName, int offset); }; } } #define AUTO_REGISTER_COMMAND_XTOKENPASTE(x, y) x ## y #define AUTO_REGISTER_COMMAND_TOKENPASTE(x, y) AUTO_REGISTER_COMMAND_XTOKENPASTE(x, y) #define AUTO_REGISTER_COMMAND(_function, _name, _shortHelp, _longHelp, _category, _categoryOffset, ...) \ namespace \ { \ struct AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__) \ { \ AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__)() \ { \ ::shareddatalayer::cli::CommandMap::getCommandMap().registerCommand(_name, _shortHelp, _longHelp, _function, _category, _categoryOffset).add_options() \ __VA_ARGS__; \ } \ ~AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__)() { } \ }; \ AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__) AUTO_REGISTER_COMMAND_TOKENPASTE(autoRegister, __LINE__); \ } #endif