1 // ****************************************************************************
2 // ^FILE: options.h - option parsing classes
5 // This file defines classes used to parse command-line options.
6 // Options may be parsed from an array of strings, or from any structure
7 // for which a corresponding option-iterator exists.
10 // 03/06/92 Brad Appleton <bradapp@enteract.com> Created
12 // 03/23/93 Brad Appleton <bradapp@enteract.com>
13 // - Added OptIstreamIter class
15 // 03/08/94 Brad Appleton <bradapp@enteract.com>
16 // - Added Options::reset() member function
18 // 07/31/97 Brad Appleton <bradapp@enteract.com>
19 // - Added PARSE_POS control flag and POSITIONAL return value
21 // 04/30/06 Chris Reed
22 // - Updated to modern C++ and STL
23 // - Converted comments to doxygen style
24 // ^^**************************************************************************
36 //! Abstract class to iterate through options/arguments
41 virtual ~OptIter(void);
43 //! curr() returns the current item in the iterator without
44 //! advancing on to the next item. If we are at the end of items
45 //! then NULL is returned.
49 //! next() advances to the next item.
53 //! operator() returns the current item in the iterator and then
54 //! advances on to the next item. If we are at the end of items
55 //! then NULL is returned.
60 //! Abstract class for a rewindable OptIter
62 class OptIterRwd : public OptIter {
66 virtual ~OptIterRwd(void);
77 //! rewind() resets the "current-element" to the first one in the "list"
82 //! Class to iterate through an array of tokens. The array may be terminated
83 //! by NULL or a count containing the number of tokens may be given.
85 class OptArgvIter : public OptIterRwd {
87 int ndx; // index of current arg
89 const char * const * av; // arg vector
92 OptArgvIter(const char * const argv[])
93 : av(argv), ac(-1), ndx(0) {}
95 OptArgvIter(int argc, const char * const argv[])
96 : av(argv), ac(argc), ndx(0) {}
113 //! index returns the current index to use for argv[]
114 int index(void) { return ndx; }
118 //! Class to iterate through a string containing delimiter-separated tokens
120 class OptStrTokIter : public OptIterRwd {
122 unsigned len; // length of token-string
123 const char * str; // the token-string
124 const char * seps; // delimiter-set (separator-characters)
125 const char * cur; // current token
126 char * tokstr; // our copy of the token-string
128 static const char * default_delims; // default delimiters = whitespace
131 OptStrTokIter(const char * tokens, const char * delimiters =0);
134 ~OptStrTokIter(void);
148 //! delimiters() with NO arguments returns the current set of delimiters,
149 //! If an argument is given then it is used as the new set of delimiters.
151 delimiters(void) { return seps; }
154 delimiters(const char * delims) {
155 seps = (delims) ? delims : default_delims ;
160 //! OptIstreamIter is a class for iterating over arguments that come
161 //! from an input stream. Each line of the input stream is considered
162 //! to be a set of white-space separated tokens. If the the first
163 //! non-white character on a line is '#' ('!' for VMS systems) then
164 //! the line is considered a comment and is ignored.
166 //! \note If a line is more than 1022 characters in length then we
167 //! treat it as if it were several lines of length 1022 or less.
169 //! \note The string tokens returned by this iterator are pointers
170 //! to temporary buffers which may not necessarily stick around
171 //! for too long after the call to curr() or operator(), hence
172 //! if you need the string value to persist - you will need to
175 class OptIstreamIter : public OptIter {
178 OptStrTokIter * tok_iter ;
184 static const unsigned MAX_LINE_LEN ;
186 OptIstreamIter(std::istream & input);
189 ~OptIstreamIter(void);
202 //! \brief parse command-line options
204 //! \section Synopsis
206 //! #include <options.h>
208 //! Options opts(cmdname, optv);
209 //! char cmdname[], *optv[];
211 //! \section Description
212 //! The Options constructor expects a command-name (usually argv[0]) and
213 //! a pointer to an array of strings. The last element in this array MUST
214 //! be NULL. Each non-NULL string in the array must have the following format:
216 //! The 1st character must be the option-name ('c' for a -c option).
218 //! The 2nd character must be one of '|', '?', ':', '*', or '+'.
219 //! '|' -- indicates that the option takes NO argument;
220 //! '?' -- indicates that the option takes an OPTIONAL argument;
221 //! ':' -- indicates that the option takes a REQUIRED argument;
222 //! '*' -- indicates that the option takes 0 or more arguments;
223 //! '+' -- indicates that the option takes 1 or more arguments;
225 //! The remainder of the string must be the long-option name.
227 //! If desired, the long-option name may be followed by one or more
228 //! spaces and then by the name of the option value. This name will
229 //! be used when printing usage messages. If the option-value-name
230 //! is not given then the string "<value>" will be used in usage
233 //! One may use a space to indicate that a particular option does not
234 //! have a corresponding long-option. For example, "c: " (or "c:")
235 //! means the -c option takes a value & has NO corresponding long-option.
237 //! To specify a long-option that has no corresponding single-character
238 //! option is a bit trickier: Options::operator() still needs an "option-
239 //! character" to return when that option is matched. One may use a whitespace
240 //! character or a non-printable character as the single-character option
241 //! in such a case. (hence " |hello" would only match "--hello").
243 //! \section Exceptions Exceptions to the above
244 //! If the 1st character of the string is '-', then the rest of the
245 //! string must correspond to the above format, and the option is
246 //! considered to be a hidden-option. This means it will be parsed
247 //! when actually matching options from the command-line, but will
248 //! NOT show-up if a usage message is printed using the usage() member
249 //! function. Such an example might be "-h|hidden". If you want to
250 //! use any "dummy" options (options that are not parsed, but that
251 //! to show up in the usage message), you can specify them along with
252 //! any positional parameters to the usage() member function.
254 //! If the 2nd character of the string is '\0' then it is assumed
255 //! that there is no corresponding long-option and that the option
256 //! takes no argument (hence "f", and "f| " are equivalent).
259 //! const char * optv[] = {
260 //! "c:count <number>",
261 //! "s?str <string>",
264 //! "g+groups <newsgroup>",
268 //! optv[] now corresponds to the following:
270 //! usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
271 //! [-x] [--hello] [-g|--groups <newsgroup> ...]
273 //! Long-option names are matched case-insensitive and only a unique prefix
274 //! of the name needs to be specified.
276 //! Option-name characters are case-sensitive!
279 //! Because of the way in which multi-valued options and options with optional
280 //! values are handled, it is NOT possible to supply a value to an option in
281 //! a separate argument (different argv[] element) if the value is OPTIONAL
282 //! and begins with a '-'. What this means is that if an option "-s" takes an
283 //! optional value value and you wish to supply a value of "-foo" then you must
284 //! specify this on the command-line as "-s-foo" instead of "-s -foo" because
285 //! "-s -foo" will be considered to be two separate sets of options.
287 //! A multi-valued option is terminated by another option or by the end-of
288 //! options. The following are all equivalent (if "-l" is a multi-valued
289 //! option and "-x" is an option that takes no value):
291 //! cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
292 //! cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
293 //! cmdname -l item1 item2 item3 -x arg1 arg2 arg3
297 //! #include <options.h>
299 //! static const char * optv[] = {
301 //! "c:count <number>",
302 //! "s?str <string>",
305 //! "g+groups <newsgroup>",
309 //! main(int argc, char * argv[]) {
311 //! const char * optarg;
312 //! const char * str = "default_string";
313 //! int count = 0, xflag = 0, hello = 0;
314 //! int errors = 0, ngroups = 0;
316 //! Options opts(*argv, optv);
317 //! OptArgvIter iter(--argc, ++argv);
319 //! while( optchar = opts(iter, optarg) ) {
320 //! switch (optchar) {
322 //! opts.usage(cout, "files ...");
326 //! ++ngroups; break; //! the groupname is in "optarg"
328 //! str = optarg; break;
334 //! if (optarg == NULL) ++errors;
335 //! else count = (int) atol(optarg);
337 //! default : ++errors; break;
341 //! if (errors || (iter.index() == argc)) {
343 //! cerr << opts.name() << ": no filenames given." << endl ;
345 //! opts.usage(cerr, "files ...");
349 //! cout << "xflag=" << ((xflag) ? "ON" : "OFF") << endl
350 //! << "hello=" << ((hello) ? "YES" : "NO") << endl
351 //! << "count=" << count << endl
352 //! << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
353 //! << "ngroups=" << ngroups << endl ;
355 //! if (iter.index() < argc) {
356 //! cout << "files=" ;
357 //! for (int i = iter.index() ; i < argc ; i++) {
358 //! cout << "\"" << argv[i] << "\" " ;
366 unsigned explicit_end : 1; //!< were we terminated because of "--"?
367 unsigned optctrls : 7; //!< control settings (a set of OptCtrl masks)
368 const char * const * optvec; //!< vector of option-specifications (last=NULL)
369 const char * nextchar; //!< next option-character to process
370 const char * listopt; //!< last list-option we matched
371 const char * cmdname; //!< name of the command
374 check_syntax(void) const;
377 match_opt(char opt, int ignore_case =0) const;
380 match_longopt(const char * opt, int len, int & ambiguous) const;
383 parse_opt(OptIter & iter, const char * & optarg);
386 parse_longopt(OptIter & iter, const char * & optarg);
390 DEFAULT = 0x00, //!< Default setting
391 ANYCASE = 0x01, //!< Ignore case when matching short-options
392 QUIET = 0x02, //!< Dont print error messages
393 PLUS = 0x04, //!< Allow "+" as a long-option prefix
394 SHORT_ONLY = 0x08, //!< Dont accept long-options
395 LONG_ONLY = 0x10, //!< Dont accept short-options
396 //!< (also allows "-" as a long-option prefix).
397 NOGUESSING = 0x20, //!< Normally, when we see a short (long) option
398 //!< on the command line that doesnt match any
399 //!< known short (long) options, then we try to
400 //!< "guess" by seeing if it will match any known
401 //!< long (short) option. Setting this mask prevents
402 //!< this "guessing" from occurring.
403 PARSE_POS = 0x40 //!< By default, Options will not present positional
404 //!< command-line arguments to the user and will
405 //!< instead stop parsing when the first positonal
406 //!< argument has been encountered. If this flag
407 //!< is given, Options will present positional
408 //!< arguments to the user with a return code of
409 //!< POSITIONAL; ENDOPTS will be returned only
410 //!< when the end of the argument list is reached.
413 //! Error return values for operator()
423 Options(const char * name, const char * const optv[]);
428 //! name() returns the command name
430 name(void) const { return cmdname; }
432 //! ctrls() (with no arguments) returns the existing control settings
434 ctrls(void) const { return optctrls; }
436 //! ctrls() (with 1 argument) sets new control settings
438 ctrls(unsigned newctrls) { optctrls = newctrls; }
440 //! reset for another pass to parse for options
442 reset(void) { nextchar = listopt = NULL; }
444 //! usage() prints options usage (followed by any positional arguments
445 //! listed in the parameter "positionals") on the given outstream
447 usage(std::ostream & os, const char * positionals) const ;
449 //! operator() iterates through the arguments as necessary (using the
450 //! given iterator) and returns the character value of the option
451 //! (or long-option) that it matched. If the option has a value
452 //! then the value given may be found in optarg (otherwise optarg
455 //! 0 is returned upon end-of-options. At this point, "iter" may
456 //! be used to process any remaining positional parameters. If the
457 //! PARSE_POS control-flag is set then 0 is returned only when all
458 //! arguments in "iter" have been exhausted.
460 //! If an invalid option is found then BADCHAR is returned and *optarg
461 //! is the unrecognized option character.
463 //! If an invalid long-option is found then BADKWD is returned and optarg
464 //! points to the bad long-option.
466 //! If an ambiguous long-option is found then AMBIGUOUS is returned and
467 //! optarg points to the ambiguous long-option.
469 //! If the PARSE_POS control-flag is set then POSITIONAL is returned
470 //! when a positional argument is encountered and optarg points to
471 //! the positonal argument (and "iter" is advanced to the next argument
472 //! in the iterator).
474 //! Unless Options::QUIET is used, missing option-arguments and
475 //! invalid options (and the like) will automatically cause error
476 //! messages to be issued to cerr.
478 operator()(OptIter & iter, const char * & optarg) ;
480 //! Call this member function after operator() has returned 0
481 //! if you want to know whether or not options were explicitly
482 //! terminated because "--" appeared on the command-line.
485 explicit_endopts() const { return explicit_end; }
488 #endif /* _options_h */