diff --git a/VERSION b/VERSION index be11103a..f0948e10 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -a12-180-g51ddb62126+1 \ No newline at end of file +a12-181-g5b199d8f25+1 \ No newline at end of file diff --git a/common/include/common/option.h b/common/include/common/option.h index 96c08218..fe6abc6d 100644 --- a/common/include/common/option.h +++ b/common/include/common/option.h @@ -25,45 +25,42 @@ enum OptionType OPTION_TYPE_NONE = 0, OPTION_TYPE_INT, OPTION_TYPE_STRING, - OPTION_TYPE_BOOL + OPTION_TYPE_BOOL, + OPTION_TYPE_CUSTOM }; -struct OptionState; - -struct OptionValue -{ - enum OptionType type; - union - { - int x_int; - char * x_string; - bool x_bool; - } - v; - - // internal state - struct OptionState * state; -}; +struct Option; struct Option { const char * module; const char * name; const char * description; - struct OptionValue value; - bool (*validator)(struct OptionValue * value, const char ** error); - void (*printHelp)(); + enum OptionType type; + union + { + int x_int; + char * x_string; + bool x_bool; + void * x_custom; + } + value; + + bool (*parser )(struct Option * opt, const char * str); + bool (*validator)(struct Option * opt, const char ** error); + char * (*toString )(struct Option * opt); + void (*printHelp)(); }; // register an NULL terminated array of options bool option_register(struct Option options[]); // lookup the value of an option -struct OptionValue * option_get (const char * module, const char * name); -int option_get_int (const char * module, const char * name); -const char * option_get_string(const char * module, const char * name); -bool option_get_bool (const char * module, const char * name); +struct Option * option_get (const char * module, const char * name); +int option_get_int (const char * module, const char * name); +const char * option_get_string(const char * module, const char * name); +bool option_get_bool (const char * module, const char * name); // called by the main application to parse the command line arguments bool option_parse(int argc, char * argv[]); diff --git a/common/src/option.c b/common/src/option.c index 6e93ae25..12ad0628 100644 --- a/common/src/option.c +++ b/common/src/option.c @@ -52,10 +52,51 @@ static struct State state = .gCount = 0 }; +static bool int_parser(struct Option * opt, const char * str) +{ + opt->value.x_int = atol(str); + return true; +} + +static bool bool_parser(struct Option * opt, const char * str) +{ + opt->value.x_bool = + strcmp(str, "1" ) == 0 || + strcmp(str, "on" ) == 0 || + strcmp(str, "yes" ) == 0 || + strcmp(str, "true") == 0; + return true; +} + +static bool string_parser(struct Option * opt, const char * str) +{ + free(opt->value.x_string); + opt->value.x_string = strdup(str); + return true; +} + +static char * int_toString(struct Option * opt) +{ + int len = snprintf(NULL, 0, "%d", opt->value.x_int); + char * ret = malloc(len + 1); + sprintf(ret, "%d", opt->value.x_int); + return ret; +} + +static char * bool_toString(struct Option * opt) +{ + return strdup(opt->value.x_bool ? "yes" : "no"); +} + +static char * string_toString(struct Option * opt) +{ + return strdup(opt->value.x_string); +} + bool option_register(struct Option options[]) { int new = 0; - for(int i = 0; options[i].value.type != OPTION_TYPE_NONE; ++i) + for(int i = 0; options[i].type != OPTION_TYPE_NONE; ++i) ++new; state.options = realloc( @@ -63,14 +104,58 @@ bool option_register(struct Option options[]) sizeof(struct Option) * (state.oCount + new) ); - for(int i = 0; options[i].value.type != OPTION_TYPE_NONE; ++i) + for(int i = 0; options[i].type != OPTION_TYPE_NONE; ++i) { struct Option * o = &state.options[state.oCount + i]; memcpy(o, &options[i], sizeof(struct Option)); + if (!o->parser) + { + switch(o->type) + { + case OPTION_TYPE_INT: + o->parser = int_parser; + break; + + case OPTION_TYPE_STRING: + o->parser = string_parser; + break; + + case OPTION_TYPE_BOOL: + o->parser = bool_parser; + break; + + default: + DEBUG_ERROR("BUG: Non int/string/bool option types must have a parser"); + continue; + } + } + + if (!o->toString) + { + switch(o->type) + { + case OPTION_TYPE_INT: + o->toString = int_toString; + break; + + case OPTION_TYPE_STRING: + o->toString = string_toString; + break; + + case OPTION_TYPE_BOOL: + o->toString = bool_toString; + break; + + default: + DEBUG_ERROR("BUG: Non int/string/bool option types must implement toString"); + continue; + } + } + // ensure the string is locally allocated - if (o->value.type == OPTION_TYPE_STRING) - o->value.v.x_string = strdup(o->value.v.x_string); + if (o->type == OPTION_TYPE_STRING) + o->value.x_string = strdup(o->value.x_string); // add the option to the correct group for help printout bool found = false; @@ -121,8 +206,8 @@ void option_free() for(int i = 0; i < state.oCount; ++i) { struct Option * o = &state.options[i]; - if (o->value.type == OPTION_TYPE_STRING) - free(o->value.v.x_string); + if (o->type == OPTION_TYPE_STRING) + free(o->value.x_string); } free(state.options); state.options = NULL; @@ -133,33 +218,9 @@ void option_free() state.gCount = 0; } -static bool option_set(struct OptionValue * v, const char * value) +static bool option_set(struct Option * opt, const char * value) { - switch(v->type) - { - case OPTION_TYPE_INT: - v->v.x_int = atol(value); - break; - - case OPTION_TYPE_STRING: - free(v->v.x_string); - v->v.x_string = strdup(value); - break; - - case OPTION_TYPE_BOOL: - v->v.x_bool = - strcmp(value, "1" ) == 0 || - strcmp(value, "yes" ) == 0 || - strcmp(value, "true") == 0 || - strcmp(value, "on" ) == 0; - break; - - default: - DEBUG_ERROR("BUG: Invalid option type, this should never happen"); - return false; - } - - return true; + return opt->parser(opt, value); } bool option_parse(int argc, char * argv[]) @@ -203,7 +264,7 @@ bool option_parse(int argc, char * argv[]) continue; } - if (!option_set(&o->value, value)) + if (!option_set(o, value)) { DEBUG_ERROR("Failed to set the option value"); free(arg); @@ -306,7 +367,7 @@ bool option_load(const char * filename) case '\n': if (name) { - struct OptionValue * o = option_get(module, name); + struct Option * o = option_get(module, name); if (!o) DEBUG_WARN("Ignored unknown option %s:%s", module, name); else @@ -396,7 +457,7 @@ bool option_validate() struct Option * o = &state.options[i]; const char * error = NULL; if (o->validator) - if (!o->validator(&o->value, &error)) + if (!o->validator(o, &error)) { printf("\nInvalid value provided to the option: %s:%s\n", o->module, o->name); @@ -430,66 +491,48 @@ void option_print() for(int i = 0; i < state.groups[g].count; ++i) { struct Option * o = state.groups[g].options[i]; - printf(" %s:%-*s - %s [", o->module, state.groups[g].pad, o->name, o->description); - - switch(o->value.type) - { - case OPTION_TYPE_INT: - printf("%d]\n", o->value.v.x_int); - break; - - case OPTION_TYPE_STRING: - printf("%s]\n", o->value.v.x_string); - break; - - case OPTION_TYPE_BOOL: - printf("%s]\n", o->value.v.x_bool ? "yes" : "no"); - break; - - default: - DEBUG_ERROR("BUG: Invalid option type, this should never happen"); - assert(false); - break; - } + char * value = o->toString(o); + printf(" %s:%-*s - %s [%s]\n", o->module, state.groups[g].pad, o->name, o->description, value); + free(value); } printf("\n"); } } -struct OptionValue * option_get(const char * module, const char * name) +struct Option * option_get(const char * module, const char * name) { for(int i = 0; i < state.oCount; ++i) { struct Option * o = &state.options[i]; if ((strcmp(o->module, module) == 0) && (strcmp(o->name, name) == 0)) - return &o->value; + return o; } return NULL; } int option_get_int(const char * module, const char * name) { - struct OptionValue * o = option_get(module, name); + struct Option * o = option_get(module, name); if (!o) return -1; assert(o->type == OPTION_TYPE_INT); - return o->v.x_int; + return o->value.x_int; } const char * option_get_string(const char * module, const char * name) { - struct OptionValue * o = option_get(module, name); + struct Option * o = option_get(module, name); if (!o) return NULL; assert(o->type == OPTION_TYPE_STRING); - return o->v.x_string; + return o->value.x_string; } bool option_get_bool(const char * module, const char * name) { - struct OptionValue * o = option_get(module, name); + struct Option * o = option_get(module, name); if (!o) return false; assert(o->type == OPTION_TYPE_BOOL); - return o->v.x_bool; + return o->value.x_bool; } \ No newline at end of file