Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 41 additions & 20 deletions include/clipp.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,27 @@ using match_function = std::function<subrange(const arg_string&)>;



/*************************************************************************//**
*
* @brief type txt (NOT FOR DIRECT USE IN CLIENT CODE!)
* no interface guarantees; might be changed or removed in the future
*
*****************************************************************************/
namespace txt {
inline bool isspace(char c) {
return (c >= 0) && std::isspace(c);
}
inline bool isdigit(char c) {
return (c >= 0) && std::isdigit(c);
}
inline bool isalnum(char c) {
return (c >= 0) && std::isalnum(c);
}
inline bool isalpha(char c) {
return (c >= 0) && std::isalpha(c);
}
}

/*************************************************************************//**
*
* @brief type traits (NOT FOR DIRECT USE IN CLIENT CODE!)
Expand Down Expand Up @@ -298,7 +319,7 @@ inline bool
fwd_to_unsigned_int(const char*& s)
{
if(!s) return false;
for(; std::isspace(*s); ++s);
for(; txt::isspace(*s); ++s);
if(!s[0] || s[0] == '-') return false;
if(s[0] == '-') return false;
return true;
Expand Down Expand Up @@ -694,7 +715,7 @@ trimr(std::basic_string<C,T,A>& s)

s.erase(
std::find_if_not(s.rbegin(), s.rend(),
[](char c) { return std::isspace(c);} ).base(),
[](char c) { return txt::isspace(c);} ).base(),
s.end() );
}

Expand All @@ -713,7 +734,7 @@ triml(std::basic_string<C,T,A>& s)
s.erase(
s.begin(),
std::find_if_not(s.begin(), s.end(),
[](char c) { return std::isspace(c);})
[](char c) { return txt::isspace(c);})
);
}

Expand Down Expand Up @@ -744,7 +765,7 @@ remove_ws(std::basic_string<C,T,A>& s)
if(s.empty()) return;

s.erase(std::remove_if(s.begin(), s.end(),
[](char c) { return std::isspace(c); }),
[](char c) { return txt::isspace(c); }),
s.end() );
}

Expand Down Expand Up @@ -967,16 +988,16 @@ first_number_match(std::basic_string<C,T,A> s,
}
else if(exp != string_t::npos && (exp+1) == j) {
//only sign or digit after exponent separator
if(s[j] != '+' && s[j] != '-' && !std::isdigit(s[j])) break;
if(s[j] != '+' && s[j] != '-' && !txt::isdigit(s[j])) break;
}
else if(!std::isdigit(s[j])) {
else if(!txt::isdigit(s[j])) {
break;
}
}
}

//if length == 1 then must be a digit
if(j-i == 1 && !std::isdigit(s[i])) return subrange{};
if(j-i == 1 && !txt::isdigit(s[i])) return subrange{};

return subrange{i,j-i};
}
Expand Down Expand Up @@ -1010,12 +1031,12 @@ first_integer_match(std::basic_string<C,T,A> s,
}
else {
sep = false;
if(!std::isdigit(s[j])) break;
if(!txt::isdigit(s[j])) break;
}
}

//if length == 1 then must be a digit
if(j-i == 1 && !std::isdigit(s[i])) return subrange{};
if(j-i == 1 && !txt::isdigit(s[i])) return subrange{};

return subrange{i,j-i};
}
Expand Down Expand Up @@ -1621,7 +1642,7 @@ nonempty(const arg_string& s) {
inline bool
alphanumeric(const arg_string& s) {
if(s.empty()) return false;
return std::all_of(s.begin(), s.end(), [](char c) {return std::isalnum(c); });
return std::all_of(s.begin(), s.end(), [](char c) {return txt::isalnum(c); });
}


Expand All @@ -1634,7 +1655,7 @@ alphanumeric(const arg_string& s) {
*****************************************************************************/
inline bool
alphabetic(const arg_string& s) {
return std::all_of(s.begin(), s.end(), [](char c) {return std::isalpha(c); });
return std::all_of(s.begin(), s.end(), [](char c) {return txt::isalpha(c); });
}


Expand Down Expand Up @@ -2811,7 +2832,7 @@ class group :
context context_;
public:
int level() const noexcept { return level_; }
const child* param() const noexcept { return &(*context_.cur); }
const child* param() const noexcept { return context_.parent ? &(*context_.cur) : nullptr; }
};

