Add first version
[ric-plt/sdl.git] / include / private / cli / commandmap.hpp
1 #ifndef SHAREDDATALAYER_CLI_COMMANDMAP_HPP
2 #define SHAREDDATALAYER_CLI_COMMANDMAP_HPP
3
4 #include <string>
5 #include <functional>
6 #include <iosfwd>
7 #include <map>
8 #include <vector>
9 #include <cstddef>
10 #include <boost/program_options.hpp>
11 #include <sdl/exception.hpp>
12
13 namespace shareddatalayer
14 {
15     namespace cli
16     {
17         class CommandMap
18         {
19         public:
20             class CommandNameAlreadyRegistered;
21
22             class UnknownCommandName;
23
24             class CategoryOffsetAlreadyRegistered;
25
26             enum class Category
27             {
28                 UNDEFINED,
29                 UTIL,
30             };
31
32             CommandMap();
33
34             ~CommandMap();
35
36             using CommandFunction = std::function<int(std::ostream& out,
37                                                       std::ostream& err,
38                                                       const boost::program_options::variables_map& params)>;
39
40             boost::program_options::options_description&
41             registerCommand(const std::string& commandName,
42                             const std::string& shortHelp,
43                             const std::string& longHelp,
44                             const CommandFunction& commandFunction,
45                             Category category,
46                             int categoryOffset);
47
48             std::vector<std::string> getCommandNames() const;
49
50             const boost::program_options::options_description&
51             getCommandOptions(const std::string& commandName) const;
52
53             int execute(const std::string& commandName,
54                         std::ostream& out,
55                         std::ostream& err,
56                         const boost::program_options::variables_map& params,
57                         size_t count);
58
59             void shortHelp(std::ostream& out) const;
60
61             void longHelp(std::ostream& out, const std::string& commandName) const;
62
63             static CommandMap& getCommandMap() noexcept;
64
65             CommandMap(const CommandMap&) = delete;
66             CommandMap(CommandMap&&) = delete;
67             CommandMap& operator = (const CommandMap&) = delete;
68             CommandMap& operator = (CommandMap&&) = delete;
69
70         private:
71             struct Info;
72
73             std::map<std::string, Info> map;
74             using CategoryKey = std::pair<Category, int>;
75             std::map<CategoryKey, std::string> categoryMap;
76         };
77
78         class CommandMap::CommandNameAlreadyRegistered: public Exception
79         {
80         public:
81             explicit CommandNameAlreadyRegistered(const std::string& commandName);
82         };
83
84         class CommandMap::UnknownCommandName: public Exception
85         {
86         public:
87             explicit UnknownCommandName(const std::string& commandName);
88         };
89
90         class CommandMap::CategoryOffsetAlreadyRegistered: public Exception
91         {
92         public:
93             CategoryOffsetAlreadyRegistered(const std::string& commandName, int offset);
94         };
95     }
96 }
97
98 #define AUTO_REGISTER_COMMAND_XTOKENPASTE(x, y) x ## y
99 #define AUTO_REGISTER_COMMAND_TOKENPASTE(x, y) AUTO_REGISTER_COMMAND_XTOKENPASTE(x, y)
100
101 #define AUTO_REGISTER_COMMAND(_function, _name, _shortHelp, _longHelp, _category, _categoryOffset, ...) \
102 namespace                                                               \
103 {                                                                       \
104     struct AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__)     \
105     {                                                                   \
106         AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__)()      \
107         {                                                               \
108             ::shareddatalayer::cli::CommandMap::getCommandMap().registerCommand(_name, _shortHelp, _longHelp, _function, _category, _categoryOffset).add_options() \
109                 __VA_ARGS__;                                            \
110         }                                                               \
111         ~AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__)() { } \
112     };                                                                  \
113     AUTO_REGISTER_COMMAND_TOKENPASTE(AutoRegister, __LINE__) AUTO_REGISTER_COMMAND_TOKENPASTE(autoRegister, __LINE__); \
114 }
115
116 #endif
117
118