The Lean Mean C++ Option Parser
The Lean Mean C++ Option Parser Documentation

The Lean Mean C++ Option Parser handles the program's command line arguments (argc, argv). It supports the short and long option formats of getopt(), getopt_long() and getopt_long_only() but has a more convenient interface.

Feedback:
Send questions, bug reports, feature requests etc. to: optionparser-feedback(a)lists.sourceforge.net
Highlights:
  • It is a header-only library. Just #include "optionparser.h" and you're set.
  • It is freestanding. There are no dependencies whatsoever, not even the C or C++ standard library.
  • It has a usage message formatter that supports column alignment and line wrapping. This aids localization because it adapts to translated strings that are shorter or longer (even if they contain Asian wide characters).
  • Unlike getopt() and derivatives it doesn't force you to loop through options sequentially. Instead you can access options directly like this:
    • Test for presence of a switch in the argument vector:
      if ( options[QUIET] ) ...
    • Evaluate –enable-foo/–disable-foo pair where the last one used wins:
      if ( options[FOO].last()->type() == DISABLE ) ...
    • Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
      int verbosity = options[VERBOSE].count();
    • Iterate over all –file=<fname> arguments:
      for (Option* opt = options[FILE]; opt; opt = opt->next())
      fname = opt->arg; ...
    • If you really want to, you can still process all arguments in order:
      for (int i = 0; i < p.optionsCount(); ++i) {
      Option& opt = buffer[i];
      switch(opt.index()) {
      case HELP: ...
      case VERBOSE: ...
      case FILE: fname = opt.arg; ...
      case UNKNOWN: ...

Despite these features the code size remains tiny. It is smaller than uClibc's GNU getopt() and just a couple 100 bytes larger than uClibc's SUSv3 getopt().
(This does not include the usage formatter, of course. But you don't have to use that.)
Download:
Tarball with examples and test programs: optionparser-1.7.tar.gz
Just the header (this is all you really need): optionparser.h
Changelog:
Version 1.7: Work on const-correctness.
Version 1.6: Fix for MSC compiler.
Version 1.5: Fixed 2 warnings about potentially uninitialized variables.
Added const version of Option::next().
Version 1.4: Fixed 2 printUsage() bugs that messed up output with small COLUMNS values.
Version 1.3: Compatible with Microsoft Visual C++.
Version 1.2: Added Option::namelen and removed the extraction of short option characters into a special buffer.
Changed Arg::Optional to accept arguments if they are attached rather than separate. This is what GNU getopt() does and how POSIX recommends utilities should interpret their arguments.
Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that options and non-options can be mixed. See Parser::parse().
Example program:
(Note: option::* identifiers are links that take you to their documentation.)
#error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ!
#include <iostream>
#include "optionparser.h"
enum optionIndex { UNKNOWN, HELP, PLUS };
const option::Descriptor usage[] =
{
{UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n"
"Options:" },
{HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." },
{PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." },
{UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n"
" example --unknown -- --this_is_no_option\n"
" example -unk --plus -ppp file1 file2\n" },
{0,0,0,0,0,0}
};
int main(int argc, char* argv[])
{
argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present
option::Stats stats(usage, argc, argv);
option::Option options[stats.options_max], buffer[stats.buffer_max];
option::Parser parse(usage, argc, argv, options, buffer);
if (parse.error())
return 1;
if (options[HELP] || argc == 0) {
option::printUsage(std::cout, usage);
return 0;
}
std::cout << "--plus count: " <<
options[PLUS].count() << "\n";
for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next())
std::cout << "Unknown option: " << opt->name << "\n";
for (int i = 0; i < parse.nonOptionsCount(); ++i)
std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n";
}
Option syntax:
  • The Lean Mean C++ Option Parser follows POSIX getopt() conventions and supports GNU-style getopt_long() long options as well as Perl-style single-minus long options (getopt_long_only()).
  • short options have the format -X where X is any character that fits in a char.
  • short options can be grouped, i.e. -X -Y is equivalent to -XY.
  • a short option may take an argument either separate (-X foo) or attached (-Xfoo). You can make the parser accept the additional format -X=foo by registering X as a long option (in addition to being a short option) and enabling single-minus long options.
  • an argument-taking short option may be grouped if it is the last in the group, e.g. -ABCXfoo or -ABCX foo (foo is the argument to the -X option).
  • a lone minus character '-' is not treated as an option. It is customarily used where a file name is expected to refer to stdin or stdout.
  • long options have the format –option-name.
  • the option-name of a long option can be anything and include any characters. Even = characters will work, but don't do that.
  • [optional] long options may be abbreviated as long as the abbreviation is unambiguous. You can set a minimum length for abbreviations.
  • [optional] long options may begin with a single minus. The double minus form is always accepted, too.
  • a long option may take an argument either separate ( –option arg ) or attached ( –option=arg ). In the attached form the equals sign is mandatory.
  • an empty string can be passed as an attached long option argument: –option-name= . Note the distinction between an empty string as argument and no argument at all.
  • an empty string is permitted as separate argument to both long and short options.
  • Arguments to both short and long options may start with a '-' character. E.g. -X-X , -X -X or –long-X=-X . If -X and –long-X take an argument, that argument will be "-X" in all 3 cases.
  • If using the built-in Arg::Optional, optional arguments must be attached.
  • the special option (i.e. without a name) terminates the list of options. Everything that follows is a non-option argument, even if it starts with a '-' character. The itself will not appear in the parse results.
  • the first argument that doesn't start with '-' or '–' and does not belong to a preceding argument-taking option, will terminate the option list and is the first non-option argument. All following command line arguments are treated as non-option arguments, even if they start with '-' .
    NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is explicitly requested (e.g. by setting POSIXLY_CORRECT).
    You can enable the GNU behaviour by passing true as first argument to e.g. Parser::parse().
  • Arguments that look like options (i.e. '-' followed by at least 1 character) but aren't, are NOT treated as non-option arguments. They are treated as unknown options and are collected into a list of unknown options for error reporting.
    This means that in order to pass a first non-option argument beginning with the minus character it is required to use the special option, e.g.
    program -x -- --strange-filename
    In this example, –strange-filename is a non-option argument. If the were omitted, it would be treated as an unknown option.
    See option::Descriptor::longopt for information on how to collect unknown options.