Skip to content

Commit

Permalink
options can be set multiple times
Browse files Browse the repository at this point in the history
  • Loading branch information
badaix committed Jan 19, 2016
1 parent ebce999 commit 59fddc9
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 96 deletions.
87 changes: 11 additions & 76 deletions PoplTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,88 +22,21 @@ using namespace std;
using namespace popl;


void test(int argc, char **argv)
{
OptionParser op("Allowed options");
std::string s;
int i, m;
bool version;

Switch helpSwitchOption("h", "help", "produce help message");
Switch versionSwitchOption("v", "version", "show version number", &version);

Value<int> longOption("", "1234567890123456789012345678901234567890", "test of a long option name");

Value<float> floatOption("f", "float", "test for float values");
Value<float> floatOptionDefault("", "floatDefault", "test for float values with default", 0.1);
Value<int> intOption("i", "int", "test for int values");
Value<int> intOptionDefault("", "intDefault", "test for int values with default", 42);
Value<int> intOptionDefaultAssign("", "intDefaultAssign", "test for int values with default\nAssign result to variable i", 42, &i);
Value<string> stringOption("s", "string", "test for string values");
Value<string> stringOptionAssign("", "stringAssign", "test for string values\nAssign result to variable s", "", &s);

Implicit<int> implicitIntOption("m", "implicit", "implicit test", 5, &m);

op.add(helpSwitchOption)
.add(versionSwitchOption)
.add(longOption)
.add(floatOption)
.add(floatOptionDefault)
.add(intOption)
.add(intOptionDefault)
.add(intOptionDefaultAssign)
.add(stringOption)
.add(stringOptionAssign)
.add(implicitIntOption);

op.parse(argc, argv);

if (helpSwitchOption.isSet())
{
cout << op << "\n";
return;
}

if (version)
{
cout << POPL_VERSION << "\n";
return;
}

cout
<< "floatOption isSet: " << floatOption.isSet() << ", value: " << floatOption.getValue() << "\n"
<< "floatOptionDefault isSet: " << floatOptionDefault.isSet() << ", value: " << floatOptionDefault.getValue() << "\n"
<< "intOption isSet: " << intOption.isSet() << ", value: " << intOption.getValue() << "\n"
<< "intOptionDefault isSet: " << intOptionDefault.isSet() << ", value: " << intOptionDefault.getValue() << "\n"
<< "intOptionDefaultA isSet: " << intOptionDefaultAssign.isSet() << ", value: " << intOptionDefaultAssign.getValue() << ", var: " << i << "\n"
<< "stringOption isSet: " << stringOption.isSet() << ", value: " << stringOption.getValue() << "\n"
<< "stringOptionAssign isSet: " << stringOptionAssign.isSet() << ", value: " << stringOptionAssign.getValue() << ", var: " << s << "\n"
<< "implicitIntOption isSet: " << implicitIntOption.isSet() << ", value: " << implicitIntOption.getValue() << ", var: " << m << "\n";

for (size_t n=0; n<op.nonOptionArgs().size(); ++n)
cout << "NonOptionArg: " << op.nonOptionArgs()[n] << "\n";

for (size_t n=0; n<op.unknownOptions().size(); ++n)
cout << "UnknownOptions: " << op.unknownOptions()[n] << "\n";
}


int main(int argc, char **argv)
{
float f;
int m;
bool t;

Switch helpOption("h", "help", "produce help message");
Switch testOption("t", "test", "execute another test", &t);
Value<float> floatOption("f", "float", "test for float values", 1.23, &f);
Value<float> floatOption("f", "float", "test for float values", 1.23f, &f);
Value<double> doubleOption("d", "double", "test for double values", 3.14159265359);
Value<string> stringOption("s", "string", "test for string values");
Implicit<int> implicitIntOption("m", "implicit", "implicit test", 42, &m);

OptionParser op("Allowed options");
op.add(helpOption)
.add(testOption)
.add(floatOption)
.add(doubleOption)
.add(stringOption)
.add(implicitIntOption);

Expand All @@ -122,13 +55,15 @@ int main(int argc, char **argv)
cout << "UnknownOptions: " << op.unknownOptions()[n] << "\n";

// print all the configured values
cout << "testOption - value: " << testOption.getValue() << ", isSet: " << testOption.isSet() << ", count: " << testOption.count() << ", reference: " << t << "\n";
cout << "floatOption - value: " << floatOption.getValue() << ", reference: " << f << "\n";
cout << "stringOption - value: " << stringOption.getValue() << "\n";
cout << "floatOption - isSet: " << floatOption.isSet() << ", value: " << floatOption.getValue() << ", reference: " << f << "\n";
cout << "doubleOption - isSet: " << doubleOption.isSet() << ", value: " << doubleOption.getValue() << "\n";
if (stringOption.isSet())
{
for (size_t n=0; n<stringOption.count(); ++n)
cout << "stringOption - value: " << stringOption.getValue(n) << "\n";
}
cout << "stringOption - value: " << stringOption.getValue(10) << "\n";
cout << "implicitIntOption - value: " << implicitIntOption.getValue() << ", isSet: " << implicitIntOption.isSet() << ", reference: " << m << "\n";

if (t)
test(argc, argv);
}


