2014-09-27 11:04:58 +04:00
|
|
|
#include "cxxopts.hpp"
|
|
|
|
|
|
|
|
namespace cxxopts
|
|
|
|
{
|
|
|
|
|
|
|
|
std::basic_regex<char> option_matcher
|
|
|
|
("--([[:alpha:]][-_[:alpha:]]+)(=(.*))?|-([a-zA-Z]+)");
|
|
|
|
|
|
|
|
std::basic_regex<char> option_specifier
|
|
|
|
("(([a-zA-Z]),)?([a-zA-Z][-_a-zA-Z]+)");
|
|
|
|
|
|
|
|
OptionAdder
|
|
|
|
Options::add_options()
|
|
|
|
{
|
|
|
|
return OptionAdder(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionAdder&
|
|
|
|
OptionAdder::operator()
|
|
|
|
(
|
|
|
|
const std::string& opts,
|
2014-09-27 16:04:53 +04:00
|
|
|
const std::string& desc,
|
|
|
|
std::shared_ptr<const Value> value
|
2014-09-27 11:04:58 +04:00
|
|
|
)
|
|
|
|
{
|
|
|
|
std::match_results<const char*> result;
|
|
|
|
std::regex_match(opts.c_str(), result, option_specifier);
|
|
|
|
|
|
|
|
if (result.empty())
|
|
|
|
{
|
|
|
|
throw invalid_option_format_error(opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& s = result[2];
|
|
|
|
const auto& l = result[3];
|
|
|
|
|
2014-09-27 16:04:53 +04:00
|
|
|
auto option = std::make_shared<OptionDetails>(desc, value);
|
2014-09-27 11:04:58 +04:00
|
|
|
|
|
|
|
if (s.length() != 0)
|
|
|
|
{
|
2014-09-27 16:04:53 +04:00
|
|
|
auto in = m_options.m_short.insert(std::make_pair(s.str(), option));
|
2014-09-27 11:04:58 +04:00
|
|
|
|
2014-09-27 16:04:53 +04:00
|
|
|
if (!in.second)
|
2014-09-27 11:04:58 +04:00
|
|
|
{
|
|
|
|
throw option_exists_error(s.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l.length() != 0)
|
|
|
|
{
|
2014-09-27 16:04:53 +04:00
|
|
|
auto in = m_options.m_long.insert(std::make_pair(l, option));
|
2014-09-27 11:04:58 +04:00
|
|
|
|
2014-09-27 16:04:53 +04:00
|
|
|
if (!in.second)
|
2014-09-27 11:04:58 +04:00
|
|
|
{
|
|
|
|
throw option_exists_error(l.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2014-10-01 11:36:43 +04:00
|
|
|
void
|
|
|
|
Options::parse_option
|
|
|
|
(
|
|
|
|
std::shared_ptr<OptionDetails> value,
|
|
|
|
const std::string& name,
|
|
|
|
const std::string& arg
|
|
|
|
)
|
|
|
|
{
|
|
|
|
auto& v = m_parsed[name];
|
|
|
|
value->parse("", v.value);
|
|
|
|
++v.count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Options::checked_parse_arg
|
|
|
|
(
|
|
|
|
int argc,
|
|
|
|
char* argv[],
|
|
|
|
int argPos,
|
|
|
|
std::shared_ptr<OptionDetails> value,
|
|
|
|
const std::string& name
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (argPos >= argc)
|
|
|
|
{
|
|
|
|
throw missing_argument_exception(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_option(value, name, argv[argPos]);
|
|
|
|
}
|
|
|
|
|
2014-09-27 16:04:53 +04:00
|
|
|
void
|
|
|
|
Options::parse(int& argc, char**& argv)
|
|
|
|
{
|
|
|
|
int current = 1;
|
|
|
|
|
|
|
|
std::set<int> consumed;
|
|
|
|
|
|
|
|
while (current != argc)
|
|
|
|
{
|
|
|
|
std::match_results<const char*> result;
|
|
|
|
std::regex_match(argv[current], result, option_matcher);
|
|
|
|
|
|
|
|
if (result.empty())
|
|
|
|
{
|
|
|
|
//handle empty
|
|
|
|
|
2014-10-01 11:36:43 +04:00
|
|
|
//for now, throw an exception
|
|
|
|
throw option_not_exists_exception(argv[current]);
|
|
|
|
|
2014-09-27 16:04:53 +04:00
|
|
|
//if we return from here then it was parsed successfully, so continue
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//short or long option?
|
|
|
|
if (result[4].length() != 0)
|
|
|
|
{
|
|
|
|
std::string s = result[4];
|
|
|
|
|
|
|
|
for (int i = 0; i != s.size(); ++i)
|
|
|
|
{
|
2014-09-28 15:09:21 +04:00
|
|
|
std::string name(1, s[i]);
|
|
|
|
auto iter = m_short.find(name);
|
2014-09-27 16:04:53 +04:00
|
|
|
|
|
|
|
if (iter == m_short.end())
|
|
|
|
{
|
2014-09-28 15:41:19 +04:00
|
|
|
throw option_not_exists_exception(name);
|
2014-09-27 16:04:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
auto value = iter->second;
|
|
|
|
|
2014-09-28 15:09:21 +04:00
|
|
|
//if no argument then just add it
|
|
|
|
if (!value->has_arg())
|
2014-09-27 16:04:53 +04:00
|
|
|
{
|
2014-10-01 11:36:43 +04:00
|
|
|
parse_option(value, name);
|
2014-09-28 15:09:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//it must be the last argument
|
|
|
|
if (i + 1 == s.size())
|
|
|
|
{
|
2014-10-01 11:36:43 +04:00
|
|
|
checked_parse_arg(argc, argv, current+1, value, name);
|
2014-10-01 11:52:34 +04:00
|
|
|
++current;
|
2014-09-28 15:09:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//error
|
2014-09-28 15:41:19 +04:00
|
|
|
throw option_requires_argument_exception(name);
|
2014-09-28 15:09:21 +04:00
|
|
|
}
|
2014-09-27 16:04:53 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (result[1].length() != 0)
|
|
|
|
{
|
2014-09-28 15:09:21 +04:00
|
|
|
std::string name = result[1];
|
|
|
|
|
|
|
|
auto iter = m_long.find(name);
|
|
|
|
|
|
|
|
if (iter == m_long.end())
|
2014-09-27 16:04:53 +04:00
|
|
|
{
|
2014-09-28 15:41:19 +04:00
|
|
|
throw option_not_exists_exception(name);
|
2014-09-28 15:09:21 +04:00
|
|
|
}
|
2014-09-27 16:04:53 +04:00
|
|
|
|
2014-09-28 15:09:21 +04:00
|
|
|
auto opt = iter->second;
|
|
|
|
|
|
|
|
//equals provided for long option?
|
|
|
|
if (result[3].length() != 0)
|
|
|
|
{
|
|
|
|
//parse the option given
|
2014-10-01 11:36:43 +04:00
|
|
|
|
|
|
|
//but if it doesn't take an argument, this is an error
|
|
|
|
if (!opt->has_arg())
|
|
|
|
{
|
|
|
|
throw option_not_has_argument_exception(name, result[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_option(opt, name, result[3]);
|
2014-09-28 15:09:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (opt->has_arg())
|
2014-09-27 16:04:53 +04:00
|
|
|
{
|
2014-09-28 15:09:21 +04:00
|
|
|
//parse the next argument
|
2014-10-01 11:36:43 +04:00
|
|
|
checked_parse_arg(argc, argv, current + 1, opt, name);
|
2014-10-01 11:52:34 +04:00
|
|
|
|
|
|
|
++current;
|
2014-09-28 15:09:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//parse with empty argument
|
2014-10-01 11:36:43 +04:00
|
|
|
parse_option(opt, name);
|
2014-09-27 16:04:53 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
++current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-27 11:04:58 +04:00
|
|
|
}
|