cxxopts/src/cxxopts.cpp

204 lines
3.9 KiB
C++
Raw Normal View History

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
}