76 changes: 56 additions & 20 deletions include/popl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
namespace popl
{

#define POPL_VERSION "0.9"
#define POPL_VERSION "0.10"

class Option
{
Expand Down Expand Up @@ -79,15 +79,16 @@ class Value : public Option

Value<T>& assignTo(T* var);
Value<T>& setDefault(const T& value);
T getValue() const;
T getValue(size_t idx = 0) const;

protected:
virtual void parse(const std::string& whatOption, const char* value);
virtual std::string optionToString() const;
virtual int hasArg() const;
virtual void addValue(const T& value);
virtual void updateReference();
T* assignTo_;
T value_;
std::vector<T> values_;
T default_;
bool hasDefault_;
};
Expand Down Expand Up @@ -202,7 +203,7 @@ unsigned int Option::count() const

bool Option::isSet() const
{
return (count_ > 0);
return (count() > 0);
}


Expand Down Expand Up @@ -248,15 +249,13 @@ Value<T>::Value(const std::string& shortOption, const std::string& longOption, c
assignTo_(NULL),
hasDefault_(false)
{
updateReference();
}


template<class T>
Value<T>::Value(const std::string& shortOption, const std::string& longOption, const std::string& description, const T& defaultVal, T* assignTo) :
Option(shortOption, longOption, description),
assignTo_(assignTo),
value_(defaultVal),
default_(defaultVal),
hasDefault_(true)
{
Expand All @@ -275,7 +274,6 @@ Value<T>& Value<T>::assignTo(T* var)
template<class T>
Value<T>& Value<T>::setDefault(const T& value)
{
value_ = value;
default_ = value;
hasDefault_ = true;
return *this;
Expand All @@ -286,14 +284,54 @@ template<class T>
void Value<T>::updateReference()
{
if (assignTo_ != NULL)
*assignTo_ = value_;
{
if (isSet() || hasDefault_)
*assignTo_ = getValue();
}
}


template<class T>
T Value<T>::getValue() const
void Value<T>::addValue(const T& value)
{
return value_;
values_.push_back(value);
++count_;
updateReference();
}


template<class T>
T Value<T>::getValue(size_t idx) const
{
if (!isSet())
{
if (hasDefault_)
return default_;
else
{
std::stringstream optionStr;
if (getShortOption() != 0)
optionStr << "-" << getShortOption();
else
optionStr << "--" << getLongOption();

throw std::out_of_range("option not set: \"" + optionStr.str() + "\"");
}
}

if (idx >= count_)
{
std::stringstream optionStr;
optionStr << "index out of range (" << idx << ") for \"";
if (getShortOption() != 0)
optionStr << "-" << getShortOption();
else
optionStr << "--" << getLongOption();
optionStr << "\"";
throw std::out_of_range(optionStr.str());
}

return values_[idx];
}


Expand All @@ -307,14 +345,14 @@ int Value<T>::hasArg() const
template<>
void Value<std::string>::parse(const std::string& whatOption, const char* value)
{
value_ = value;
updateReference();
addValue(value);
}


template<class T>
void Value<T>::parse(const std::string& whatOption, const char* value)
{
T parsedValue;
std::string strValue;
if (value != NULL)
strValue = value;
Expand All @@ -324,7 +362,7 @@ void Value<T>::parse(const std::string& whatOption, const char* value)
while (is.good())
{
if (is.peek() != EOF)
is >> value_;
is >> parsedValue;
else
break;

Expand All @@ -340,7 +378,7 @@ void Value<T>::parse(const std::string& whatOption, const char* value)
if (strValue.empty())
throw std::invalid_argument("missing argument for " + whatOption);

updateReference();
addValue(parsedValue);
}


Expand Down Expand Up @@ -392,7 +430,7 @@ void Implicit<T>::parse(const std::string& whatOption, const char* value)
if (value != NULL)
Value<T>::parse(whatOption, value);
else
this->updateReference();
this->addValue(this->default_);
}


Expand Down Expand Up @@ -424,8 +462,7 @@ Switch::Switch(const std::string& shortOption, const std::string& longOption, co

void Switch::parse(const std::string& whatOption, const char* value)
{
value_ = true;
updateReference();
addValue(true);
}


Expand Down Expand Up @@ -538,7 +575,6 @@ void OptionParser::parse(int argc, char **argv)
for (size_t opt = 0; opt < options_.size(); ++opt)
{
Option* option(options_[opt]);
option->updateReference();
if (!option->getLongOption().empty())
{
::option o;
Expand Down Expand Up @@ -595,7 +631,8 @@ void OptionParser::parse(int argc, char **argv)
else if (c == '?')
{
// std::cout << "unknown(?): " << c << ", " << (char)c << ", " << optopt << ", " << (char)optopt << ", " << argv[curind] << "\n";
unknownOptions_.push_back(argv[curind]);
if (std::find(unknownOptions_.begin(), unknownOptions_.end(), argv[curind]) == unknownOptions_.end())
unknownOptions_.push_back(argv[curind]);
}
/// missing argument
else if (c == ':')
Expand All @@ -605,7 +642,6 @@ void OptionParser::parse(int argc, char **argv)

if (option != NULL)
{
++option->count_;
option->parse(argv[curind], optarg);
}
}
Expand Down

0 comments on commit 59fddc9

Please sign in to comment.