first version
This commit is contained in:
207
README.md
Normal file
207
README.md
Normal file
@@ -0,0 +1,207 @@
|
||||
## args.h
|
||||
|
||||
Single header command line argument parser for C and C++
|
||||
loosely based on python's argparse module.
|
||||
|
||||
## Usage:
|
||||
|
||||
Define implementation macro before you include this file in *one* C or C++ file:
|
||||
|
||||
```c
|
||||
#define ARGS_IMPLEMENTATION
|
||||
```
|
||||
|
||||
Should look like this:
|
||||
|
||||
```c
|
||||
#include ...
|
||||
#include ...
|
||||
|
||||
#define ARGS_IMPLEMENTATION
|
||||
#include "args.h"
|
||||
```
|
||||
|
||||
This will expand the implementation into that file, in other files you can just
|
||||
include the header without the macro.
|
||||
|
||||
```c
|
||||
#include "args.h"
|
||||
```
|
||||
|
||||
## Example:
|
||||
|
||||
```c
|
||||
void example(int argc, char **argv) {
|
||||
args_t args = {
|
||||
.program = argv[0],
|
||||
.description = "this program does very cool things on many files and outputs it somewhere",
|
||||
.epilogue = "it also shows cool epilogue text in it's help",
|
||||
};
|
||||
args_add(&args, (args_desc_t){"filenames", .nargs = "+" });
|
||||
args_add(&args, (args_desc_t){"--output", "-o" });
|
||||
args_add(&args, (args_desc_t){"--force", "-f", .store_value = "1", .default_value = "0"});
|
||||
args_add(&args, (args_desc_t){"--recursive", "-r", .store_value = "1", .default_value = "0"});
|
||||
args_add(&args, (args_desc_t){"--help", "-h", .store_value = "1", .default_value = "0"});
|
||||
args_parse(&args, argc, argv);
|
||||
|
||||
const char **filenames = args_get(&args, "filenames");
|
||||
const char **output = args_get(&args, "--output");
|
||||
int force = atoi(args_get(&args, "-f")[0]);
|
||||
int recursive = atoi(args_get(&args, "--recursive")[0]);
|
||||
int help = atoi(args_get(&args, "--help")[0]);
|
||||
|
||||
if (help) {
|
||||
args_print_help(&args);
|
||||
return;
|
||||
}
|
||||
|
||||
// ..
|
||||
|
||||
for (int i = 0; filenames[i]; i += 1) {
|
||||
// ..
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Execute like this:
|
||||
|
||||
> app.exe file1 file2 file3 --force --output /folder/.
|
||||
|
||||
Help menu:
|
||||
|
||||
```
|
||||
usage: ./a.out [options] filenames ...
|
||||
|
||||
this program does very cool things on many files and outputs it somewhere
|
||||
|
||||
options:
|
||||
filenames <arg> ... list of filenames to process
|
||||
--output -o <arg> path to the folder where output will be gathered
|
||||
--force -f force the processing
|
||||
--recursive -r apply recursively to files in current directory
|
||||
--help -h show this help window
|
||||
|
||||
it also shows cool epilogue text in it's help
|
||||
```
|
||||
|
||||
## How To's
|
||||
|
||||
1. Single positional argument
|
||||
|
||||
> program.exe argument
|
||||
|
||||
Specifying `.nargs = "<digit>"` enforces a strict number
|
||||
of arguments, so supplying less or more will result in
|
||||
an error.
|
||||
|
||||
```c
|
||||
args_t args = {0};
|
||||
args_add(&args, (args_desc_t){"argument", .nargs = "1"});
|
||||
args_parse(&args, argc, argv);
|
||||
const char *argument = args_get(&args, "argument")[0];
|
||||
```
|
||||
|
||||
2. One or more positional arguments
|
||||
|
||||
> program.exe a b c
|
||||
|
||||
You need to set `.nargs = "+"` this will make it so that one
|
||||
or more arguments are expected. Alternatively `.nargs = "*"`,
|
||||
which makes it so that having even one argumenti is optional.
|
||||
|
||||
```c
|
||||
args_t args = {0};
|
||||
args_add(&args, (args_desc_t){"arguments", .nargs = "+"});
|
||||
args_parse(&args, argc, argv);
|
||||
const char **arguments = args_get(&args, "arguments");
|
||||
```
|
||||
|
||||
3. Help menu, help flag
|
||||
|
||||
> program.exe --help
|
||||
|
||||
```
|
||||
args_t args = {0};
|
||||
args_add(&args, (args_desc_t){"--help", "-h", .store_value = "1", .default_value = "0"});
|
||||
args_parse(&args, argc, argv);
|
||||
int help = atoi(args_get(&args, "help")[0]);
|
||||
if (help) {
|
||||
args_print_help(&args);
|
||||
exit(0);
|
||||
}
|
||||
```
|
||||
|
||||
4. Typechecked optional list of integers
|
||||
|
||||
> program.exe --list 1 2 3
|
||||
> program.exe
|
||||
|
||||
```c
|
||||
args_t args = {0};
|
||||
args_add(&args, (args_desc_t){"--list", "-l", .type = ARGS_TYPE_INT, .nargs = "*"});
|
||||
args_parse(&args, argc, argv);
|
||||
const char **list = args_get(&args, "--list");
|
||||
```
|
||||
|
||||
5. Custom logging
|
||||
|
||||
You can override the ARGS_PRINTF macro, at compile time
|
||||
the library will use that. By default it uses fprintf(stderr)
|
||||
|
||||
```c
|
||||
#define ARGS_PRINTF(...) fprintf(stdout, __VA_ARGS__)
|
||||
#define ARGS_IMPLEMENTATION
|
||||
#include "args.h"
|
||||
```
|
||||
|
||||
6. User defined memory allocator
|
||||
|
||||
```c
|
||||
#define ARGS_MALLOC(x) my_malloc(x)
|
||||
#define ARGS_FREE(x) my_free(x)
|
||||
#define ARGS_IMPLEMENTATION
|
||||
#include "args.h"
|
||||
```
|
||||
|
||||
7. C++
|
||||
|
||||
The library works in C++ but leverages special C syntax for aggregate types,
|
||||
in later C++ the syntax might be simiar so no issues there but for older
|
||||
versions you will either need to write some small wrapper functions or just
|
||||
bare with initializing structures inline. For example:
|
||||
|
||||
```c
|
||||
void args_add_bool(args_t *args, const char *name, const char *alt_name, const char *help) {
|
||||
args_desc_t desc = {name, alt_name};
|
||||
desc.help = help;
|
||||
desc.store_value = "1";
|
||||
desc.default_value = "0";
|
||||
args_add(args, desc);
|
||||
}
|
||||
|
||||
void args_add_nargs(args_t *args, const char *name, const char *alt_name, const char *nargs, const char *help) {
|
||||
args_desc_t desc = {name, alt_name};
|
||||
desc.nargs = nargs;
|
||||
desc.help = help;
|
||||
args_add(args, desc);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
args_t args = {
|
||||
.program = argv[0],
|
||||
.description = "this program does very cool things on many files and outputs it somewhere",
|
||||
.epilogue = "it also shows cool epilogue text in it's help",
|
||||
};
|
||||
args_add_nargs(&args, "filenames", NULL, "+", "list of filenames to process");
|
||||
args_add_nargs(&args, "--output", "-o", "?", "path to the folder where output will be gathered");
|
||||
args_add_bool(&args, "--force", "-f", "force the processing");
|
||||
args_add_bool(&args, "--recursive", "-r", "apply recursively to files in current directory");
|
||||
args_add_bool(&args, "--help", "-h", "show this help window");
|
||||
args_parse(&args, argc, argv);
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Library is in public domain. See end of code file for license.
|
||||
|
||||
Reference in New Issue
Block a user