/*
* The Lean Mean C++ Option Parser
*
* Copyright (C) 2012-2017 Matthias S. Benkmann
*
* The "Software" in the following 2 paragraphs refers to this file containing
* the code to The Lean Mean C++ Option Parser.
* The "Software" does NOT refer to any other files which you
* may have received alongside this file (e.g. as part of a larger project that
* incorporates The Lean Mean C++ Option Parser).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software, to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following
* conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* NOTE: It is recommended that you read the processed HTML doxygen documentation
* rather than this source. If you don't know doxygen, it's like javadoc for C++.
* If you don't want to install doxygen you can find a copy of the processed
* documentation at
*
* http://optionparser.sourceforge.net/
*
*/
/**
* @file
*
* @brief This is the only file required to use The Lean Mean C++ Option Parser.
* Just \#include it and you're set.
*
* 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.
*
* @par Feedback:
* Send questions, bug reports, feature requests etc. to: optionparser-feedback(a)lists.sourceforge.net
*
* @par 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:
* @code if ( options[QUIET] ) ... @endcode
*
Evaluate --enable-foo/--disable-foo pair where the last one used wins:
* @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
*
Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
* @code int verbosity = options[VERBOSE].count(); @endcode
*
Iterate over all --file=<fname> arguments:
* @code for (Option* opt = options[FILE]; opt; opt = opt->next())
* fname = opt->arg; ... @endcode
*
If you really want to, you can still process all arguments in order:
* @code
* 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: ...
* @endcode
*
*
@n
* 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(). @n
* (This does not include the usage formatter, of course. But you don't have to use that.)
*
* @par Download:
* Tarball with examples and test programs:
* optionparser-1.7.tar.gz @n
* Just the header (this is all you really need):
* optionparser.h
*
* @par Changelog:
* Version 1.7: Work on const-correctness. @n
* Version 1.6: Fix for MSC compiler. @n
* Version 1.5: Fixed 2 warnings about potentially uninitialized variables. @n
* Added const version of Option::next(). @n
* Version 1.4: Fixed 2 printUsage() bugs that messed up output with small COLUMNS values. @n
* Version 1.3: Compatible with Microsoft Visual C++. @n
* Version 1.2: Added @ref option::Option::namelen "Option::namelen" and removed the extraction
* of short option characters into a special buffer. @n
* Changed @ref option::Arg::Optional "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.@n
* Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that
* options and non-options can be mixed. See
* @ref option::Parser::parse() "Parser::parse()".
*
*
* @par Example program:
* (Note: @c option::* identifiers are links that take you to their documentation.)
* @code
* #error EXAMPLE SHORTENED FOR READABILITY. BETTER EXAMPLES ARE IN THE .TAR.GZ!
* #include
* #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";
* }
* @endcode
*
* @par Option syntax:
* @li 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()).
* @li short options have the format @c -X where @c X is any character that fits in a char.
* @li short options can be grouped, i.e. -X -Y is equivalent to @c -XY.
* @li a short option may take an argument either separate (-X foo) or
* attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by
* registering @c X as a long option (in addition to being a short option) and
* enabling single-minus long options.
* @li an argument-taking short option may be grouped if it is the last in the group, e.g.
* @c -ABCXfoo or -ABCX foo (@c foo is the argument to the @c -X option).
* @li a lone minus character @c '-' is not treated as an option. It is customarily used where
* a file name is expected to refer to stdin or stdout.
* @li long options have the format @c --option-name.
* @li the option-name of a long option can be anything and include any characters.
* Even @c = characters will work, but don't do that.
* @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous.
* You can set a minimum length for abbreviations.
* @li [optional] long options may begin with a single minus. The double minus form is always
* accepted, too.
* @li a long option may take an argument either separate ( --option arg ) or
* attached ( --option=arg ). In the attached form the equals sign is mandatory.
* @li 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.
* @li an empty string is permitted as separate argument to both long and short options.
* @li Arguments to both short and long options may start with a @c '-' character. E.g.
* -X-X , -X -X or --long-X=-X . If @c -X
* and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases.
* @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must
* be attached.
* @li the special option @c -- (i.e. without a name) terminates the list of
* options. Everything that follows is a non-option argument, even if it starts with
* a @c '-' character. The @c -- itself will not appear in the parse results.
* @li the first argument that doesn't start with @c '-' or @c '--' 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 @c '-' . @n
* NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is
* explicitly requested (e.g. by setting POSIXLY_CORRECT). @n
* You can enable the GNU behaviour by passing @c true as first argument to
* e.g. @ref option::Parser::parse() "Parser::parse()".
* @li Arguments that look like options (i.e. @c '-' 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. @n
* This means that in order to pass a first non-option
* argument beginning with the minus character it is required to use the
* @c -- special option, e.g.
* @code
* program -x -- --strange-filename
* @endcode
* In this example, @c --strange-filename is a non-option argument. If the @c --
* were omitted, it would be treated as an unknown option. @n
* See @ref option::Descriptor::longopt for information on how to collect unknown options.
*
*/
#ifndef OPTIONPARSER_H_
#define OPTIONPARSER_H_
#ifdef _MSC_VER
#include
#pragma intrinsic(_BitScanReverse)
#endif
/** @brief The namespace of The Lean Mean C++ Option Parser. */
namespace option
{
#ifdef _MSC_VER
struct MSC_Builtin_CLZ
{
static int builtin_clz(unsigned x)
{
unsigned long index;
_BitScanReverse(&index, x);
return 32-index; // int is always 32bit on Windows, even for target x64
}
};
#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x)
#endif
class Option;
/**
* @brief Possible results when checking if an argument is valid for a certain option.
*
* In the case that no argument is provided for an option that takes an
* optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent.
*/
enum ArgStatus
{
//! The option does not take an argument.
ARG_NONE,
//! The argument is acceptable for the option.
ARG_OK,
//! The argument is not acceptable but that's non-fatal because the option's argument is optional.
ARG_IGNORE,
//! The argument is not acceptable and that's fatal.
ARG_ILLEGAL
};
/**
* @brief Signature of functions that check if an argument is valid for a certain type of option.
*
* Every Option has such a function assigned in its Descriptor.
* @code
* Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... };
* @endcode
*
* A CheckArg function has the following signature:
* @code ArgStatus CheckArg(const Option& option, bool msg); @endcode
*
* It is used to check if a potential argument would be acceptable for the option.
* It will even be called if there is no argument. In that case @c option.arg will be @c NULL.
*
* If @c msg is @c true and the function determines that an argument is not acceptable and
* that this is a fatal error, it should output a message to the user before
* returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you
* will get duplicate messages).
*
* See @ref ArgStatus for the meaning of the return values.
*
* While you can provide your own functions,
* often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice:
*
* @li @c Arg::None @copybrief Arg::None
* @li @c Arg::Optional @copybrief Arg::Optional
*
*/
typedef ArgStatus (*CheckArg)(const Option& option, bool msg);
/**
* @brief Describes an option, its help text (usage) and how it should be parsed.
*
* The main input when constructing an option::Parser is an array of Descriptors.
* @par Example:
* @code
* enum OptionIndex {CREATE, ...};
* enum OptionType {DISABLE, ENABLE, OTHER};
*
* const option::Descriptor usage[] = {
* { CREATE, // index
* OTHER, // type
* "c", // shortopt
* "create", // longopt
* Arg::None, // check_arg
* "--create Tells the program to create something." // help
* }
* , ...
* };
* @endcode
*/
struct Descriptor
{
/**
* @brief Index of this option's linked list in the array filled in by the parser.
*
* Command line options whose Descriptors have the same index will end up in the same
* linked list in the order in which they appear on the command line. If you have
* multiple long option aliases that refer to the same option, give their descriptors
* the same @c index.
*
* If you have options that mean exactly opposite things
* (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same
* @c index, but distinguish them through different values for @ref type.
* That way they end up in the same list and you can just take the last element of the
* list and use its type. This way you get the usual behaviour where switches later
* on the command line override earlier ones without having to code it manually.
*
* @par Tip:
* Use an enum rather than plain ints for better readability, as shown in the example
* at Descriptor.
*/
const unsigned index;
/**
* @brief Used to distinguish between options with the same @ref index.
* See @ref index for details.
*
* It is recommended that you use an enum rather than a plain int to make your
* code more readable.
*/
const int type;
/**
* @brief Each char in this string will be accepted as a short option character.
*
* The string must not include the minus character @c '-' or you'll get undefined
* behaviour.
*
* If this Descriptor should not have short option characters, use the empty
* string "". NULL is not permitted here!
*
* See @ref longopt for more information.
*/
const char* const shortopt;
/**
* @brief The long option name (without the leading @c -- ).
*
* If this Descriptor should not have a long option name, use the empty
* string "". NULL is not permitted here!
*
* While @ref shortopt allows multiple short option characters, each
* Descriptor can have only a single long option name. If you have multiple
* long option names referring to the same option use separate Descriptors
* that have the same @ref index and @ref type. You may repeat
* short option characters in such an alias Descriptor but there's no need to.
*
* @par Dummy Descriptors:
* You can use dummy Descriptors with an
* empty string for both @ref shortopt and @ref longopt to add text to
* the usage that is not related to a specific option. See @ref help.
* The first dummy Descriptor will be used for unknown options (see below).
*
* @par Unknown Option Descriptor:
* The first dummy Descriptor in the list of Descriptors,
* whose @ref shortopt and @ref longopt are both the empty string, will be used
* as the Descriptor for unknown options. An unknown option is a string in
* the argument vector that is not a lone minus @c '-' but starts with a minus
* character and does not match any Descriptor's @ref shortopt or @ref longopt. @n
* Note that the dummy descriptor's @ref check_arg function @e will be called and
* its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL
* the parsing will be aborted with Parser::error()==true. @n
* if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's
* @ref index @e will be used to pick the linked list into which
* to put the unknown option. @n
* If there is no dummy descriptor, unknown options will be dropped silently.
*
*/
const char* const longopt;
/**
* @brief For each option that matches @ref shortopt or @ref longopt this function
* will be called to check a potential argument to the option.
*
* This function will be called even if there is no potential argument. In that case
* it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty
* string.
*
* See @ref CheckArg for more information.
*/
const CheckArg check_arg;
/**
* @brief The usage text associated with the options in this Descriptor.
*
* You can use option::printUsage() to format your usage message based on
* the @c help texts. You can use dummy Descriptors where
* @ref shortopt and @ref longopt are both the empty string to add text to
* the usage that is not related to a specific option.
*
* See option::printUsage() for special formatting characters you can use in
* @c help to get a column layout.
*
* @attention
* Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8"
* prefix to make sure string literals are properly encoded.
*/
const char* help;
};
/**
* @brief A parsed option from the command line together with its argument if it has one.
*
* The Parser chains all parsed options with the same Descriptor::index together
* to form a linked list. This allows you to easily implement all of the common ways
* of handling repeated options and enable/disable pairs.
*
* @li Test for presence of a switch in the argument vector:
* @code if ( options[QUIET] ) ... @endcode
* @li Evaluate --enable-foo/--disable-foo pair where the last one used wins:
* @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode
* @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
* @code int verbosity = options[VERBOSE].count(); @endcode
* @li Iterate over all --file=<fname> arguments:
* @code for (Option* opt = options[FILE]; opt; opt = opt->next())
* fname = opt->arg; ... @endcode
*/
class Option
{
Option* next_;
Option* prev_;
public:
/**
* @brief Pointer to this Option's Descriptor.
*
* Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used
* for unknown options.
*
* @attention
* @c desc==NULL signals that this Option is unused. This is the default state of
* elements in the result array. You don't need to test @c desc explicitly. You
* can simply write something like this:
* @code
* if (options[CREATE])
* {
* ...
* }
* @endcode
* This works because of operator const Option*() .
*/
const Descriptor* desc;
/**
* @brief The name of the option as used on the command line.
*
* The main purpose of this string is to be presented to the user in messages.
*
* In the case of a long option, this is the actual @c argv pointer, i.e. the first
* character is a '-'. In the case of a short option this points to the option
* character within the @c argv string.
*
* Note that in the case of a short option group or an attached option argument, this
* string will contain additional characters following the actual name. Use @ref namelen
* to filter out the actual option name only.
*
*/
const char* name;
/**
* @brief Pointer to this Option's argument (if any).
*
* NULL if this option has no argument. Do not confuse this with the empty string which
* is a valid argument.
*/
const char* arg;
/**
* @brief The length of the option @ref name.
*
* Because @ref name points into the actual @c argv string, the option name may be
* followed by more characters (e.g. other short options in the same short option group).
* This value is the number of bytes (not characters!) that are part of the actual name.
*
* For a short option, this length is always 1. For a long option this length is always
* at least 2 if single minus long options are permitted and at least 3 if they are disabled.
*
* @note
* In the pathological case of a minus within a short option group (e.g. @c -xf-z), this
* length is incorrect, because this case will be misinterpreted as a long option and the
* name will therefore extend to the string's 0-terminator or a following '=" character
* if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you
* really need to distinguish the case of a long and a short option, compare @ref name to
* the @c argv pointers. A long option's @c name is always identical to one of them,
* whereas a short option's is never.
*/
int namelen;
/**
* @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option
* is invalid (unused).
*
* Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided
* you arrange your types properly) switch on type() without testing validity first.
* @code
* enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 };
* enum OptionIndex { FOO };
* const Descriptor usage[] = {
* { FOO, ENABLED, "", "enable-foo", Arg::None, 0 },
* { FOO, DISABLED, "", "disable-foo", Arg::None, 0 },
* { 0, 0, 0, 0, 0, 0 } };
* ...
* switch(options[FOO].last()->type()) // no validity check required!
* {
* case ENABLED: ...
* case DISABLED: ... // UNUSED==DISABLED !
* }
* @endcode
*/
int type() const
{
return desc == 0 ? 0 : desc->type;
}
/**
* @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option
* is invalid (unused).
*/
int index() const
{
return desc == 0 ? -1 : (int)desc->index;
}
/**
* @brief Returns the number of times this Option (or others with the same Descriptor::index)
* occurs in the argument vector.
*
* This corresponds to the number of elements in the linked list this Option is part of.
* It doesn't matter on which element you call count(). The return value is always the same.
*
* Use this to implement cumulative options, such as -v, -vv, -vvv for
* different verbosity levels.
*
* Returns 0 when called for an unused/invalid option.
*/
int count() const
{
int c = (desc == 0 ? 0 : 1);
const Option* p = first();
while (!p->isLast())
{
++c;
p = p->next_;
};
return c;
}
/**
* @brief Returns true iff this is the first element of the linked list.
*
* The first element in the linked list is the first option on the command line
* that has the respective Descriptor::index value.
*
* Returns true for an unused/invalid option.
*/
bool isFirst() const
{
return isTagged(prev_);
}
/**
* @brief Returns true iff this is the last element of the linked list.
*
* The last element in the linked list is the last option on the command line
* that has the respective Descriptor::index value.
*
* Returns true for an unused/invalid option.
*/
bool isLast() const
{
return isTagged(next_);
}
/**
* @brief Returns a pointer to the first element of the linked list.
*
* Use this when you want the first occurrence of an option on the command line to
* take precedence. Note that this is not the way most programs handle options.
* You should probably be using last() instead.
*
* @note
* This method may be called on an unused/invalid option and will return a pointer to the
* option itself.
*/
Option* first()
{
Option* p = this;
while (!p->isFirst())
p = p->prev_;
return p;
}
/**
* const version of Option::first().
*/
const Option* first() const
{
return const_cast