aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.cli/dispatch_command.cc
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.cli/dispatch_command.cc')
-rw-r--r--nihil.cli/dispatch_command.cc42
1 files changed, 22 insertions, 20 deletions
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 <stdlib.h> // getprogname, NOLINT
+#include <sysexits.h> // EX_USAGE
#include <unistd.h> // 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;
}