diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index f4780ef..163a3e1 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -851,7 +851,7 @@ namespace cxxopts ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); std::basic_regex option_specifier - ("(([[:alnum:]]),)?([[:alnum:]][-_[:alnum:]]+)"); + ("(([[:alnum:]]),)?([[:alnum:]][-_[:alnum:]]*)?"); String format_option @@ -985,8 +985,39 @@ OptionAdder::operator() const auto& s = result[2]; const auto& l = result[3]; - m_options.add_option(m_group, s.str(), l.str(), desc, value, - std::move(arg_help)); + if (!s.length() && !l.length()) + { + throw invalid_option_format_error(opts); + } else if (l.length() == 1 && s.length()) + { + throw invalid_option_format_error(opts); + } + + auto option_names = [] + ( + const std::sub_match& s, + const std::sub_match& l + ) + { + if (l.length() == 1) + { + return std::make_tuple(l.str(), s.str()); + } + else + { + return std::make_tuple(s.str(), l.str()); + } + }(s, l); + + m_options.add_option + ( + m_group, + std::get<0>(option_names), + std::get<1>(option_names), + desc, + value, + std::move(arg_help) + ); return *this; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 19aa960..734e902 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ if (CXXOPTS_BUILD_TESTS) - add_executable(options_test options.cpp) + add_executable(options_test main.cpp options.cpp) target_link_libraries(options_test cxxopts) if (MSVC) diff --git a/test/options.cpp b/test/options.cpp index 316724b..389178b 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -1,4 +1,3 @@ -#define CATCH_CONFIG_MAIN #include "catch.hpp" #include @@ -80,6 +79,27 @@ TEST_CASE("Basic options", "[options]") CHECK(options.count("6") == 1); } +TEST_CASE("Short options", "[options]") +{ + cxxopts::Options options("test_short", " - test short options"); + + options.add_options() + ("a", "a short option", cxxopts::value()); + + Argv argv({"test_short", "-a", "value"}); + + auto actual_argv = argv.argv(); + auto argc = argv.argc(); + + options.parse(argc, actual_argv); + + CHECK(options.count("a") == 1); + CHECK(options["a"].as() == "value"); + + REQUIRE_THROWS_AS(options.add_options()("", "nothing option"), + cxxopts::invalid_option_format_error); +} + TEST_CASE("No positional", "[positional]") { cxxopts::Options options("test_no_positional",