AxlSubcommand — Multi-command CLI dispatch

Warning

Deprecated. Use AxlArgs — Argument Parsing (axl_args_run from <axl/axl-args.h>) instead — it handles flags, positionals, and arbitrarily nested subcommands in one declarative AxlArgsNode tree. The axl_subcommand_* functions are marked __attribute__((deprecated)) and remain only for existing consumers; new tools should not use them.

Helper for UEFI applications that expose multiple distinct operations under a common executable (e.g. tool bios, tool sysid, tool crb …). Pairs with AxlConfig — Configuration — each subcommand uses its own AxlConfig descriptor table for flag parsing.

See AxlSys — System Utilities for an overview of all utility modules.

Header: <axl/axl-subcommand.h>

Single-purpose tools (e.g. mkrd) skip this layer and use axl_config_* directly. Multi-command tool wrappers declare an AxlSubcommand table and call axl_subcommand_dispatch from main.

API Reference

Typedefs

typedef int (*AxlSubcommandFn)(int argc, char **argv)

axl-subcommand.h:

Deprecated:

Use axl_args_run from <axl/axl-args.h> instead. AxlArgs’s multi-verb mode (AxlArgsApp.verbs[]) strictly subsumes this dispatcher and adds typed positional args, bounds checking, and auto-generated --help. AxlSubcommand is retained as a thin wrapper for source compatibility while out-of-tree consumers migrate. New tools should not use this header.

Subcommand-style CLI dispatch for multi-command UEFI apps. Pairs with axl-config — mkrd was the canonical “single-purpose tool” shape; the multi-command shape has been migrated to AxlArgs in tree.

Migrating to AxlArgs in one diff:

// before:
static int tool_bios(int argc, char **argv) { ... }
static const AxlSubcommand commands[] = {
    { "bios", tool_bios, "[test|pci|irq|slot|emb]",
      "tool bios test  — ..." },
};
int main(int argc, char **argv) {
    return axl_subcommand_dispatch(commands, ARRAY_LEN(commands),
        argc, argv, "tool");
}

// after:
static const AxlArgDesc bios_args[] = {
    { .name = "args", .type = AXL_ARG_MULTI,
      .help = "subcommand arguments" }, {0}
};
static int tool_bios(AxlArgs *a) {
    int n = axl_args_get_pos_count(a);
    const char *sub = (n > 0) ? axl_args_get_pos(a, 0) : NULL;
    ...
}
static const AxlArgsNode verbs[] = {
    { .name = "bios", .handler = tool_bios, .positionals = bios_args,
      .help = "BIOS / SMBIOS info (test|pci|irq|slot|emb)" }, {0}
};
int main(int argc, char **argv) {
    return axl_args_run(argc, argv, &(AxlArgsNode){
        .name = "tool", .verbs = verbs,
    });
}
Subcommand implementation function signature.

Receives (argc, argv) where argv[0] is the subcommand name (the dispatcher rewrites it from the parent’s argv so subcommand implementations don’t need to know about the parent’s name). Use AxlConfig or hand-written parsing on the remaining args.

Functions

int axl_subcommand_dispatch(const AxlSubcommand *table, size_t count, int argc, char **argv, const char *prog_name)

Dispatch argv[1] to the matching subcommand, or print help.

Behavior:

  • argc < 2, or argv[1] is “help” / “-h” / “–help” with no further args → prints the formatted help table and returns 0.

  • argv[1] is “help <cmd>” → prints cmd’s usage field (or summary if usage is NULL) and returns 0.

  • argv[1] matches a table entry → invokes its fn with (argc - 1, argv + 1) so the subcommand sees its own name as argv[0]. Returns the function’s return value.

  • argv[1] doesn’t match anything → prints “<prog>: unknown command

    ’foo’” plus a “did you mean ‘bar’?” suggestion if a close match exists, and returns -1.

The table is 100% caller-owned. No allocation; no internal state.

Parameters:
  • table – array of AxlSubcommand

  • count – number of entries in table

  • argc – forwarded from main()

  • argv – forwarded from main()

  • prog_name – used in help / error output. NULL → use the basename of argv[0].

Returns:

whatever the subcommand returned, 0 for help/empty, or -1 if the command wasn’t found.

void axl_subcommand_print_help(const AxlSubcommand *table, size_t count, const char *prog_name)

Print only the formatted help table.

Useful when the caller wants to show help in response to an invalid argument outside the dispatch path. Output format:

Usage: <prog> <command> [args...]

Commands: bios [test|pci|irq|slot|emb] sysid [hexValue]

Run <prog> help <command> for detailed usage.

void axl_subcommand_print_command_help(const AxlSubcommand *entry, const char *prog_name)

Print a single subcommand’s detailed usage.

Used by <prog> help <cmd>. Prints entry->usage, falling back to entry->summary if entry->usage is NULL. Pass NULL entry to print the global help (same as axl_subcommand_print_help).

struct AxlSubcommand
#include <axl-subcommand.h>

One entry in a subcommand table. Define a static array of these (or allocate dynamically — the dispatcher doesn’t care) and pass it to axl_subcommand_dispatch.

Public Members

const char *name

e.g. “bios”, “sysid”, “crb”

AxlSubcommandFn fn

Implementation function.

const char *summary

One-line, shown in <prog> help

const char *usage

Multiline, shown in <prog> help <cmd> (NULL = use summary)