# libcli A lightweight C library for parsing command-line arguments. Wraps `getopt_long` with a descriptor-based API, typed parse utilities, duplicate detection, and automatic help formatting. ## Dependencies - clang - autoconf ≥ 2.69, automake, libtool - [Criterion](https://github.com/Snaipe/Criterion) — optional, required for `--enable-tests` ## Build ```sh ./autogen.sh ./configure make make install ldconfig ``` To build and run the test suite: ```sh ./configure --enable-tests make check ``` ## Quickstart ```c #include "cli.h" #include "cli_parse_utils.h" #include "compiler.h" struct config { const char *name; }; static int handle_name(const char *arg, void *cfg) { ((struct config *)cfg)->name = arg; return CLI_SUCCESS; } static int handle_help(const char *arg, void *cfg) { printf("Usage: myprog [OPTIONS]\n\n"); cli_print_options(g_opts, NB_OPTS, cli_arg_type_to_str); return CLI_EXIT_SUCCESS; } #define OPTIONS_LIST \ X('h', "help", no_argument, handle_help, OPT_ARG_NONE, "Display this help") \ X('n', "name", required_argument, handle_name, OPT_ARG_STRING, "Your name") #define X(s, l, a, h, t, d) + 1 enum { NB_OPTS = 0 OPTIONS_LIST }; #undef X #define X(s, l, a, h, t, d) + (1 + (a != no_argument ? 1 : 0)) enum { OPTSTR_LEN = 1 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[] = { OPTIONS_LIST }; #undef X int main(int argc, char **argv) { struct config cfg = { .name = "world" }; char opt_str[OPTSTR_LEN + 1]; struct option long_opts[NB_OPTS + 1]; cli_set_prog_name(argv[0]); if (CLI_SUCCESS != cli_parse(argc, argv, &cfg, g_opts, NB_OPTS, opt_str, long_opts)) return 1; printf("Hello, %s!\n", cfg.name); return 0; } ``` See `example/` for a complete working example. ## API ### Parsing ```c enum cli_code cli_parse(int argc, char **argv, void *config, const struct option_descriptor *opts, size_t nb_opts, char *opt_str, struct option *long_opts); ``` Parses `argv` against the descriptor table `opts`. Calls each option's handler with the raw argument string and `config`. Returns `CLI_SUCCESS`, `CLI_ERROR`, or `CLI_EXIT_SUCCESS` (handler requested early exit, e.g. `--help`). `opt_str` and `long_opts` are caller-allocated scratch buffers — size them with the X-macro pattern shown above. ```c void cli_set_prog_name(const char *name); ``` Sets the program name used in error messages. Call with `argv[0]` before `cli_parse`. ### Option descriptor ```c struct option_descriptor { char short_opt; // e.g. 'h' const char *long_opt; // e.g. "help" int has_arg; // no_argument / required_argument / optional_argument t_option_handler handler; // callback: int f(const char *arg, void *config) int arg_type; // display hint for cli_print_options const char *description; // displayed by cli_print_options }; ``` ### Help ```c void cli_print_options(const struct option_descriptor *opts, size_t nb_opts, t_arg_type_to_str to_str); ``` Prints a formatted options table to stdout. `to_str` maps `arg_type` integers to placeholder strings (`""`, `""`, etc.). ```c const char *cli_arg_type_to_str(int type); ``` Default `to_str` implementation covering the built-in types. Pass directly to `cli_print_options` if you don't need custom types. ### Return codes | Value | Meaning | |---|---| | `CLI_SUCCESS` | Continue — option handled successfully | | `CLI_ERROR` | Abort — invalid option or argument | | `CLI_EXIT_SUCCESS` | Abort — clean exit requested (e.g. after printing help) | ### Parse utilities ```c int cli_parse_uint64(const char *s, uint64_t *out); // non-negative integers int cli_parse_int64(const char *s, int64_t *out); // signed integers (use --opt=-N syntax) int cli_parse_float(const char *s, float *out); // floats (use --opt=-1.5 syntax) ``` All return 0 on success, 1 on failure. They reject NULL, empty strings, trailing characters, and out-of-range values. ## Custom arg types The built-in `CLI_OPT_ARG_TYPES` X-macro covers `OPT_ARG_NONE`, `OPT_ARG_INT`, `OPT_ARG_UINT`, `OPT_ARG_FLOAT`, `OPT_ARG_STRING`. To define custom types with their own display strings, declare your own list and generate both the enum and the `to_str` function from it: ```c #define MY_ARG_TYPES \ X(OPT_ARG_NONE, "") \ X(OPT_ARG_UINT, "") \ X(OPT_ARG_SECONDS, "") \ X(OPT_ARG_STRING, "") #define X(name, str) name, enum { MY_ARG_TYPES }; #undef X static const char *my_arg_type_to_str(int type) { static const char *strs[] = { #define X(name, str) str, MY_ARG_TYPES #undef X }; if ((size_t)type < COUNT_OF(strs)) return strs[type]; return ""; } ``` Then pass `my_arg_type_to_str` to `cli_print_options`. ## Limitations - Maximum 64 options ## License GPLv3 — see [LICENSE](LICENSE).