1 #ifndef MSP_CORE_GETOPT_H_
2 #define MSP_CORE_GETOPT_H_
8 #include <msp/strings/lexicalcast.h>
9 #include "noncopyable.h"
13 class usage_error: public std::runtime_error
19 usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), help_(h) { }
20 virtual ~usage_error() throw() = default;
22 const char *help() const throw() { return help_.c_str(); }
27 Command line option processor. Both short and long options are supported, with
28 optional and required arguments. Automatic help text generation is also
31 Short options begin with a single dash and are identified by a single letter.
32 Multiple short options may be grouped if they take no arguments; for example,
33 the string "-abc" could be interpreted as having the options 'a', 'b' and 'c'.
34 If the option takes an argument and there are unused characters in the argv
35 element, then those characters are interpreted as the argument. Otherwise the
36 next element is taken as the argument. An optional argument must be given in
37 the same element if it is given.
39 Long options begin with a double dash and are identified by an arbitrary
40 string. An argument can be specified either in the same argv element,
41 separated by an equals sign, or in the next element. As with short options,
42 an optional argument, if given, must be in the same element.
44 A single option may have both alternative forms, but must always have at least
45 a long form. This is to encourage self-documenting options; it's much easier
46 to remember words than letters.
48 Positional arguments are also supported. They are identified by an arbitrary
49 string, but the identifier is only used in help text and error messages. Any
50 number of the final arguments may be optional.
52 To support applications that take an arbitrary amount of arguments, a single
53 positional argument list can be specified. Fixed positional arguments are
54 allowed together with a list, but they can't be optional. An application that
55 wants to do complex processing on the argument list can declare a list of
58 A built-in --help option is provided and will output a list of options,
59 arguments and their associated help texts. An application may override this by
60 providing its own option with the same name.
62 class GetOpt: private NonCopyable
77 virtual ~Option() = default;
79 /// Sets help text for the option.
80 virtual Option &set_help(const std::string &) = 0;
82 /** Sets help text for the option, with a placeholder metavariable. The
83 metavariable is used to denote the argument in the option list. */
84 virtual Option &set_help(const std::string &, const std::string &) = 0;
86 virtual Option &bind_seen_count(unsigned &) = 0;
88 /// Returns the number of times this option was seen on the command line.
89 virtual unsigned get_seen_count() const = 0;
97 virtual ~Argument() = default;
99 virtual Argument &set_help(const std::string &) = 0;
108 virtual ~Store() = default;
110 virtual Store *clone() const = 0;
112 virtual bool is_list() const = 0;
113 virtual void store() = 0;
114 virtual void store(const std::string &) = 0;
117 class OptionImpl: public Option
122 ArgType arg_type = NO_ARG;
123 unsigned seen_count = 0;
124 unsigned *ext_seen_count = 0;
126 std::string metavar = "ARG";
130 OptionImpl(char, const std::string &, const Store &, ArgType);
131 virtual ~OptionImpl();
133 virtual OptionImpl &set_help(const std::string &);
134 virtual OptionImpl &set_help(const std::string &, const std::string &);
135 virtual OptionImpl &bind_seen_count(unsigned &);
136 char get_short() const { return shrt; }
137 const std::string &get_long() const { return lng; }
138 ArgType get_arg_type() const { return arg_type; }
139 const std::string &get_help() const { return help; }
140 const std::string &get_metavar() const { return metavar; }
141 virtual unsigned get_seen_count() const { return seen_count; }
143 void process(const std::string &);
146 class ArgumentImpl: public Argument
150 ArgType type = REQUIRED_ARG;
155 ArgumentImpl(const std::string &, const Store &, ArgType);
156 virtual ~ArgumentImpl();
158 virtual ArgumentImpl &set_help(const std::string &);
159 const std::string &get_name() const { return name; }
160 ArgType get_type() const { return type; }
161 const std::string &get_help() const { return help; }
162 bool is_list_store() const { return store->is_list(); }
163 void process(const std::string &);
167 class SimpleStore: public Store
173 SimpleStore(T &d): data(d) { }
175 virtual SimpleStore *clone() const
176 { return new SimpleStore(data); }
178 virtual bool is_list() const { return false; }
180 virtual void store() { }
182 virtual void store(const std::string &a)
183 { data = lexical_cast<T>(a); }
187 class ListStore: public Store
193 ListStore(T &d): data(d) { }
195 virtual ListStore *clone() const
196 { return new ListStore(data); }
198 virtual bool is_list() const { return true; }
200 virtual void store() { }
202 virtual void store(const std::string &a)
203 { data.push_back(lexical_cast<typename T::value_type>(a)); }
207 std::vector<OptionImpl *> opts;
208 std::vector<ArgumentImpl *> args;
209 std::vector<std::string> args_raw;
215 /** Adds an option with both short and long forms. Processing depends on
216 the type of the destination variable and whether an argument is taken or
217 not. With an argument, the value is lexical_cast to the appropriate type
218 and stored in the destination. Without an argument, a bool will be set to
219 true and an unsigned will be incremented; any other type will be ignored. */
221 Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG)
222 { return add_option(s, l, SimpleStore<T>(d), a); }
224 /** Adds an option with both short and long forms. The option may be
225 specified multiple times, and the argument from each occurrence is stored in
226 the list. The argument type must be REQUIRED_ARG. */
228 Option &add_option(char s, const std::string &l, std::vector<T> &d, ArgType a = REQUIRED_ARG)
229 { return add_option(s, l, ListStore<std::vector<T> >(d), a); }
231 /** Adds an option with both short and long forms. The option may be
232 specified multiple times, and the argument from each occurrence is stored in
233 the list. The argument type must be REQUIRED_ARG. */
235 Option &add_option(char s, const std::string &l, std::list<T> &d, ArgType a = REQUIRED_ARG)
236 { return add_option(s, l, ListStore<std::list<T> >(d), a); }
238 /** Adds an option with only a long form. */
240 Option &add_option(const std::string &l, T &d, ArgType a)
241 { return add_option(0, l, d, a); }
243 /** Adds a positional argument. The value will be lexical_cast to the
244 appropriate type and stored in the destination. */
246 Argument &add_argument(const std::string &n, T &d, ArgType a = REQUIRED_ARG)
247 { return add_argument(n, SimpleStore<T>(d), a); }
249 /** Adds a positional argument list. If the list is declared as required,
250 at least one element must be given; an optional list may be empty. Only one
251 list may be added, and optional fixed arguments can't be used with it. */
253 Argument &add_argument(const std::string &n, std::vector<T> &d, ArgType a = REQUIRED_ARG)
254 { return add_argument(n, ListStore<std::vector<T> >(d), a); }
256 /** Adds a positional argument list. If the list is declared as required,
257 at least one element must be given; an optional list may be empty. Only one
258 list may be added, and optional fixed arguments can't be used with it. */
260 Argument &add_argument(const std::string &n, std::list<T> &d, ArgType a = REQUIRED_ARG)
261 { return add_argument(n, ListStore<std::list<T> >(d), a); }
264 OptionImpl &add_option(char, const std::string &, const Store &, ArgType);
265 ArgumentImpl &add_argument(const std::string &, const Store &, ArgType);
267 OptionImpl &get_option(char);
268 OptionImpl &get_option(const std::string &);
271 /** Processes argc/argv style command line arguments. The contents of argv
272 will be unchanged; use get_args to access non-option arguments. */
273 void operator()(unsigned, const char *const *);
276 /** Processes a long option. Returns the number of arguments eaten. */
277 unsigned process_long(const char *const *);
279 /** Processes short options. Returns the number of arguments eaten. */
280 unsigned process_short(const char *const *);
283 /** Generates a single line that describes known options and arguments. If
284 compact is true, the options list is replaced with a placeholder. This
285 provides cleaner output if full help text is printed. */
286 std::string generate_usage(const std::string &, bool compact = false) const;
288 /** Generates help for known options and arguments in tabular format, one
289 item per line. The returned string will have a linefeed at the end. */
290 std::string generate_help() const;
293 template<> inline void GetOpt::SimpleStore<bool>::store()
296 template<> inline void GetOpt::SimpleStore<unsigned>::store()
299 template<> inline void GetOpt::SimpleStore<std::string>::store(const std::string &a)
302 template<> inline void GetOpt::ListStore<std::vector<std::string> >::store(const std::string &a)
303 { data.push_back(a); }
305 template<> inline void GetOpt::ListStore<std::list<std::string> >::store(const std::string &a)
306 { data.push_back(a); }