1 #ifndef MSP_CORE_GETOPT_H_
2 #define MSP_CORE_GETOPT_H_
8 #include <msp/strings/lexicalcast.h>
9 #include "attributes.h"
10 #include "noncopyable.h"
14 class usage_error: public std::runtime_error
20 usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), help_(h) { }
21 ~usage_error() throw() { }
23 const char *help() const throw() { return help_.c_str(); }
28 Command line option processor. Both short and long options are supported, with
29 optional and required arguments. Automatic help text generation is also
32 Short options begin with a single dash and are identified by a single letter.
33 Multiple short options may be grouped if they take no arguments; for example,
34 the string "-abc" could be interpreted as having the options 'a', 'b' and 'c'.
35 If the option takes an argument and there are unused characters in the argv
36 element, then those characters are interpreted as the argument. Otherwise the
37 next element is taken as the argument. An optional argument must be given in
38 the same element if it is given.
40 Long options begin with a double dash and are identified by an arbitrary
41 string. An argument can be specified either in the same argv element,
42 separated by an equals sign, or in the next element. As with short options,
43 an optional argument, if given, must be in the same element.
45 A single option may have both alternative forms, but must always have at least
46 a long form. This is to encourage self-documenting options; it's much easier
47 to remember words than letters.
49 Positional arguments are also supported. They are identified by an arbitrary
50 string, but the identifier is only used in help text and error messages. Any
51 number of the final arguments may be optional.
53 To support applications that take an arbitrary amount of arguments, a single
54 positional argument list can be specified. Fixed positional arguments are
55 allowed together with a list, but they can't be optional. An application that
56 wants to do complex processing on the argument list can declare a list of
59 A built-in --help option is provided and will output a list of options,
60 arguments and their associated help texts. An application may override this by
61 providing its own option with the same name.
63 class GetOpt: private NonCopyable
80 /// Sets help text for the option.
81 virtual Option &set_help(const std::string &) = 0;
83 /** Sets help text for the option, with a placeholder metavariable. The
84 metavariable is used to denote the argument in the option list. */
85 virtual Option &set_help(const std::string &, const std::string &) = 0;
87 virtual Option &bind_seen_count(unsigned &) = 0;
89 /// Returns the number of times this option was seen on the command line.
90 virtual unsigned get_seen_count() const = 0;
98 virtual ~Argument() { }
100 virtual Argument &set_help(const std::string &) = 0;
111 virtual Store *clone() const = 0;
113 virtual bool is_list() const = 0;
114 virtual void store() = 0;
115 virtual void store(const std::string &) = 0;
118 class OptionImpl: public Option
125 unsigned *ext_seen_count;
131 OptionImpl(char, const std::string &, const Store &, ArgType);
132 virtual ~OptionImpl();
134 virtual OptionImpl &set_help(const std::string &);
135 virtual OptionImpl &set_help(const std::string &, const std::string &);
136 virtual OptionImpl &bind_seen_count(unsigned &);
137 char get_short() const { return shrt; }
138 const std::string &get_long() const { return lng; }
139 ArgType get_arg_type() const { return arg_type; }
140 const std::string &get_help() const { return help; }
141 const std::string &get_metavar() const { return metavar; }
142 virtual unsigned get_seen_count() const { return seen_count; }
144 void process(const std::string &);
147 class ArgumentImpl: public Argument
156 ArgumentImpl(const std::string &, const Store &, ArgType);
157 virtual ~ArgumentImpl();
159 virtual ArgumentImpl &set_help(const std::string &);
160 const std::string &get_name() const { return name; }
161 ArgType get_type() const { return type; }
162 const std::string &get_help() const { return help; }
163 bool is_list_store() const { return store->is_list(); }
164 void process(const std::string &);
168 class SimpleStore: public Store
174 SimpleStore(T &d): data(d) { }
176 virtual SimpleStore *clone() const
177 { return new SimpleStore(data); }
179 virtual bool is_list() const { return false; }
181 virtual void store() { }
183 virtual void store(const std::string &a)
184 { data = lexical_cast<T>(a); }
188 class ListStore: public Store
194 ListStore(T &d): data(d) { }
196 virtual ListStore *clone() const
197 { return new ListStore(data); }
199 virtual bool is_list() const { return true; }
201 virtual void store() { }
203 virtual void store(const std::string &a)
204 { data.push_back(lexical_cast<typename T::value_type>(a)); }
207 typedef std::list<OptionImpl *> OptionList;
208 typedef std::list<ArgumentImpl *> ArgumentList;
213 std::vector<std::string> args_raw;
219 /** Returns any non-option arguments encountered during processing.
220 Deprecated; use add_argument instead. */
221 DEPRECATED const std::vector<std::string> &get_args() const { return args_raw; }
223 /** Adds an option with both short and long forms. Processing depends on
224 the type of the destination variable and whether an argument is taken or
225 not. With an argument, the value is lexical_cast to the appropriate type
226 and stored in the destination. Without an argument, a bool will be set to
227 true and an unsigned will be incremented; any other type will be ignored. */
229 Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG)
230 { return add_option(s, l, SimpleStore<T>(d), a); }
232 /** Adds an option with both short and long forms. The option may be
233 specified multiple times, and the argument from each occurrence is stored in
234 the list. The argument type must be REQUIRED_ARG. */
236 Option &add_option(char s, const std::string &l, std::vector<T> &d, ArgType a = REQUIRED_ARG)
237 { return add_option(s, l, ListStore<std::vector<T> >(d), a); }
239 /** Adds an option with both short and long forms. The option may be
240 specified multiple times, and the argument from each occurrence is stored in
241 the list. The argument type must be REQUIRED_ARG. */
243 Option &add_option(char s, const std::string &l, std::list<T> &d, ArgType a = REQUIRED_ARG)
244 { return add_option(s, l, ListStore<std::list<T> >(d), a); }
246 /** Adds an option with only a long form. */
248 Option &add_option(const std::string &l, T &d, ArgType a)
249 { return add_option(0, l, d, a); }
251 /** Adds a positional argument. The value will be lexical_cast to the
252 appropriate type and stored in the destination. */
254 Argument &add_argument(const std::string &n, T &d, ArgType a = REQUIRED_ARG)
255 { return add_argument(n, SimpleStore<T>(d), a); }
257 /** Adds a positional argument list. If the list is declared as required,
258 at least one element must be given; an optional list may be empty. Only one
259 list may be added, and optional fixed arguments can't be used with it. */
261 Argument &add_argument(const std::string &n, std::vector<T> &d, ArgType a = REQUIRED_ARG)
262 { return add_argument(n, ListStore<std::vector<T> >(d), a); }
264 /** Adds a positional argument list. If the list is declared as required,
265 at least one element must be given; an optional list may be empty. Only one
266 list may be added, and optional fixed arguments can't be used with it. */
268 Argument &add_argument(const std::string &n, std::list<T> &d, ArgType a = REQUIRED_ARG)
269 { return add_argument(n, ListStore<std::list<T> >(d), a); }
272 OptionImpl &add_option(char, const std::string &, const Store &, ArgType);
273 ArgumentImpl &add_argument(const std::string &, const Store &, ArgType);
275 OptionImpl &get_option(char);
276 OptionImpl &get_option(const std::string &);
279 /** Processes argc/argv style command line arguments. The contents of argv
280 will be unchanged; use get_args to access non-option arguments. */
281 void operator()(unsigned, const char *const *);
284 /** Processes a long option. Returns the number of arguments eaten. */
285 unsigned process_long(const char *const *);
287 /** Processes short options. Returns the number of arguments eaten. */
288 unsigned process_short(const char *const *);
291 /** Generates a single line that describes known options and arguments. If
292 compact is true, the options list is replaced with a placeholder. This
293 provides cleaner output if full help text is printed. */
294 std::string generate_usage(const std::string &, bool compact = false) const;
296 /** Generates help for known options and arguments in tabular format, one
297 item per line. The returned string will have a linefeed at the end. */
298 std::string generate_help() const;
301 template<> inline void GetOpt::SimpleStore<bool>::store()
304 template<> inline void GetOpt::SimpleStore<unsigned>::store()
307 template<> inline void GetOpt::SimpleStore<std::string>::store(const std::string &a)
310 template<> inline void GetOpt::ListStore<std::vector<std::string> >::store(const std::string &a)
311 { data.push_back(a); }
313 template<> inline void GetOpt::ListStore<std::list<std::string> >::store(const std::string &a)
314 { data.push_back(a); }