comparison C++/modules/OptionParser/OptionParser.h @ 334:0b576ee64d45

* Create brand new hierarchy * Rename DynLib to Dynlib * Remove some warnings
author David Demelier <markand@malikania.fr>
date Sun, 08 Mar 2015 14:26:33 +0100
parents C++/OptionParser.h@99e83685d4da
children d5ec1174b707
comparison
equal deleted inserted replaced
333:412ca7a5e1ea 334:0b576ee64d45
1 /*
2 * OptionParser.h -- command line option parser
3 *
4 * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #ifndef _OPTION_PARSER_H_
20 #define _OPTION_PARSER_H_
21
22 /**
23 * @file OptionParser.h
24 * @brief Command line option parser
25 */
26
27 #include <initializer_list>
28 #include <string>
29 #include <vector>
30
31 /**
32 * @class Option
33 * @brief Option definition
34 */
35 class Option {
36 public:
37 enum Flags {
38 NoArg = (1 << 0),
39 };
40
41 private:
42 std::string m_key;
43 std::string m_full;
44 int m_flags;
45
46 public:
47 /**
48 * Construct an option. By default, an option requires an argument
49 * unless flags is set to NoArg.
50 *
51 * You <strong>must</strong> not prepend dashes to the option names.
52 *
53 * You don't need to set both short and long names, but you need at
54 * least one.
55 *
56 * @param key the short name (e.g v)
57 * @param full the long name (e.g verbose)
58 * @param flags the optional flags
59 * @see Flags
60 */
61 inline Option(std::string key, std::string full, int flags = 0)
62 : m_key(std::move(key))
63 , m_full(std::move(full))
64 , m_flags(flags)
65 {
66 }
67
68 /**
69 * Get the short name (e.g v)
70 *
71 * @return the short name
72 */
73 inline const std::string &key() const noexcept
74 {
75 return m_key;
76 }
77
78 /**
79 * Get the long name (e.g verbose)
80 *
81 * @return the long name
82 */
83 inline const std::string &full() const noexcept
84 {
85 return m_full;
86 }
87
88 /**
89 * Get the flags.
90 *
91 * @return the flags
92 * @see Flags
93 */
94 inline int flags() const noexcept
95 {
96 return m_flags;
97 }
98 };
99
100 /**
101 * @class OptionValue
102 * @brief Result of an option parse
103 */
104 class OptionValue {
105 private:
106 std::string m_key;
107 std::string m_full;
108 std::string m_value;
109
110 public:
111 /**
112 * Construct an option value
113 *
114 * @param option the option
115 * @param value the value
116 */
117 inline OptionValue(const Option &option, std::string value)
118 : m_key(option.key())
119 , m_full(option.full())
120 , m_value(std::move(value))
121 {
122 }
123
124 /**
125 * Get the value (if the option requires an argument).
126 *
127 * @return the value
128 */
129 inline const std::string &value() const noexcept
130 {
131 return m_value;
132 }
133
134 friend bool operator==(const OptionValue &o1, const std::string &name);
135 };
136
137 /**
138 * Test the option value with the specified option name.
139 *
140 * You can use both the short option or the long option name depending
141 * on what you have registered to the OptionParser class.
142 *
143 * @param o the option
144 * @param name the short or the full name
145 * @return true if matches
146 */
147 inline bool operator==(const OptionValue &o, const std::string &name)
148 {
149 return o.m_key == name || o.m_full == name;
150 }
151
152 /**
153 * @class OptionPack
154 * @brief Object containing results of a parse
155 *
156 * Because parsing bad options does not throw exceptions, this class is
157 * convertible to bool and has the error contained.
158 *
159 * It also have the number of arguments parsed so you can cut your options
160 * depending on the full command line.
161 *
162 * Example:
163 * -y install -d foo
164 * -y remove -f
165 *
166 * In that case, you can do two parsing, it will stops (unless Unstrict is set)
167 * until install or remove.
168 */
169 class OptionPack : public std::vector<OptionValue> {
170 private:
171 friend class OptionParser;
172
173 std::string m_error{"No error"};
174 int m_argsParsed{0};
175
176 public:
177 /**
178 * Get the error.
179 *
180 * @return the error
181 */
182 inline const std::string &error() const noexcept
183 {
184 return m_error;
185 }
186
187 /**
188 * Get the number of arguments parsed <strong>not the number of
189 * options</strong>.
190 *
191 * @return the number of arguments parsed
192 */
193 inline int parsed() const noexcept
194 {
195 return m_argsParsed;
196 }
197
198 /**
199 * Convert to true on success.
200 *
201 * @return true on success
202 */
203 inline operator bool() const noexcept
204 {
205 return m_error == "No error";
206 }
207 };
208
209 /**
210 * @class OptionParser
211 * @brief Base class for parsing command line options
212 *
213 * The option parser is a replacement for getopt(3) which is reentrant
214 * and does not use globals.
215 */
216 class OptionParser {
217 public:
218 using Map = std::vector<Option>;
219 using Args = std::vector<std::string>;
220
221 enum Flags {
222 Unstrict = (1 << 0)
223 };
224
225 private:
226 Map m_options;
227
228 const Option &get(const std::string &arg) const;
229 std::string key(const std::string &arg) const;
230 bool isDefined(const std::string &arg) const;
231 bool isToggle(const std::string &arg) const;
232 bool isShortCompacted(const std::string &arg) const;
233 bool isShort(const std::string &arg) const;
234 bool isLong(const std::string &arg) const;
235 bool isOption(const std::string &arg) const;
236 void readShort(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const;
237 void readFull(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const;
238 OptionPack parse(Args::const_iterator it, Args::const_iterator end, int flags) const;
239
240 public:
241 /**
242 * Construct an option parser from an initializer_list of options.
243 *
244 * @param options the list of options
245 */
246 OptionParser(std::initializer_list<Option> options);
247
248 /**
249 * Construct an option parser from a vector of options.
250 *
251 * @param options the options
252 */
253 OptionParser(std::vector<Option> options);
254
255 /**
256 * Parse the arguments from main arguments.
257 *
258 * @param argc the number of arguments
259 * @param argv the arguments
260 * @param flags the optional flags
261 * @return the packed result
262 */
263 OptionPack parse(int argc, char **argv, int flags = 0) const;
264
265 /**
266 * Parse the arguments from a vector.
267 *
268 * @param args the arguments
269 * @param flags the optional flags
270 * @return the packed result
271 */
272 OptionPack parse(const std::vector<std::string> &args, int flags = 0) const;
273 };
274
275 #endif // !_OPTION_PARSER_H_