21namespace seqan3::detail
50class format_parse :
public format_base
56 format_parse() =
delete;
57 format_parse(format_parse
const & pf) =
default;
58 format_parse & operator=(format_parse
const & pf) =
default;
59 format_parse(format_parse &&) =
default;
60 format_parse & operator=(format_parse &&) =
default;
61 ~format_parse() =
default;
73 template <
typename option_type,
typename val
idator_type>
74 void add_option(option_type & value,
79 validator_type && option_validator)
81 option_calls.push_back(
82 [
this, &value, short_id, long_id, spec, option_validator]()
84 get_option(value, short_id, long_id, spec, option_validator);
91 void add_flag(
bool & value,
98 [
this, &value, short_id, long_id]()
100 get_flag(value, short_id, long_id);
107 template <
typename option_type,
typename val
idator_type>
108 void add_positional_option(option_type & value,
110 validator_type && option_validator)
112 positional_option_calls.push_back(
113 [
this, &value, option_validator]()
115 get_positional_option(value, option_validator);
120 void parse(argument_parser_meta_data
const & )
122 end_of_options_it =
std::find(argv.begin(), argv.end(),
"--");
126 for (
auto && f : option_calls)
129 for (
auto && f : flag_calls)
132 check_for_unknown_ids();
134 if (end_of_options_it != argv.end())
135 *end_of_options_it =
"";
137 for (
auto && f : positional_option_calls)
140 check_for_left_over_args();
156 template <
typename id_type>
157 static bool is_empty_id(id_type
const &
id)
159 if constexpr (std::same_as<std::remove_cvref_t<id_type>,
std::string>)
162 return is_char<'\0'>(
id);
186 template <
typename iterator_type,
typename id_type>
187 static iterator_type find_option_id(iterator_type begin_it, iterator_type end_it, id_type
const &
id)
198 if constexpr (std::same_as<id_type, char>)
202 return current_arg.
substr(0, full_id.
size()) == full_id;
207 return current_arg.
substr(0, full_id.
size()) == full_id &&
208 (current_arg.
size() == full_id.
size()
209 || current_arg[full_id.
size()] ==
'=');
216 enum class option_parse_result
229 return {
"--" + long_id};
236 static std::string prepend_dash(
char const short_id)
238 return {
'-', short_id};
248 if (short_id ==
'\0')
249 return prepend_dash(long_id);
250 else if (long_id.
empty())
251 return prepend_dash(short_id);
253 return prepend_dash(short_id) +
"/" + prepend_dash(long_id);
261 auto it =
std::find(argv.begin(), end_of_options_it, prepend_dash(long_id));
263 if (it != end_of_options_it)
266 return (it != end_of_options_it);
272 bool flag_is_set(
char const short_id)
277 if (arg[0] ==
'-' && arg.size() > 1 && arg[1] !=
'-')
279 auto pos = arg.find(short_id);
281 if (pos != std::string::npos)
302 template <
typename option_t>
304 option_parse_result parse_option_value(option_t & value,
std::string const & in)
309 if (stream.fail() || !stream.eof())
310 return option_parse_result::error;
312 return option_parse_result::success;
322 template <named_enumeration option_t>
323 option_parse_result parse_option_value(option_t & value,
std::string const & in)
325 auto map = seqan3::enumeration_names<option_t>;
327 if (
auto it = map.find(in); it == map.end())
331 [](
auto pair1,
auto pair2)
333 if constexpr (std::totally_ordered<option_t>)
335 if (pair1.second != pair2.second)
336 return pair1.second < pair2.second;
338 return pair1.first < pair2.first;
341 throw user_input_error{detail::to_string(
"You have chosen an invalid input value: ",
343 ". Please use one of: ",
344 key_value_pairs | std::views::keys)};
351 return option_parse_result::success;
358 return option_parse_result::success;
373 template <detail::is_container_option container_option_t,
typename format_parse_t = format_parse>
374 requires requires (format_parse_t fp,
375 typename container_option_t::value_type & container_value,
378 fp.parse_option_value(container_value, in)
379 } -> std::same_as<option_parse_result>;
381 option_parse_result parse_option_value(container_option_t & value,
std::string const & in)
383 typename container_option_t::value_type tmp{};
385 auto res = parse_option_value(tmp, in);
387 if (res == option_parse_result::success)
388 value.push_back(tmp);
405 template <arithmetic option_t>
407 option_parse_result parse_option_value(option_t & value,
std::string const & in)
411 if (res.ec == std::errc::result_out_of_range)
412 return option_parse_result::overflow_error;
413 else if (res.ec == std::errc::invalid_argument || res.ptr != &in[in.
size()])
414 return option_parse_result::error;
416 return option_parse_result::success;
429 option_parse_result parse_option_value(
bool & value,
std::string const & in)
435 else if (in ==
"true")
437 else if (in ==
"false")
440 return option_parse_result::error;
442 return option_parse_result::success;
452 template <
typename option_type>
453 void throw_on_input_error(option_parse_result
const res,
457 std::string msg{
"Value parse failed for " + option_name +
": "};
459 if (res == option_parse_result::error)
461 throw user_input_error{msg +
"Argument " + input_value +
" could not be parsed as type "
462 + get_type_name_as_string(option_type{}) +
"."};
467 if (res == option_parse_result::overflow_error)
469 throw user_input_error{msg +
"Numeric argument " + input_value +
" is not in the valid range ["
475 assert(res == option_parse_result::success);
495 template <
typename option_type,
typename id_type>
496 bool identify_and_retrieve_option_value(option_type & value,
500 if (option_it != end_of_options_it)
503 size_t id_size = (prepend_dash(
id)).
size();
505 if ((*option_it).size() > id_size)
507 if ((*option_it)[id_size] ==
'=')
509 if ((*option_it).size() == id_size + 1)
510 throw too_few_arguments(
"Missing value for option " + prepend_dash(
id));
511 input_value = (*option_it).
substr(id_size + 1);
515 input_value = (*option_it).
substr(id_size);
524 if (option_it == end_of_options_it)
525 throw too_few_arguments(
"Missing value for option " + prepend_dash(
id));
526 input_value = *option_it;
530 auto res = parse_option_value(value, input_value);
531 throw_on_input_error<option_type>(res, prepend_dash(
id), input_value);
555 template <
typename option_type,
typename id_type>
556 bool get_option_by_id(option_type & value, id_type
const &
id)
558 auto it = find_option_id(argv.begin(), end_of_options_it,
id);
560 if (it != end_of_options_it)
561 identify_and_retrieve_option_value(value, it,
id);
563 if (find_option_id(it, end_of_options_it,
id) != end_of_options_it)
564 throw option_declared_multiple_times(
"Option " + prepend_dash(
id)
565 +
" is no list/container but declared multiple times.");
567 return (it != end_of_options_it);
581 template <detail::is_container_option option_type,
typename id_type>
582 bool get_option_by_id(option_type & value, id_type
const &
id)
584 auto it = find_option_id(argv.begin(), end_of_options_it,
id);
585 bool seen_at_least_once{it != end_of_options_it};
587 if (seen_at_least_once)
590 while (it != end_of_options_it)
592 identify_and_retrieve_option_value(value, it,
id);
593 it = find_option_id(it, end_of_options_it,
id);
596 return seen_at_least_once;
612 void check_for_unknown_ids()
614 for (
auto it = argv.begin(); it != end_of_options_it; ++it)
617 if (!arg.empty() && arg[0] ==
'-')
623 else if (arg[1] !=
'-' && arg.size() > 2)
625 throw unknown_option(
"Unknown flags " + expand_multiple_flags(arg)
626 +
". In case this is meant to be a non-option/argument/parameter, "
627 +
"please specify the start of arguments with '--'. "
628 +
"See -h/--help for program information.");
632 throw unknown_option(
"Unknown option " + arg
633 +
". In case this is meant to be a non-option/argument/parameter, "
634 +
"please specify the start of non-options with '--'. "
635 +
"See -h/--help for program information.");
652 void check_for_left_over_args()
661 throw too_many_arguments(
"Too many arguments provided. Please see -h/--help for more information.");
684 template <
typename option_type,
typename val
idator_type>
685 void get_option(option_type & value,
691 bool short_id_is_set{get_option_by_id(value, short_id)};
692 bool long_id_is_set{get_option_by_id(value, long_id)};
695 if (short_id_is_set && long_id_is_set && !detail::is_container_option<option_type>)
696 throw option_declared_multiple_times(
"Option " + combine_option_names(short_id, long_id)
697 +
" is no list/container but specified multiple times");
699 if (short_id_is_set || long_id_is_set)
707 throw validation_error(
std::string(
"Validation failed for option ")
708 + combine_option_names(short_id, long_id) +
": " + ex.
what());
715 throw required_option_missing(
"Option " + combine_option_names(short_id, long_id)
716 +
" is required but not set.");
727 void get_flag(
bool & value,
char const short_id,
std::string const & long_id)
729 value = flag_is_set(short_id) || flag_is_set(long_id);
754 template <
typename option_type,
typename val
idator_type>
755 void get_positional_option(option_type & value, validator_type &&
validator)
757 ++positional_option_count;
765 if (it == argv.end())
766 throw too_few_arguments(
"Not enough positional arguments provided (Need at least "
768 +
"). See -h/--help for more information.");
770 if constexpr (detail::is_container_option<
773 assert(positional_option_count == positional_option_calls.size());
777 while (it != argv.end())
779 auto res = parse_option_value(value, *it);
781 throw_on_input_error<option_type>(res,
id, *it);
790 ++positional_option_count;
795 auto res = parse_option_value(value, *it);
797 throw_on_input_error<option_type>(res,
id, *it);
808 throw validation_error(
"Validation failed for positional option " +
std::to_string(positional_option_count)
820 unsigned positional_option_count{0};
The <charconv> header from C++17's standard library.
option_spec
Used to further specify argument_parser options/flags.
Definition auxiliary.hpp:245
@ required
Definition auxiliary.hpp:247
constexpr size_t size
The size of a type pack.
Definition type_pack/traits.hpp:143
A type that satisfies std::is_arithmetic_v<t>.
The concept for option validators passed to add_option/positional_option.
SeqAn specific customisations in the standard namespace.
Provides character predicates for tokenisation.