d66164d38d6f622e7f81440c5ba4845bcd4e6a7a
[command.git] / include / option.h
1 #ifndef __COMMAND_OPTION_H
2 #define __COMMAND_OPTION_H
3
4 #include <string>
5 #include <sstream>
6 #include <stdexcept>
7
8 #include "parameter.h"
9 #include "exception/missingOptionValue.h"
10 #include "exception/optionFailedConversion.h"
11 #include "exception/optionValueNotSpecified.h"
12
13 namespace command {
14     /**
15      * Class responsible for handling commandline options.
16      * Options are named parameters of program.
17      *
18      * Example:
19      *  - ./myprog OptionName=OptionValue
20      *  - ./myprog -f=/some/file
21      *  - ./myprog --level=15
22      */
23     template<typename ParameterType>
24     class Option
25         : public Parameter, public Callable<ParameterType>  {
26     public:
27         typedef std::string OptionName;
28     protected:
29         /**
30          * Current Option name
31          */
32         const OptionName name;
33
34         /**
35          * Current Option value
36          */
37         ParameterType value;
38
39     public:
40         /**
41          * Default constructor.
42          *
43          * @param name Name of the current Option
44          * @param description Description of current Option
45          * @param function Function used to handle current Option.
46          */
47         Option(const std::string & name, const std::string & description, void (*function)(ParameterType))
48             : Parameter(description), Callable<ParameterType>(function), name(name) {
49         }
50
51         /**
52          *
53          */
54         virtual ~Option() { }
55
56         /**
57          * \inheritdoc
58          */
59         virtual void handle() {
60             this->call(value);
61             used = true;
62         }
63
64         /**
65          * Method used for checking if Option understands given user value.
66          * If so current Option is flagged as used and no more checks against
67          * it will be done in future.
68          *
69          * Passed value should be in form of:
70          *      OptionName=OptionValue
71          *
72          * If no equal sign is after OptionName part,
73          * std::invalid_argument exception with appropriate message is thrown
74          *
75          * If conversion of OptionValue part to ParameterType failed,
76          * std::invalid_argument exception with appropriate message is thrown
77          *
78          * @param argv command line value against which test will be made.
79          *  User value should be in format: OptionName=OptionValue.
80          *
81          * @return If passed argv succesfully detected OptionName part as a
82          *  current option and its OptionValue part has been succesfully
83          *  converted to ParameterType, returns true and Option is set as used one.
84          *  Otherwise returns false and can be used to check against next value.
85          *
86          * @throw MissingOptionValue when OptionValue part is missing after
87          *  equal sign
88          * @throw OptionFailedConversion when OptionValue part failed conversion
89          *  to ParameterType
90          */
91         virtual bool understand(const std::string & argv) {
92
93             if (argv.find(name) == 0) {
94                 std::size_t pos = this->valuePosition(argv);
95
96                 if (pos != name.size()) {
97                     throw MissingOptionValue("Option: " + name + " requires value but no one has been provided");
98                 }
99
100                 std::stringstream ss;
101                 ss << argv.substr(pos + 1);
102                 ss >> value;
103
104                 if (ss.fail()) {
105                     throw OptionFailedConversion("Value for option: " + name + " failed conversion to the required type");
106                 }
107
108                 return true;
109             }
110             return false;
111         }
112
113         /**
114          * \inheritdoc
115          */
116         virtual unsigned int valuePosition(const std::string & value) {
117             std::size_t pos = value.find("=");
118
119             if (pos == std::string::npos) {
120                 throw OptionValueNotSpecified("Option: " + name + " requires value to be specified using equal sign");
121             }
122
123             return pos;
124         }
125     };
126
127     /**
128      * Template class responsible for handling commandline options.
129      * Options are non-required, named parameters of program.
130      * This template specialization allows Options to work like switches.
131      * It means that just named parameter is needed to invoke command. No value
132      * is used.
133      *
134      * Example:
135      *  ./myprog OptionName
136      *  ./myprog -h
137      *  ./myprog --help
138      */
139     template<>
140     class Option<void>
141         : public Parameter, public Callable<void>  {
142     public:
143         typedef std::string OptionName;
144     protected:
145         /**
146          * Current Option name
147          */
148         const OptionName name;
149     public:
150         /**
151          * Default constructor.
152          *
153          * @param name Name of the current Option
154          * @param description Description of current Option
155          * @param function Function used to handle current Option.
156          */
157         Option(const std::string & name, const std::string & description, void (*function)(void))
158             : Parameter(description), Callable<void>(function), name(name) {
159         }
160
161         /**
162          *
163          */
164         virtual void handle() {
165             this->call();
166             used = true;
167         }
168
169         /**
170          * Method used for checking if Option understands given user value.
171          * If so, current Option is flagged as used and no more checks against
172          * it will be done in future.
173          *
174          * Passed value should be in form of:
175          *      OptionName
176          *
177          * @param argv command line value against which test will be made.
178          *  User value should be in format: OptionName.
179          *
180          * @return If passed argv succesfully detected OptionName returns true
181          *  and Option is set as used one. Otherwise returns false and can be
182          *  used to check against next value.
183          */
184         virtual bool understand(const std::string & argv) {
185             if (argv == name) {
186                 return true;
187             }
188             return false;
189         }
190
191         /**
192          * \inheritdoc
193          */
194         virtual unsigned int valuePosition(const std::string & ) {
195             throw new std::invalid_argument(this->describe() + " is void Option, so it does not have value part");
196         }
197     };
198 }
199
200 #endif /* __COMMAND_OPTION_H */