mirror of
https://github.com/boostorg/program_options.git
synced 2026-01-19 04:22:15 +00:00
@@ -78,17 +78,19 @@ namespace boost { namespace program_options {
|
||||
ambiguous_option(const std::string& name,
|
||||
const std::vector<std::string>& alternatives)
|
||||
: error(std::string("ambiguous option ").append(name))
|
||||
, alternatives(alternatives)
|
||||
, m_alternatives(alternatives)
|
||||
, m_option_name(name)
|
||||
{}
|
||||
|
||||
~ambiguous_option() throw() {}
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
const std::vector<std::string>& alternatives() const throw();
|
||||
|
||||
private:
|
||||
// TODO: copy ctor might throw
|
||||
std::vector<std::string> alternatives;
|
||||
std::vector<std::string> m_alternatives;
|
||||
std::string m_option_name;
|
||||
};
|
||||
|
||||
|
||||
@@ -273,6 +273,8 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
shared_ptr<option_description> found;
|
||||
vector<string> approximate_matches;
|
||||
vector<string> full_matches;
|
||||
|
||||
// We use linear search because matching specified option
|
||||
// name with the declared option name need to take care about
|
||||
// case sensitivity and trailing '*' and so we can't use simple map.
|
||||
@@ -284,26 +286,29 @@ namespace boost { namespace program_options {
|
||||
if (r == option_description::no_match)
|
||||
continue;
|
||||
|
||||
// If we have a full patch, and an approximate match,
|
||||
// ignore approximate match instead of reporting error.
|
||||
// Say, if we have options "all" and "all-chroots", then
|
||||
// "--all" on the command line should select the first one,
|
||||
// without ambiguity.
|
||||
//
|
||||
// For now, we don't check the situation when there are
|
||||
// two full matches.
|
||||
|
||||
if (r == option_description::full_match)
|
||||
{
|
||||
return m_options[i].get();
|
||||
{
|
||||
full_matches.push_back(m_options[i]->key(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: the use of 'key' here might not
|
||||
// be the best approach.
|
||||
approximate_matches.push_back(m_options[i]->key(name));
|
||||
}
|
||||
|
||||
found = m_options[i];
|
||||
// FIXME: the use of 'key' here might not
|
||||
// be the best approach.
|
||||
approximate_matches.push_back(m_options[i]->key(name));
|
||||
}
|
||||
if (approximate_matches.size() > 1)
|
||||
if (full_matches.size() > 1)
|
||||
boost::throw_exception(
|
||||
ambiguous_option(name, full_matches));
|
||||
|
||||
// If we have a full match, and an approximate match,
|
||||
// ignore approximate match instead of reporting error.
|
||||
// Say, if we have options "all" and "all-chroots", then
|
||||
// "--all" on the command line should select the first one,
|
||||
// without ambiguity.
|
||||
if (full_matches.empty() && approximate_matches.size() > 1)
|
||||
boost::throw_exception(
|
||||
ambiguous_option(name, approximate_matches));
|
||||
|
||||
|
||||
@@ -227,6 +227,12 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
const std::vector<std::string>&
|
||||
ambiguous_option::alternatives() const throw()
|
||||
{
|
||||
return m_alternatives;
|
||||
}
|
||||
|
||||
void
|
||||
multiple_values::set_option_name(const std::string& option_name)
|
||||
|
||||
@@ -19,6 +19,30 @@ using namespace std;
|
||||
#include "minitest.hpp"
|
||||
|
||||
|
||||
void test_ambiguous()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<string>()->multitoken(), "the config file")
|
||||
("output,c", value<string>(), "the output file")
|
||||
("output,o", value<string>(), "the output file")
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "-c", "file", "-o", "anotherfile"};
|
||||
|
||||
variables_map vm;
|
||||
try {
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
}
|
||||
catch (ambiguous_option& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "-c");
|
||||
BOOST_CHECK_EQUAL(e.alternatives()[0], "cfgfile");
|
||||
BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
|
||||
}
|
||||
}
|
||||
|
||||
void test_unknown_option()
|
||||
{
|
||||
@@ -101,27 +125,11 @@ void test_multiple_occurrences()
|
||||
|
||||
int main(int /*ac*/, char** /*av*/)
|
||||
{
|
||||
test_ambiguous();
|
||||
test_unknown_option();
|
||||
test_multiple_values();
|
||||
test_multiple_occurrences();
|
||||
|
||||
bool helpflag = false;
|
||||
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<string>(), "the configfile")
|
||||
("help,h", value<bool>(&helpflag)->implicit_value(true), "help")
|
||||
;
|
||||
|
||||
const char* cmdline[] = {"program", "--cfgfile", "hugo", "-h", "yes" };
|
||||
|
||||
variables_map vm;
|
||||
store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
|
||||
const_cast<char**>(cmdline), desc), vm);
|
||||
notify(vm);
|
||||
|
||||
cout << " help: " << (helpflag ? "true" : "false") << endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user