From 85baf16dd366fb501dc522a0957ec680dc9478f0 Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Tue, 1 Jul 2025 21:12:11 +0100 Subject: cli: clean up --- nihil.cli/dispatch_command.cc | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'nihil.cli/dispatch_command.cc') diff --git a/nihil.cli/dispatch_command.cc b/nihil.cli/dispatch_command.cc index 6cf7f05..6e3a757 100644 --- a/nihil.cli/dispatch_command.cc +++ b/nihil.cli/dispatch_command.cc @@ -1,9 +1,9 @@ // This source code is released into the public domain. module; -#include // getprogname, NOLINT +#include // getprogname, NOLINT #include // EX_USAGE -#include // getopt +#include // getopt module nihil.cli; @@ -19,39 +19,36 @@ auto print_commands(command_tree_node const &node) -> void for (auto &&child : node.children()) std::print(std::cerr, " {}\n", child.command().path()); } -} +} // namespace auto dispatch_command(int argc, char **argv) -> int { - auto tree = build_command_tree(); - - // The caller should have stripped argv[0] already. find() will - // strip all the remaining elements except the last, which means - // argv[0] will be set to something reasonable for the next call - // to getopt(). - - // find() never returns nullptr; at worst it will return the root node. - auto const *node = tree.find(argc, argv); - auto const &command = node->command(); - // Reset getopt(3) for the command, in case main() used it already. optreset = 1; optind = 1; + // Node that tree.find() never fails, at worst it will return the root node. + auto tree = build_command_tree(); + auto [node, rest] = tree.find(std::span(argv, argc)); + auto const &command = node->command(); + // Set the program name to the existing progname plus the full path to the command being // invoked; this makes error messages nicer. Save the old progname so we can restore it // after invoking the command. auto const *old_progname = ::getprogname(); { - auto cprogname = std::format("{} {}", ::getprogname(), - command.path()); + auto cprogname = std::format("{} {}", ::getprogname(), command.path()); ::setprogname(cprogname.c_str()); } // Invoke the command see what it returns. If it's an exit code, just return it. // Otherwise, handle the error. - auto ret = command.invoke(argc, argv); + auto nrest = static_cast(std::ranges::distance(rest)); + // Keep the first argument, because getopt() wants it + if (nrest < argc) + ++nrest; + auto ret = command.invoke(nrest, argv + (argc - nrest)); // Restore the old progname. ::setprogname(old_progname); -- cgit v1.2.3