Commit ca6e9f70eb6b5fab44504daf57d92a9412ab301c
Committed by
jarro2783
1 parent
00e8ecc4
Allow unrecognised options. (#105)
Allows unrecognised options to be left alone by the parser without throwing an exception.
Showing
3 changed files
with
70 additions
and
4 deletions
include/cxxopts.hpp
| @@ -1095,6 +1095,7 @@ namespace cxxopts | @@ -1095,6 +1095,7 @@ namespace cxxopts | ||
| 1095 | ParseResult( | 1095 | ParseResult( |
| 1096 | const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&, | 1096 | const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&, |
| 1097 | std::vector<std::string>, | 1097 | std::vector<std::string>, |
| 1098 | + bool allow_unrecognised, | ||
| 1098 | int&, char**&); | 1099 | int&, char**&); |
| 1099 | 1100 | ||
| 1100 | size_t | 1101 | size_t |
| @@ -1174,6 +1175,8 @@ namespace cxxopts | @@ -1174,6 +1175,8 @@ namespace cxxopts | ||
| 1174 | std::unordered_set<std::string> m_positional_set; | 1175 | std::unordered_set<std::string> m_positional_set; |
| 1175 | std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results; | 1176 | std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results; |
| 1176 | 1177 | ||
| 1178 | + bool m_allow_unrecognised; | ||
| 1179 | + | ||
| 1177 | std::vector<KeyValue> m_sequential; | 1180 | std::vector<KeyValue> m_sequential; |
| 1178 | }; | 1181 | }; |
| 1179 | 1182 | ||
| @@ -1187,6 +1190,7 @@ namespace cxxopts | @@ -1187,6 +1190,7 @@ namespace cxxopts | ||
| 1187 | , m_custom_help("[OPTION...]") | 1190 | , m_custom_help("[OPTION...]") |
| 1188 | , m_positional_help("positional parameters") | 1191 | , m_positional_help("positional parameters") |
| 1189 | , m_show_positional(false) | 1192 | , m_show_positional(false) |
| 1193 | + , m_allow_unrecognised(false) | ||
| 1190 | , m_next_positional(m_positional.end()) | 1194 | , m_next_positional(m_positional.end()) |
| 1191 | { | 1195 | { |
| 1192 | } | 1196 | } |
| @@ -1212,6 +1216,13 @@ namespace cxxopts | @@ -1212,6 +1216,13 @@ namespace cxxopts | ||
| 1212 | return *this; | 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 | ParseResult | 1226 | ParseResult |
| 1216 | parse(int& argc, char**& argv); | 1227 | parse(int& argc, char**& argv); |
| 1217 | 1228 | ||
| @@ -1275,6 +1286,7 @@ namespace cxxopts | @@ -1275,6 +1286,7 @@ namespace cxxopts | ||
| 1275 | std::string m_custom_help; | 1286 | std::string m_custom_help; |
| 1276 | std::string m_positional_help; | 1287 | std::string m_positional_help; |
| 1277 | bool m_show_positional; | 1288 | bool m_show_positional; |
| 1289 | + bool m_allow_unrecognised; | ||
| 1278 | 1290 | ||
| 1279 | std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options; | 1291 | std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options; |
| 1280 | std::vector<std::string> m_positional; | 1292 | std::vector<std::string> m_positional; |
| @@ -1431,11 +1443,13 @@ ParseResult::ParseResult | @@ -1431,11 +1443,13 @@ ParseResult::ParseResult | ||
| 1431 | ( | 1443 | ( |
| 1432 | const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>& options, | 1444 | const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>& options, |
| 1433 | std::vector<std::string> positional, | 1445 | std::vector<std::string> positional, |
| 1446 | + bool allow_unrecognised, | ||
| 1434 | int& argc, char**& argv | 1447 | int& argc, char**& argv |
| 1435 | ) | 1448 | ) |
| 1436 | : m_options(options) | 1449 | : m_options(options) |
| 1437 | , m_positional(std::move(positional)) | 1450 | , m_positional(std::move(positional)) |
| 1438 | , m_next_positional(m_positional.begin()) | 1451 | , m_next_positional(m_positional.begin()) |
| 1452 | +, m_allow_unrecognised(allow_unrecognised) | ||
| 1439 | { | 1453 | { |
| 1440 | parse(argc, argv); | 1454 | parse(argc, argv); |
| 1441 | } | 1455 | } |
| @@ -1641,7 +1655,7 @@ inline | @@ -1641,7 +1655,7 @@ inline | ||
| 1641 | ParseResult | 1655 | ParseResult |
| 1642 | Options::parse(int& argc, char**& argv) | 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 | return result; | 1659 | return result; |
| 1646 | } | 1660 | } |
| 1647 | 1661 | ||
| @@ -1697,7 +1711,15 @@ ParseResult::parse(int& argc, char**& argv) | @@ -1697,7 +1711,15 @@ ParseResult::parse(int& argc, char**& argv) | ||
| 1697 | 1711 | ||
| 1698 | if (iter == m_options.end()) | 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 | auto value = iter->second; | 1725 | auto value = iter->second; |
| @@ -1726,7 +1748,19 @@ ParseResult::parse(int& argc, char**& argv) | @@ -1726,7 +1748,19 @@ ParseResult::parse(int& argc, char**& argv) | ||
| 1726 | 1748 | ||
| 1727 | if (iter == m_options.end()) | 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 | auto opt = iter->second; | 1766 | auto opt = iter->second; |
src/example.cpp
| @@ -37,7 +37,9 @@ int main(int argc, char* argv[]) | @@ -37,7 +37,9 @@ int main(int argc, char* argv[]) | ||
| 37 | 37 | ||
| 38 | bool apple = false; | 38 | bool apple = false; |
| 39 | 39 | ||
| 40 | - options.add_options() | 40 | + options |
| 41 | + .allow_unrecognised_options() | ||
| 42 | + .add_options() | ||
| 41 | ("a,apple", "an apple", cxxopts::value<bool>(apple)) | 43 | ("a,apple", "an apple", cxxopts::value<bool>(apple)) |
| 42 | ("b,bob", "Bob") | 44 | ("b,bob", "Bob") |
| 43 | ("t,true", "True", cxxopts::value<bool>()->default_value("true")) | 45 | ("t,true", "True", cxxopts::value<bool>()->default_value("true")) |
test/options.cpp
| @@ -473,3 +473,33 @@ TEST_CASE("std::optional", "[optional]") { | @@ -473,3 +473,33 @@ TEST_CASE("std::optional", "[optional]") { | ||
| 473 | CHECK(*optional == "foo"); | 473 | CHECK(*optional == "foo"); |
| 474 | } | 474 | } |
| 475 | #endif | 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 | \ No newline at end of file | 506 | \ No newline at end of file |