Merge branch 'default_implicit'
This commit is contained in:
commit
fdf49ba719
211
src/cxxopts.hpp
211
src/cxxopts.hpp
@ -214,15 +214,36 @@ namespace cxxopts
|
|||||||
|
|
||||||
namespace cxxopts
|
namespace cxxopts
|
||||||
{
|
{
|
||||||
class Value
|
class Value : public std::enable_shared_from_this<Value>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
parse(const std::string& text) const = 0;
|
parse(const std::string& text) const = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
parse() const = 0;
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
has_arg() const = 0;
|
has_arg() const = 0;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
has_default() const = 0;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
has_implicit() const = 0;
|
||||||
|
|
||||||
|
virtual std::string
|
||||||
|
get_default_value() const = 0;
|
||||||
|
|
||||||
|
virtual std::string
|
||||||
|
get_implicit_value() const = 0;
|
||||||
|
|
||||||
|
virtual std::shared_ptr<Value>
|
||||||
|
default_value(const std::string& value) = 0;
|
||||||
|
|
||||||
|
virtual std::shared_ptr<Value>
|
||||||
|
implicit_value(const std::string& value) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OptionException : public std::exception
|
class OptionException : public std::exception
|
||||||
@ -375,7 +396,7 @@ namespace cxxopts
|
|||||||
|
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
parse_value(const std::string& text, bool& value)
|
parse_value(const std::string& /*text*/, bool& value)
|
||||||
{
|
{
|
||||||
//TODO recognise on, off, yes, no, enable, disable
|
//TODO recognise on, off, yes, no, enable, disable
|
||||||
//so that we can write --long=yes explicitly
|
//so that we can write --long=yes explicitly
|
||||||
@ -395,16 +416,16 @@ namespace cxxopts
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class default_value : public Value
|
class standard_value : public Value
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
default_value()
|
standard_value()
|
||||||
: m_result(std::make_shared<T>())
|
: m_result(std::make_shared<T>())
|
||||||
, m_store(m_result.get())
|
, m_store(m_result.get())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
default_value(T* t)
|
standard_value(T* t)
|
||||||
: m_store(t)
|
: m_store(t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -412,7 +433,20 @@ namespace cxxopts
|
|||||||
void
|
void
|
||||||
parse(const std::string& text) const
|
parse(const std::string& text) const
|
||||||
{
|
{
|
||||||
parse_value(text, *m_store);
|
if (m_implicit && text.empty())
|
||||||
|
{
|
||||||
|
parse_value(m_implicit_value, *m_store);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parse_value(text, *m_store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parse() const
|
||||||
|
{
|
||||||
|
parse_value(m_default_value, *m_store);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -421,6 +455,44 @@ namespace cxxopts
|
|||||||
return value_has_arg<T>::value;
|
return value_has_arg<T>::value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
has_default() const
|
||||||
|
{
|
||||||
|
return m_default;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
has_implicit() const
|
||||||
|
{
|
||||||
|
return m_implicit;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::shared_ptr<Value>
|
||||||
|
default_value(const std::string& value){
|
||||||
|
m_default = true;
|
||||||
|
m_default_value = value;
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::shared_ptr<Value>
|
||||||
|
implicit_value(const std::string& value){
|
||||||
|
m_implicit = true;
|
||||||
|
m_implicit_value = value;
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
get_default_value() const
|
||||||
|
{
|
||||||
|
return m_default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
get_implicit_value() const
|
||||||
|
{
|
||||||
|
return m_implicit_value;
|
||||||
|
}
|
||||||
|
|
||||||
const T&
|
const T&
|
||||||
get() const
|
get() const
|
||||||
{
|
{
|
||||||
@ -434,25 +506,28 @@ namespace cxxopts
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::shared_ptr<T> m_result;
|
std::shared_ptr<T> m_result;
|
||||||
T* m_store;
|
T* m_store;
|
||||||
|
bool m_default = false;
|
||||||
|
std::string m_default_value;
|
||||||
|
bool m_implicit = false;
|
||||||
|
std::string m_implicit_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<Value>
|
std::shared_ptr<Value>
|
||||||
value()
|
value()
|
||||||
{
|
{
|
||||||
return std::make_shared<values::default_value<T>>();
|
return std::make_shared<values::standard_value<T>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<Value>
|
std::shared_ptr<Value>
|
||||||
value(T& t)
|
value(T& t)
|
||||||
{
|
{
|
||||||
return std::make_shared<values::default_value<T>>(&t);
|
return std::make_shared<values::standard_value<T>>(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
class OptionAdder;
|
class OptionAdder;
|
||||||
@ -490,17 +565,28 @@ namespace cxxopts
|
|||||||
++m_count;
|
++m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parse_default()
|
||||||
|
{
|
||||||
|
m_value->parse();
|
||||||
|
++m_count;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
count() const
|
count() const
|
||||||
{
|
{
|
||||||
return m_count;
|
return m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Value& value() const {
|
||||||
|
return *m_value;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T&
|
const T&
|
||||||
as() const
|
as() const
|
||||||
{
|
{
|
||||||
return dynamic_cast<const values::default_value<T>&>(*m_value).get();
|
return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -515,6 +601,10 @@ namespace cxxopts
|
|||||||
std::string l;
|
std::string l;
|
||||||
String desc;
|
String desc;
|
||||||
bool has_arg;
|
bool has_arg;
|
||||||
|
bool has_default;
|
||||||
|
std::string default_value;
|
||||||
|
bool has_implicit;
|
||||||
|
std::string implicit_value;
|
||||||
std::string arg_help;
|
std::string arg_help;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -622,7 +712,7 @@ namespace cxxopts
|
|||||||
(
|
(
|
||||||
int argc,
|
int argc,
|
||||||
char* argv[],
|
char* argv[],
|
||||||
int argPos,
|
int& current,
|
||||||
std::shared_ptr<OptionDetails> value,
|
std::shared_ptr<OptionDetails> value,
|
||||||
const std::string& name
|
const std::string& name
|
||||||
);
|
);
|
||||||
@ -686,12 +776,12 @@ namespace cxxopts
|
|||||||
String
|
String
|
||||||
format_option
|
format_option
|
||||||
(
|
(
|
||||||
const std::string& s,
|
const HelpOptionDetails& o
|
||||||
const std::string& l,
|
|
||||||
bool has_arg,
|
|
||||||
const std::string& arg_help
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
auto& s = o.s;
|
||||||
|
auto& l = o.l;
|
||||||
|
|
||||||
String result = " ";
|
String result = " ";
|
||||||
|
|
||||||
if (s.size() > 0)
|
if (s.size() > 0)
|
||||||
@ -708,15 +798,17 @@ namespace cxxopts
|
|||||||
result += " --" + toLocalString(l);
|
result += " --" + toLocalString(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_arg)
|
if (o.has_arg)
|
||||||
{
|
{
|
||||||
if (arg_help.size() != 0)
|
auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
|
||||||
|
|
||||||
|
if (o.has_implicit)
|
||||||
{
|
{
|
||||||
result += " " + toLocalString(arg_help);
|
result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result += " arg";
|
result += " " + arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -726,20 +818,27 @@ namespace cxxopts
|
|||||||
String
|
String
|
||||||
format_description
|
format_description
|
||||||
(
|
(
|
||||||
const String& text,
|
const HelpOptionDetails& o,
|
||||||
int start,
|
int start,
|
||||||
int width
|
int width
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
auto desc = o.desc;
|
||||||
|
|
||||||
|
if (o.has_default)
|
||||||
|
{
|
||||||
|
desc += toLocalString(" (default:" + o.default_value + ")");
|
||||||
|
}
|
||||||
|
|
||||||
String result;
|
String result;
|
||||||
|
|
||||||
auto current = std::begin(text);
|
auto current = std::begin(desc);
|
||||||
auto startLine = current;
|
auto startLine = current;
|
||||||
auto lastSpace = current;
|
auto lastSpace = current;
|
||||||
|
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
while (current != std::end(text))
|
while (current != std::end(desc))
|
||||||
{
|
{
|
||||||
if (*current == ' ')
|
if (*current == ' ')
|
||||||
{
|
{
|
||||||
@ -816,7 +915,7 @@ void
|
|||||||
Options::parse_option
|
Options::parse_option
|
||||||
(
|
(
|
||||||
std::shared_ptr<OptionDetails> value,
|
std::shared_ptr<OptionDetails> value,
|
||||||
const std::string& name,
|
const std::string& /*name*/,
|
||||||
const std::string& arg
|
const std::string& arg
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -828,17 +927,34 @@ Options::checked_parse_arg
|
|||||||
(
|
(
|
||||||
int argc,
|
int argc,
|
||||||
char* argv[],
|
char* argv[],
|
||||||
int argPos,
|
int& current,
|
||||||
std::shared_ptr<OptionDetails> value,
|
std::shared_ptr<OptionDetails> value,
|
||||||
const std::string& name
|
const std::string& name
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (argPos >= argc)
|
if (current + 1 >= argc)
|
||||||
{
|
{
|
||||||
throw missing_argument_exception(name);
|
if (value->value().has_implicit())
|
||||||
|
{
|
||||||
|
parse_option(value, name, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw missing_argument_exception(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (argv[current + 1][0] == '-' && value->value().has_implicit())
|
||||||
|
{
|
||||||
|
parse_option(value, name, "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parse_option(value, name, argv[current + 1]);
|
||||||
|
++current;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_option(value, name, argv[argPos]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -909,7 +1025,7 @@ Options::parse(int& argc, char**& argv)
|
|||||||
{
|
{
|
||||||
const std::string& s = result[4];
|
const std::string& s = result[4];
|
||||||
|
|
||||||
for (int i = 0; i != s.size(); ++i)
|
for (std::size_t i = 0; i != s.size(); ++i)
|
||||||
{
|
{
|
||||||
std::string name(1, s[i]);
|
std::string name(1, s[i]);
|
||||||
auto iter = m_options.find(name);
|
auto iter = m_options.find(name);
|
||||||
@ -931,8 +1047,11 @@ Options::parse(int& argc, char**& argv)
|
|||||||
//it must be the last argument
|
//it must be the last argument
|
||||||
if (i + 1 == s.size())
|
if (i + 1 == s.size())
|
||||||
{
|
{
|
||||||
checked_parse_arg(argc, argv, current+1, value, name);
|
checked_parse_arg(argc, argv, current, value, name);
|
||||||
++current;
|
}
|
||||||
|
else if (value->value().has_implicit())
|
||||||
|
{
|
||||||
|
parse_option(value, name, "");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -973,9 +1092,7 @@ Options::parse(int& argc, char**& argv)
|
|||||||
if (opt->has_arg())
|
if (opt->has_arg())
|
||||||
{
|
{
|
||||||
//parse the next argument
|
//parse the next argument
|
||||||
checked_parse_arg(argc, argv, current + 1, opt, name);
|
checked_parse_arg(argc, argv, current, opt, name);
|
||||||
|
|
||||||
++current;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -990,6 +1107,16 @@ Options::parse(int& argc, char**& argv)
|
|||||||
++current;
|
++current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& opt : m_options)
|
||||||
|
{
|
||||||
|
auto& detail = opt.second;
|
||||||
|
auto& value = detail->value();
|
||||||
|
|
||||||
|
if(!detail->count() && value.has_default()){
|
||||||
|
detail->parse_default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
argc = nextKeep;
|
argc = nextKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,10 +1146,12 @@ Options::add_option
|
|||||||
|
|
||||||
//add the help details
|
//add the help details
|
||||||
auto& options = m_help[group];
|
auto& options = m_help[group];
|
||||||
options.options.
|
|
||||||
emplace_back(HelpOptionDetails{s, l, stringDesc, value->has_arg(),
|
options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
|
||||||
std::move(arg_help)}
|
value->has_arg(),
|
||||||
);
|
value->has_default(), value->get_default_value(),
|
||||||
|
value->has_implicit(), value->get_implicit_value(),
|
||||||
|
std::move(arg_help)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1064,7 +1193,7 @@ Options::help_one_group(const std::string& g) const
|
|||||||
|
|
||||||
for (const auto& o : group->second.options)
|
for (const auto& o : group->second.options)
|
||||||
{
|
{
|
||||||
auto s = format_option(o.s, o.l, o.has_arg, o.arg_help);
|
auto s = format_option(o);
|
||||||
longest = std::max(longest, stringLength(s));
|
longest = std::max(longest, stringLength(s));
|
||||||
format.push_back(std::make_pair(s, String()));
|
format.push_back(std::make_pair(s, String()));
|
||||||
}
|
}
|
||||||
@ -1077,7 +1206,7 @@ Options::help_one_group(const std::string& g) const
|
|||||||
auto fiter = format.begin();
|
auto fiter = format.begin();
|
||||||
for (const auto& o : group->second.options)
|
for (const auto& o : group->second.options)
|
||||||
{
|
{
|
||||||
auto d = format_description(o.desc, longest + OPTION_DESC_GAP, allowed);
|
auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
|
||||||
|
|
||||||
result += fiter->first;
|
result += fiter->first;
|
||||||
if (stringLength(fiter->first) > longest)
|
if (stringLength(fiter->first) > longest)
|
||||||
|
|||||||
@ -38,6 +38,8 @@ int main(int argc, char* argv[])
|
|||||||
("a,apple", "an apple", cxxopts::value<bool>(apple))
|
("a,apple", "an apple", cxxopts::value<bool>(apple))
|
||||||
("b,bob", "Bob")
|
("b,bob", "Bob")
|
||||||
("f,file", "File", cxxopts::value<std::vector<std::string>>(), "FILE")
|
("f,file", "File", cxxopts::value<std::vector<std::string>>(), "FILE")
|
||||||
|
("o,output", "Output file", cxxopts::value<std::string>()
|
||||||
|
->default_value("a.out")->implicit_value("b.def"), "BIN")
|
||||||
("positional",
|
("positional",
|
||||||
"Positional arguments: these are the arguments that are entered "
|
"Positional arguments: these are the arguments that are entered "
|
||||||
"without an option", cxxopts::value<std::string>())
|
"without an option", cxxopts::value<std::string>())
|
||||||
@ -92,6 +94,12 @@ int main(int argc, char* argv[])
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.count("output"))
|
||||||
|
{
|
||||||
|
std::cout << "Output = " << options["output"].as<std::string>()
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.count("int"))
|
if (options.count("int"))
|
||||||
{
|
{
|
||||||
std::cout << "int = " << options["int"].as<int>() << std::endl;
|
std::cout << "int = " << options["int"].as<int>() << std::endl;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user