24 namespace seqan3::detail
51 class format_parse :
public format_base
57 format_parse() =
delete;
58 format_parse(format_parse
const & pf) =
default;
59 format_parse & operator=(format_parse
const & pf) =
default;
60 format_parse(format_parse &&) =
default;
61 format_parse & operator=(format_parse &&) =
default;
62 ~format_parse() =
default;
86 template <
typename option_type,
typename val
idator_type>
87 void add_option(option_type & value,
94 option_calls.push_back([
this, &value, short_id, long_id, spec,
validator]()
96 get_option(value, short_id, long_id, spec,
validator);
108 void add_flag(
bool & value,
114 flag_calls.push_back([
this, &value, short_id, long_id]()
116 get_flag(value, short_id, long_id);
130 template <
typename option_type,
typename val
idator_type>
131 void add_positional_option(option_type & value,
135 positional_option_calls.push_back([
this, &value,
validator]()
142 void parse(argument_parser_meta_data
const & )
144 end_of_options_it =
std::find(argv.begin(), argv.end(),
"--");
148 for (
auto && f : option_calls)
151 for (
auto && f : flag_calls)
154 check_for_unknown_ids();
156 if (end_of_options_it != argv.end())
157 *end_of_options_it =
"";
159 for (
auto && f : positional_option_calls)
162 check_for_left_over_args();
174 template <
typename id_type>
175 static bool is_empty_id(id_type
const &
id)
189 std::
string prepend_dash(
std::
string const & long_id)
191 return (
"--" + long_id);
210 if (short_id ==
'\0')
211 return prepend_dash(long_id);
212 else if (long_id.
empty())
213 return prepend_dash(short_id);
215 return prepend_dash(short_id) +
"/" + prepend_dash(long_id);
230 template <
typename id_type>
234 return end_of_options_it;
239 size_t id_size{(prepend_dash(
id)).
size()};
240 if (v.
size() < id_size)
243 return v.
substr(0, id_size) == prepend_dash(
id);
252 auto it =
std::find(argv.begin(), end_of_options_it, prepend_dash(long_id));
254 if (it != end_of_options_it)
257 return(it != end_of_options_it);
263 bool flag_is_set(
char const short_id)
268 if (arg[0] ==
'-' && arg.size() > 1 && arg[1] !=
'-')
270 auto pos = arg.find(short_id);
272 if (pos != std::string::npos)
293 template <
typename option_t>
297 void retrieve_value(option_t & value,
std::string const & in)
302 if (stream.fail() || !stream.eof())
304 throw type_conversion_failed(
"Argument " + in +
" could not be casted to type " +
305 get_type_name_as_string(value) +
".");
316 template <named_enumeration option_t>
319 auto map = seqan3::enumeration_names<option_t>;
321 if (
auto it = map.find(in); it == map.end())
323 throw type_conversion_failed(
"Argument " +
std::string{in} +
" could not be cast to enum type " +
324 type_name_as_string<option_t> +
".");
347 template <sequence_container container_option_t>
351 void retrieve_value(container_option_t & value,
std::string const & in)
353 typename container_option_t::value_type tmp;
355 retrieve_value(tmp, in);
356 value.push_back(tmp);
371 template <arithmetic option_t>
375 void retrieve_value(option_t & value,
std::string const & in)
379 if (res.ec == std::errc::result_out_of_range)
380 throw overflow_error_on_conversion(
"Argument " + in +
" is not in integer range [" +
383 else if (res.ec == std::errc::invalid_argument || res.ptr != &in[in.
size()])
384 throw type_conversion_failed(
"Argument " + in +
" could not be casted to type " +
385 get_type_name_as_string(value) +
".");
398 void retrieve_value(
bool & value,
std::string const & in)
404 else if (in ==
"true")
406 else if (in ==
"false")
409 throw type_conversion_failed(
"Argument '" + in +
"' could not be casted to boolean.");
428 template <
typename option_type,
typename id_type>
429 bool identify_and_retrieve_option_value(option_type & value,
433 if (option_it != end_of_options_it)
436 size_t id_size = (prepend_dash(
id)).
size();
438 if ((*option_it).size() > id_size)
440 if ((*option_it)[id_size] ==
'=')
442 if ((*option_it).size() == id_size + 1)
443 throw parser_invalid_argument(
"Value cast failed for option " +
445 ": No value was provided.");
446 input_value = (*option_it).
substr(id_size + 1);
450 input_value = (*option_it).
substr(id_size);
459 if (option_it == end_of_options_it)
460 throw parser_invalid_argument(
"Value cast failed for option " +
462 ": No value was provided.");
463 input_value = *option_it;
469 retrieve_value(value, input_value);
471 catch (parser_invalid_argument
const & ex)
473 throw parser_invalid_argument(
"Value cast failed for option " + prepend_dash(
id) +
": " + ex.what());
498 template <
typename option_type,
typename id_type>
499 bool get_option_by_id(option_type & value, id_type
const &
id)
501 auto it = find_option_id(argv.begin(),
id);
503 if (it != end_of_options_it)
504 identify_and_retrieve_option_value(value, it,
id);
506 if (find_option_id(it,
id) != end_of_options_it)
507 throw option_declared_multiple_times(
"Option " + prepend_dash(
id) +
508 " is no list/container but declared multiple times.");
510 return (it != end_of_options_it);
524 template <sequence_container option_type,
typename id_type>
526 requires !std::is_same_v<option_type, std::string>
528 bool get_option_by_id(option_type & value, id_type
const &
id)
530 auto it = find_option_id(argv.begin(),
id);
531 bool seen_at_least_once{it != end_of_options_it};
533 while (it != end_of_options_it)
535 identify_and_retrieve_option_value(value, it,
id);
536 it = find_option_id(it,
id);
539 return seen_at_least_once;
555 void check_for_unknown_ids()
557 for (
auto it = argv.begin(); it != end_of_options_it; ++it)
560 if (!arg.empty() && arg[0] ==
'-')
566 else if (arg[1] !=
'-' && arg.size() > 2)
568 throw unknown_option(
"Unknown flags " + expand_multiple_flags(arg) +
569 ". In case this is meant to be a non-option/argument/parameter, " +
570 "please specify the start of arguments with '--'. " +
571 "See -h/--help for program information.");
575 throw unknown_option(
"Unknown option " + arg +
576 ". In case this is meant to be a non-option/argument/parameter, " +
577 "please specify the start of non-options with '--'. " +
578 "See -h/--help for program information.");
595 void check_for_left_over_args()
598 throw too_many_arguments(
"Too many arguments provided. Please see -h/--help for more information.");
621 template <
typename option_type,
typename val
idator_type>
622 void get_option(option_type & value,
628 bool short_id_is_set{get_option_by_id(value, short_id)};
629 bool long_id_is_set{get_option_by_id(value, long_id)};
632 if (short_id_is_set && long_id_is_set &&
634 throw option_declared_multiple_times(
"Option " + combine_option_names(short_id, long_id) +
635 " is no list/container but specified multiple times");
637 if (short_id_is_set || long_id_is_set)
645 throw validation_failed(
std::string(
"Validation failed for option ") +
646 combine_option_names(short_id, long_id) +
": " + ex.
what());
653 throw required_option_missing(
"Option " + combine_option_names(short_id, long_id) +
654 " is required but not set.");
665 void get_flag(
bool & value,
669 value = flag_is_set(short_id) || flag_is_set(long_id);
697 template <
typename option_type,
typename val
idator_type>
698 void get_positional_option(option_type & value,
701 ++positional_option_count;
704 if (it == argv.end())
705 throw too_few_arguments(
"Not enough positional arguments provided (Need at least " +
706 std::to_string(positional_option_calls.size()) +
"). See -h/--help for more information.");
710 assert(positional_option_count == positional_option_calls.size());
712 while (it != argv.end())
716 retrieve_value(value, *it);
718 catch (parser_invalid_argument
const & ex)
720 throw parser_invalid_argument(
"Value cast failed for positional option " +
726 ++positional_option_count;
733 retrieve_value(value, *it);
735 catch (parser_invalid_argument
const & ex)
737 throw parser_invalid_argument(
"Value cast failed for positional option " +
750 throw validation_failed(
"Validation failed for positional option " +
762 unsigned positional_option_count{0};