Commit 7237c468 authored by Kenneth Moreland's avatar Kenneth Moreland
Browse files

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.
parent 184fe792
# 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.
......@@ -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)
......
......@@ -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()
#-----------------------------------------------------------------------------
......
......@@ -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: <tt><b>optionparser-feedback(a)lists.sourceforge.net</b></tt>
*
* @par Highlights:
* <ul style="padding-left:1em;margin-left:0">
* <li> It is a header-only library. Just <code>\#include "optionparser.h"</code> and you're set.
* <li> It is freestanding. There are no dependencies whatsoever, not even the
* C or C++ standard library.
* <li> 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).
* <li> Unlike getopt() and derivatives it doesn't force you to loop through
* options sequentially. Instead you can access options directly like this:
* <ul style="margin-top:.5em">
* <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=&lt;fname> arguments:
* @code for (Option* opt = options[FILE]; opt; opt = opt->next())
* fname = opt->arg; ... @endcode
* <li> 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
* </ul>
* </ul> @n
* Despite these features the code size remains tiny.
* It is smaller than <a href="http://uclibc.org">uClibc</a>'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:
* <a style="font-size:larger;font-weight:bold" href="http://sourceforge.net/projects/optionparser/files/optionparser-1.7.tar.gz/download">optionparser-1.7.tar.gz</a> @n
* Just the header (this is all you really need):
* <a style="font-size:larger;font-weight:bold" href="http://optionparser.sourceforge.net/optionparser.h">optionparser.h</a>
*
* @par Changelog:
* <b>Version 1.7:</b> Work on const-correctness. @n
* <b>Version 1.6:</b> Fix for MSC compiler. @n
* <b>Version 1.5:</b> Fixed 2 warnings about potentially uninitialized variables. @n
* Added const version of Option::next(). @n
* <b>Version 1.4:</b> Fixed 2 printUsage() bugs that messed up output with small COLUMNS values. @n
* <b>Version 1.3:</b> Compatible with Microsoft Visual C++. @n
* <b>Version 1.2:</b> 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
* <b>Version 1.1:</b> 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 <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";
* }
* @endcode
*
* @par Option syntax:
* @li The Lean Mean C++ Option Parser follows POSIX <code>getopt()</code> conventions and supports
* GNU-style <code>getopt_long()</code> long options as well as Perl-style single-minus
* long options (<code>getopt_long_only()</code>).
* @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. <code>-X -Y</code> is equivalent to @c -XY.
* @li a short option may take an argument either separate (<code>-X foo</code>) 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 <code> -ABCX foo </code> (@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 (<code> --option arg </code>) or
* attached (<code> --option=arg </code>). In the attached form the equals sign is mandatory.
* @li an empty string can be passed as an attached long option argument: <code> --option-name= </code>.
* 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.
* <code> -X-X </code>, <code>-X -X</code> or <code> --long-X=-X </code>. 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 <vtkm/internal/ExportMacros.h>
#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 <intrin.h>
#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 <code>Parser::error()==true</code>. @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=&lt;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 <code> operator const Option*() </code>.
*/
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);