From 378dd663a402fe196f2b56c6413eb3f623aecbbf Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Tue, 1 Jul 2025 19:18:42 +0100 Subject: cli: refactoring --- nihil.cli/dispatch_command.cc | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'nihil.cli/dispatch_command.cc') diff --git a/nihil.cli/dispatch_command.cc b/nihil.cli/dispatch_command.cc index 7b4cf39..6cf7f05 100644 --- a/nihil.cli/dispatch_command.cc +++ b/nihil.cli/dispatch_command.cc @@ -2,6 +2,7 @@ module; #include // getprogname, NOLINT +#include // EX_USAGE #include // getopt module nihil.cli; @@ -11,6 +12,15 @@ import nihil.core; namespace nihil { +namespace { +// Print this node's children in a form useful to humans. +auto print_commands(command_tree_node const &node) -> void +{ + for (auto &&child : node.children()) + std::print(std::cerr, " {}\n", child.command().path()); +} +} + auto dispatch_command(int argc, char **argv) -> int { auto tree = build_command_tree(); @@ -20,52 +30,44 @@ auto dispatch_command(int argc, char **argv) -> int // 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. + // find() never returns nullptr; at worst it will return the root node. auto const *node = tree.find(argc, argv); - - // Get the command_node. auto const &command = node->command(); // Reset getopt(3) for the command, in case main() used it already. optreset = 1; optind = 1; - /* - * Set the program name to the existing progname plus the full path - * to the command being invoked; this makes error messages nicer. - */ + // 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()); + command.path()); ::setprogname(cprogname.c_str()); } - // Invoke the command see what it returns. - auto ret = command->invoke(argc, argv); + // 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); // Restore the old progname. ::setprogname(old_progname); - // If the command produced an exit code, return it. if (ret) return *ret; - /* - * We have special handling for some errors. - */ - // Incomplete command: print the list of valid commands at this node. if (ret.error() == errc::incomplete_command) { - std::print(std::cerr, "{}: usage:\n", ::getprogname()); - node->print_commands(); - return 1; + std::println(std::cerr, "{}: usage:", ::getprogname()); + print_commands(*node); + return EX_USAGE; } // We didn't recognise the error, so just print it and exit. - std::print(std::cerr, "{}\n", ret.error()); + std::println(std::cerr, "{}", ret.error()); return 1; } -- cgit v1.2.3