1 #ifndef OOKII_COMMAND_LINE_CORE_H_
7 #define OOKII_COMMAND_LINE_CORE_H_
27 using default_char_type = wchar_t;
29 using default_char_type = char;
32 template<
typename CharType,
typename Traits,
typename Alloc>
35 using string_type = std::basic_string<CharType, Traits, Alloc>;
37 parser_storage(string_type command_name)
38 : command_name(command_name)
42 string_type command_name;
43 string_type description;
44 std::vector<string_type> prefixes;
46 CharType argument_value_separator{
':'};
47 bool allow_white_space_separator{
true};
48 bool allow_duplicate_arguments{
false};
90 template<
typename CharType = details::default_
char_type,
typename Traits = std::
char_traits<CharType>,
typename Alloc = std::allocator<CharType>>
128 std::vector<string_type> result;
136 constexpr
auto prefix1 = literal_cast<CharType>(
"-");
137 result.push_back(prefix1.data());
140 constexpr
auto prefix2 = literal_cast<CharType>(
"/");
141 result.push_back(prefix2.data());
157 template<
typename Range>
159 : _storage{std::move(storage)},
164 auto actual_arg = argument->to_argument();
165 auto name = actual_arg->name();
166 const auto [it, success] = _arguments.insert(std::pair{name, std::move(actual_arg)});
168 throw std::logic_error(
"Duplicate argument name.");
170 if (it->second->position())
176 const auto pos = std::lower_bound(_positional_arguments.begin(),
177 _positional_arguments.end(),
179 [](
const auto &left,
const auto &right)
181 return *left->position() < *right->position();
184 _positional_arguments.insert(pos, it->second.get());
187 for (
const auto &alias : it->second->aliases())
190 const auto [alias_it, alias_success] = _arguments.insert(std::pair{alias, it->second.as_borrowed()});
192 throw std::logic_error(
"Duplicate argument name.");
202 return _storage.command_name;
210 return _storage.command_name;
218 return _storage.allow_white_space_separator;
226 return _storage.allow_duplicate_arguments;
234 return _storage.argument_value_separator;
242 const std::vector<string_type> &
prefixes() const noexcept
244 return _storage.prefixes;
250 const std::locale &
locale() const noexcept
252 return _storage.locale;
262 return _arguments | std::views::filter([](
const auto &a)
265 return a.second.is_owned();
267 | std::views::transform([](
const auto &a) ->
auto&
278 return _positional_arguments.size();
292 return *_positional_arguments.at(pos);
304 return *_arguments.at(name);
317 template<
typename Iterator>
320 for (
auto &arg : _arguments)
324 for (
auto current = begin; current != end; ++current)
327 auto prefix_length = check_prefix(arg);
328 if (prefix_length > 0)
331 auto result = parse_named_argument(arg, current, end, prefix_length);
339 while (position < _positional_arguments.size() &&
340 !_positional_arguments[position]->is_multi_value() &&
341 _positional_arguments[position]->has_value())
346 if (position >= _positional_arguments.size())
349 auto result = set_argument_value(*_positional_arguments[position], arg);
358 if (arg.is_required())
360 if (!arg.has_value())
362 result = {parse_error::missing_required_argument, arg.name()};
368 arg.apply_default_value();
390 template<
typename Iterator>
393 auto result = parse(begin, end);
394 handle_error(result, options);
407 template<
typename Range>
413 return parse(begin(range), end(range));
428 template<
typename Range>
431 auto result = parse(range);
432 handle_error(result, options);
448 return parse(args.begin(), args.end());
466 auto result = parse(args);
467 handle_error(result, options);
483 return parse<const CharType *>({});
485 return parse(argv + 1, argv + argc);
502 auto result = parse(argc, argv);
503 handle_error(result, options);
515 if (!_storage.description.empty())
517 options.output << _storage.description << std::endl << std::endl;
520 write_usage_syntax(options);
521 write_usage_descriptions(options);
535 template<
typename Func>
539 for (
auto &arg : _positional_arguments)
541 auto result = f(*arg);
547 for (
auto &arg : _arguments)
549 if (arg.second.is_owned() && !arg.second->position() && arg.second->is_required())
551 auto result = f(*arg.second);
558 for (
auto &arg : _arguments)
560 if (arg.second.is_owned() && !arg.second->position() && !arg.second->is_required())
562 auto result = f(*arg.second);
587 _on_parsed_callback = callback;
591 void handle_error(
const result_type &result,
const usage_options_type &options)
599 options.error << result.get_error_message(options.error.rdbuf()->getloc()) << std::endl << std::endl;
602 write_usage(options);
606 size_t check_prefix(string_view_type argument)
609 if (argument.length() >= 2 && argument[0] ==
'-' && std::isdigit(argument[1], _storage.locale))
612 for (
auto &prefix : _storage.prefixes)
614 if (argument.starts_with(prefix))
615 return prefix.length();
621 template<
typename Iterator>
622 result_type parse_named_argument(string_view_type arg, Iterator ¤t, Iterator end,
size_t prefix_length)
624 string_view_type name;
625 string_view_type value;
626 bool has_value =
false;
628 auto separator_index = arg.find(_storage.argument_value_separator);
629 if (separator_index == string_view_type::npos)
631 name = arg.substr(prefix_length);
635 name = arg.substr(prefix_length, separator_index - prefix_length);
636 value = arg.substr(separator_index + 1);
640 auto it = this->_arguments.find(name);
641 if (it == this->_arguments.end())
646 if (it->second->set_switch_value())
648 return post_process_argument(*it->second, {});
651 auto value_it = current;
652 if (_storage.allow_white_space_separator && ++value_it != end)
657 has_value = check_prefix(value) == 0;
663 if (!_storage.allow_duplicate_arguments && !it->second->is_multi_value() && it->second->has_value())
666 return set_argument_value(*it->second, value);
674 result_type set_argument_value(argument_base_type &arg, string_view_type value)
676 if (!arg.set_value(value, _storage.locale))
679 return post_process_argument(arg, value);
682 result_type post_process_argument(argument_base_type &arg, string_view_type value)
685 if (_on_parsed_callback)
686 action = _on_parsed_callback(arg, value);
697 void write_usage_syntax(
const usage_options_type &options = {})
699 auto &stream = options.output;
701 stream <<
format::ncformat(_storage.locale, options.usage_prefix_format, _storage.command_name);
702 for_each_argument_in_usage_order([
this, &options, &stream](
const auto &arg)
704 auto syntax = _storage.prefixes[0] + arg.name();
706 syntax =
format::ncformat(_storage.locale, options.optional_argument_format, syntax);
708 if (!arg.is_switch())
710 CharType separator = (_storage.allow_white_space_separator && options.use_white_space_value_separator) ?
' ' : _storage.argument_value_separator;
711 auto value = format::ncformat(_storage.locale, options.value_description_format, arg.value_description());
712 syntax += separator + value;
715 if (arg.is_multi_value())
716 syntax += options.multi_value_suffix;
718 if (!arg.is_required())
719 syntax =
format::ncformat(_storage.locale, options.optional_argument_format, syntax);
721 stream <<
' ' << syntax;
725 stream << std::endl << std::endl;
728 void write_usage_descriptions(
const usage_options_type &options = {})
730 auto &stream = options.output;
732 for_each_argument_in_usage_order([
this, &options, &stream](
const auto &arg)
734 if (arg.description().empty())
737 auto value_description =
format::ncformat(_storage.locale, options.value_description_format, arg.value_description());
739 value_description =
format::ncformat(_storage.locale, options.optional_argument_format, value_description);
741 auto default_value = arg.format_default_value(options, _storage.locale);
744 if (options.include_aliases_in_description && !arg.aliases().empty())
747 for (const auto &alias : arg.aliases())
752 aliases += options.alias_separator;
754 aliases += _storage.prefixes[0] + alias;
761 _storage.prefixes[0], arg.name(), value_description, aliases, arg.description(), default_value)
768 storage_type _storage;
772 std::map<string_type, owned_or_borrowed_ptr<argument_base_type>, string_less> _arguments;
773 std::vector<argument_base_type *> _positional_arguments;
774 on_parsed_callback _on_parsed_callback;
Parses command line arguments into strongly-typed values.
Definition: command_line_core.h:92
result_type parse(int argc, const CharType *const argv[])
Parses the provided arguments.
Definition: command_line_core.h:480
std::function< on_parsed_action(argument_base_type &, string_view_type value)> on_parsed_callback
The callback function type for on_parsed().
Definition: command_line_core.h:107
CharType argument_value_separator() const noexcept
Definition: command_line_core.h:232
result_type parse(std::initializer_list< T > args)
Parses the arguments in the specified initializer list.
Definition: command_line_core.h:446
void write_usage(const usage_options_type &options={})
Writes usage help for this parser's arguments.
Definition: command_line_core.h:513
const argument_base_type & get_argument(size_t pos) const
Gets an argument by position.
Definition: command_line_core.h:290
void on_parsed(on_parsed_callback callback)
Sets a callback that will be invoked every time an argument is parsed.
Definition: command_line_core.h:585
typename argument_type< T >::typed_storage_type::converter_type converter_type
The specialized type of the custom command line converter function used.
Definition: command_line_core.h:119
result_type parse(std::initializer_list< T > args, const usage_options_type &options)
Parses the arguments in the specified initializer list, and writes error and usage information to the...
Definition: command_line_core.h:464
const string_type & command_name() const noexcept
Returns the command name used when generating usage help.
Definition: command_line_core.h:200
basic_command_line_parser(const Range &arguments, storage_type &&storage, bool case_sensitive)
Creates a new instance of the basic_command_line_parser class.
Definition: command_line_core.h:158
static constexpr std::vector< string_type > get_default_prefixes()
Gets the default prefixes accepted by the parser.
Definition: command_line_core.h:126
const string_type & description() const noexcept
Returns the description used when generating usage help.
Definition: command_line_core.h:208
size_t positional_argument_count() const
Gets the number of positional arguments.
Definition: command_line_core.h:276
const std::vector< string_type > & prefixes() const noexcept
Gets a list of all the argument name prefixes accepted by the parser.
Definition: command_line_core.h:242
const std::locale & locale() const noexcept
Gets the locale used to parse argument values and to format strings.
Definition: command_line_core.h:250
bool allow_duplicate_arguments() const noexcept
Indicates whether duplicate arguments are allowed.
Definition: command_line_core.h:224
result_type parse(Iterator begin, Iterator end, const usage_options_type &options)
Parses the arguments in the range specified by the iterators, and writes error and usage information ...
Definition: command_line_core.h:391
details::parser_storage< CharType, Traits, Alloc > storage_type
The specialized type of parser parameter storage used. For internal use.
Definition: command_line_core.h:105
result_type parse(const Range &range)
Parses the arguments in the specified range.
Definition: command_line_core.h:408
result_type parse(int argc, const CharType *const argv[], const usage_options_type &options)
Parses the provided arguments, and writes error and usage information to the console if a parsing err...
Definition: command_line_core.h:500
bool allow_white_space_separator() const noexcept
Indicates whether argument names and values can be separated by white space.
Definition: command_line_core.h:216
std::basic_string_view< CharType, Traits > string_view_type
The specialized type of std::basic_string_view used.
Definition: command_line_core.h:99
bool for_each_argument_in_usage_order(Func f) const
Invokes the specified function on each argument in the order they are shown in in the usage help.
Definition: command_line_core.h:536
auto arguments() const
Gets a view of all the arguments defined by the parser.
Definition: command_line_core.h:260
const argument_base_type & get_argument(const string_type &name) const
Gets an argument by name.
Definition: command_line_core.h:302
result_type parse(Range range, const usage_options_type &options)
Parses the arguments in the specified range, and writes error and usage information to the console if...
Definition: command_line_core.h:429
typename argument_base_type::string_type string_type
The specialized type of std::basic_string used.
Definition: command_line_core.h:97
result_type parse(Iterator begin, Iterator end)
Parses the arguments in the range specified by the iterators.
Definition: command_line_core.h:318
Provides options for how to format usage help.
Definition: usage_options.h:29
Abstract base class for regular and multi-value arguments.
Definition: command_line_argument.h:75
typename storage_type::string_type string_type
The concrete type of std::basic_string used.
Definition: command_line_argument.h:80
Class that provides information about arguments that are not multi-value arguments.
Definition: command_line_argument.h:313
Provides the ookii::command_line_argument class.
Namespace containing the core Ookii.CommandLine.Cpp types.
Definition: command_line_argument.h:16
std::basic_ostream< CharType, Traits > & reset_indent(std::basic_ostream< CharType, Traits > &stream)
IO manipulator that lets the next line start at the beginning of the line, without indenting it.
Definition: line_wrapping_stream.h:515
details::set_indent_helper set_indent(size_t indent)
IO manipulator that changes the number of spaces that each line is indented with for a line wrapping ...
Definition: line_wrapping_stream.h:493
on_parsed_action
Value to be returned from the callback passed to the basic_command_line_parser::on_parsed() method.
Definition: command_line_core.h:55
@ always_continue
Continue parsing even if command_line_argument::cancel_parsing() returns true.
@ none
Don't take any special action.
@ cancel_parsing
Cancel parsing immediately, disregarding the rest of the command line. Parsing will return with parse...
@ invalid_value
A supplied value could not be converted to the argument's type.
@ parsing_cancelled
Parsing was cancelled by an argument using basic_parser_builder::argument_builder::cancel_parsing(),...
@ unknown_argument
An argument name was supplied that doesn't exist.
@ duplicate_argument
An argument, other than a multi-value argument, was supplied more than once, and basic_parser_builder...
@ missing_value
A named argument, other than a switch argument, was supplied without a value.
@ too_many_arguments
More positional arguments were supplied than were defined.
Provides a smart pointer that can optionally own the contained pointer.
Provides error handling for the ookii::basic_command_line_parser class.
Provides the result, success or error, of a command line argument parsing operation.
Definition: parse_result.h:74
A version of the std::less predicate for strings that supports case insensitive comparison.
Definition: string_helper.h:23