diff --git a/include/clipp.h b/include/clipp.h index 06d45ee..d7b101e 100644 --- a/include/clipp.h +++ b/include/clipp.h @@ -1,7 +1,7 @@ /***************************************************************************** * ___ _ _ ___ ___ * | _|| | | | | _ \ _ \ CLIPP - command line interfaces for modern C++ - * | |_ | |_ | | | _/ _/ version 1.2.2 + * | |_ | |_ | | | _/ _/ version 1.2.3 * |___||___||_| |_| |_| https://github.com/muellan/clipp * * Licensed under the MIT License . @@ -4366,11 +4366,16 @@ struct select_values { *****************************************************************************/ class match_t { public: + using size_type = arg_string::size_type; + match_t() = default; + match_t(arg_string s, scoped_dfs_traverser p): str_{std::move(s)}, pos_{std::move(p)} {} + size_type length() const noexcept { return str_.size(); } + const arg_string& str() const noexcept { return str_; } const scoped_dfs_traverser& pos() const noexcept { return pos_; } @@ -4420,28 +4425,30 @@ full_match(scoped_dfs_traverser pos, const arg_string& arg, *****************************************************************************/ template match_t -prefix_match(scoped_dfs_traverser pos, const arg_string& arg, - const ParamSelector& select) +longest_prefix_match(scoped_dfs_traverser pos, const arg_string& arg, + const ParamSelector& select) { + match_t longest; + while(pos) { if(pos->is_param()) { const auto& param = pos->as_param(); if(select(param)) { - const auto match = param.match(arg); + auto match = param.match(arg); if(match.prefix()) { if(match.length() == arg.size()) { return match_t{arg, std::move(pos)}; } - else { - return match_t{arg.substr(match.at(), match.length()), - std::move(pos)}; + else if(match.length() > longest.length()) { + longest = match_t{arg.substr(match.at(), match.length()), + pos}; } } } } ++pos; } - return match_t{}; + return longest; } @@ -4747,7 +4754,7 @@ class parser bool try_match_joined_sequence(arg_string arg, const ParamSelector& acceptFirst) { - auto fstMatch = detail::prefix_match(pos_, arg, acceptFirst); + auto fstMatch = detail::longest_prefix_match(pos_, arg, acceptFirst); if(!fstMatch) return false; @@ -4824,7 +4831,7 @@ class parser std::vector matches; while(!arg.empty()) { - auto match = detail::prefix_match(parse.pos_, arg, select); + auto match = detail::longest_prefix_match(parse.pos_, arg, select); if(!match) return false; diff --git a/test/prefix_test.cpp b/test/prefix_test.cpp new file mode 100644 index 0000000..6282ce8 --- /dev/null +++ b/test/prefix_test.cpp @@ -0,0 +1,92 @@ +/***************************************************************************** + * + * CLIPP - command line interfaces for modern C++ + * + * released under MIT license + * + * (c) 2017-2019 André Müller; foss@andremueller-online.de + * + *****************************************************************************/ + +#include "testing.h" + + +//------------------------------------------------------------------- +struct active { + active() = default; + active(bool a_, int i_): a{a_}, i{i_} {} + bool a = false; + int i = 0; + + friend bool operator == (const active& x, const active& y) noexcept { + return (x.a == y.a && x.i == y.i); + } +}; + + +//------------------------------------------------------------------- +static void +test(int lineNo, + const std::initializer_list args, + const active& matches ) +{ + using namespace clipp; + active m; + + auto cli = ( + option("-a").set(m.a), + option("-ab", "-a-b", "-a-b=") & value("i", m.i) + ); + + run_wrapped_variants({ __FILE__, lineNo }, args, cli, + [&]{ m = active{}; }, + [&]{ return m == matches; }); +} + + +//------------------------------------------------------------------- +int main() +{ + using std::string; + + try { + test(__LINE__, {""}, active{0,0}); + test(__LINE__, {"-a"}, active{1,0}); + + test(__LINE__, {"-ab"}, active{0,0}); + test(__LINE__, {"-a-b"}, active{0,0}); + test(__LINE__, {"-a-b="}, active{0,0}); + + test(__LINE__, {"-ab", "2"}, active{0,2}); + test(__LINE__, {"-a-b", "3"}, active{0,3}); + test(__LINE__, {"-a-b=", "4"}, active{0,4}); + + test(__LINE__, {"-ab2" }, active{0,2}); + test(__LINE__, {"-a-b3" }, active{0,3}); + test(__LINE__, {"-a-b=4"}, active{0,4}); + + test(__LINE__, {"-a", "-ab", "2"}, active{1,2}); + test(__LINE__, {"-a", "-a-b", "3"}, active{1,3}); + test(__LINE__, {"-a", "-a-b=", "4"}, active{1,4}); + + test(__LINE__, {"-a", "-ab2" }, active{1,2}); + test(__LINE__, {"-a", "-a-b3" }, active{1,3}); + test(__LINE__, {"-a", "-a-b=4"}, active{1,4}); + + test(__LINE__, {"-ab", "2", "-a"}, active{1,2}); + test(__LINE__, {"-a-b", "3", "-a"}, active{1,3}); + test(__LINE__, {"-a-b=", "4", "-a"}, active{1,4}); + + test(__LINE__, {"-a", "-ab" }, active{1,0}); + test(__LINE__, {"-a", "-a-b" }, active{1,0}); + test(__LINE__, {"-a", "-a-b="}, active{1,0}); + + test(__LINE__, {"-ab", "-a"}, active{1,0}); + test(__LINE__, {"-a-b", "-a"}, active{1,0}); + test(__LINE__, {"-a-b=", "-a"}, active{1,0}); + } + catch(std::exception& e) { + std::cerr << e.what() << std::endl; + return 1; + } +}