docs: add README
This commit is contained in:
parent
f91ed23cb0
commit
960ed4584f
1 changed files with 192 additions and 0 deletions
192
README.md
Normal file
192
README.md
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
# 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
|
||||
|
||||
- GCC (uses `__attribute__((unused))`)
|
||||
- autoconf ≥ 2.69, automake, libtool
|
||||
- [Criterion](https://github.com/Snaipe/Criterion) — optional, required for
|
||||
`--enable-tests`
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
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 (`"<NUM>"`, `"<STR>"`, 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, "<NUM>") \
|
||||
X(OPT_ARG_SECONDS, "<SEC>") \
|
||||
X(OPT_ARG_STRING, "<STR>")
|
||||
|
||||
#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 "<ARG>";
|
||||
}
|
||||
```
|
||||
|
||||
Then pass `my_arg_type_to_str` to `cli_print_options`.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Maximum 64 options
|
||||
|
||||
## License
|
||||
|
||||
GPLv3 — see [LICENSE](LICENSE).
|
||||
Loading…
Add table
Reference in a new issue