#include "opts.h" #include "version.h" #include "util/opts/log.h" #include #include #include #define OPT_LENGTH 30 const char *opt_value_to_string(const option_value_t *values, int value, const char *def) { for (int i = 0; values[i].name; i++) { if (values[i].value == value) { return values[i].name; } } return def; } int opt_string_to_value(const option_value_t *values, const char *name, int def) { for (int i = 0; values[i].name; i++) { if (!strcmp(values[i].name, name)) { return values[i].value; } } return def; } static void print_version(const char *cmd) { printf("%s (%s)\n", GIT_VERSION, GIT_REVISION); } static void print_help(option_t *options, const char *cmd) { printf("Usage:\n"); printf("$ %s \n", cmd); printf("\n"); printf("Options:\n"); for (int i = 0; options[i].name; i++) { option_t *option = &options[i]; int len = 0; len += printf(" --%s", option->name); if (option->default_value) { len += printf("[=%s]", option->default_value); } else if (option->value_mapping) { len += printf("=arg"); } else { len += printf("=%s", option->format); } if (len < OPT_LENGTH) { printf("%*s", OPT_LENGTH-len, " "); } printf("- %s", option->description); if (option->value_mapping) { printf(" Values: "); for (int j = 0; option->value_mapping[j].name; j++) { if (j > 0) printf(", "); printf("%s", option->value_mapping[j].name); } printf("."); } printf("\n"); } printf("\n"); printf("Command line:\n\n"); printf("$ %s \\\n", cmd); for (int i = 0; options[i].name; i++) { option_t *option = &options[i]; int len = 0; if (option->value_list) { char *string = option->value_list; char *token; if (!*string) continue; while ((token = strsep(&string, OPTION_VALUE_LIST_SEP)) != NULL) { len = printf(" --%s=", option->name); printf("%s \\\n", token); } } else if (option->value_string) { len += printf(" --%s=", option->name); printf(option->format, option->value_string); printf(" \\\n"); } else { bool found = false; len += printf(" --%s=", option->name); if (option->value_mapping) { const char *name = opt_value_to_string(option->value_mapping, *option->value_uint, NULL); if (name) { len += printf("%s", name); found = true; } } if (!found) { unsigned mask = UINT_MAX >> ((sizeof(*option->value_uint) - option->size) * 8); printf(option->format, *option->value_uint & mask); } printf(" \\\n"); } } printf("\n"); } static int parse_opt(option_t *options, const char *key, int dash) { option_t *option = NULL; const char *value = strchr(key, '='); for (int i = 0; options[i].name; i++) { if (value) { if (!strncmp(key, options[i].name, value - key)) { option = &options[i]; value++; // ignore '=' break; } } else { // require exact match if (!strcmp(key, options[i].name)) { option = &options[i]; value = option->default_value; break; } } } if (dash == 2 && strlen(key) == 1) { LOG_INFO(NULL, "Usage of '--%s' is deprecated change to '-%s'.", key, key); } else if (dash == 1 && strlen(key) > 1) { LOG_INFO(NULL, "Usage of '-%s' is deprecated change to '--%s'.", key, key); } LOG_DEBUG(NULL, "Parsing '%s'. Got value='%s', and option='%s'", key, value, option ? option->name : NULL); if (!option || !value) { return -EINVAL; } int ret = 0; if (option->value_list) { char *ptr = option->value_list; if (*ptr) { strcat(ptr, OPTION_VALUE_LIST_SEP); ptr += strlen(ptr); } ret = sscanf(value, option->format, ptr); } else if (option->value_string) { ret = sscanf(value, option->format, option->value_string); } else if (option->value_mapping) { int ret = opt_string_to_value(option->value_mapping, value, -1); if (ret != -1) { *option->value_uint = ret; return 1; } ret = sscanf(value, option->format, option->value); } else { ret = sscanf(value, option->format, option->value); } return ret; } int parse_opts(option_t *options, int argc, char *argv[]) { int arg; for (arg = 1; arg < argc; arg++) { const char *key = argv[arg]; if (key[0] == '-') { key++; if (key[0] == '-') { key++; } } else { LOG_ERROR(NULL, "The '%s' is not option (should start with - or --).", key); } if (!strcmp(key, "help")) { print_help(options, argv[0]); exit(-1); return -1; } if (!strcmp(key, "version")) { print_version(argv[0]); exit(0); return 0; } int ret = parse_opt(options, key, key - argv[arg]); if (ret <= 0) { LOG_ERROR(NULL, "Parsing '%s' returned '%d'.", argv[arg], ret); } } return 0; error: return -1; }