cmd: add functions to report option/arg errors to the public API

This commit is contained in:
2025-07-17 17:56:00 +01:00
parent 92ccc5626d
commit 5d6423057a
6 changed files with 498 additions and 195 deletions

View File

@@ -55,10 +55,10 @@ static void command_usage_destroy(struct b_command_usage *usage)
{
struct b_queue_iterator it = {0};
b_queue_iterator_begin(&usage->u_arg, &it);
b_queue_iterator_begin(&usage->u_parts, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_usage_arg *arg = b_unbox(
struct b_command_usage_arg, it.entry, arg_entry);
struct b_command_usage_entry *arg = b_unbox(
struct b_command_usage_entry, it.entry, e_entry);
if (!arg) {
continue;
}
@@ -67,18 +67,6 @@ static void command_usage_destroy(struct b_command_usage *usage)
free(arg);
}
b_queue_iterator_begin(&usage->u_opt, &it);
while (b_queue_iterator_is_valid(&it)) {
struct b_command_usage_opt *opt = b_unbox(
struct b_command_usage_opt, it.entry, opt_entry);
if (!opt) {
continue;
}
b_queue_iterator_erase(&it);
free(opt);
}
free(usage);
}
@@ -277,47 +265,50 @@ struct b_command_usage *b_command_add_usage(struct b_command *cmd)
b_status b_command_usage_add_option(
struct b_command_usage *usage, struct b_command_option *opt)
{
struct b_command_usage_opt *u_opt = malloc(sizeof *u_opt);
struct b_command_usage_entry *u_opt = malloc(sizeof *u_opt);
if (!u_opt) {
return B_ERR_NO_MEMORY;
}
memset(u_opt, 0x0, sizeof *u_opt);
u_opt->opt = opt;
u_opt->e_type = CMD_USAGE_OPT;
u_opt->e_opt = opt;
b_queue_push_back(&usage->u_opt, &u_opt->opt_entry);
b_queue_push_back(&usage->u_parts, &u_opt->e_entry);
return B_SUCCESS;
}
b_status b_command_usage_add_arg(
struct b_command_usage *usage, struct b_command_arg *arg)
{
struct b_command_usage_arg *u_arg = malloc(sizeof *u_arg);
struct b_command_usage_entry *u_arg = malloc(sizeof *u_arg);
if (!u_arg) {
return B_ERR_NO_MEMORY;
}
memset(u_arg, 0x0, sizeof *u_arg);
u_arg->arg = arg;
u_arg->e_type = CMD_USAGE_ARG;
u_arg->e_arg = arg;
b_queue_push_back(&usage->u_arg, &u_arg->arg_entry);
b_queue_push_back(&usage->u_parts, &u_arg->e_entry);
return B_SUCCESS;
}
b_status b_command_usage_add_command(b_command_usage *usage, unsigned int cmd_id)
{
struct b_command_usage_command *u_cmd = malloc(sizeof *u_cmd);
struct b_command_usage_entry *u_cmd = malloc(sizeof *u_cmd);
if (!u_cmd) {
return B_ERR_NO_MEMORY;
}
memset(u_cmd, 0x0, sizeof *u_cmd);
u_cmd->cmd_id = cmd_id;
u_cmd->e_type = CMD_USAGE_COMMAND;
u_cmd->e_cmd_id = cmd_id;
b_queue_push_back(&usage->u_cmd, &u_cmd->cmd_entry);
b_queue_push_back(&usage->u_parts, &u_cmd->e_entry);
return B_SUCCESS;
}
@@ -381,66 +372,52 @@ static void get_usage_string(
struct b_string *cmd_name = b_string_create();
b_queue_iterator it;
b_queue_foreach (&it, &usage->u_cmd) {
struct b_command_usage_command *subcmd = b_unbox(
struct b_command_usage_command, it.entry, cmd_entry);
b_queue_foreach (&it, &usage->u_parts) {
struct b_command_usage_entry *entry = b_unbox(
struct b_command_usage_entry, it.entry, e_entry);
if (!subcmd) {
if (!entry) {
break;
}
b_string_clear(cmd_name);
b_string_append_cstr(out, " ");
if (subcmd->cmd_id == B_COMMAND_INVALID_ID) {
b_string_append_cstr(out, "[COMMAND]");
} else {
switch (entry->e_type) {
case CMD_USAGE_ARG:
if (entry->e_arg) {
z__b_get_arg_usage_string(entry->e_arg, false, out);
} else {
b_string_append_cstr(out, "[[ARGS]");
}
break;
case CMD_USAGE_OPT:
if (entry->e_opt) {
z__b_get_option_usage_string(
entry->e_opt, CMD_STR_DIRECT_USAGE, out);
} else {
b_string_append_cstr(out, "[[OPTIONS]");
}
break;
case CMD_USAGE_COMMAND:
if (entry->e_cmd_id == B_COMMAND_INVALID_ID) {
b_string_append_cstr(out, "[[COMMAND]");
break;
}
struct b_command *subcmd_info
= get_command(&command_list, subcmd->cmd_id);
= get_command(&command_list, entry->e_cmd_id);
prepend_command_name(subcmd_info, cmd_name);
b_string_append_s(out, cmd_name);
break;
default:
break;
}
}
b_string_release(cmd_name);
b_queue_foreach (&it, &usage->u_opt) {
struct b_command_usage_opt *opt = b_unbox(
struct b_command_usage_opt, it.entry, opt_entry);
if (!opt) {
break;
}
b_string_append_cstr(out, " ");
if (opt->opt
== (struct b_command_option *)(uintptr_t)B_COMMAND_INVALID_ID) {
b_string_append_cstr(out, "[OPTIONS]");
} else {
z__b_get_option_usage_string(
opt->opt, CMD_STR_DIRECT_USAGE, out);
}
}
b_queue_foreach (&it, &usage->u_arg) {
struct b_command_usage_arg *arg = b_unbox(
struct b_command_usage_arg, it.entry, arg_entry);
if (!arg) {
break;
}
b_string_append_cstr(out, " ");
if (arg->arg
== (struct b_command_arg *)(uintptr_t)B_COMMAND_INVALID_ID) {
b_string_append_cstr(out, "[ARGS]");
} else {
z__b_get_arg_usage_string(arg->arg, false, out);
}
}
}
b_string *z__b_command_default_usage_string(
@@ -833,6 +810,44 @@ struct b_command_option *b_command_get_option_with_short_name(
return NULL;
}
struct b_command_option *b_command_get_option_with_id(
struct b_command *cmd, unsigned int id)
{
b_queue_iterator it;
b_queue_foreach (&it, &cmd->b_opt) {
struct b_command_option *opt
= b_unbox(struct b_command_option, it.entry, opt_entry);
if (!opt) {
continue;
}
if (opt->opt_id == id) {
return opt;
}
}
return NULL;
}
struct b_command_arg *b_command_get_arg_with_id(
struct b_command *cmd, unsigned int id)
{
b_queue_iterator it;
b_queue_foreach (&it, &cmd->b_arg) {
struct b_command_arg *arg
= b_unbox(struct b_command_arg, it.entry, arg_entry);
if (!arg) {
continue;
}
if (arg->arg_id == id) {
return arg;
}
}
return NULL;
}
static void print_usage(struct b_command *cmd)
{
b_paragraph_format format = {0};
@@ -963,6 +978,8 @@ int b_command_dispatch(unsigned int cmd_id, int argc, const char **argv)
}
struct b_arglist *args = b_arglist_create();
args->list_command = cmd;
b_status status = b_arglist_parse(args, &cmd, argc, argv);
if (B_ERR(status)) {
b_arglist_destroy(args);