diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 1ef1e15..59a7178 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1095,6 +1095,7 @@ namespace cxxopts ParseResult( const std::unordered_map>&, std::vector, + bool allow_unrecognised, int&, char**&); size_t @@ -1174,6 +1175,8 @@ namespace cxxopts std::unordered_set m_positional_set; std::unordered_map, OptionValue> m_results; + bool m_allow_unrecognised; + std::vector m_sequential; }; @@ -1187,6 +1190,7 @@ namespace cxxopts , m_custom_help("[OPTION...]") , m_positional_help("positional parameters") , m_show_positional(false) + , m_allow_unrecognised(false) , m_next_positional(m_positional.end()) { } @@ -1212,6 +1216,13 @@ namespace cxxopts return *this; } + Options& + allow_unrecognised_options() + { + m_allow_unrecognised = true; + return *this; + } + ParseResult parse(int& argc, char**& argv); @@ -1275,6 +1286,7 @@ namespace cxxopts std::string m_custom_help; std::string m_positional_help; bool m_show_positional; + bool m_allow_unrecognised; std::unordered_map> m_options; std::vector m_positional; @@ -1431,11 +1443,13 @@ ParseResult::ParseResult ( const std::unordered_map>& options, std::vector positional, + bool allow_unrecognised, int& argc, char**& argv ) : m_options(options) , m_positional(std::move(positional)) , m_next_positional(m_positional.begin()) +, m_allow_unrecognised(allow_unrecognised) { parse(argc, argv); } @@ -1641,7 +1655,7 @@ inline ParseResult Options::parse(int& argc, char**& argv) { - ParseResult result(m_options, m_positional, argc, argv); + ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); return result; } @@ -1697,7 +1711,15 @@ ParseResult::parse(int& argc, char**& argv) if (iter == m_options.end()) { - throw option_not_exists_exception(name); + if (m_allow_unrecognised) + { + continue; + } + else + { + //error + throw option_not_exists_exception(name); + } } auto value = iter->second; @@ -1726,7 +1748,19 @@ ParseResult::parse(int& argc, char**& argv) if (iter == m_options.end()) { - throw option_not_exists_exception(name); + if (m_allow_unrecognised) + { + // keep unrecognised options in argument list, skip to next argument + argv[nextKeep] = argv[current]; + ++nextKeep; + ++current; + continue; + } + else + { + //error + throw option_not_exists_exception(name); + } } auto opt = iter->second; diff --git a/src/example.cpp b/src/example.cpp index 64709f2..7fddf13 100644 --- a/src/example.cpp +++ b/src/example.cpp @@ -37,7 +37,9 @@ int main(int argc, char* argv[]) bool apple = false; - options.add_options() + options + .allow_unrecognised_options() + .add_options() ("a,apple", "an apple", cxxopts::value(apple)) ("b,bob", "Bob") ("t,true", "True", cxxopts::value()->default_value("true")) diff --git a/test/options.cpp b/test/options.cpp index aae6239..bfaa635 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -473,3 +473,33 @@ TEST_CASE("std::optional", "[optional]") { CHECK(*optional == "foo"); } #endif + +TEST_CASE("Unrecognised options", "[options]") { + cxxopts::Options options("unknown_options", " - test unknown options"); + + options.add_options() + ("long", "a long option") + ("s,short", "a short option"); + + Argv av({ + "unknown_options", + "--unknown", + "--long", + "-su", + "--another_unknown", + }); + + char** argv = av.argv(); + auto argc = av.argc(); + + SECTION("Default behaviour") { + CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception); + } + + SECTION("After allowing unrecognised options") { + options.allow_unrecognised_options(); + CHECK_NOTHROW(options.parse(argc, argv)); + REQUIRE(argc == 3); + CHECK_THAT(argv[1], Catch::Equals("--unknown")); + } +} \ No newline at end of file