diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index ebb3fcd..1e4e475 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -337,13 +337,21 @@ class value_base : public std::enable_shared_from_this { } private: + /// A default value for the option. std::string default_value_{}; + /// A name of an environment variable from which a default + /// value will be read. std::string env_var_{}; + /// An implicit value for the option. std::string implicit_value_{}; + /// Configuration of the value parser. parse_context parse_ctx_{}; + /// The default value has been set. bool default_{false}; + /// The environment variable has been set. bool env_{false}; + /// The implicit value has been set. bool implicit_{false}; }; #if defined(__GNUC__) @@ -768,7 +776,6 @@ class options { struct help_group_details { std::string name{}; - std::string description{}; std::vector options{}; }; @@ -792,33 +799,6 @@ class options { public: explicit options(std::string program, std::string help_string = {}); - options& - positional_help(std::string help_text); - - options& - custom_help(std::string help_text); - - options& - show_positional_help(); - - options& - allow_unrecognised_options(); - - options& - set_tab_expansion(bool expansion = true); - - options& - set_width(size_t width); - - /** - * Stop parsing at first positional argument. - */ - options& - stop_on_positional(); - - option_adder - add_options(std::string group = {}); - /** * Adds list of options to the specific group. */ @@ -835,6 +815,15 @@ class options { const std::string& group, const option& option); + option_adder + add_options(std::string group = {}); + + options& + allow_unrecognised_options(const bool value = true); + + options& + custom_help(std::string help_text); + template void parse_positional(Args&& ... args) { @@ -853,6 +842,34 @@ class options { void parse_positional(std::vector options); + options& + positional_help(std::string help_text); + + options& + set_tab_expansion(bool expansion = true); + + options& + set_width(size_t width); + + options& + show_positional_help(const bool value = true); + + /** + * Stop parsing at first positional argument. + */ + options& + stop_on_positional(const bool value = true); + +public: + /** + * Parses the command line arguments according to the current specification. + */ + parse_result + parse(int argc, const char* const* argv) const; + + /** + * Generates help for the options. + */ std::string help(const std::vector& groups = {}) const; @@ -865,19 +882,12 @@ class options { const help_group_details& group_help(const std::string& group) const; -public: - /** - * Parses the command line arguments according to the current specification. - */ - parse_result - parse(int argc, const char* const* argv) const; - private: void add_option( const std::string& group, - const std::string& s, - const std::string& l, + std::string s, + std::string l, std::string desc, const std::shared_ptr& value, std::string arg_help); diff --git a/src/cxxopts.cpp b/src/cxxopts.cpp index 84a5c5d..7c6382d 100644 --- a/src/cxxopts.cpp +++ b/src/cxxopts.cpp @@ -223,7 +223,7 @@ static const std::basic_regex option_matcher ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-(\\?|[[:alnum:]]+)"); static const std::basic_regex option_specifier - ("((\\?|[[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); + ("((\\?|[[:alnum:]]),)?[ ]*(\\?|([[:alnum:]][-_[:alnum:]]*))?"); static const std::basic_regex integer_pattern ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); @@ -797,6 +797,7 @@ class options::option_parser { if (oi == options_.end()) { if (allow_unrecognised_) { + // TODO: keep unrecognized. continue; } // Error. @@ -1015,8 +1016,8 @@ options::options(std::string program, std::string help_string) } options& -options::positional_help(std::string help_text) { - positional_help_ = std::move(help_text); +options::allow_unrecognised_options(const bool value) { + allow_unrecognised_ = value; return *this; } @@ -1027,32 +1028,32 @@ options::custom_help(std::string help_text) { } options& -options::show_positional_help() { - show_positional_ = true; +options::positional_help(std::string help_text) { + positional_help_ = std::move(help_text); return *this; } options& -options::allow_unrecognised_options() { - allow_unrecognised_ = true; +options::show_positional_help(const bool value) { + show_positional_ = value; return *this; } options& -options::set_width(size_t width) { - width_ = width; +options::set_tab_expansion(bool expansion) { + tab_expansion_ = expansion; return *this; } options& -options::set_tab_expansion(bool expansion) { - tab_expansion_ = expansion; +options::set_width(size_t width) { + width_ = width; return *this; } options& -options::stop_on_positional() { - stop_on_positional_ = true; +options::stop_on_positional(const bool value) { + stop_on_positional_ = value; return *this; } @@ -1090,8 +1091,8 @@ options::add_option(const std::string& group, const option& opt) { void options::add_option( const std::string& group, - const std::string& s, - const std::string& l, + std::string s, + std::string l, std::string desc, const std::shared_ptr& value, std::string arg_help) @@ -1292,8 +1293,7 @@ options::help_one_group(const std::string& g) const { } for (const auto& o : group->second.options) { - if (positional_set_.find(o.l) != positional_set_.end() && - !show_positional_) + if (!show_positional_ && positional_set_.find(o.l) != positional_set_.end()) { continue; } @@ -1312,8 +1312,7 @@ options::help_one_group(const std::string& g) const { auto fiter = format.begin(); for (const auto& o : group->second.options) { - if (positional_set_.find(o.l) != positional_set_.end() && - !show_positional_) + if (!show_positional_ && positional_set_.find(o.l) != positional_set_.end()) { continue; } @@ -1439,9 +1438,12 @@ options::option_adder::operator()( throw_or_mimic(opts); } - const auto& short_match = result[2]; - const auto& long_match = result[3]; + std::string short_match = result[2].str(); + std::string long_match = result[3].str(); + if (short_match.empty() && long_match.length() == 1) { + std::swap(short_match, long_match); + } if ((!short_match.length() && !long_match.length()) || ( short_match.length() && long_match.length() == 1)) { @@ -1450,8 +1452,8 @@ options::option_adder::operator()( options_.add_option( group_, - short_match.str(), - long_match.str(), + std::move(short_match), + std::move(long_match), desc, value, std::move(arg_help)); diff --git a/test/options.cpp b/test/options.cpp index 65d1027..855e0a1 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -57,6 +57,14 @@ TEST_CASE("Value", "traits") { CHECK(cxxopts::value>()->is_container()); } +TEST_CASE("Question mark only", "[options]") { + cxxopts::options options("test_short", " - test question mark"); + options.add_options()("?", "show help"); + + const Argv argv({"test_short", "-?"}); + CHECK(options.parse(argv.argc(), argv.argv()).count("?") == 1); +} + TEST_CASE("Question mark help", "[options]") { cxxopts::options options("test_short", " - test question mark");