50 class 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;
68 argc{argc_ - 1}, argv{std::move(argv_)}
85 template <
typename option_type,
typename val
idator_type>
86 void add_option(option_type & value,
91 validator_type && validator)
93 option_calls.push_back([
this, &value, short_id, long_id, spec, validator]()
95 get_option(value, short_id, long_id, spec, validator);
107 void add_flag(
bool & value,
113 flag_calls.push_back([
this, &value, short_id, long_id]()
115 get_flag(value, short_id, long_id);
129 template <
typename option_type,
typename val
idator_type>
130 void add_positional_option(option_type & value,
132 validator_type && validator)
134 positional_option_calls.push_back([
this, &value, validator]()
136 get_positional_option(value, validator);
141 void parse(argument_parser_meta_data
const & )
143 end_of_options_it =
std::find(argv.begin(), argv.end(),
"--");
147 for (
auto && f : option_calls)
150 for (
auto && f : flag_calls)
153 check_for_unknown_ids();
155 if (end_of_options_it != argv.end())
156 *end_of_options_it =
"";
158 for (
auto && f : positional_option_calls)
161 check_for_left_over_args();
173 template <
typename id_type>
174 static bool is_empty_id(id_type
const &
id)
188 std::
string prepend_dash(
std::
string const & long_id)
190 return (
"--" + long_id);
209 if (short_id ==
'\0')
210 return prepend_dash(long_id);
211 else if (long_id.
empty())
212 return prepend_dash(short_id);
214 return prepend_dash(short_id) +
"/" + prepend_dash(long_id);
229 template <
typename id_type>
233 return end_of_options_it;
238 size_t id_size{(prepend_dash(
id)).
size()};
239 if (v.
size() < id_size)
242 return v.
substr(0, id_size) == prepend_dash(
id);
251 auto it =
std::find(argv.begin(), end_of_options_it, prepend_dash(long_id));
253 if (it != end_of_options_it)
256 return(it != end_of_options_it);
262 bool flag_is_set(
char const short_id)
267 if (arg[0] ==
'-' && arg.size() > 1 && arg[1] !=
'-')
269 auto pos = arg.find(short_id);
271 if (pos != std::string::npos)
294 template <
typename option_t>
296 requires IStream<std::istringstream, option_t>
298 void retrieve_value(option_t & value,
std::string const & in)
303 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) +
".");
323 template <SequenceContainer container_option_t>
325 requires IStream<std::istringstream, typename container_option_t::value_type>
327 void retrieve_value(container_option_t & value,
std::string const & in)
329 typename container_option_t::value_type tmp;
331 retrieve_value(tmp, in);
332 value.push_back(tmp);
347 template <Arithmetic option_t>
349 requires IStream<std::istringstream, option_t>
351 void retrieve_value(option_t & value,
std::string const & in)
355 if (res.ec == std::errc::result_out_of_range)
356 throw overflow_error_on_conversion(
"Argument " + in +
" is not in integer range [" +
359 else if (res.ec == std::errc::invalid_argument || res.ptr != &in[in.
size()])
360 throw type_conversion_failed(
"Argument " + in +
" could not be casted to type " +
361 get_type_name_as_string(value) +
".");
374 void retrieve_value(
bool & value,
std::string const & in)
380 else if (in ==
"true")
382 else if (in ==
"false")
385 throw type_conversion_failed(
"Argument '" + in +
"' could not be casted to boolean.");
404 template <
typename option_type,
typename id_type>
405 bool identify_and_retrieve_option_value(option_type & value,
409 if (option_it != end_of_options_it)
412 size_t id_size = (prepend_dash(
id)).
size();
414 if ((*option_it).size() > id_size)
416 if ((*option_it)[id_size] ==
'=')
418 if ((*option_it).size() == id_size + 1)
419 throw parser_invalid_argument(
"Value cast failed for option " +
421 ": No value was provided.");
422 input_value = (*option_it).
substr(id_size + 1);
426 input_value = (*option_it).
substr(id_size);
435 if (option_it == end_of_options_it)
436 throw parser_invalid_argument(
"Value cast failed for option " +
438 ": No value was provided.");
439 input_value = *option_it;
445 retrieve_value(value, input_value);
447 catch (parser_invalid_argument
const & ex)
449 throw parser_invalid_argument(
"Value cast failed for option " + prepend_dash(
id) +
": " + ex.what());
474 template <
typename option_type,
typename id_type>
475 bool get_option_by_id(option_type & value, id_type
const &
id)
477 auto it = find_option_id(argv.begin(), id);
479 if (it != end_of_options_it)
480 identify_and_retrieve_option_value(value, it,
id);
482 if (find_option_id(it,
id) != end_of_options_it)
483 throw option_declared_multiple_times(
"Option " + prepend_dash(
id) +
484 " is no list/container but declared multiple times.");
486 return (it != end_of_options_it);
500 template <SequenceContainer option_type,
typename id_type>
502 requires !std::is_same_v<option_type, std::string>
504 bool get_option_by_id(option_type & value, id_type
const &
id)
506 auto it = find_option_id(argv.begin(), id);
507 bool seen_at_least_once{it != end_of_options_it};
509 while (it != end_of_options_it)
511 identify_and_retrieve_option_value(value, it,
id);
512 it = find_option_id(it,
id);
515 return seen_at_least_once;
531 void check_for_unknown_ids()
533 for (
auto it = argv.begin(); it != end_of_options_it; ++it)
536 if (!arg.empty() && arg[0] ==
'-')
542 else if (arg[1] !=
'-' && arg.size() > 2)
544 throw unknown_option(
"Unknown flags " + expand_multiple_flags(arg) +
545 ". In case this is meant to be a non-option/argument/parameter, " +
546 "please specify the start of arguments with '--'. " +
547 "See -h/--help for program information.");
551 throw unknown_option(
"Unknown option " + arg +
552 ". In case this is meant to be a non-option/argument/parameter, " +
553 "please specify the start of non-options with '--'. " +
554 "See -h/--help for program information.");
571 void check_for_left_over_args()
574 throw too_many_arguments(
"Too many arguments provided. Please see -h/--help for more information.");
597 template <
typename option_type,
typename val
idator_type>
598 void get_option(option_type & value,
602 validator_type && validator)
604 bool short_id_is_set{get_option_by_id(value, short_id)};
605 bool long_id_is_set{get_option_by_id(value, long_id)};
608 if (short_id_is_set && long_id_is_set &&
609 !(SequenceContainer<option_type> && !std::is_same_v<option_type, std::string>))
610 throw option_declared_multiple_times(
"Option " + combine_option_names(short_id, long_id) +
611 " is no list/container but specified multiple times");
613 if (short_id_is_set || long_id_is_set)
621 throw validation_failed(
std::string(
"Validation failed for option ") +
622 combine_option_names(short_id, long_id) +
": " + ex.
what());
629 throw required_option_missing(
"Option " + combine_option_names(short_id, long_id) +
630 " is required but not set.");
641 void get_flag(
bool & value,
645 value = flag_is_set(short_id) || flag_is_set(long_id);
673 template <
typename option_type,
typename val
idator_type>
674 void get_positional_option(option_type & value,
675 validator_type && validator)
677 ++positional_option_count;
680 if (it == argv.end())
681 throw too_few_arguments(
"Not enough positional arguments provided (Need at least " +
682 std::to_string(positional_option_calls.size()) +
"). See -h/--help for more information.");
684 if (SequenceContainer<option_type> && !std::is_same_v<option_type, std::string>)
686 if (positional_option_count != (positional_option_calls.size()))
687 throw parser_design_error(
"Lists are only allowed as the last positional option!");
689 while (it != argv.end())
693 retrieve_value(value, *it);
695 catch (parser_invalid_argument
const & ex)
697 throw parser_invalid_argument(
"Value cast failed for positional option " +
703 ++positional_option_count;
710 retrieve_value(value, *it);
712 catch (parser_invalid_argument
const & ex)
714 throw parser_invalid_argument(
"Value cast failed for positional option " +
727 throw validation_failed(
"Validation failed for positional option " +
739 unsigned positional_option_count{0};
constexpr auto is_char
Checks whether a given letter is the same as the template non-type argument.
Definition: predicate.hpp:83
SeqAn specific customisations in the standard namespace.
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:189
Provides std::from_chars and std::to_chars if not defined in the stl <charconv> header.
std::from_chars_result from_chars(char const *first, char const *last, value_type &value, int base) noexcept
Parse a char sequence into an integral.
Definition: charconv:174
The concept std::Same<T, U> is satisfied if and only if T and U denote the same type.
Definition: aligned_sequence_concept.hpp:35
::ranges::empty empty
Alias for ranges::empty. Checks whether a range is empty.
Definition: ranges:194
option_spec
Used to further specify argument_parser options/flags.
Definition: auxiliary.hpp:34
Definition: auxiliary.hpp:37