Skip to content

Commit

Permalink
Cleanup MRView::Window::parse_arguments
Browse files Browse the repository at this point in the history
- Logic has been rewritten using STL algorithms. Not that previously we
were using pointer arithmetic to achieve this, which was technically
more efficient but less readable and safe. However, performance is
not a concern considering the data size involved.

- A new `index` member has been added to ParsedOption to identify an
option's position in the list of raw command-line arguments list.
  • Loading branch information
daljit46 committed Jun 6, 2024
1 parent d76e8ad commit ff9502a
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 21 deletions.
9 changes: 5 additions & 4 deletions core/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -896,7 +896,8 @@ void sort_arguments(const std::vector<std::string> &arguments) {
throw Exception(std::string("not enough parameters to option \"-") + opt->id + "\"");
}
std::copy_n(it, opt->size(), std::back_inserter(option_args));
option.push_back(ParsedOption(opt, option_args));
const size_t index = std::distance(arguments.begin(), it);
option.push_back(ParsedOption(opt, option_args, index));
it += opt->size();
} else {
argument.push_back(ParsedArgument(nullptr, nullptr, *it));
Expand Down Expand Up @@ -1200,7 +1201,7 @@ const std::vector<ParsedOption> get_options(const std::string &name) {
for (size_t i = 0; i < option.size(); ++i) {
assert(option[i].opt);
if (option[i].opt->is(name))
matches.push_back({option[i].opt, option[i].args});
matches.push_back({option[i].opt, option[i].args, option[i].index});
}
return matches;
}
Expand Down Expand Up @@ -1373,8 +1374,8 @@ void check_overwrite(const std::string &name) {
}
}


ParsedOption::ParsedOption(const Option *option, const std::vector<std::string> &arguments) : opt(option), args(arguments) {
ParsedOption::ParsedOption(const Option *option, const std::vector<std::string> &arguments, size_t i)
: opt(option), args(arguments), index(i) {
for (size_t i = 0; i != option->size(); ++i) {
const auto &p = arguments[i];
if (!is_dash(p))
Expand Down
6 changes: 4 additions & 2 deletions core/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,14 @@ class ParsedArgument {
* returned by App::get_options(). */
class ParsedOption {
public:
ParsedOption(const Option *option, const std::vector<std::string> &arguments);
ParsedOption(const Option *option, const std::vector<std::string> &arguments, size_t index);

//! reference to the corresponding Option entry in the OPTIONS section
const Option *opt;
//! pointer into \c argv corresponding to the option's first argument
//! list of arguments supplied to the option
std::vector<std::string> args;
//! the index of this option in the raw command-line arguments list
size_t index;

ParsedArgument operator[](size_t num) const;

Expand Down
34 changes: 19 additions & 15 deletions src/gui/mrview/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,22 +721,26 @@ void Window::parse_arguments() {
if (!MR::App::argument.empty()) {
if (!MR::App::option.empty()) {
// check that first non-standard option appears after last argument:
size_t last_arg_pos = 1;
for (; MR::App::argv[last_arg_pos] != MR::App::argument.back().c_str(); ++last_arg_pos)
if (MR::App::argv[last_arg_pos] == nullptr)
throw Exception("FIXME: error determining position of last argument!");

// identify first non-standard option:
size_t first_option = 0;
for (; first_option < MR::App::option.size(); ++first_option) {
if (size_t(MR::App::option[first_option].opt - &MR::App::__standard_options[0]) >=
MR::App::__standard_options.size())
break;
const auto last_arg = std::find(
MR::App::raw_arguments_list.rbegin(), MR::App::raw_arguments_list.rend(), MR::App::argument.back().c_str());

if (last_arg == MR::App::raw_arguments_list.rend()) {
throw Exception("FIXME: error determining position of last argument!");
}
if (MR::App::option.size() > first_option) {
first_option = MR::App::option[first_option].args - MR::App::argv;
if (first_option < last_arg_pos)
throw Exception("options must appear after the last argument - see help page for details");

const auto last_arg_pos = std::distance(last_arg, MR::App::raw_arguments_list.rend()) - 1;

const auto is_non_standard_option = [](const MR::App::ParsedOption &option) {
return std::none_of(MR::App::__standard_options.begin(),
MR::App::__standard_options.end(),
[&option](const auto &standard_option) { return option.opt == &standard_option; });
};

const auto first_non_standard_option =
std::find_if(MR::App::option.begin(), MR::App::option.end(), is_non_standard_option);

if (first_non_standard_option != MR::App::option.end() && first_non_standard_option->index < last_arg_pos) {
throw Exception("options must appear after the last argument - see help page for details");
}
}

Expand Down

0 comments on commit ff9502a

Please sign in to comment.