diff --git a/docs/changelog/optionparser-to-third-party.md b/docs/changelog/optionparser-to-third-party.md
new file mode 100644
index 000000000..34190ef38
--- /dev/null
+++ b/docs/changelog/optionparser-to-third-party.md
@@ -0,0 +1,13 @@
+# Wrap third party optionparser.h in vtkm/cont/internal/OptionParser.h
+
+Previously we just took the optionparser.h file and stuck it right in
+our source code. That was problematic for a variety of reasons.
+
+1. It incorrectly assigned our license to external code.
+2. It made lots of unnecessary changes to the original source (like
+ reformatting).
+3. It made it near impossible to track patches we make and updates to
+ the original software.
+
+Instead, use the third-party system to track changes to optionparser.h
+in a different repository and then pull that into ours.
diff --git a/vtkm/CMakeLists.txt b/vtkm/CMakeLists.txt
index 1919270bd..e1bf45620 100644
--- a/vtkm/CMakeLists.txt
+++ b/vtkm/CMakeLists.txt
@@ -81,6 +81,7 @@ vtkm_declare_headers(
#-----------------------------------------------------------------------------
#first add all the components vtkm that are shared between control and exec
add_subdirectory(thirdparty/diy)
+add_subdirectory(thirdparty/optionparser)
add_subdirectory(thirdparty/taotuple)
if(VTKm_ENABLE_LOGGING)
add_subdirectory(thirdparty/loguru)
diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt
index 136901fe8..29482745c 100644
--- a/vtkm/cont/CMakeLists.txt
+++ b/vtkm/cont/CMakeLists.txt
@@ -205,9 +205,10 @@ if (VTKm_ENABLE_LOGGING)
list(APPEND DL_LIBS ${CMAKE_DL_LIBS} Threads::Threads) # dladdr function
endif()
target_link_libraries(vtkm_cont PUBLIC vtkm_compiler_flags ${backends} ${DL_LIBS})
+target_link_libraries(vtkm_cont PUBLIC vtkm_taotuple vtkm_optionparser)
if(TARGET vtkm_diy)
# This will become a required dependency eventually.
- target_link_libraries(vtkm_cont PUBLIC vtkm_diy vtkm_taotuple)
+ target_link_libraries(vtkm_cont PUBLIC vtkm_diy)
endif()
#-----------------------------------------------------------------------------
diff --git a/vtkm/cont/internal/OptionParser.h b/vtkm/cont/internal/OptionParser.h
index 5a4514aba..861a1dc8d 100644
--- a/vtkm/cont/internal/OptionParser.h
+++ b/vtkm/cont/internal/OptionParser.h
@@ -8,9 +8,9 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
-// Copyright 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-// Copyright 2018 UT-Battelle, LLC.
-// Copyright 2018 Los Alamos National Security.
+// Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
+// Copyright 2019 UT-Battelle, LLC.
+// Copyright 2019 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
@@ -19,2973 +19,54 @@
// this software.
//
//=============================================================================
-
-/*
- * The Lean Mean C++ Option Parser
- *
- * Copyright (C) 2012 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 vtk_m_cont_internal_OptionParser_h
+#define vtk_m_cont_internal_OptionParser_h
// For warning suppression macros:
#include
-#ifndef vtk_m_testing_OPTIONPARSER_H_
-#define vtk_m_testing_OPTIONPARSER_H_
+VTKM_THIRDPARTY_PRE_INCLUDE
+// Preemptively load any includes required by optionparser.h so they don't get embedded in
+// our namespace.
#ifdef _MSC_VER
#include
#pragma intrinsic(_BitScanReverse)
#endif
+// We are embedding the code in optionparser.h in a VTK-m namespace so that if other code
+// is using a different version the two don't get mixed up.
+
namespace vtkm
{
namespace cont
{
namespace internal
{
-/** @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)
+// Check to make sure that optionparser.h has not been included before. If it has, remove its
+// header guard so we can include it again under our namespace.
+#ifdef OPTIONPARSER_H_
+#undef OPTIONPARSER_H_
+#define VTK_M_REMOVED_OPTIONPARSER_HEADER_GUARD
#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