depth_first_traverser() = default;
Expand Down Expand Up @@ -4258,7 +4279,7 @@ class scoped_dfs_traverser
//but if the current scope is the first element, then we are
//conceptually at a position 'before' the group
repeatGroupStarted_ = scopes_.empty() || (
newrg == pos_.root() &&
newrg == pos_.root() && !pos_.root()->empty() &&
scopes_.top().param() == &(*pos_.root()->begin()) );
}
repeatGroupContinues_ = repeatGroupStarted_;
Expand Down Expand Up @@ -5177,14 +5198,14 @@ void sanitize_args(arg_list& args)

for(auto i = begin(args)+1; i != end(args); ++i) {
if(i != begin(args) && i->size() > 1 &&
i->find('.') == 0 && std::isdigit((*i)[1]) )
i->find('.') == 0 && txt::isdigit((*i)[1]) )
{
//find trailing digits in previous arg
using std::prev;
auto& prv = *prev(i);
auto fstDigit = std::find_if_not(prv.rbegin(), prv.rend(),
[](arg_string::value_type c){
return std::isdigit(c);
return txt::isdigit(c);
}).base();

//handle leading sign
Expand Down Expand Up @@ -5904,7 +5925,7 @@ class formatting_ostream
template<class Iter>
bool only_whitespace(Iter first, Iter last) const {
return last == std::find_if_not(first, last,
[](char_type c) { return std::isspace(c); });
[](char_type c) { return txt::isspace(c); });
}

/** @brief write any object */
Expand Down Expand Up @@ -5960,7 +5981,7 @@ class formatting_ostream
if(at_begin_of_line()) {
//discard whitespace, it we start a new line
first = std::find_if(first, last,
[](char_type c) { return !std::isspace(c); });
[](char_type c) { return !txt::isspace(c); });
if(first == last) return;
}

