1#ifndef KOUTIL_ARGS_COMMAND_IMPL_H
2#define KOUTIL_ARGS_COMMAND_IMPL_H
18#include <unordered_map>
25 if (m_cmd_map.contains(command.name())) {
29 command.m_path = m_path;
30 command.m_path +=
' ';
31 command.m_path += m_name;
33 const std::uint32_t
id = m_commands.size();
34 m_cmd_map.emplace(command.name(),
id);
36 m_commands.emplace_back(std::move(command));
42 const auto long_name = option.long_name();
43 const auto short_name = option.short_name();
45 if ((long_name.has_value() && m_long_options.contains(*long_name))
46 || (short_name.has_value() && m_short_options.contains(*short_name))) {
50 const std::size_t index = m_options.size();
52 if (long_name.has_value()) {
53 m_long_options[*long_name] = index;
56 if (short_name.has_value()) {
57 m_short_options[*short_name] = index;
60 m_options.push_back(option);
66 m_arguments.push_back(argument);
69template <extends_result Result>
71 process(std::span<const char* const>(args, argc), result);
75 std::uint32_t arguments = 0;
77 const std::uint32_t needed_arguments = m_arguments.size();
79 auto create_argument_error = [
this, needed_arguments](std::uint32_t provided) -> std::string {
87 bool only_arguments =
false;
88 for (std::uint32_t i = 0; i < args.size(); ++i) {
89 if (result.need_exit()) {
93 std::string_view arg { args[i] };
95 if (!only_arguments && arg ==
"--") {
96 only_arguments =
true;
100 if (!only_arguments) {
101 if (arg.starts_with(
'-')) {
102 i = process_option(arg, args, i, result);
106 auto cmd_it = m_cmd_map.find(arg);
107 if (cmd_it != m_cmd_map.end()) {
108 if (needed_arguments != arguments) {
109 result.add_error(create_argument_error(arguments));
112 check_options(result);
114 auto rest = args.subspan(i + 1);
116 auto& cmd = m_commands[cmd_it->second];
118 cmd.m_handle(rest, result);
121 cmd.process(rest, result);
126 if (arguments < needed_arguments) {
127 m_arguments[arguments].process(arg, result);
135 if (result.need_exit()) {
139 if (needed_arguments != arguments) {
140 result.add_error(create_argument_error(arguments));
143 check_options(result);
146template <extends_result Result>
148 std::string_view name, std::span<const char* const> args, std::uint32_t index,
result_t& result
150 using namespace std::string_view_literals;
152 std::string_view arg = name;
155 name.remove_prefix(1);
157 auto value_start = arg.find(
'=');
158 bool has_value = value_start != std::string_view::npos;
160 std::string_view whole_name = arg;
162 whole_name = whole_name.substr(0, value_start);
165 std::uint32_t option_id;
168 if (name.starts_with(
'-')) {
171 name = name.substr(0, value_start - 1);
175 std::string_view option_name = name.substr(1);
177 auto option_it = m_long_options.find(option_name);
178 if (option_it == m_long_options.end()) {
183 option_id = option_it->second;
187 name = name.substr(0, value_start);
190 if (name.size() != 1) {
195 auto option_it = m_short_options.find(name[0]);
196 if (option_it == m_short_options.end()) {
201 option_id = option_it->second;
204 auto& option = m_options[option_id];
206 if (!option.has_value()) {
212 option.process(std::nullopt, result);
216 std::string_view value;
219 value = arg.substr(value_start + 1);
220 }
else if (args.size() > index + 1) {
228 option.process(value, result);
233 for (
const auto& option : m_options) {
234 if (option.required() && !option.used()) {
247 for (
auto& option : m_options) {
251 for (
auto& cmd : m_commands) {
Represents a command in the command-line interface.
Definition help.h:15
void check_options(result_t &result)
Definition command_impl.h:232
void clear_used()
Clears state.
Definition command_impl.h:246
option_t< result_t > option_t
Definition command.h:33
Result result_t
Definition command.h:32
bool add_option(const option_t &option)
Adds an option to the command.
Definition command_impl.h:41
void add_argument(const argument_t &argument)
Adds a positional argument.
Definition command_impl.h:65
argument_t< result_t > argument_t
Definition command.h:34
bool add_command(command_t &&command)
Adds a subcommand.
Definition command_impl.h:24
void process(const char *const *args, std::uint32_t argc, result_t &result)
Processes command-line arguments.
Definition command_impl.h:70
void show_help(std::ostream &out, std::size_t terminal_size=80) const
Displays help text for this command.
Definition command_impl.h:240
std::uint32_t process_option(std::string_view name, std::span< const char *const > args, std::uint32_t index, result_t &result)
Definition command_impl.h:147
void print(std::ostream &out)
Definition help_impl.h:19
std::string make_invalid_short_option(std::string_view name)
Definition errors.h:36
std::string make_missing_required_option(const option_t< Result > &option)
Definition errors.h:48
std::string make_command_argument_count(std::string_view name, std::uint32_t expected, std::uint32_t provided)
Definition errors.h:24
std::string make_unknown_argument(std::string_view name)
Definition errors.h:28
std::string make_unexpected_option_value(std::string_view whole_name)
Definition errors.h:44
std::string make_unknown_short_option(char name)
Definition errors.h:34
std::string make_argument_count(std::string_view name, std::uint32_t expected, std::uint32_t provided)
Definition errors.h:13
std::string make_option_requires_value(std::string_view whole_name)
Definition errors.h:40
std::string make_unknown_long_option(std::string_view name)
Definition errors.h:30