diff options
Diffstat (limited to '')
-rw-r--r-- | util/argconfig.c | 365 |
1 files changed, 188 insertions, 177 deletions
diff --git a/util/argconfig.c b/util/argconfig.c index 231a704..3eb885f 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -42,6 +42,12 @@ #include <string.h> #include <stdbool.h> +#if __has_attribute(__fallthrough__) +#define fallthrough __attribute__((__fallthrough__)) +#else +#define fallthrough do {} while (0) +#endif + static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = { NULL }; static char END_DEFAULT[] = "__end_default__"; @@ -122,69 +128,197 @@ static void show_option(const struct argconfig_commandline_options *option) } void argconfig_print_help(const char *program_desc, - const struct argconfig_commandline_options *options) + struct argconfig_commandline_options *s) { - const struct argconfig_commandline_options *s; - fprintf(stderr, "\033[1mUsage: %s\033[0m\n\n", append_usage_str); print_word_wrapped(program_desc, 0, 0, stderr); fprintf(stderr, "\n"); - if (!options || !options->option) + if (!s || !s->option) return; fprintf(stderr, "\n\033[1mOptions:\033[0m\n"); - for (s = options; (s != NULL) && (s->option != NULL); s++) + for (; s && s->option; s++) show_option(s); } +static int argconfig_error(char *type, const char *opt, const char *arg) +{ + fprintf(stderr, "Expected %s argument for '%s' but got '%s'!\n", type, opt, arg); + return -EINVAL; +} + int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val) { char *endptr; unsigned long tmp = strtoul(str, &endptr, 0); - if (errno || tmp >= 1 << 8 || str == endptr) { - fprintf(stderr, - "Expected byte argument for '%s' but got '%s'!\n", opt, - str); - return -EINVAL; - } + if (errno || tmp >= 1 << 8 || str == endptr) + return argconfig_error("byte", opt, str); *val = tmp; return 0; } +static int argconfig_parse_type(struct argconfig_commandline_options *s, struct option *option, + int index) +{ + void *value = (void *)(char *)s->default_value; + char *endptr; + const char *fopts = NULL; + FILE *f; + int ret = 0; + char **opts = ((char **)value); + int remaining_space = CFG_MAX_SUBOPTS - 2; + + switch (s->config_type) { + case CFG_STRING: + *((char **)value) = optarg; + break; + case CFG_SIZE: + *((size_t *)value) = strtol(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("integer", option[index].name, optarg); + break; + case CFG_INT: + *((int *)value) = strtol(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("integer", option[index].name, optarg); + break; + case CFG_BOOL: { + int tmp = strtol(optarg, &endptr, 0); + if (errno || tmp < 0 || tmp > 1 || optarg == endptr) + ret = argconfig_error("0 or 1", option[index].name, optarg); + else + *((int *)value) = tmp; + break; + } + case CFG_BYTE: + ret = argconfig_parse_byte(option[index].name, optarg, (uint8_t *)value); + break; + case CFG_SHORT: { + unsigned long tmp = strtoul(optarg, &endptr, 0); + if (errno || tmp >= 1 << 16 || optarg == endptr) + ret = argconfig_error("short", option[index].name, optarg); + else + *((uint16_t *)value) = tmp; + break; + } + case CFG_POSITIVE: { + uint32_t tmp = strtoul(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("word", option[index].name, optarg); + else + *((uint32_t *)value) = tmp; + break; + } + case CFG_INCREMENT: + *((int *)value) += 1; + break; + case CFG_LONG: + *((unsigned long *)value) = strtoul(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("long integer", option[index].name, optarg); + break; + case CFG_LONG_SUFFIX: + ret = suffix_binary_parse(optarg, &endptr, (uint64_t*)value); + if (ret) + argconfig_error("long suffixed integer", option[index].name, optarg); + break; + case CFG_DOUBLE: + *((double *)value) = strtod(optarg, &endptr); + if (errno || optarg == endptr) + ret = argconfig_error("float", option[index].name, optarg); + break; + case CFG_SUBOPTS: + *opts = END_DEFAULT; + opts += 2; + ret = argconfig_parse_subopt_string(optarg, opts, remaining_space); + if (ret) { + if (ret == 2) + fprintf(stderr, "Error Parsing Sub-Options: Too many options!\n"); + else + fprintf(stderr, "Error Parsing Sub-Options\n"); + ret = -EINVAL; + } + break; + case CFG_FILE_A: + fopts = "a"; + fallthrough; + case CFG_FILE_R: + if (!fopts) + fopts = "r"; + fallthrough; + case CFG_FILE_W: + if (!fopts) + fopts = "w"; + fallthrough; + case CFG_FILE_AP: + if (!fopts) + fopts = "a+"; + fallthrough; + case CFG_FILE_RP: + if (!fopts) + fopts = "r+"; + fallthrough; + case CFG_FILE_WP: + if (!fopts) + fopts = "w+"; + f = fopen(optarg, fopts); + if (!f) { + fprintf(stderr, "Unable to open %s file: %s\n", s->option, optarg); + ret = -EINVAL; + } else { + *((FILE **)value) = f; + } + break; + case CFG_FLAG: + *((bool *)value) = true; + break; + default: + break; + } + + return ret; +} + +bool argconfig_output_format_json(bool set) +{ + static bool output_format_json = false; + + if (set) + output_format_json = true; + + return output_format_json; +} + int argconfig_parse(int argc, char *argv[], const char *program_desc, - const struct argconfig_commandline_options *options) + struct argconfig_commandline_options *options) { char *short_opts; - char *endptr; struct option *long_opts; - const struct argconfig_commandline_options *s; + struct argconfig_commandline_options *s; int c, option_index = 0, short_index = 0, options_count = 0; - void *value_addr; - int ret = -EINVAL; + int ret = 0; errno = 0; - for (s = options; s->option != NULL; s++) + for (s = options; s->option; s++) options_count++; - long_opts = malloc(sizeof(struct option) * (options_count + 2)); - short_opts = malloc(sizeof(*short_opts) * (options_count * 3 + 4)); + long_opts = calloc(1, sizeof(struct option) * (options_count + 3)); + short_opts = calloc(1, sizeof(*short_opts) * (options_count * 3 + 5)); if (!long_opts || !short_opts) { - fprintf(stderr, "failed to allocate memory for opts: %s\n", - strerror(errno)); + fprintf(stderr, "failed to allocate memory for opts: %s\n", strerror(errno)); ret = -errno; goto out; } - for (s = options; (s->option != NULL) && (option_index < options_count); - s++) { - if (s->short_option != 0) { + for (s = options; s->option && option_index < options_count; s++) { + if (s->short_option) { short_opts[short_index++] = s->short_option; if (s->argument_type == required_argument || s->argument_type == optional_argument) @@ -195,35 +329,32 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (s->option && strlen(s->option)) { long_opts[option_index].name = s->option; long_opts[option_index].has_arg = s->argument_type; - long_opts[option_index].flag = NULL; - long_opts[option_index].val = 0; } + s->seen = false; option_index++; } long_opts[option_index].name = "help"; - long_opts[option_index].flag = NULL; - long_opts[option_index].val = 'h'; - option_index++; + long_opts[option_index++].val = 'h'; - long_opts[option_index].name = NULL; - long_opts[option_index].flag = NULL; - long_opts[option_index].val = 0; + long_opts[option_index].name = "json"; + long_opts[option_index].val = 'j'; short_opts[short_index++] = '?'; short_opts[short_index++] = 'h'; - short_opts[short_index] = 0; + short_opts[short_index] = 'j'; optind = 0; - while ((c = getopt_long_only(argc, argv, short_opts, long_opts, - &option_index)) != -1) { - if (c != 0) { + while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &option_index)) != -1) { + if (c) { if (c == '?' || c == 'h') { argconfig_print_help(program_desc, options); - goto out; + ret = -EINVAL; + break; } - for (option_index = 0; option_index < options_count; - option_index++) { + if (c == 'j') + argconfig_output_format_json(true); + for (option_index = 0; option_index < options_count; option_index++) { if (c == options[option_index].short_option) break; } @@ -232,147 +363,16 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, } s = &options[option_index]; - value_addr = (void *)(char *)s->default_value; - if (s->config_type == CFG_STRING) { - *((char **)value_addr) = optarg; - } else if (s->config_type == CFG_SIZE) { - *((size_t *) value_addr) = strtol(optarg, &endptr, 0); - if (errno || optarg == endptr) { - fprintf(stderr, - "Expected integer argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - } else if (s->config_type == CFG_INT) { - *((int *)value_addr) = strtol(optarg, &endptr, 0); - if (errno || optarg == endptr) { - fprintf(stderr, - "Expected integer argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - } else if (s->config_type == CFG_BOOL) { - int tmp = strtol(optarg, &endptr, 0); - if (errno || tmp < 0 || tmp > 1 || optarg == endptr) { - fprintf(stderr, - "Expected 0 or 1 argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - *((int *)value_addr) = tmp; - } else if (s->config_type == CFG_BYTE) { - if (argconfig_parse_byte(long_opts[option_index].name, - optarg, (uint8_t *)value_addr)) - goto out; - } else if (s->config_type == CFG_SHORT) { - unsigned long tmp = strtoul(optarg, &endptr, 0); - if (errno || tmp >= (1 << 16) || optarg == endptr) { - fprintf(stderr, - "Expected short argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - *((uint16_t *) value_addr) = tmp; - } else if (s->config_type == CFG_POSITIVE) { - uint32_t tmp = strtoul(optarg, &endptr, 0); - if (errno || optarg == endptr) { - fprintf(stderr, - "Expected word argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - *((uint32_t *) value_addr) = tmp; - } else if (s->config_type == CFG_INCREMENT) { - *((int *)value_addr) += 1; - } else if (s->config_type == CFG_LONG) { - *((unsigned long *)value_addr) = strtoul(optarg, &endptr, 0); - if (errno || optarg == endptr) { - fprintf(stderr, - "Expected long integer argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - } else if (s->config_type == CFG_LONG_SUFFIX) { - *((uint64_t *)value_addr) = suffix_binary_parse(optarg); - if (errno) { - fprintf(stderr, - "Expected long suffixed integer argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - } else if (s->config_type == CFG_DOUBLE) { - *((double *)value_addr) = strtod(optarg, &endptr); - if (errno || optarg == endptr) { - fprintf(stderr, - "Expected float argument for '%s' but got '%s'!\n", - long_opts[option_index].name, optarg); - goto out; - } - } else if (s->config_type == CFG_SUBOPTS) { - char **opts = ((char **)value_addr); - int remaining_space = CFG_MAX_SUBOPTS; - int enddefault = 0; - int r; - while (0 && *opts != NULL) { - if (*opts == END_DEFAULT) - enddefault = 1; - remaining_space--; - opts++; - } + s->seen = true; - if (!enddefault) { - *opts = END_DEFAULT; - remaining_space -= 2; - opts += 2; - } + if (!s->default_value) + continue; - r = argconfig_parse_subopt_string(optarg, opts, - remaining_space); - if (r == 2) { - fprintf(stderr, - "Error Parsing Sub-Options: Too many options!\n"); - goto out; - } else if (r) { - fprintf(stderr, "Error Parsing Sub-Options\n"); - goto out; - } - } else if (s->config_type == CFG_FILE_A || - s->config_type == CFG_FILE_R || - s->config_type == CFG_FILE_W || - s->config_type == CFG_FILE_AP || - s->config_type == CFG_FILE_RP || - s->config_type == CFG_FILE_WP) { - const char *fopts = ""; - FILE *f; - if (s->config_type == CFG_FILE_A) - fopts = "a"; - else if (s->config_type == CFG_FILE_R) - fopts = "r"; - else if (s->config_type == CFG_FILE_W) - fopts = "w"; - else if (s->config_type == CFG_FILE_AP) - fopts = "a+"; - else if (s->config_type == CFG_FILE_RP) - fopts = "r+"; - else if (s->config_type == CFG_FILE_WP) - fopts = "w+"; - - f = fopen(optarg, fopts); - if (f == NULL) { - fprintf(stderr, "Unable to open %s file: %s\n", - s->option, optarg); - goto out; - } - *((FILE **) value_addr) = f; - } else if (s->config_type == CFG_FLAG) { - *((bool *)value_addr) = true; - } + ret = argconfig_parse_type(s, long_opts,option_index); + if (ret) + break; } - free(short_opts); - free(long_opts); - - return 0; - out: +out: free(short_opts); free(long_opts); return ret; @@ -592,3 +592,14 @@ void argconfig_register_help_func(argconfig_help_func * f) } } } + +bool argconfig_parse_seen(struct argconfig_commandline_options *s, + const char *option) +{ + for (; s && s->option; s++) { + if (!strcmp(s->option, option)) + return s->seen; + } + + return false; +} |