76 class format_parse :
public format_base
83 format_parse() =
delete;
84 format_parse(format_parse
const & pf) =
default;
85 format_parse & operator=(format_parse
const & pf) =
default;
86 format_parse(format_parse &&) =
default;
87 format_parse & operator=(format_parse &&) =
default;
93 format_parse(
int const argc_,
char const *
const *
const argv_) :
99 ~format_parse() =
default;
115 template <
typename option_type,
typename val
idator_type>
116 void add_option(option_type & value,
118 std::string
const & long_id,
119 std::string
const & ,
121 validator_type && validator)
123 option_calls.push_back([=, &value]()
125 get_option(value, short_id, long_id, spec, validator);
137 void add_flag(
bool & value,
139 std::string
const & long_id,
140 std::string
const & ,
143 flag_calls.push_back([=, &value]()
145 get_flag(value, short_id, long_id);
159 template <
typename option_type,
typename val
idator_type>
160 void add_positional_option(option_type & value,
161 std::string
const & ,
162 validator_type && validator)
164 positional_option_calls.push_back([=, &value]()
166 get_positional_option(value, validator);
171 void parse(argument_parser_meta_data
const & )
173 end_of_options_it = std::find(argv.begin(), argv.end(),
"--");
177 for (
auto && f : option_calls)
180 for (
auto && f : flag_calls)
183 check_for_unknown_ids();
185 if (end_of_options_it != argv.end())
186 *end_of_options_it =
"";
188 for (
auto && f : positional_option_calls)
191 check_for_left_over_args();
196 void add_section(std::string
const &) {}
197 void add_subsection(std::string
const &) {}
198 void add_line(std::string
const &,
bool) {}
199 void add_list_item(std::string
const &, std::string
const &) {}
212 void init(
int argc_,
char const *
const *
const argv_)
214 argv.resize(argc_ - 1);
216 for(
int i = 1; i < argc_; ++i)
217 argv.push_back(argv_[i]);
224 std::string prepend_dash(std::string
const & long_id)
226 return (
"--" + long_id);
233 std::string prepend_dash(
char const short_id)
235 return (
"-" + std::string(1, short_id));
250 template <
typename id_type>
251 std::vector<std::string>::iterator find_option_id(std::vector<std::string>::iterator
const begin_it, id_type
const &
id)
253 return(std::find_if(begin_it, end_of_options_it,
254 [&] (
const std::string & v)
256 size_t id_size{(prepend_dash(
id)).
size()};
257 if (v.size() < id_size)
260 return v.substr(0, id_size) == prepend_dash(
id);
267 bool flag_is_set(std::string
const & long_id)
269 auto it = std::find(argv.begin(), end_of_options_it, prepend_dash(long_id));
271 if (it != end_of_options_it)
274 return(it != end_of_options_it);
280 bool flag_is_set(
char const short_id)
283 for (std::string & arg : argv)
285 if (arg[0] ==
'-' && arg.size() > 1 && arg[1] !=
'-')
287 auto pos = arg.find(short_id);
289 if (pos != std::string::npos)
312 template <
typename option_t>
314 requires istream_concept<std::istringstream, option_t>
316 void retrieve_value(option_t & value, std::string
const & in)
318 std::istringstream stream{in};
321 if (stream.fail() || !stream.eof())
322 throw type_conversion_failed(
"Argument " + in +
" could not be casted to type " +
323 get_type_name_as_string(value) +
".");
327 void retrieve_value(std::string & value, std::string
const & in)
341 template <sequence_container_concept container_option_t>
343 requires istream_concept<std::istringstream, typename container_option_t::value_type>
345 void retrieve_value(container_option_t & value, std::string
const & in)
347 typename container_option_t::value_type tmp;
349 retrieve_value(tmp, in);
350 value.push_back(tmp);
372 template <std::Integral option_t>
374 requires istream_concept<std::istringstream, option_t>
376 void retrieve_value(option_t & value, std::string
const & in)
379 std::istringstream stream{in};
382 if (stream.fail() || !stream.eof())
383 throw type_conversion_failed(
"Argument " + in +
" could not be casted to type " +
384 get_type_name_as_string(value) +
".");
386 if (tmp > static_cast<int64_t>(std::numeric_limits<option_t>::max()) ||
387 tmp < static_cast<int64_t>(std::numeric_limits<option_t>::min()))
388 throw overflow_error_on_conversion(
"Argument " + in +
" is not in integer range [" +
389 std::to_string(std::numeric_limits<option_t>::min()) +
"," +
390 std::to_string(std::numeric_limits<option_t>::max()) +
"].");
392 value =
static_cast<option_t
>(tmp);
411 template <
typename option_type,
typename id_type>
412 bool identify_and_retrieve_option_value(option_type & value,
413 std::vector<std::string>::iterator & option_it,
416 if (option_it != end_of_options_it)
418 std::string input_value;
419 size_t id_size = (prepend_dash(
id)).
size();
421 if ((*option_it).size() > id_size)
423 if ((*option_it)[id_size] ==
'=')
425 if ((*option_it).size() == id_size + 1)
426 throw parser_invalid_argument(
"Value cast failed for option " +
428 ": No value was provided.");
429 input_value = (*option_it).substr(id_size + 1);
433 input_value = (*option_it).substr(id_size);
442 if (option_it == end_of_options_it)
443 throw parser_invalid_argument(
"Value cast failed for option " +
445 ": No value was provided.");
446 input_value = *option_it;
452 retrieve_value(value, input_value);
454 catch (parser_invalid_argument
const & ex)
456 throw parser_invalid_argument(
"Value cast failed for option " + prepend_dash(
id) +
": " + ex.what());
481 template <
typename option_type,
typename id_type>
482 bool get_option_by_id(option_type & value, id_type
const &
id)
484 auto it = find_option_id(argv.begin(), id);
486 if (it != end_of_options_it)
487 identify_and_retrieve_option_value(value, it,
id);
489 if (find_option_id(it,
id) != end_of_options_it)
490 throw option_declared_multiple_times(
"Option " + prepend_dash(
id) +
491 "is no list/container but declared multiple times.");
493 return (it != end_of_options_it);
507 template <sequence_container_concept option_type,
typename id_type>
509 requires !std::is_same_v<option_type, std::string>
511 bool get_option_by_id(option_type & value, id_type
const &
id)
513 auto it = find_option_id(argv.begin(), id);
514 bool seen_at_least_once{it != end_of_options_it};
516 while (it != end_of_options_it)
518 identify_and_retrieve_option_value(value, it,
id);
519 it = find_option_id(it,
id);
522 return seen_at_least_once;
538 void check_for_unknown_ids()
540 for (
auto it = argv.begin(); it != end_of_options_it; ++it)
542 std::string arg{*it};
543 if (!arg.empty() && arg[0] ==
'-')
549 else if (arg[1] !=
'-' && arg.size() > 2)
551 throw unknown_option(
"Unknown flags " + expand_multiple_flags(arg) +
552 ". In case this is meant to be a non-option/argument/parameter, " +
553 "please specify the start of arguments with '--'. " +
554 "See -h/--help for program information.");
558 throw unknown_option(
"Unknown option " + arg +
559 ". In case this is meant to be a non-option/argument/parameter, " +
560 "please specify the start of non-options with '--'. " +
561 "See -h/--help for program information.");
578 void check_for_left_over_args()
580 if (std::find_if(argv.begin(), argv.end(), [](std::string
const & s){
return (s !=
"");}) != argv.end())
581 throw too_many_arguments(
"Too many arguments provided. Please see -h/--help for more information.");
604 template <
typename option_type,
typename val
idator_type>
605 void get_option(option_type & value,
607 std::string
const & long_id,
609 validator_type && validator)
611 bool short_id_is_set{get_option_by_id(value, short_id)};
612 bool long_id_is_set{get_option_by_id(value, long_id)};
615 if (short_id_is_set && long_id_is_set &&
616 !(sequence_container_concept<option_type> && !std::is_same_v<option_type, std::string>))
617 throw option_declared_multiple_times(
"Option " + prepend_dash(short_id) +
"/" + prepend_dash(long_id) +
618 " is no list/container but specified multiple times");
620 if (short_id_is_set || long_id_is_set)
626 catch (std::exception & ex)
628 throw validation_failed(std::string(
"Validation failed for option ") + prepend_dash(short_id) +
"/" +
629 prepend_dash(long_id) +
": " + ex.what());
636 throw required_option_missing(
"Option " + prepend_dash(short_id) +
"/" + prepend_dash(long_id) +
637 " is required but not set.");
648 void get_flag(
bool & value,
650 std::string
const & long_id)
652 value = flag_is_set(short_id) || flag_is_set(long_id);
680 template <
typename option_type,
typename val
idator_type>
681 void get_positional_option(option_type & value,
682 validator_type && validator)
684 ++positional_option_count;
685 auto it = std::find_if(argv.begin(), argv.end(), [](std::string
const & s){
return (s !=
"");});
687 if (it == argv.end())
688 throw too_few_arguments(
"Not enough positional arguments provided (Need at least " +
689 std::to_string(positional_option_calls.size()) +
"). See -h/--help for more information.");
691 if (sequence_container_concept<option_type> && !std::is_same_v<option_type, std::string>)
693 if (positional_option_count != (positional_option_calls.size()))
694 throw parser_design_error(
"Lists are only allowed as the last positional option!");
696 while (it != argv.end())
700 retrieve_value(value, *it);
702 catch (parser_invalid_argument
const & ex)
704 throw parser_invalid_argument(
"Value cast failed for positional option " +
705 std::to_string(positional_option_count) +
": " + ex.what());
709 it = std::find_if(it, argv.end(), [](std::string
const & s){
return (s !=
"");});
710 ++positional_option_count;
717 retrieve_value(value, *it);
719 catch (parser_invalid_argument
const & ex)
721 throw parser_invalid_argument(
"Value cast failed for positional option " +
722 std::to_string(positional_option_count) +
": " + ex.what());
732 catch (std::exception & ex)
734 throw validation_failed(
"Validation failed for positional option " +
735 std::to_string(positional_option_count) +
": " + ex.what());
740 std::vector<std::function<void()>> option_calls;
742 std::vector<std::function<void()>> flag_calls;
744 std::vector<std::function<void()>> positional_option_calls;
746 unsigned positional_option_count{0};
748 std::vector<std::string> argv;
752 std::vector<std::string>::iterator end_of_options_it;
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:195
Definition: aligned_sequence_concept.hpp:288
option_spec
Used to further specify argument_parser options/flags.
Definition: auxiliary.hpp:60
Definition: auxiliary.hpp:63