Skip to content

Commit

Permalink
Add a dry_run argument to Argument::consume(), and change ArgumentPar…
Browse files Browse the repository at this point in the history
…ser private section to protected

Both changes are needed in the special case of GDAL where our existing
hand-made argument parser accepts positional arguments placed anywhere
in the arguments, not just after optional arguments.

In the GDAL code, in OSGeo/gdal@8bb3455#diff-4592e7daae8543536dbeadf05a3c110282ea0fc089216186138c923a0d4d8000R170 ,
I've implemented a preliminary pass before calling
ArgumentParser::process_args() that re-order arguments. For that, I need
to be able to call consume() but without side-effects (dry_run=False)
and accept members that are private
  • Loading branch information
rouault committed Mar 12, 2024
1 parent 874b939 commit f2e7db6
Showing 1 changed file with 44 additions and 33 deletions.
77 changes: 44 additions & 33 deletions include/argparse/argparse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,11 +897,16 @@ class Argument {
}
}

/* The dry_run parameter can be set to true to avoid running the actions,
* and setting m_is_used. This may be used by a pre-processing step to do
* a first iteration over arguments.
*/
template <typename Iterator>
Iterator consume(Iterator start, Iterator end,
std::string_view used_name = {}) {
std::string_view used_name = {}, bool dry_run = false) {
if (!m_is_repeatable && m_is_used) {
throw std::runtime_error("Duplicate argument");
throw std::runtime_error(
std::string("Duplicate argument ").append(used_name));
}
m_used_name = used_name;

Expand All @@ -923,9 +928,11 @@ class Argument {
const auto num_args_min = m_num_args_range.get_min();
std::size_t dist = 0;
if (num_args_max == 0) {
m_values.emplace_back(m_implicit_value);
std::visit([](const auto &f) { f({}); }, m_action);
m_is_used = true;
if (!dry_run) {
m_values.emplace_back(m_implicit_value);
std::visit([](const auto &f) { f({}); }, m_action);
m_is_used = true;
}
return start;
}
if ((dist = static_cast<std::size_t>(std::distance(start, end))) >=
Expand Down Expand Up @@ -962,12 +969,16 @@ class Argument {
Iterator first, last;
Argument &self;
};
std::visit(ActionApply{start, end, *this}, m_action);
m_is_used = true;
if (!dry_run) {
std::visit(ActionApply{start, end, *this}, m_action);
m_is_used = true;
}
return end;
}
if (m_default_value.has_value()) {
m_is_used = true;
if (!dry_run) {
m_is_used = true;
}
return start;
}
throw std::runtime_error("Too few arguments for '" +
Expand Down Expand Up @@ -1162,6 +1173,30 @@ class Argument {
}
}

/*
* positional:
* _empty_
* '-'
* '-' decimal-literal
* !'-' anything
*/
static bool is_positional(std::string_view name,
std::string_view prefix_chars) {
auto first = lookahead(name);

if (first == eof) {
return true;
} else if (prefix_chars.find(static_cast<char>(first)) !=
std::string_view::npos) {
name.remove_prefix(1);
if (name.empty()) {
return true;
}
return is_decimal_literal(name);
}
return true;
}

private:
class NArgsRange {
std::size_t m_min;
Expand Down Expand Up @@ -1397,30 +1432,6 @@ class Argument {
return !is_positional(name, prefix_chars);
}

/*
* positional:
* _empty_
* '-'
* '-' decimal-literal
* !'-' anything
*/
static bool is_positional(std::string_view name,
std::string_view prefix_chars) {
auto first = lookahead(name);

if (first == eof) {
return true;
} else if (prefix_chars.find(static_cast<char>(first)) !=
std::string_view::npos) {
name.remove_prefix(1);
if (name.empty()) {
return true;
}
return is_decimal_literal(name);
}
return true;
}

/*
* Get argument value given a type
* @throws std::logic_error in case of incompatible types
Expand Down Expand Up @@ -1966,7 +1977,7 @@ class ArgumentParser {

void set_suppress(bool suppress) { m_suppress = suppress; }

private:
protected:
bool is_valid_prefix_char(char c) const {
return m_prefix_chars.find(c) != std::string::npos;
}
Expand Down

0 comments on commit f2e7db6

Please sign in to comment.