Expand All @@ -5970,11 +5991,11 @@ class formatting_ostream
if(n > m) {
//break before word, if break is mid-word
auto breakat = first + m;
while(breakat > first && !std::isspace(*breakat)) --breakat;
while(breakat > first && !txt::isspace(*breakat)) --breakat;
//could not find whitespace before word -> try after the word
if(!std::isspace(*breakat) && breakat == first) {
if(!txt::isspace(*breakat) && breakat == first) {
breakat = std::find_if(first+m, last,
[](char_type c) { return std::isspace(c); });
[](char_type c) { return txt::isspace(c); });
}
if(breakat > first) {
if(curCol_ < 1) ++totalNonBlankLines_;
Expand Down
12 changes: 10 additions & 2 deletions test/blocking_test09.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,16 @@ struct active {

friend bool operator == (const active& x, const active& y) noexcept {
return x.http == y.http && x.f == y.f &&
std::equal(x.tgts.begin(), x.tgts.end(), y.tgts.begin()) &&
std::equal(x.wrong.begin(), x.wrong.end(), y.wrong.begin());
(
(x.tgts.size() == 0 && y.tgts.size() == 0) ||
(x.tgts.size() > 0 && y.tgts.size() > 0 && x.tgts.size() == y.tgts.size() &&
std::equal(x.tgts.begin(), x.tgts.end(), y.tgts.begin()))
) &&
(
(x.wrong.size() == 0 && y.wrong.size() == 0) ||
(x.wrong.size() > 0 && y.wrong.size() > 0 && x.wrong.size() == y.wrong.size() &&
std::equal(x.wrong.begin(), x.wrong.end(), y.wrong.begin()))
);
}
};

Expand Down
6 changes: 5 additions & 1 deletion test/blocking_test10.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ struct active {

friend bool operator == (const active& x, const active& y) noexcept {
return x.n == y.n && x.s == y.s && x.str == y.str &&
std::equal(x.nums.begin(), x.nums.end(), y.nums.begin());
(
(x.nums.size() == 0 && y.nums.size() == 0) ||
(x.nums.size() > 0 && y.nums.size() > 0 && x.nums.size() == y.nums.size() &&
std::equal(x.nums.begin(), x.nums.end(), y.nums.begin()))
);
}
};

Expand Down
14 changes: 9 additions & 5 deletions test/joined_params_test1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ struct active {

std::vector<double> xs;

friend bool operator == (const active& a, const active& b) noexcept {
return std::equal(begin(a.xs), end(a.xs), begin(b.xs),
[](double x, double y) {
return std::abs(x - y) < 1e-5;
});
friend bool operator == (const active& x, const active& y) noexcept {
return (
(x.xs.size() == 0 && y.xs.size() == 0) ||
(x.xs.size() > 0 && y.xs.size() > 0 && x.xs.size() == y.xs.size() &&
std::equal(begin(x.xs), end(x.xs), begin(y.xs),
[](double x, double y) {
return std::abs(x - y) < 1e-5;
}))
);
}
};

Expand Down
12 changes: 10 additions & 2 deletions test/repeatable_alternatives_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ struct active {

friend bool operator == (const active& x, const active& y) noexcept {
return x.a == y.a && x.b == y.b &&
std::equal(begin(x.i), end(x.i), begin(y.i)) &&
std::equal(begin(x.j), end(x.j), begin(y.j));
(
(x.i.size() == 0 && y.i.size() == 0) ||
(x.i.size() > 0 && y.i.size() > 0 && x.i.size() == y.i.size() &&
std::equal(x.i.begin(), x.i.end(), y.i.begin()))
) &&
(
(x.j.size() == 0 && y.j.size() == 0) ||
(x.j.size() > 0 && y.j.size() > 0 && x.j.size() == y.j.size() &&
std::equal(x.j.begin(), x.j.end(), y.j.begin()))
);
}
};

Expand Down
46 changes: 25 additions & 21 deletions test/testing.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,19 @@ void run_wrapped_variants(

parse(args, wrappedCli);

// cout << "==============================================\n"
// << " in file " << info.file << " in line " << info.line
// << " with variant " << variant << '\n'
// << "==============================================\n";
// clipp::debug::print(cout, wrappedCli);
// cout << "args = { ";
// for(const auto& a : args) cout << '"' << a << "\" ";
// cout << "}\n";
// auto res = clipp::parse(args, wrappedCli);
// cout << "----------------------------------------------\n";
// clipp::debug::print(cout, res);
#if 0
cout << "==============================================\n"
<< " in file " << info.file << " in line " << info.line
<< " with variant " << variant << '\n'
<< "==============================================\n";
clipp::debug::print(cout, wrappedCli);
cout << "args = { ";
for(const auto& a : args) cout << '"' << a << "\" ";
cout << "}\n";
auto res = clipp::parse(args, wrappedCli);
cout << "----------------------------------------------\n";
clipp::debug::print(cout, res);
#endif

if(!valid()) {
throw std::runtime_error{"failed test " + info.file +
Expand Down Expand Up @@ -133,16 +135,18 @@ void run_test(

parse(args, cli);

// cout << "==============================================\n"
// << " in file " << info.file << " in line " << info.line << '\n'
// << "==============================================\n";
// clipp::debug::print(cout, cli);
// cout << "args = { ";
// for(const auto& a : args) cout << '"' << a << "\" ";
// cout << "}\n";
// auto res = clipp::parse(args, cli);
// cout << "----------------------------------------------\n";
// clipp::debug::print(cout, res);
#if 0
cout << "==============================================\n"
<< " in file " << info.file << " in line " << info.line << '\n'
<< "==============================================\n";
clipp::debug::print(cout, cli);
cout << "args = { ";
for(const auto& a : args) cout << '"' << a << "\" ";
cout << "}\n";
auto res = clipp::parse(args, cli);
cout << "----------------------------------------------\n";
clipp::debug::print(cout, res);
#endif

if(!valid()) {
throw std::runtime_error{"failed test " + info.file +
Expand Down
6 changes: 5 additions & 1 deletion test/values_sequencing_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ struct active {
return (x.a == y.a && x.ie == y.ie && x.je == y.je &&
x.ke == y.ke && x.ve == y.ve && x.i == y.i &&
x.j == y.j && x.k == y.k &&
std::equal(begin(x.v), end(x.v), begin(y.v)));
(
(x.v.size() == 0 && y.v.size() == 0) ||
(x.v.size() > 0 && y.v.size() > 0 && x.v.size() == y.v.size() &&
std::equal(x.v.begin(), x.v.end(), y.v.begin()))
));
}

template<class OStream>
Expand Down