25 namespace seqan3::detail
52 class format_parse :
public format_base
58 format_parse() =
delete;
59 format_parse(format_parse
const & pf) =
default;
60 format_parse & operator=(format_parse
const & pf) =
default;
61 format_parse(format_parse &&) =
default;
62 format_parse & operator=(format_parse &&) =
default;
63 ~format_parse() =
default;
77 template <
typename option_type,
typename val
idator_type>
78 void add_option(option_type & value,
83 validator_type && option_validator)
85 option_calls.push_back([
this, &value, short_id, long_id, spec, option_validator]()
87 get_option(value, short_id, long_id, spec, option_validator);
94 void add_flag(
bool & value,
100 flag_calls.push_back([
this, &value, short_id, long_id]()
102 get_flag(value, short_id, long_id);
109 template <
typename option_type,
typename val
idator_type>
110 void add_positional_option(option_type & value,
112 validator_type && option_validator)
114 positional_option_calls.push_back([
this, &value, option_validator]()
116 get_positional_option(value, option_validator);
121 void parse(argument_parser_meta_data
const & )
123 end_of_options_it =
std::find(argv.begin(), argv.end(),
"--");
127 for (
auto && f : option_calls)
130 for (
auto && f : flag_calls)
133 check_for_unknown_ids();
135 if (end_of_options_it != argv.end())
136 *end_of_options_it =
"";
138 for (
auto && f : positional_option_calls)
141 check_for_left_over_args();
153 template <
typename id_type>
154 static bool is_empty_id(id_type
const &
id)
164 enum class option_parse_result
177 return (
"--" + long_id);
196 if (short_id ==
'\0')
197 return prepend_dash(long_id);
198 else if (long_id.
empty())
199 return prepend_dash(short_id);
201 return prepend_dash(short_id) +
"/" + prepend_dash(long_id);
225 template <
typename id_type>
229 return end_of_options_it;
236 if constexpr (std::same_as<id_type, char>)
240 return current_arg.
substr(0, full_id.
size()) == full_id;
245 return current_arg.
substr(0, full_id.
size()) == full_id &&
246 (current_arg.
size() == full_id.
size() || current_arg[full_id.
size()] ==
'=');
256 auto it =
std::find(argv.begin(), end_of_options_it, prepend_dash(long_id));
258 if (it != end_of_options_it)
261 return(it != end_of_options_it);
267 bool flag_is_set(
char const short_id)
272 if (arg[0] ==
'-' && arg.size() > 1 && arg[1] !=
'-')
274 auto pos = arg.find(short_id);
276 if (pos != std::string::npos)
297 template <
typename option_t>
301 option_parse_result parse_option_value(option_t & value,
std::string const & in)
306 if (stream.fail() || !stream.eof())
307 return option_parse_result::error;
309 return option_parse_result::success;
319 template <named_enumeration option_t>
320 option_parse_result parse_option_value(option_t & value,
std::string_view const in)
322 auto map = seqan3::enumeration_names<option_t>;
324 if (
auto it = map.find(in); it == map.end())
325 return option_parse_result::error;
329 return option_parse_result::success;
336 return option_parse_result::success;
348 template <sequence_container container_option_t>
352 option_parse_result parse_option_value(container_option_t & value,
std::string const & in)
354 typename container_option_t::value_type tmp{};
356 auto res = parse_option_value(tmp, in);
358 if (res == option_parse_result::success)
359 value.push_back(tmp);
376 template <arithmetic option_t>
380 option_parse_result parse_option_value(option_t & value,
std::string const & in)
384 if (res.ec == std::errc::result_out_of_range)
385 return option_parse_result::overflow_error;
386 else if (res.ec == std::errc::invalid_argument || res.ptr != &in[in.
size()])
387 return option_parse_result::error;
389 return option_parse_result::success;
402 option_parse_result parse_option_value(
bool & value,
std::string const & in)
408 else if (in ==
"true")
410 else if (in ==
"false")
413 return option_parse_result::error;
415 return option_parse_result::success;
425 template <
typename option_type>
426 void throw_on_input_error(option_parse_result
const res,
430 std::string msg{
"Value parse failed for " + option_name +
": "};
432 if (res == option_parse_result::error)
434 throw user_input_error{msg +
"Argument " + input_value +
" could not be parsed as type " +
435 get_type_name_as_string(input_value) +
"."};
440 if (res == option_parse_result::overflow_error)
442 throw user_input_error{msg +
"Numeric argument " + input_value +
" is not in the valid range [" +
448 assert(res == option_parse_result::success);
468 template <
typename option_type,
typename id_type>
469 bool identify_and_retrieve_option_value(option_type & value,
473 if (option_it != end_of_options_it)
476 size_t id_size = (prepend_dash(
id)).
size();
478 if ((*option_it).size() > id_size)
480 if ((*option_it)[id_size] ==
'=')
482 if ((*option_it).size() == id_size + 1)
483 throw too_few_arguments(
"Missing value for option " + prepend_dash(
id));
484 input_value = (*option_it).
substr(id_size + 1);
488 input_value = (*option_it).
substr(id_size);
497 if (option_it == end_of_options_it)
498 throw too_few_arguments(
"Missing value for option " + prepend_dash(
id));
499 input_value = *option_it;
503 auto res = parse_option_value(value, input_value);
504 throw_on_input_error<option_type>(res, prepend_dash(
id), input_value);
528 template <
typename option_type,
typename id_type>
529 bool get_option_by_id(option_type & value, id_type
const &
id)
531 auto it = find_option_id(argv.begin(),
id);
533 if (it != end_of_options_it)
534 identify_and_retrieve_option_value(value, it,
id);
536 if (find_option_id(it,
id) != end_of_options_it)
537 throw option_declared_multiple_times(
"Option " + prepend_dash(
id) +
538 " is no list/container but declared multiple times.");
540 return (it != end_of_options_it);
554 template <sequence_container option_type,
typename id_type>
556 requires (!std::is_same_v<option_type, std::string>)
558 bool get_option_by_id(option_type & value, id_type
const &
id)
560 auto it = find_option_id(argv.begin(),
id);
561 bool seen_at_least_once{it != end_of_options_it};
563 while (it != end_of_options_it)
565 identify_and_retrieve_option_value(value, it,
id);
566 it = find_option_id(it,
id);
569 return seen_at_least_once;
585 void check_for_unknown_ids()
587 for (
auto it = argv.begin(); it != end_of_options_it; ++it)
590 if (!arg.empty() && arg[0] ==
'-')
596 else if (arg[1] !=
'-' && arg.size() > 2)
598 throw unknown_option(
"Unknown flags " + expand_multiple_flags(arg) +
599 ". In case this is meant to be a non-option/argument/parameter, " +
600 "please specify the start of arguments with '--'. " +
601 "See -h/--help for program information.");
605 throw unknown_option(
"Unknown option " + arg +
606 ". In case this is meant to be a non-option/argument/parameter, " +
607 "please specify the start of non-options with '--'. " +
608 "See -h/--help for program information.");
625 void check_for_left_over_args()
628 throw too_many_arguments(
"Too many arguments provided. Please see -h/--help for more information.");
651 template <
typename option_type,
typename val
idator_type>
652 void get_option(option_type & value,
658 bool short_id_is_set{get_option_by_id(value, short_id)};
659 bool long_id_is_set{get_option_by_id(value, long_id)};
662 if (short_id_is_set && long_id_is_set &&
664 throw option_declared_multiple_times(
"Option " + combine_option_names(short_id, long_id) +
665 " is no list/container but specified multiple times");
667 if (short_id_is_set || long_id_is_set)
675 throw validation_error(
std::string(
"Validation failed for option ") +
676 combine_option_names(short_id, long_id) +
": " + ex.
what());
683 throw required_option_missing(
"Option " + combine_option_names(short_id, long_id) +
684 " is required but not set.");
695 void get_flag(
bool & value,
699 value = flag_is_set(short_id) || flag_is_set(long_id);
724 template <
typename option_type,
typename val
idator_type>
725 void get_positional_option(option_type & value,
728 ++positional_option_count;
731 if (it == argv.end())
732 throw too_few_arguments(
"Not enough positional arguments provided (Need at least " +
734 "). See -h/--help for more information.");
738 assert(positional_option_count == positional_option_calls.size());
740 while (it != argv.end())
742 auto res = parse_option_value(value, *it);
744 throw_on_input_error<option_type>(res,
id, *it);
748 ++positional_option_count;
753 auto res = parse_option_value(value, *it);
755 throw_on_input_error<option_type>(res,
id, *it);
766 throw validation_error(
"Validation failed for positional option " +
778 unsigned positional_option_count{0};