HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
command_line.hpp
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "utility/module.hpp"
8#include "generator.hpp"
9#include <optional>
10#include <string>
11#include <variant>
12
13namespace hi::inline v1 {
14
16 char32_t option;
17 std::optional<std::string> argument;
18};
19
21 std::string option;
22 std::optional<std::string> argument;
23};
24
26 std::string executable;
27};
28
30 std::string argument;
31};
32
33using cmdline_option = std::variant<cmline_executable, cmdline_short_option, cmdline_long_option, cmdline_argument>;
34
63template<typename It>
64generator<cmdln_option> command_line_parser(It first, It last, std::string_view options_with_arguments)
65{
66 hilet options_with_arguments_ = hi::to_u32string(options_with_arguments);
67 auto it = first;
68
69 if (it != last) {
70 co_yield cmdln_option::executable{*it};
71 ++it;
72 }
73
74 char32_t short_option_name = 0;
75 for (; it != last; ++it) {
76 if (short_option_name) {
77 // Add the argument to the option.
78 co_yield cmdln_short_option{short_option_name, *it};
79 short_option_name = 0;
80
81 } else if (*it == "--") {
82 break;
83
84 } else if (it->starts_with("--")) {
85 // Long-option
86 hilet eq_index = it->find('=');
87 if (eq_index == std::string::npos) {
88 // Long-option without argument
89 co_yield cmdln_long_option{it->substr(2), {}};
90
91 } else {
92 // Long-option with argument in same token.
93 hi_assert(eq_index >= 2);
94 hilet name_length = eq_index - 2;
95 co_yield cmdln_long_option(it->substr(2, name_length), it->substr(eq_index + 1));
96 }
97
98 } else if (it.front() == '-' or it.front() == '+') {
99 // List of short-options.
100 // Short options are processed as UTF-32 units.
101 hilet token = to_u32string(*it);
102 hilet first_c = std::next(begin(token));
103 hilet last_c = end(token);
104 negative = it.front() == '+';
105
106 for (auto jt = first_c; jt != last_c; ++jt) {
107 hilet c = *jt;
108 auto name = hi::to_string(std::u32string(1, c));
109
110 if (not options_with_arguments_.contains(c)) {
111 // Option without argument
112 co_yield cmdln_short_option(c, {});
113
114 } else if (std::next(jt) == last) {
115 // Option with the argument in the next token.
116 short_option_name = c;
117
118 } else {
119 // Option with argument, where the argument is inside this token
120 auto argument = hi::to_string(std::u32string(std::next(jt), last_c));
121 co_yield cmdln_short_option(c, std::move(argument));
122 break;
123 }
124 }
125
126 } else {
127 // Anything not looking like an option is a non-option
128 co_yield cmdln_non_option{*it};
129 }
130 }
131
132 // All tokens after double hyphen '--' are non-options.
133 for (; it != last; ++it) {
134 co_yield cmdln_non_option{*it};
135 }
136
137 if (short_option_name) {
138 throw parse_error("Missing argument for option -{}", short_option_name);
139 }
140}
141
143public:
144 char32_t short_option;
145 std::string long_option;
146 std::string argument_name;
147 std::string description;
148 hi::notifier<void(std::string_view argument)> notifier;
149
169 constexpr command_line_option(std::string_view option_help)
170 {
171 auto it = begin(option_help);
172 hilet last = end(option_help);
173 }
174
175 static char32_t parse_short_option(std::string_view::iterator &it, std::string_view::iterator last)
176 {
177 if (it == last || *it != '-') {
178 throw parse_error("Expecting '-'");
179 }
180
181 ++it;
182
183 if (it == last) {
184 throw parse_error("Missing character after '-'");
185 }
186 if (*it == '-') {
187 return 0;
188 }
189 }
190};
191
195public:
196#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
197 void parse();
198#else
199 void parse(int argc, char **argv);
200#endif
201
202 template<typename... Args>
203 command_line_option &add_option(Args &&...args) noexcept
204 {
205 return _options.emplace(std::forward<Args>(args)...);
206 }
207
208private:
210};
211
212} // namespace hi::inline v1
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:199
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
constexpr std::string to_string(std::u32string_view rhs) noexcept
Conversion from UTF-32 to UTF-8.
Definition to_string.hpp:215
constexpr std::u32string to_u32string(std::u32string_view rhs) noexcept
Identity conversion from UTF-32 to UTF-32.
Definition to_string.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
generator< cmdln_option > command_line_parser(It first, It last, std::string_view options_with_arguments)
A POSIX command line parser.
Definition command_line.hpp:64
Definition command_line.hpp:15
Definition command_line.hpp:20
Definition command_line.hpp:25
Definition command_line.hpp:29
Definition command_line.hpp:142
constexpr command_line_option(std::string_view option_help)
Syntax:
Definition command_line.hpp:169
Command line parser.
Definition command_line.hpp:194
A return value for a generator-function.
Definition generator.hpp:29
A notifier which can be used to call a set of registered callbacks.
Definition notifier.hpp:25
T move(T... args)
T next(T... args)