1 #ifndef HLWM_ARGPARSE_H
2 #define HLWM_ARGPARSE_H
3 
4 #include <functional>
5 
6 #include "commandio.h"
7 #include "ipc-protocol.h"
8 #include "types.h"
9 
10 /**
11  * @brief The InputConvert class is a convenience wrapper around Input::operator>> and
12  * Converter<X>::parse(). If an argument cannot be parsed, a meaningful error message
13  * is printed to the output stream.
14  */
15 class ArgParse
16 {
17 public:
ArgParse()18     ArgParse() {
19     }
20 
21     bool parsingFails(Input& input, Output& output);
22     bool parsingAllFails(Input& input, Output& output);
23 
24     class Argument {
25     public:
26         /** try to parse the argument from the given string or
27          * throw an exception
28          */
29         std::function<void(std::string)> tryParse_;
30         //! whether the present argument is only optional
31         bool optional_;
32     };
33 
34     /**
35      * @brief A flag is a command line flag (prefixed with one or two dashes)
36      * and without a parameter. If a flag is given, the callback
37      * function is called.
38      */
39     class Flag {
40     public:
Flag(std::string name,std::function<void ()> callback)41         Flag(std::string name, std::function<void()> callback)
42             : name_(name)
43             , callback_(callback)
44         {}
45         //! directly activate a boolean variable
Flag(std::string name,bool * target)46         Flag(std::string name, bool* target)
47             : name_(name)
48         {
49             callback_ = [target] () {
50                 if (target) {
51                     *target = true;
52                 }
53             };
54         }
55 
56         std::string name_;
57         std::function<void()> callback_;
58     };
59 
60     /**
61      * Defines a mandatory argument of type X
62      */
63     template<typename X>
mandatory(X & value)64     ArgParse& mandatory(X& value) {
65         Argument arg {
66             [&value] (std::string source) {
67                 value = Converter<X>::parse(source);
68             },
69             false};
70         arguments_.push_back(arg);
71         return *this;
72     }
73 
74     /**
75      * Defines an optional argument of type X.
76      * If there are more arguments in the input than there are
77      * mandatory arguments, then the optional arguments are filled with
78      * input (earlier optional arguments are preferred).
79      * The target of the whetherArgumentSupplied pointer is set to 'true'
80      * if the present optional argument was supplied in the input.
81      */
82     template<typename X>
83     ArgParse& optional(X& value, bool* whetherArgumentSupplied = nullptr) {
84         if (whetherArgumentSupplied) {
85             *whetherArgumentSupplied = false;
86         }
87         Argument arg {
88             [&value, whetherArgumentSupplied] (std::string source) {
89                 value = Converter<X>::parse(source);
90                 if (whetherArgumentSupplied) {
91                     *whetherArgumentSupplied = true;
92                 }
93             },
94             true};
95         arguments_.push_back(arg);
96         return *this;
97     }
98 
99     ArgParse& flags(std::initializer_list<Flag> flagTable);
100 
exitCode()101     int exitCode() const { return errorCode_; }
102 
103 private:
104     bool unparsedTokens(Input& input, Output& output);
105     bool tryParseFlag(std::string inputToken);
106     std::vector<Argument> arguments_;
107     std::map<std::string, Flag> flags_;
108     int errorCode_ = 0;
109 };
110 
111 #endif // HLWM_ARGPARSE_H
112