54 explicit C_EZArgs(
const std::string &description = {}): m_desc(description) {}
60 std::string_view description,
61 std::invocable<>
auto &&trigger,
62 std::invocable<std::string_view>
auto &&
parse){
63 auto &def = create_flag_def(name, short_name, description);
64 def.m_trigger = std::move(trigger);
65 def.m_parse = std::move(
parse);
69 std::string_view description,
70 std::invocable<>
auto &&trigger){
71 create_flag_def(name, short_name, description).m_trigger = std::move(trigger);
75 std::string_view description,
76 std::invocable<std::string_view>
auto &&
parse){
77 create_flag_def(name, short_name, description).m_parse = std::move(
parse);
81 std::string_view description,
82 std::invocable<>
auto trigger,
83 std::invocable<std::string_view>
auto &&
parse) {
84 auto &def = create_flag_def(name,
char(), description);
85 def.m_trigger = std::move(trigger);
86 def.m_parse = std::move(
parse);
90 std::string_view description,
91 std::invocable<>
auto &&trigger) {
92 create_flag_def(name,
char(), description).m_trigger = std::move(trigger);
96 std::string_view description,
97 std::invocable<std::string_view>
auto &&
parse){
98 create_flag_def(name,
char(), description).m_parse = std::move(
parse);
102 std::string_view description,
103 std::invocable<>
auto &&trigger,
104 std::invocable<std::string_view>
auto &&
parse) {
105 auto &def = create_flag_def({}, short_name, description);
106 def.m_trigger = std::move(trigger);
107 def.m_parse = std::move(
parse);
111 std::string_view description,
112 std::invocable<>
auto &&trigger) {
113 create_flag_def({}, short_name, description).m_trigger = std::move(trigger);
117 std::string_view description,
118 std::invocable<std::string_view>
auto &&
parse) {
119 create_flag_def({}, short_name, description).m_parse = std::move(
parse);
123 C_EZArgs &
add_subcommand(
const std::string &name, std::invocable<>
auto onParsed,
const std::string &description = {});
124 void details(std::string_view s) { m_details = s; }
127 const std::ranges::forward_range
auto &count_optionals,
bool unlimited =
false);
129 {
return position_args(arg_names, std::ranges::views::empty<size_t>, unlimited); }
132 [[nodiscard]]
C_ErrorOrIndex parse(std::integral
auto argc,
const char *
const argv[])
const;
140 std::string m_name, m_descOneLiner;
142 std::function<void()> m_trigger;
143 std::function<void(std::string_view)> m_parse;
148 std::vector<std::string> m_posArgs;
149 std::vector<size_t> m_posCounts;
152 using C_ArgLayoutMap = std::list<std::pair<std::string,C_EZArgs>>;
154 using C_UP2U = std::variant<std::monostate,C_ArgLayout,C_ArgLayoutMap>;
163 const std::string m_desc;
164 std::string m_details;
165 std::deque<C_FlagDef> m_flags;
168 std::function<void()> m_onParsed;
169 size_t mutable m_totoalPositionArgs{};
170 bool m_helpShielded{
false};
171 bool m_hShielded{
false};
174 static_assert(std::variant_size_v<C_UP2U> == 3);
175 static_assert(std::is_same_v<std::monostate, std::variant_alternative_t<UP2U_NULL, C_UP2U>>);
176 static_assert(std::is_same_v<C_ArgLayout, std::variant_alternative_t<UP2U_LAYOUT, C_UP2U>>);
177 static_assert(std::is_same_v<C_ArgLayoutMap, std::variant_alternative_t<UP2U_SUBCMD, C_UP2U>>);
180 C_FlagDef &create_flag_def(std::string_view name,
char short_name, std::string_view description);
181 const C_FlagDef *find_shortname_def(
char sname)
const;
182 const C_FlagDef* find_longname_def(std::string_view name)
const;
183 bool is_valid_flag(
const char *
const *argv_rest,
int argc_rest)
const;
184 std::string help_flags()
const;
185 C_ErrorOrIndex help_full(
const char *
const argv[])
const;
186 std::string help_tip(
const std::string &error,
const char *
const argv[])
const;
187 std::string retro_path(
const char *
const argv[])
const;
201 switch (m_up2u.index())
204 m_up2u.emplace<UP2U_SUBCMD>();
211 auto &ret = std::get<UP2U_SUBCMD>(m_up2u).emplace_back(name, description).second;
213 ret.m_helpShielded = m_helpShielded;
214 ret.m_hShielded = m_hShielded;
216 ret.m_onParsed = onParsed;
221 const std::ranges::forward_range
auto &arg_names,
222 const std::ranges::forward_range
auto &count_optionals,
235 if (!std::empty(arg_names) || unlimited)
238 switch (m_up2u.index())
241 m_up2u.emplace<C_ArgLayout>();
248 auto &dst = std::get<1>(m_up2u);
249 dst.m_posArgs.assign(std::begin(arg_names), std::end(arg_names));
250 dst.m_unlimited = unlimited;
253 dst.m_posCounts.assign(std::begin(count_optionals), std::end(count_optionals));
254 sort(dst.m_posCounts.begin(), dst.m_posCounts.end());
255 const auto n_args = dst.m_posArgs.size();
256 while (!dst.m_posCounts.empty() && dst.m_posCounts.back() >= n_args)
257 dst.m_posCounts.pop_back();
259 dst.m_posCounts.emplace_back(n_args);
272 decltype(argc) ind = 1;
273 switch (m_up2u.index())
278 for (; ind < argc && argv[ind][0] !=
'-'; ++ind);
279 m_totoalPositionArgs = ind;
280 if (ind < argc && (argv[ind][1] ==
'h' || !strcmp(argv[ind],
"--help")))
281 return help_full(argv);
284 auto &lo = std::get<1>(m_up2u);
285 decltype(argc) lower_bound = 0;
286 for (
auto i: lo.m_posCounts)
288 if (lower_bound < ind && ind <=
static_cast<decltype(argc)
>(i))
293 const bool plural = i > 1;
294 message =
"Positional argument";
297 for (
size_t j = 0; j < i; ++j)
298 message.append(
" <").append(lo.m_posArgs[j]) +=
'>';
300 message += plural?
" are required":
" is required";
303 message = std::to_string(ind-1).append(ind > 2?
" positonal arguments are":
" positonal argument is").append(
" not allowed");
305 return {help_tip(message,argv), ind};
307 lower_bound =
static_cast<decltype(argc)
>(i + 1);
309 if (!lo.m_unlimited && ind >
static_cast<decltype(argc)
>(lo.m_posArgs.size() + 1))
311 std::string message =
"Too many positional arguments:";
312 for (
auto &i: lo.m_posArgs)
313 message.append(
" <").append(i) +=
'>';
314 return {help_tip(message,argv), ind};
319 if (ind >= argc || !strcmp(argv[ind],
"-h") || !strcmp(argv[ind],
"--help"))
320 return help_full(argv);
323 for (
auto &i: std::get<2>(m_up2u))
324 if (i.first == argv[ind])
326 auto ret = i.second.parse(argc-ind, argv+ind);
329 m_totoalPositionArgs = i.second.m_totoalPositionArgs + ind;
330 return ret.m_optIndex.value() + ind;
335 return {help_tip(std::string(
"Unknown subcommand: ")+argv[ind], argv), ind};
338 const auto flagStartInd = ind;
341 for (; ind < argc; ++ind)
343 auto arg = argv[ind];
346 return {help_tip(std::string(
"Unexpected argument: ")+arg, argv), ind};
351 const auto flag = arg + 2;
352 const auto eqsign = strchr(flag,
'=');
353 const auto flag_name = eqsign? std::string_view(flag,
size_t(eqsign-flag)): std::string_view(flag);
354 if (
auto def = find_longname_def(flag_name))
361 def->m_parse(eqsign+1);
364 return {help_tip(std::string(
"Value parser absent: ")+arg, argv), ind};
366 else if (ind+1 < argc && !is_valid_flag(&argv[ind+1],
int(argc-(ind+1))))
371 def->m_parse(argv[++ind]);
374 return {help_tip(std::string(
"Value parser absent: ")+arg, argv), ind};
384 return {help_tip(std::string(def->m_parse?
"Missing flag value: ":
"Triggerless flag: ")+arg, argv), ind};
387 if (
"help" == flag_name)
388 return help_full(argv);
390 return {help_tip(std::string(
"Unknown flag: --")+=flag_name, argv), ind};
394 while (
char sname = *++arg)
396 if (
auto def = find_shortname_def(sname))
398 if (!arg[1] && ind+1 < argc && !is_valid_flag(&argv[ind+1],
int(argc-(ind+1))))
403 def->m_parse(argv[++ind]);
406 return {help_tip(std::string(
"Value parser absent: -")+sname, argv), ind};
416 return {help_tip(std::string(def->m_parse?
"Missing flag value: -":
"Triggerless flag: -")+sname, argv), ind};
420 return help_full(argv);
422 return {help_tip(std::string(
"Unknown flag: -")+=sname, argv), ind};
#define RUNTIME_ERROR(fmtStr,...)
Wrap FILE(DATE)#__LINE__ FUNCTION: msg into std::runtime_error.
C_EZArgs & add_subcommand(const std::string &name, std::invocable<> auto onParsed, const std::string &description={})
C_EZArgs & add_flag(char short_name, std::string_view description, std::invocable<> auto &&trigger)
C_EZArgs & add_flag(std::string_view name, char short_name, std::string_view description, std::invocable<> auto &&trigger)
C_EZArgs & add_flag(char short_name, std::string_view description, std::invocable<> auto &&trigger, std::invocable< std::string_view > auto &&parse)
auto parsed_position_argc() const
C_EZArgs(const C_EZArgs &)=delete
C_EZArgs & add_flag(std::string_view name, std::string_view description, std::invocable<> auto trigger, std::invocable< std::string_view > auto &&parse)
C_EZArgs & add_flag(std::string_view name, char short_name, std::string_view description, std::invocable< std::string_view > auto &&parse)
C_ErrorOrIndex parse(std::integral auto argc, const char *const argv[]) const
C_EZArgs & add_flag(char short_name, std::string_view description, std::invocable< std::string_view > auto &&parse)
C_EZArgs & add_flag(std::string_view name, std::string_view description, std::invocable< std::string_view > auto &&parse)
C_EZArgs & operator=(const C_EZArgs &)=delete
C_EZArgs & add_flag(std::string_view name, std::string_view description, std::invocable<> auto &&trigger)
C_EZArgs(const std::string &description={})
C_EZArgs & add_flag(std::string_view name, char short_name, std::string_view description, std::invocable<> auto &&trigger, std::invocable< std::string_view > auto &&parse)
C_EZArgs & position_args(const std::ranges::forward_range auto &arg_names, const std::ranges::forward_range auto &count_optionals, bool unlimited=false)
C_EZArgs & position_args(const std::ranges::forward_range auto &arg_names, bool unlimited=false)
void details(std::string_view s)
THE common namespace of bux library.
C_ErrorOrIndex(const std::string &error, auto flagErrInd)
std::string message() const
C_ErrorOrIndex(const std::string &help)
std::optional< size_t > m_optIndex
C_ErrorOrIndex(auto flagStartInd)