From 243c6651b03e442a1c9d641fb9c63bedcc5aabb5 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 4 Feb 2025 12:59:44 +0000 Subject: [PATCH] cmd: improve API for accessing multi-arg options --- cmd/arglist.c | 113 +++++++++++++++++++++++++++++++---------- cmd/include/blue/cmd.h | 14 ++++- 2 files changed, 97 insertions(+), 30 deletions(-) diff --git a/cmd/arglist.c b/cmd/arglist.c index 413519b..9327284 100644 --- a/cmd/arglist.c +++ b/cmd/arglist.c @@ -1,3 +1,4 @@ +#include "blue/core/misc.h" #include "command.h" #include @@ -174,23 +175,9 @@ static b_status put_arg( } static b_status put_opt_arg( - struct b_arglist *args, struct b_command_option *opt, + struct b_arglist_option *arglist_opt, struct b_command_option *opt, struct b_command_arg *arg, const char *value) { - struct b_arglist_option *arglist_opt - = get_arglist_option(&args->list_options, opt->opt_id); - if (!arglist_opt) { - arglist_opt = malloc(sizeof *arglist_opt); - - if (!arglist_opt) { - return B_ERR_NO_MEMORY; - } - - memset(arglist_opt, 0x0, sizeof *arglist_opt); - - arglist_opt->opt_id = opt->opt_id; - put_arglist_option(&args->list_options, arglist_opt); - } if (arg->arg_allowed_values) { bool value_ok = false; @@ -438,23 +425,35 @@ static b_status parse_short_opt(struct argv_parser *parser) break; } - advance(parser); - if (!opt || b_queue_empty(&opt->opt_args)) { + advance(parser); return B_SUCCESS; } + struct b_arglist_option *arglist_opt = malloc(sizeof *arglist_opt); + + if (!arglist_opt) { + return B_ERR_NO_MEMORY; + } + + memset(arglist_opt, 0x0, sizeof *arglist_opt); + + arglist_opt->opt_id = opt->opt_id; + put_arglist_option(&parser->arglist->list_options, arglist_opt); + b_queue_iterator it; b_queue_iterator_begin(&opt->opt_args, &it); const char *value = flags; if (*value == '\0') { - value = advance(parser); - if (!value || *value == '-') { - value = NULL; - } + advance(parser); } while (b_queue_iterator_is_valid(&it)) { + value = peek(parser); + if (!value || *value == '-') { + value = NULL; + } + arg = b_unbox(struct b_command_arg, it.entry, arg_entry); if (!arg) { @@ -468,7 +467,7 @@ static b_status parse_short_opt(struct argv_parser *parser) if (value) { b_status status - = put_opt_arg(parser->arglist, opt, arg, value); + = put_opt_arg(arglist_opt, opt, arg, value); nr_args_cur_opt++; if (status == B_ERR_INVALID_ARGUMENT) { @@ -483,20 +482,20 @@ static b_status parse_short_opt(struct argv_parser *parser) if (arg->arg_nr_values == B_ARG_0_OR_1_VALUES) { b_queue_iterator_next(&it); nr_args_cur_opt = 0; - continue; + goto next_value; } if (arg->arg_nr_values == B_ARG_0_OR_MORE_VALUES && !value) { b_queue_iterator_next(&it); nr_args_cur_opt = 0; - continue; + goto next_value; } if (arg->arg_nr_values == B_ARG_1_OR_MORE_VALUES && !value) { if (nr_args_cur_opt > 0) { b_queue_iterator_next(&it); nr_args_cur_opt = 0; - continue; + goto next_value; } report_missing_args(parser, opt, arg, nr_args_cur_opt); @@ -506,14 +505,14 @@ static b_status parse_short_opt(struct argv_parser *parser) if (nr_args_cur_opt == arg->arg_nr_values) { b_queue_iterator_next(&it); nr_args_cur_opt = 0; - continue; + goto next_value; } if (!value) { report_missing_args(parser, opt, arg, nr_args_cur_opt); return B_ERR_BAD_FORMAT; } - + next_value: value = advance(parser); } @@ -560,6 +559,17 @@ static b_status parse_long_opt(struct argv_parser *parser) int nr_args_total = 0; int nr_args_cur_opt = 0; + struct b_arglist_option *arglist_opt = malloc(sizeof *arglist_opt); + + if (!arglist_opt) { + return B_ERR_NO_MEMORY; + } + + memset(arglist_opt, 0x0, sizeof *arglist_opt); + + arglist_opt->opt_id = opt->opt_id; + put_arglist_option(&parser->arglist->list_options, arglist_opt); + b_queue_iterator it; b_queue_iterator_begin(&opt->opt_args, &it); struct b_command_arg *arg @@ -578,7 +588,7 @@ static b_status parse_long_opt(struct argv_parser *parser) if (value) { b_status status - = put_opt_arg(parser->arglist, opt, arg, value); + = put_opt_arg(arglist_opt, opt, arg, value); nr_args_total++; nr_args_cur_opt++; advance(parser); @@ -811,6 +821,30 @@ b_status b_arglist_get_uint( return B_ERR_NO_ENTRY; } +b_status b_arglist_get_option( + const b_arglist *args, unsigned int opt_id, unsigned int index, + b_arglist_option **out) +{ + b_btree_iterator it = {0}; + b_btree_foreach (&it, &args->list_options) { + b_arglist_option *cur + = b_unbox(b_arglist_option, it.node, opt_node); + + if (cur->opt_id != opt_id) { + continue; + } + + if (index == 0) { + *out = cur; + return B_SUCCESS; + } + + index--; + } + + return B_ERR_NO_ENTRY; +} + size_t b_arglist_get_count( const b_arglist *args, unsigned int opt_id, unsigned int arg_id) { @@ -825,6 +859,29 @@ size_t b_arglist_get_count( return count; } +b_status b_arglist_option_get_value( + const b_arglist_option *opt, unsigned int arg_id, unsigned int index, + b_arglist_value **out) +{ + b_btree_iterator it = {0}; + b_btree_foreach (&it, &opt->opt_values) { + b_arglist_value *cur = b_unbox(b_arglist_value, it.node, val_node); + + if (cur->val_id != arg_id) { + continue; + } + + if (index == 0) { + *out = cur; + return B_SUCCESS; + } + + index--; + } + + return B_ERR_NO_ENTRY; +} + static bool arglist_iterator_next(struct b_iterator *it) { return b_arglist_iterator_next((struct b_arglist_iterator *)it); diff --git a/cmd/include/blue/cmd.h b/cmd/include/blue/cmd.h index 31ef8ed..efd7f81 100644 --- a/cmd/include/blue/cmd.h +++ b/cmd/include/blue/cmd.h @@ -169,6 +169,7 @@ typedef struct b_command_option b_command_option; typedef struct b_command_arg b_command_arg; typedef struct b_command_usage b_command_usage; typedef struct b_arglist b_arglist; +typedef struct b_arglist_option b_arglist_option; typedef int (*b_command_callback)( const b_command *, const b_arglist *, const b_array *); @@ -183,7 +184,8 @@ BLUE_API b_status b_command_set_long_name(b_command *cmd, const char *name); BLUE_API b_status b_command_set_short_name(b_command *cmd, char name); BLUE_API b_status b_command_set_flags(b_command *cmd, b_command_flags flags); BLUE_API b_status b_command_set_description(b_command *cmd, const char *description); -BLUE_API b_status b_command_set_callback(b_command *cmd, b_command_callback callback); +BLUE_API b_status b_command_set_callback( + b_command *cmd, b_command_callback callback); BLUE_API b_status b_command_set_parent(b_command *cmd, unsigned int parent_id); BLUE_API b_command_option *b_command_add_option(b_command *cmd, int id); BLUE_API b_command_arg *b_command_add_arg(b_command *cmd, int id); @@ -206,7 +208,8 @@ BLUE_API b_status b_command_arg_set_allowed_values( BLUE_API b_status b_command_usage_add_option( b_command_usage *usage, b_command_option *opt); -BLUE_API b_status b_command_usage_add_arg(b_command_usage *usage, b_command_arg *opt); +BLUE_API b_status b_command_usage_add_arg( + b_command_usage *usage, b_command_arg *opt); BLUE_API b_status b_command_usage_add_command( b_command_usage *usage, unsigned int cmd_id); @@ -219,9 +222,16 @@ BLUE_API b_status b_arglist_get_int( BLUE_API b_status b_arglist_get_uint( const b_arglist *args, unsigned int opt_id, unsigned int arg_id, unsigned int index, unsigned long long *out); +BLUE_API b_status b_arglist_get_option( + const b_arglist *args, unsigned int opt_id, unsigned int index, + b_arglist_option **out); BLUE_API size_t b_arglist_get_count( const b_arglist *args, unsigned int opt_id, unsigned int arg_id); +BLUE_API b_status b_arglist_option_get_value( + const b_arglist_option *opt, unsigned int arg_id, unsigned int index, + b_arglist_value **out); + BLUE_API int b_arglist_iterator_begin( const b_arglist *args, unsigned int opt_filter, unsigned int arg_filter, b_arglist_iterator *it);