Commit ca6e9f70eb6b5fab44504daf57d92a9412ab301c

Authored by Frank Schoenmann
Committed by jarro2783
1 parent 00e8ecc4

Allow unrecognised options. (#105)

Allows unrecognised options to be left alone by the parser without throwing an exception.
include/cxxopts.hpp
... ... @@ -1095,6 +1095,7 @@ namespace cxxopts
1095 1095 ParseResult(
1096 1096 const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&,
1097 1097 std::vector<std::string>,
  1098 + bool allow_unrecognised,
1098 1099 int&, char**&);
1099 1100  
1100 1101 size_t
... ... @@ -1174,6 +1175,8 @@ namespace cxxopts
1174 1175 std::unordered_set<std::string> m_positional_set;
1175 1176 std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
1176 1177  
  1178 + bool m_allow_unrecognised;
  1179 +
1177 1180 std::vector<KeyValue> m_sequential;
1178 1181 };
1179 1182  
... ... @@ -1187,6 +1190,7 @@ namespace cxxopts
1187 1190 , m_custom_help("[OPTION...]")
1188 1191 , m_positional_help("positional parameters")
1189 1192 , m_show_positional(false)
  1193 + , m_allow_unrecognised(false)
1190 1194 , m_next_positional(m_positional.end())
1191 1195 {
1192 1196 }
... ... @@ -1212,6 +1216,13 @@ namespace cxxopts
1212 1216 return *this;
1213 1217 }
1214 1218  
  1219 + Options&
  1220 + allow_unrecognised_options()
  1221 + {
  1222 + m_allow_unrecognised = true;
  1223 + return *this;
  1224 + }
  1225 +
1215 1226 ParseResult
1216 1227 parse(int& argc, char**& argv);
1217 1228  
... ... @@ -1275,6 +1286,7 @@ namespace cxxopts
1275 1286 std::string m_custom_help;
1276 1287 std::string m_positional_help;
1277 1288 bool m_show_positional;
  1289 + bool m_allow_unrecognised;
1278 1290  
1279 1291 std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options;
1280 1292 std::vector<std::string> m_positional;
... ... @@ -1431,11 +1443,13 @@ ParseResult::ParseResult
1431 1443 (
1432 1444 const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>& options,
1433 1445 std::vector<std::string> positional,
  1446 + bool allow_unrecognised,
1434 1447 int& argc, char**& argv
1435 1448 )
1436 1449 : m_options(options)
1437 1450 , m_positional(std::move(positional))
1438 1451 , m_next_positional(m_positional.begin())
  1452 +, m_allow_unrecognised(allow_unrecognised)
1439 1453 {
1440 1454 parse(argc, argv);
1441 1455 }
... ... @@ -1641,7 +1655,7 @@ inline
1641 1655 ParseResult
1642 1656 Options::parse(int& argc, char**& argv)
1643 1657 {
1644   - ParseResult result(m_options, m_positional, argc, argv);
  1658 + ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
1645 1659 return result;
1646 1660 }
1647 1661  
... ... @@ -1697,7 +1711,15 @@ ParseResult::parse(int&amp; argc, char**&amp; argv)
1697 1711  
1698 1712 if (iter == m_options.end())
1699 1713 {
1700   - throw option_not_exists_exception(name);
  1714 + if (m_allow_unrecognised)
  1715 + {
  1716 + continue;
  1717 + }
  1718 + else
  1719 + {
  1720 + //error
  1721 + throw option_not_exists_exception(name);
  1722 + }
1701 1723 }
1702 1724  
1703 1725 auto value = iter->second;
... ... @@ -1726,7 +1748,19 @@ ParseResult::parse(int&amp; argc, char**&amp; argv)
1726 1748  
1727 1749 if (iter == m_options.end())
1728 1750 {
1729   - throw option_not_exists_exception(name);
  1751 + if (m_allow_unrecognised)
  1752 + {
  1753 + // keep unrecognised options in argument list, skip to next argument
  1754 + argv[nextKeep] = argv[current];
  1755 + ++nextKeep;
  1756 + ++current;
  1757 + continue;
  1758 + }
  1759 + else
  1760 + {
  1761 + //error
  1762 + throw option_not_exists_exception(name);
  1763 + }
1730 1764 }
1731 1765  
1732 1766 auto opt = iter->second;
... ...
src/example.cpp
... ... @@ -37,7 +37,9 @@ int main(int argc, char* argv[])
37 37  
38 38 bool apple = false;
39 39  
40   - options.add_options()
  40 + options
  41 + .allow_unrecognised_options()
  42 + .add_options()
41 43 ("a,apple", "an apple", cxxopts::value<bool>(apple))
42 44 ("b,bob", "Bob")
43 45 ("t,true", "True", cxxopts::value<bool>()->default_value("true"))
... ...
test/options.cpp
... ... @@ -473,3 +473,33 @@ TEST_CASE(&quot;std::optional&quot;, &quot;[optional]&quot;) {
473 473 CHECK(*optional == "foo");
474 474 }
475 475 #endif
  476 +
  477 +TEST_CASE("Unrecognised options", "[options]") {
  478 + cxxopts::Options options("unknown_options", " - test unknown options");
  479 +
  480 + options.add_options()
  481 + ("long", "a long option")
  482 + ("s,short", "a short option");
  483 +
  484 + Argv av({
  485 + "unknown_options",
  486 + "--unknown",
  487 + "--long",
  488 + "-su",
  489 + "--another_unknown",
  490 + });
  491 +
  492 + char** argv = av.argv();
  493 + auto argc = av.argc();
  494 +
  495 + SECTION("Default behaviour") {
  496 + CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception);
  497 + }
  498 +
  499 + SECTION("After allowing unrecognised options") {
  500 + options.allow_unrecognised_options();
  501 + CHECK_NOTHROW(options.parse(argc, argv));
  502 + REQUIRE(argc == 3);
  503 + CHECK_THAT(argv[1], Catch::Equals("--unknown"));
  504 + }
  505 +}
476 506 \ No newline at end of file
... ...