Created
December 8, 2021 05:17
-
-
Save fowlmouth/40ac4ac274df8495722c74f23e331189 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdbool.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
struct cli; | |
typedef void(*cli_cb)(struct cli*, const char***, const char**, void*); | |
struct cli_option | |
{ | |
const char* key; | |
void* value; | |
cli_cb cb; | |
}; | |
struct cli | |
{ | |
int opt_count, opt_capacity; | |
struct cli_option* options; | |
}; | |
bool cli_init(struct cli* cli, int capacity) | |
{ | |
if(capacity < 1) | |
{ | |
capacity = 8; | |
} | |
void* opts = calloc(sizeof(struct cli_option), capacity); | |
if(!opts) | |
{ | |
return false; | |
} | |
cli->opt_count = 0; | |
cli->opt_capacity = capacity; | |
cli->options = (struct cli_option*)opts; | |
return true; | |
} | |
void cli_deinit(struct cli* cli) | |
{ | |
if(cli->options) | |
{ | |
free(cli->options); | |
} | |
memset(cli, 0, sizeof(struct cli)); | |
} | |
struct cli_option* cli_next_opt(struct cli* cli) | |
{ | |
if(cli->opt_count == cli->opt_capacity) | |
{ | |
int new_capacity = cli->opt_capacity * 2; | |
if(!new_capacity) // cant happen if cli_init is used | |
{ | |
new_capacity = 4; | |
} | |
struct cli_option* new_opts = calloc(sizeof(struct cli_option), new_capacity); | |
memcpy(new_opts, cli->options, sizeof(struct cli_option) * cli->opt_capacity); | |
if(cli->options) | |
{ | |
free(cli->options); | |
} | |
cli->opt_capacity = new_capacity; | |
cli->options = new_opts; | |
} | |
return cli->options + cli->opt_count++; | |
} | |
void cli_bool_cb(struct cli* cli, const char*** input, const char** end, void* value) | |
{ | |
++*input; | |
bool* bool_value = (bool*)value; | |
*bool_value = true; | |
} | |
void cli_bool(struct cli* cli, const char* key, bool* value) | |
{ | |
struct cli_option* opt = cli_next_opt(cli); | |
opt->key = key; | |
opt->value = (void*)value; | |
opt->cb = cli_bool_cb; | |
} | |
void cli_string_cb(struct cli* cli, const char*** input, const char** end, void* value) | |
{ | |
const char** str_value = (const char**)value; | |
*str_value = *++*input; | |
++*input; | |
} | |
void cli_string(struct cli* cli, const char* key, const char** value) | |
{ | |
struct cli_option* opt = cli_next_opt(cli); | |
opt->key = key; | |
opt->value = (void*)value; | |
opt->cb = cli_string_cb; | |
} | |
bool cli_match_opt(struct cli* cli, const char* arg, struct cli_option** out) | |
{ | |
printf("cli match opt count=%d\n", cli->opt_count); | |
for(int i = 0; i < cli->opt_count; ++i) | |
{ | |
struct cli_option* opt = cli->options + i; | |
printf("comparing '%s' and '%s'\n", arg, opt->key); | |
if(!strcmp(arg, opt->key)) | |
{ | |
*out = opt; | |
return true; | |
} | |
} | |
return false; | |
} | |
bool cli_parse_arg(struct cli* cli, const char*** input, const char** input_end) | |
{ | |
const char* str = **input; | |
int len = strlen(str); | |
if(len && str[0] == '-') | |
{ | |
struct cli_option* opt; | |
if(cli_match_opt(cli, str, &opt)) | |
{ | |
if(opt->cb) | |
{ | |
const char** old_input = *input; | |
opt->cb(cli, input, input_end, opt->value); | |
return *input != old_input; | |
} | |
} | |
} | |
return false; | |
} | |
void cli_parse(struct cli* cli, int argc, const char** argv) | |
{ | |
const char** argv_end = argv + argc; | |
++argv; | |
while(argv != argv_end) | |
{ | |
printf("argv= '%s'\n", *argv); | |
if(!cli_parse_arg(cli, &argv, argv_end)) | |
{ | |
printf("breaking from cli_parse\n"); | |
break; | |
} | |
} | |
} | |
int main(int argc, const char** argv) | |
{ | |
bool run_tests = false; | |
const char* file = NULL; | |
struct cli cli; | |
cli_init(&cli, 1); | |
cli_bool(&cli, "-test", &run_tests); | |
cli_string(&cli, "-file", &file); | |
printf("cli count= %d capacity= %d\n", cli.opt_count, cli.opt_capacity); | |
cli_parse(&cli, argc, argv); | |
cli_deinit(&cli); | |
printf("run_tests: %d\n", (int)run_tests); | |
printf("file: '%s'\n", file); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment