feat: add cli_print_options with extensible arg type system
This commit is contained in:
parent
64794a97a4
commit
41f3b13f91
3 changed files with 83 additions and 39 deletions
|
|
@ -16,17 +16,42 @@ struct greet_config {
|
|||
uint8_t flags;
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
static int handle_help(const char *arg, void *cfg);
|
||||
static int handle_version(const char *arg, void *cfg);
|
||||
static int handle_verbose(const char *arg, void *cfg);
|
||||
static int handle_name(const char *arg, void *cfg);
|
||||
static int handle_count(const char *arg, void *cfg);
|
||||
/* ------------------- */
|
||||
|
||||
/* Option table */
|
||||
|
||||
#define GREET_OPTIONS_LIST \
|
||||
X('h', "help", no_argument, handle_help, OPT_ARG_NONE, "Display this help") \
|
||||
X('V', "version", no_argument, handle_version, OPT_ARG_NONE, "Display version") \
|
||||
X('v', "verbose", no_argument, handle_verbose, OPT_ARG_NONE, "Verbose output") \
|
||||
X('n', "name", required_argument, handle_name, OPT_ARG_STRING, "Name to greet") \
|
||||
X('c', "count", required_argument, handle_count, OPT_ARG_UINT, "Number of greetings")
|
||||
|
||||
#define X(s, l, a, h, t, d) + 1
|
||||
enum { GREET_NB_OPTS = 0 GREET_OPTIONS_LIST };
|
||||
#undef X
|
||||
|
||||
#define X(s, l, a, h, t, d) + (1 + (a != no_argument ? 1 : 0))
|
||||
enum { GREET_OPTSTR_LEN = 1 GREET_OPTIONS_LIST };
|
||||
#undef X
|
||||
|
||||
#define X(s, l, a, h, t, d) { s, l, a, h, t, d },
|
||||
static const struct option_descriptor g_opts[] = { GREET_OPTIONS_LIST };
|
||||
#undef X
|
||||
|
||||
/* Handlers */
|
||||
|
||||
static int
|
||||
handle_help(__unused const char *arg, __unused void *cfg)
|
||||
{
|
||||
printf("Usage: greet [OPTIONS] ...\n\n");
|
||||
printf(" -h, --help Display this help\n");
|
||||
printf(" -V, --version Display version\n");
|
||||
printf(" -v, --verbose Verbose output\n");
|
||||
printf(" -n, --name NAME Name to greet (default: world)\n");
|
||||
printf(" -c, --count N Number of greetings (default: 1)\n");
|
||||
printf("Usage: greet [OPTIONS]\n\n");
|
||||
cli_print_options(g_opts, GREET_NB_OPTS, cli_arg_type_to_str);
|
||||
return CLI_EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -62,27 +87,6 @@ handle_count(const char *arg, void *cfg)
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Option table */
|
||||
|
||||
#define GREET_OPTIONS_LIST \
|
||||
X('h', "help", no_argument, handle_help, OPT_ARG_NONE, "Display this help") \
|
||||
X('V', "version", no_argument, handle_version, OPT_ARG_NONE, "Display version") \
|
||||
X('v', "verbose", no_argument, handle_verbose, OPT_ARG_NONE, "Verbose output") \
|
||||
X('n', "name", required_argument, handle_name, OPT_ARG_STRING, "Name to greet") \
|
||||
X('c', "count", required_argument, handle_count, OPT_ARG_UINT, "Number of greetings")
|
||||
|
||||
#define X(s, l, a, h, t, d) + 1
|
||||
enum { GREET_NB_OPTS = 0 GREET_OPTIONS_LIST };
|
||||
#undef X
|
||||
|
||||
#define X(s, l, a, h, t, d) + (1 + (a != no_argument ? 1 : 0))
|
||||
enum { GREET_OPTSTR_LEN = 1 GREET_OPTIONS_LIST };
|
||||
#undef X
|
||||
|
||||
#define X(s, l, a, h, t, d) { s, l, a, h, t, d },
|
||||
static const struct option_descriptor g_opts[] = { GREET_OPTIONS_LIST };
|
||||
#undef X
|
||||
|
||||
/* Main */
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -11,17 +11,7 @@ enum cli_code {
|
|||
};
|
||||
|
||||
typedef int (*t_option_handler)(const char *arg, void *config);
|
||||
|
||||
enum option_arg_type
|
||||
{
|
||||
OPT_ARG_NONE = 0,
|
||||
OPT_ARG_INT,
|
||||
OPT_ARG_UINT,
|
||||
OPT_ARG_SECONDS,
|
||||
OPT_ARG_BYTES,
|
||||
OPT_ARG_TTL,
|
||||
OPT_ARG_STRING
|
||||
};
|
||||
typedef const char *(*t_arg_type_to_str)(int type);
|
||||
|
||||
struct option_descriptor
|
||||
{
|
||||
|
|
@ -29,11 +19,27 @@ struct option_descriptor
|
|||
const char *long_opt;
|
||||
int has_arg;
|
||||
t_option_handler handler;
|
||||
enum option_arg_type arg_type;
|
||||
int arg_type;
|
||||
const char *description;
|
||||
};
|
||||
|
||||
/* Default arg types — clients may define their own */
|
||||
#define CLI_OPT_ARG_TYPES \
|
||||
X(OPT_ARG_NONE, "" ) \
|
||||
X(OPT_ARG_INT, "<NUM>") \
|
||||
X(OPT_ARG_UINT, "<NUM>") \
|
||||
X(OPT_ARG_FLOAT, "<NUM>") \
|
||||
X(OPT_ARG_STRING, "<STR>")
|
||||
|
||||
#define X(name, str) name,
|
||||
enum { CLI_OPT_ARG_TYPES };
|
||||
#undef X
|
||||
|
||||
void cli_set_prog_name(const char *name);
|
||||
void cli_print_options(const struct option_descriptor *opts, size_t nb_opts,
|
||||
t_arg_type_to_str to_str);
|
||||
|
||||
const char *cli_arg_type_to_str(int type);
|
||||
|
||||
enum cli_code cli_parse(int argc, char **argv, void *config,
|
||||
const struct option_descriptor *opts, size_t nb_opts,
|
||||
|
|
|
|||
34
src/help.c
Normal file
34
src/help.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "cli.h"
|
||||
#include "compiler.h"
|
||||
|
||||
const char *
|
||||
cli_arg_type_to_str(int type)
|
||||
{
|
||||
static const char *strs[] = {
|
||||
#define X(name, str) str,
|
||||
CLI_OPT_ARG_TYPES
|
||||
#undef X
|
||||
};
|
||||
if ((size_t)type < COUNT_OF(strs))
|
||||
return strs[type];
|
||||
return "<ARG>";
|
||||
}
|
||||
|
||||
void
|
||||
cli_print_options(const struct option_descriptor *opts, size_t nb_opts,
|
||||
t_arg_type_to_str to_str)
|
||||
{
|
||||
printf("Options:\n");
|
||||
for (size_t i = 0; i < nb_opts; i++)
|
||||
{
|
||||
const char *argstr = to_str(opts[i].arg_type);
|
||||
printf(" -%c, --%-15s %-8s %s\n",
|
||||
opts[i].short_opt,
|
||||
opts[i].long_opt,
|
||||
argstr,
|
||||
opts[i].description);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue