Skip to content

Commit

Permalink
fixed issue due to not using *longest* prefix match in joined paramet…
Browse files Browse the repository at this point in the history
…er/value sequences
  • Loading branch information
muellan committed Apr 27, 2019
1 parent 380c117 commit 4cda95d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 10 deletions.
27 changes: 17 additions & 10 deletions include/clipp.h
Original file line number Diff line number Diff line change
@@ -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 <http://opensource.org/licenses/MIT>.
Expand Down Expand Up @@ -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_; }

Expand Down Expand Up @@ -4420,28 +4425,30 @@ full_match(scoped_dfs_traverser pos, const arg_string& arg,
*****************************************************************************/
template<class ParamSelector>
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;
}


Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -4824,7 +4831,7 @@ class parser
std::vector<match_t> 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;

Expand Down
92 changes: 92 additions & 0 deletions test/prefix_test.cpp
Original file line number Diff line number Diff line change
@@ -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<const char*> 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;
}
}

0 comments on commit 4cda95d

Please sign in to comment.