[PATCH setup 1/2] Implement paired boolean options
Jon Turney
jon.turney@dronecode.org.uk
Thu Mar 19 13:15:10 GMT 2020
Add some infrastructure for options which may appear with multiple
prefixes.
Add an implementation of paired boolean options like '--enable-foo' and
'--disable-foo', or '--bar' and '--no-bar'.
Add/fix tests
---
libgetopt++/include/getopt++/BoolOption.h | 17 +++++--
libgetopt++/include/getopt++/Option.h | 6 ++-
libgetopt++/include/getopt++/OptionSet.h | 3 +-
.../include/getopt++/StringArrayOption.h | 2 +-
libgetopt++/include/getopt++/StringOption.h | 2 +-
libgetopt++/src/BoolOption.cc | 40 ++++++++++++---
libgetopt++/src/Option.cc | 7 +++
libgetopt++/src/OptionSet.cc | 50 ++++++++++++-------
libgetopt++/src/StringArrayOption.cc | 2 +-
libgetopt++/src/StringOption.cc | 2 +-
libgetopt++/tests/BoolOptionTest.cc | 26 ++++++++--
libgetopt++/tests/OptionSet.cc | 4 +-
12 files changed, 118 insertions(+), 43 deletions(-)
diff --git a/libgetopt++/include/getopt++/BoolOption.h b/libgetopt++/include/getopt++/BoolOption.h
index 35227cb..8b20e1c 100644
--- a/libgetopt++/include/getopt++/BoolOption.h
+++ b/libgetopt++/include/getopt++/BoolOption.h
@@ -23,17 +23,25 @@
class BoolOption : public Option
{
public:
+ enum class BoolOptionType
+ {
+ simple,
+ pairedAble,
+ pairedNo,
+ };
+
BoolOption(bool const defaultvalue, char shortopt, char const *longopt = 0,
- std::string const &shorthelp = std::string(),
- OptionSet &owner=GetOption::GetInstance());
+ std::string const &shorthelp = std::string(),
+ BoolOptionType type = BoolOptionType::simple,
+ OptionSet &owner=GetOption::GetInstance());
virtual ~ BoolOption ();
virtual std::string const shortOption () const;
virtual std::string const longOption () const;
+ virtual std::vector<std::string> const & longOptionPrefixes () const;
virtual std::string const shortHelp () const;
- virtual Result Process (char const *);
+ virtual Result Process (char const *, int);
virtual Argument argument () const;
operator bool () const;
-
private:
bool _value;
@@ -41,6 +49,7 @@ private:
char _shortopt;
char const *_longopt;
std::string _shorthelp;
+ BoolOptionType _type;
};
#endif // _BOOLOPTION_H_
diff --git a/libgetopt++/include/getopt++/Option.h b/libgetopt++/include/getopt++/Option.h
index a32f949..b3b140f 100644
--- a/libgetopt++/include/getopt++/Option.h
+++ b/libgetopt++/include/getopt++/Option.h
@@ -21,9 +21,10 @@
#endif
#if HAVE_STRING_H
#include <string>
-#else
+#else
#error "<string> required"
#endif
+#include <vector>
// Each registered option must implement this class.
class Option
@@ -32,13 +33,14 @@ public:
virtual ~ Option ();
virtual std::string const shortOption () const = 0;
virtual std::string const longOption () const = 0;
+ virtual std::vector<std::string> const & longOptionPrefixes () const;
virtual std::string const shortHelp () const = 0;
enum Result {
Failed,
Ok,
Stop
};
- virtual Result Process (char const *) = 0;
+ virtual Result Process (char const *, int) = 0;
enum Argument {
None,
Optional,
diff --git a/libgetopt++/include/getopt++/OptionSet.h b/libgetopt++/include/getopt++/OptionSet.h
index 4ccadda..dbd8046 100644
--- a/libgetopt++/include/getopt++/OptionSet.h
+++ b/libgetopt++/include/getopt++/OptionSet.h
@@ -44,7 +44,8 @@ private:
bool isOption(std::string::size_type) const;
void doOption(std::string &option, std::string::size_type const &pos);
bool doNoArgumentOption(std::string &option, std::string::size_type const &pos);
- Option * findOption(std::string &option, std::string::size_type const &pos) const;
+ void findOption(std::string &option, std::string::size_type const &pos,
+ Option *&theOption, int & prefixIndex) const;
std::vector<Option *> options;
std::vector<std::string> argv;
std::vector<std::string> nonoptions;
diff --git a/libgetopt++/include/getopt++/StringArrayOption.h b/libgetopt++/include/getopt++/StringArrayOption.h
index d3f87c0..b589d28 100644
--- a/libgetopt++/include/getopt++/StringArrayOption.h
+++ b/libgetopt++/include/getopt++/StringArrayOption.h
@@ -29,7 +29,7 @@ public:
virtual std::string const shortOption () const;
virtual std::string const longOption () const;
virtual std::string const shortHelp () const;
- virtual Result Process (char const *);
+ virtual Result Process (char const *, int);
virtual Argument argument () const;
operator std::vector<std::string> () const;
diff --git a/libgetopt++/include/getopt++/StringOption.h b/libgetopt++/include/getopt++/StringOption.h
index f13be8c..37e723a 100644
--- a/libgetopt++/include/getopt++/StringOption.h
+++ b/libgetopt++/include/getopt++/StringOption.h
@@ -30,7 +30,7 @@ public:
virtual std::string const shortOption () const;
virtual std::string const longOption () const;
virtual std::string const shortHelp () const;
- virtual Result Process (char const *);
+ virtual Result Process (char const *, int);
virtual Argument argument () const;
operator const std::string& () const;
diff --git a/libgetopt++/src/BoolOption.cc b/libgetopt++/src/BoolOption.cc
index 4b26553..37d9a22 100644
--- a/libgetopt++/src/BoolOption.cc
+++ b/libgetopt++/src/BoolOption.cc
@@ -16,10 +16,10 @@
#include <getopt++/BoolOption.h>
BoolOption::BoolOption(bool const defaultvalue, char shortopt,
- char const *longopt, std::string const &shorthelp,
- OptionSet &owner) : _value (defaultvalue) ,
- _ovalue (defaultvalue), _shortopt(shortopt),
- _longopt (longopt), _shorthelp (shorthelp)
+ char const *longopt, std::string const &shorthelp,
+ BoolOptionType type, OptionSet &owner) :
+ _value (defaultvalue), _ovalue (defaultvalue), _shortopt(shortopt),
+ _longopt (longopt), _shorthelp (shorthelp), _type(type)
{
owner.Register (this);
};
@@ -38,6 +38,24 @@ BoolOption::longOption () const
return _longopt;
}
+std::vector<std::string> const &
+BoolOption::longOptionPrefixes () const
+{
+ switch (_type)
+ {
+ default:
+ case BoolOption::BoolOptionType::simple:
+ static std::vector<std::string> simple = {""};
+ return simple;
+ case BoolOption::BoolOptionType::pairedAble:
+ static std::vector<std::string> able = {"enable-", "disable-"};
+ return able;
+ case BoolOption::BoolOptionType::pairedNo:
+ static std::vector<std::string> no = {"", "no-"};
+ return no;
+ }
+}
+
std::string const
BoolOption::shortHelp () const
{
@@ -45,9 +63,19 @@ BoolOption::shortHelp () const
}
Option::Result
-BoolOption::Process (char const *)
+BoolOption::Process (char const *, int prefixIndex)
{
- _value = !_ovalue;
+ switch (_type)
+ {
+ default:
+ case BoolOption::BoolOptionType::simple:
+ _value = !_ovalue;
+ case BoolOption::BoolOptionType::pairedAble:
+ _value = (prefixIndex == 0);
+ case BoolOption::BoolOptionType::pairedNo:
+ _value = (prefixIndex == 0);
+ }
+
return Ok;
}
diff --git a/libgetopt++/src/Option.cc b/libgetopt++/src/Option.cc
index 7c61eba..2e6e9d8 100644
--- a/libgetopt++/src/Option.cc
+++ b/libgetopt++/src/Option.cc
@@ -22,3 +22,10 @@ Option::Option () : present(false)
Option::~Option ()
{
}
+
+std::vector<std::string> const &
+Option::longOptionPrefixes () const
+{
+ static std::vector<std::string> noprefix = {""};
+ return noprefix;
+}
diff --git a/libgetopt++/src/OptionSet.cc b/libgetopt++/src/OptionSet.cc
index a8f02e8..5a8ddee 100644
--- a/libgetopt++/src/OptionSet.cc
+++ b/libgetopt++/src/OptionSet.cc
@@ -38,37 +38,47 @@ OptionSet::processOne()
if (!isOption(pos)) {
/* Push the non option into storage */
- if (nonOptionHandler) {
- lastResult = nonOptionHandler->Process(option.c_str());
- } else {
- nonoptions.push_back(option);
- lastResult = Option::Ok;
- }
+ if (nonOptionHandler) {
+ lastResult = nonOptionHandler->Process(option.c_str(), 0);
+ } else {
+ nonoptions.push_back(option);
+ lastResult = Option::Ok;
+ }
} else {
- doOption(option, pos);
+ doOption(option, pos);
}
}
-Option *
-OptionSet::findOption(std::string &option, std::string::size_type const &pos) const
+void
+OptionSet::findOption(std::string &option, std::string::size_type const &pos,
+ Option *&theOption, int & prefixIndex) const
{
- Option *theOption = NULL;
+ theOption = NULL;
+ prefixIndex = 0;
for (std::vector<Option *>::const_iterator i = options.begin(); i != options.end();
++i) {
if (pos == 1) {
if (option[0] == (*i)->shortOption()[0]) {
theOption = (*i);
+ return;
}
} else {
- /* pos == 2 : todo - prefix matches */
-
- if (option.find((*i)->longOption()) == 0) {
+ /* pos == 2 */
+ std::vector<std::string> prefixes = (*i)->longOptionPrefixes();
+ for (std::vector<std::string>::const_iterator j = prefixes.begin();
+ j != prefixes.end();
+ j++)
+ {
+ std::string prefixedOption = *j + (*i)->longOption();
+ if (option.find(prefixedOption) == 0) {
theOption = (*i);
+ prefixIndex = j - prefixes.begin();
+ return;
+ }
}
}
}
- return theOption;
}
bool
@@ -98,7 +108,9 @@ OptionSet::doOption(std::string &option, std::string::size_type const &pos)
{
lastResult = Option::Failed;
option.erase(0, pos);
- Option *theOption = findOption(option, pos);
+ Option *theOption = NULL;
+ int prefixIndex = 0;
+ findOption(option, pos, theOption, prefixIndex);
char const *optionValue = NULL;
std::string value;
@@ -108,9 +120,9 @@ OptionSet::doOption(std::string &option, std::string::size_type const &pos)
switch (theOption->argument()) {
case Option::None:
- if (!doNoArgumentOption (option, pos))
- return;
- break;
+ if (!doNoArgumentOption (option, pos))
+ return;
+ break;
case Option::Optional: {
if (pos == 1) {
@@ -231,7 +243,7 @@ OptionSet::doOption(std::string &option, std::string::size_type const &pos)
break;
}
theOption->setPresent(true);
- lastResult = theOption->Process(optionValue);
+ lastResult = theOption->Process(optionValue, prefixIndex);
}
OptionSet::OptionSet () {}
diff --git a/libgetopt++/src/StringArrayOption.cc b/libgetopt++/src/StringArrayOption.cc
index 7cbee20..fe6f613 100644
--- a/libgetopt++/src/StringArrayOption.cc
+++ b/libgetopt++/src/StringArrayOption.cc
@@ -44,7 +44,7 @@ StringArrayOption::shortHelp () const
}
Option::Result
-StringArrayOption::Process (char const *optarg)
+StringArrayOption::Process (char const *optarg, int prefixIndex)
{
if (optarg)
{
diff --git a/libgetopt++/src/StringOption.cc b/libgetopt++/src/StringOption.cc
index d359236..e3c4af6 100644
--- a/libgetopt++/src/StringOption.cc
+++ b/libgetopt++/src/StringOption.cc
@@ -49,7 +49,7 @@ StringOption::shortHelp () const
}
Option::Result
-StringOption::Process (char const *optarg)
+StringOption::Process (char const *optarg, int prefixIndex)
{
if (optarg)
_value = optarg;
diff --git a/libgetopt++/tests/BoolOptionTest.cc b/libgetopt++/tests/BoolOptionTest.cc
index d2c5190..7fdd259 100644
--- a/libgetopt++/tests/BoolOptionTest.cc
+++ b/libgetopt++/tests/BoolOptionTest.cc
@@ -20,16 +20,18 @@
#include <iostream>
#include <string.h>
-static BoolOption testoption (false, 't', "testoption", "Tests the use of boolean options");
int
main (int anargc, char **anargv)
{
+ BoolOption helpoption (false, 'h', "help", "Tests the use of help output.");
+ BoolOption helpoption2 (false, 'o', "help2", "Tests the use of help output.");
+ BoolOption ableoption (false, '\0', "foo", "Tests the use of paired option.", BoolOption::BoolOptionType::pairedAble);
+
int argc=2;
char *argv[4];
argv[0] = strdup("BoolOptionTest");
argv[1] = strdup("-h");
{
- BoolOption helpoption (false, 'h', "help", "Tests the use of help output.");
if (!GetOption::GetInstance().Process (argc, argv, NULL))
{
std::cout << "Failed to process options" << std::endl;
@@ -44,17 +46,31 @@ main (int anargc, char **anargv)
argc = 0;
}
{
- BoolOption helpoption (false, 'h', "help", "Tests the use of help output.");
if (!GetOption::GetInstance().Process (argc, argv, NULL))
{
std::cout << "Failed to process options (2) " << std::endl;
return 1;
}
- if (helpoption)
+ if (helpoption2)
{
- std::cout << "Recieved unexpected help option" << std::endl;
+ std::cout << "Received unexpected help option" << std::endl;
return 1;
}
}
+ argc=2;
+ argv[0] = strdup("BoolOptionTest");
+ argv[1] = strdup("--enable-foo");
+ {
+ if (!GetOption::GetInstance().Process (argc, argv, NULL))
+ {
+ std::cout << "Failed to process options (3) " << std::endl;
+ return 1;
+ }
+ if (!ableoption)
+ {
+ std::cout << "Did not receive expected enable-foo option" << std::endl;
+ return 1;
+ }
+ }
return 0;
}
diff --git a/libgetopt++/tests/OptionSet.cc b/libgetopt++/tests/OptionSet.cc
index ff63e39..4eac880 100644
--- a/libgetopt++/tests/OptionSet.cc
+++ b/libgetopt++/tests/OptionSet.cc
@@ -36,7 +36,7 @@ class StringCollector : public Option
{
return "";
}
- virtual Option::Result Process(const char * value);
+ virtual Option::Result Process(const char * value, int index);
virtual Option::Argument argument() const
{
return Required;
@@ -46,7 +46,7 @@ class StringCollector : public Option
};
Option::Result
-StringCollector::Process(const char * value)
+StringCollector::Process(const char * value, int index)
{
values.push_back(value);
if (values.size() == 1)
--
2.21.0
More information about the Cygwin-apps
mailing list