1 #ifndef MSP_CORE_GETOPT_H_
2 #define MSP_CORE_GETOPT_H_
8 #include <msp/strings/lexicalcast.h>
12 class usage_error: public std::runtime_error
18 usage_error(const std::string &w, const std::string &h = std::string()): std::runtime_error(w), help_(h) { }
19 ~usage_error() throw() { }
21 const char *help() const throw() { return help_.c_str(); }
26 Command line option processor. Both short and long options are supported, with
27 optional and required arguments. Automatic help text generation is also
30 Short options begin with a single dash and are identified by a single letter.
31 Multiple short options may be grouped if they take no arguments; for example,
32 the string "-abc" could be interpreted as having the options 'a', 'b' and 'c'.
33 If the option takes an argument and there are unused characters in the argv
34 element, then those characters are interpreted as the argument. Otherwise the
35 next element is taken as the argument. An optional argument must be given in
38 Long options begin with a double dash and are identified by an arbitrary
39 string. An argument can be specified either in the same argv element,
40 separated by an equals sign, or in the next element. As with short options,
41 an optional argument must be in the same element.
43 A single option may have both alternative forms, but must always have at least
44 a long form. This is to encourage self-documenting options; it's much easier
45 to remember words than letters.
47 Positional arguments are also supported. They are identified by an arbitrary
48 string, but the identifier is only used in help text and error messages. Any
49 number of the final arguments may be optional.
51 To support applications that take an arbitrary amount of arguments, a single
52 positional argument list can be specified. Fixed positional arguments are
53 allowed together with a list, but they can't be optional. An application that
54 wants to do complex processing on the argument list can declare a list of
57 A built-in --help option is provided and will output a list of options,
58 arguments and their associated help texts. An application may override this by
59 providing its own option with the same name.
78 /// Sets help text for the option.
79 virtual Option &set_help(const std::string &) = 0;
81 /** Sets help text for the option, with a placeholder metavariable. The
82 metavariable is used to denote the argument in the option list. */
83 virtual Option &set_help(const std::string &, const std::string &) = 0;
85 virtual Option &bind_seen_count(unsigned &) = 0;
87 /// Returns the number of times this option was seen on the command line.
88 virtual unsigned get_seen_count() const = 0;
96 virtual ~Argument() { }
98 virtual Argument &set_help(const std::string &) = 0;
109 virtual Store *clone() const = 0;
111 virtual bool is_list() const = 0;
112 virtual void store() = 0;
113 virtual void store(const std::string &) = 0;
116 class OptionImpl: public Option
123 unsigned *ext_seen_count;
129 OptionImpl(char, const std::string &, const Store &, ArgType);
130 virtual ~OptionImpl();
132 virtual OptionImpl &set_help(const std::string &);
133 virtual OptionImpl &set_help(const std::string &, const std::string &);
134 virtual OptionImpl &bind_seen_count(unsigned &);
135 char get_short() const { return shrt; }
136 const std::string &get_long() const { return lng; }
137 ArgType get_arg_type() const { return arg_type; }
138 const std::string &get_help() const { return help; }
139 const std::string &get_metavar() const { return metavar; }
140 virtual unsigned get_seen_count() const { return seen_count; }
142 void process(const std::string &);
145 class ArgumentImpl: public Argument
154 ArgumentImpl(const std::string &, const Store &, ArgType);
155 virtual ~ArgumentImpl();
157 virtual ArgumentImpl &set_help(const std::string &);
158 const std::string &get_name() const { return name; }
159 ArgType get_type() const { return type; }
160 const std::string &get_help() const { return help; }
161 bool is_list_store() const { return store->is_list(); }
162 void process(const std::string &);
166 class SimpleStore: public Store
172 SimpleStore(T &d): data(d) { }
174 virtual SimpleStore *clone() const
175 { return new SimpleStore(data); }
177 virtual bool is_list() const { return false; }
179 virtual void store() { }
181 virtual void store(const std::string &a)
182 { data = lexical_cast<T>(a); }
186 class ListStore: public Store
192 ListStore(T &d): data(d) { }
194 virtual ListStore *clone() const
195 { return new ListStore(data); }
197 virtual bool is_list() const { return true; }
199 virtual void store() { }
201 virtual void store(const std::string &a)
202 { data.push_back(lexical_cast<typename T::value_type>(a)); }
205 typedef std::list<OptionImpl *> OptionList;
206 typedef std::list<ArgumentImpl *> ArgumentList;
211 std::vector<std::string> args_raw;
217 /** Returns any non-option arguments encountered during processing.
219 const std::vector<std::string> &get_args() const { return args_raw; }
221 /** Adds an option with both short and long forms. Processing depends on
222 the type of the destination variable and whether an argument is taken or
223 not. With an argument, the value is lexical_cast to appropriate type and
224 stored in the destination. Without an argument, a bool will be set to true
225 and an unsigned will be incremented; any other type will be ignored. */
227 Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG)
228 { return add_option(s, l, SimpleStore<T>(d), a); }
230 /** Adds an option with both short and long forms. The option may be
231 specified multiple times, and the argument from each occurrence is stored in
232 the list. The argument type must be REQUIRED_ARG. */
234 Option &add_option(char s, const std::string &l, std::list<T> &d, ArgType a = REQUIRED_ARG)
235 { return add_option(s, l, ListStore<std::list<T> >(d), a); }
237 /** Adds an option with only a long form. */
239 Option &add_option(const std::string &l, T &d, ArgType a)
240 { return add_option(0, l, d, a); }
242 /** Adds a positional argument. The value will be lexical_cast to the
243 appropriate type and stored in the destination. */
245 Argument &add_argument(const std::string &n, T &d, ArgType a = REQUIRED_ARG)
246 { return add_argument(n, SimpleStore<T>(d), a); }
248 /** Adds a positional argument list. If the list is declared as required,
249 at least one element must be given; an optional list may be empty. Only one
250 list may be added, and optional fixed arguments can't be used with it. */
252 Argument &add_argument(const std::string &n, std::list<T> &d, ArgType a = REQUIRED_ARG)
253 { return add_argument(n, ListStore<std::list<T> >(d), a); }
256 OptionImpl &add_option(char, const std::string &, const Store &, ArgType);
257 ArgumentImpl &add_argument(const std::string &, const Store &, ArgType);
259 OptionImpl &get_option(char);
260 OptionImpl &get_option(const std::string &);
263 /** Processes argc/argv style command line arguments. The contents of argv
264 will be unchanged; use get_args to access non-option arguments. */
265 void operator()(unsigned, const char *const *);
268 /** Processes a long option. Returns the number of arguments eaten. */
269 unsigned process_long(const char *const *);
271 /** Processes short options. Returns the number of arguments eaten. */
272 unsigned process_short(const char *const *);
275 /** Generates a single line that describes known options and arguments. */
276 std::string generate_usage(const std::string &) const;
278 /** Generates help for known options and arguments in tabular format, one
279 item per line. The returned string will have a linefeed at the end. */
280 std::string generate_help() const;
283 template<> inline void GetOpt::SimpleStore<bool>::store()
286 template<> inline void GetOpt::SimpleStore<unsigned>::store()
289 template<> inline void GetOpt::SimpleStore<std::string>::store(const std::string &a)
292 template<> inline void GetOpt::ListStore<std::list<std::string> >::store(const std::string &a)
293 { data.push_back(a); }