Add RzConfigValidator for validating (on set) owned variables (#6356)
This commit is contained in:
parent
ee3e628c8a
commit
5e7fa12b5a
3 changed files with 106 additions and 7 deletions
|
|
@ -825,6 +825,13 @@ RZ_API RZ_OWN char *rz_config_var_flags_as_string(ut32 flags) {
|
|||
return rz_strbuf_drain_nofree(&sb);
|
||||
}
|
||||
|
||||
static bool config_var_is_valid_value(const RzConfigVar *var, const void *value) {
|
||||
if (!var->value.validator) {
|
||||
return true;
|
||||
}
|
||||
return var->value.validator(var->value.validator_user, value);
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_config_var_set_bool(RzConfigVar *var, bool value) {
|
||||
config_var_assert_return(RZ_CONFIG_VAR_IS_TYPE(var->flags, RZ_CONFIG_VAR_TYPE_BOOL), var->name, false);
|
||||
if (rz_config_var_is_readonly(var)) {
|
||||
|
|
@ -834,6 +841,8 @@ RZ_IPI bool rz_config_var_set_bool(RzConfigVar *var, bool value) {
|
|||
|
||||
if (RZ_CONFIG_VAR_HAS_FLAG(var->flags, RZ_CONFIG_VAR_FLAG_BIND)) {
|
||||
return config_var_bind_set_value(var, &value);
|
||||
} else if (!config_var_is_valid_value(var, &value)) {
|
||||
return false;
|
||||
}
|
||||
var->value.boolean = value;
|
||||
return true;
|
||||
|
|
@ -848,6 +857,8 @@ RZ_IPI bool rz_config_var_set_integer(RzConfigVar *var, ut64 value) {
|
|||
|
||||
if (RZ_CONFIG_VAR_HAS_FLAG(var->flags, RZ_CONFIG_VAR_FLAG_BIND)) {
|
||||
return config_var_bind_set_value(var, &value);
|
||||
} else if (!config_var_is_valid_value(var, &value)) {
|
||||
return false;
|
||||
}
|
||||
var->value.integer = value;
|
||||
return true;
|
||||
|
|
@ -884,6 +895,8 @@ RZ_IPI bool rz_config_var_set_string(RzConfigVar *var, const char *value) {
|
|||
|
||||
if (RZ_CONFIG_VAR_HAS_FLAG(var->flags, RZ_CONFIG_VAR_FLAG_BIND)) {
|
||||
return config_var_bind_set_value(var, value);
|
||||
} else if (!config_var_is_valid_value(var, value)) {
|
||||
return false;
|
||||
}
|
||||
free(var->value.string);
|
||||
var->value.string = rz_str_dup(value);
|
||||
|
|
@ -899,7 +912,10 @@ RZ_IPI bool rz_config_var_set_list(RzConfigVar *var, const RzList /*<const char
|
|||
|
||||
if (RZ_CONFIG_VAR_HAS_FLAG(var->flags, RZ_CONFIG_VAR_FLAG_BIND)) {
|
||||
return config_var_bind_set_value(var, value);
|
||||
} else if (!config_var_is_valid_value(var, value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rz_list_free(var->value.list);
|
||||
var->value.list = rz_config_dup_list(value);
|
||||
return true;
|
||||
|
|
@ -916,6 +932,9 @@ RZ_IPI bool rz_config_var_set_list2(RzConfigVar *var, RZ_OWN RzList /*<char *>*/
|
|||
bool ret = config_var_bind_set_value(var, value);
|
||||
rz_list_free(value);
|
||||
return ret;
|
||||
} else if (!config_var_is_valid_value(var, value)) {
|
||||
rz_list_free(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
rz_list_free(var->value.list);
|
||||
|
|
@ -932,7 +951,10 @@ RZ_IPI bool rz_config_var_set_interval(RzConfigVar *var, RzInterval value) {
|
|||
|
||||
if (RZ_CONFIG_VAR_HAS_FLAG(var->flags, RZ_CONFIG_VAR_FLAG_BIND)) {
|
||||
return config_var_bind_set_value(var, &value);
|
||||
} else if (!config_var_is_valid_value(var, &value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var->value.interval = value;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1563,6 +1585,37 @@ RZ_API bool rz_config_set_options2(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const ch
|
|||
return config_entry_set_options(entry, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets the validator callback for a given RzConfigVar (owned types).
|
||||
*
|
||||
* \param[in] cfg The RzConfig to use
|
||||
* \param[in] name The name of the string type variable to update
|
||||
* \param[in] validator The validator callback to set (can be NULL)
|
||||
*
|
||||
* \return On success returns a true, otherwise false.
|
||||
*/
|
||||
RZ_API bool rz_config_set_validator(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE RzConfigBindSet validator, RZ_NULLABLE void *user) {
|
||||
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), false);
|
||||
RzConfigEntry *entry = config_find_entry(cfg, name);
|
||||
if (!entry) {
|
||||
RZ_LOG_ERROR("config: variable '%s' does not exists.\n", name);
|
||||
return false;
|
||||
} else if (!entry->is_variable) {
|
||||
RZ_LOG_ERROR("config: variable '%s' is not an RzConfigVar.\n", name);
|
||||
return false;
|
||||
} else if (rz_config_var_has_flags(&entry->var, RZ_CONFIG_VAR_FLAG_BIND)) {
|
||||
RZ_LOG_ERROR("config: cannot set validator when variable '%s' is a bind.\n", name);
|
||||
return false;
|
||||
} else if (rz_config_var_get_options(&entry->var)) {
|
||||
RZ_LOG_ERROR("config: cannot set validator for '%s' when options are set.\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
entry->var.value.validator = validator;
|
||||
entry->var.value.validator_user = user;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief DEPRECATED: returns the RzConfigEntry name
|
||||
*
|
||||
|
|
|
|||
|
|
@ -69,6 +69,18 @@ typedef bool (*RzConfigBindGet)(void *user, void *value);
|
|||
typedef bool (*RzConfigBindSet)(void *user, const void *value);
|
||||
typedef bool (*RzConfigBindOpts)(void *user, RzList /*<char *>*/ **options);
|
||||
|
||||
typedef struct rz_config_owned_t {
|
||||
union {
|
||||
bool boolean; ///< Owned boolean
|
||||
ut64 integer; ///< Owned unsigned integer
|
||||
char *string; ///< Owned zero-terminated string (can be NULL)
|
||||
RzList /*<char *>*/ *list; ///< Owned list of zero-terminated string (can be NULL)
|
||||
RzInterval interval; ///< Owned interval
|
||||
};
|
||||
RzConfigBindSet validator; ///< Validator callback
|
||||
void *validator_user; ///< Validator callback user pointer
|
||||
} RzConfigOwned;
|
||||
|
||||
typedef struct rz_config_bind_t {
|
||||
void *user;
|
||||
RzConfigBindGet get_value;
|
||||
|
|
@ -82,13 +94,7 @@ typedef struct rz_config_var_t {
|
|||
RzList /*<char *>*/ *options; ///< Variable possible values
|
||||
ut32 flags; ///< Define the type of the data via RzConfigVar (see RzConfigVarFlags)
|
||||
union {
|
||||
union {
|
||||
bool boolean;
|
||||
ut64 integer;
|
||||
char *string;
|
||||
RzList /*<char *>*/ *list;
|
||||
RzInterval interval;
|
||||
} value; ///< owned value
|
||||
RzConfigOwned value; ///< owned value
|
||||
RzConfigBind bind; ///< bind value
|
||||
};
|
||||
} RzConfigVar;
|
||||
|
|
@ -152,6 +158,7 @@ RZ_API bool rz_config_set_interval3(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const c
|
|||
RZ_API bool rz_config_set_any(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *value);
|
||||
RZ_API bool rz_config_set_options(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE RZ_OWN RzList /*<char *>*/ *options);
|
||||
RZ_API bool rz_config_set_options2(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, ...);
|
||||
RZ_API bool rz_config_set_validator(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE RzConfigBindSet validator, RZ_NULLABLE void *user);
|
||||
|
||||
RZ_API bool rz_config_get_bool(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
|
||||
RZ_API ut64 rz_config_get_integer(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
#include <rz_config.h>
|
||||
#include "minunit.h"
|
||||
|
||||
static bool test_config_validator(void *user, const void *value) {
|
||||
(void)value;
|
||||
return user != NULL;
|
||||
}
|
||||
|
||||
bool test_config_strings() {
|
||||
RzConfig *cfg = rz_config_new(NULL);
|
||||
bool ret = false;
|
||||
|
|
@ -14,6 +19,9 @@ bool test_config_strings() {
|
|||
ret = rz_config_add_string(cfg, "foo.bar", "is foo.bar desc", "bla");
|
||||
mu_assert_true(ret, "added foo.bar");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "foo.bar", test_config_validator, &ret);
|
||||
mu_assert_true(ret, "can set validator when options NOT are set");
|
||||
|
||||
ret = rz_config_is_readonly(cfg, "foo.bar");
|
||||
mu_assert_false(ret, "foo.bar is not readonly");
|
||||
|
||||
|
|
@ -59,6 +67,9 @@ bool test_config_strings() {
|
|||
ret = rz_config_add_options(cfg, "foo.options", "is foo.options desc", "option1", "option2", "option3", "option4", NULL);
|
||||
mu_assert_true(ret, "added foo.options");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "foo.options", test_config_validator, &ret);
|
||||
mu_assert_false(ret, "cannot set validator when options are set");
|
||||
|
||||
bla = rz_config_get_string(cfg, "foo.options");
|
||||
mu_assert_streq(bla, "option1", "options variable 1");
|
||||
|
||||
|
|
@ -96,6 +107,9 @@ bool test_config_intergers() {
|
|||
ret = rz_config_add_integer(cfg, "universe.question", "is universe.question desc", 42);
|
||||
mu_assert_true(ret, "added universe.question");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "universe.question", test_config_validator, &ret);
|
||||
mu_assert_true(ret, "can set validator for int");
|
||||
|
||||
ut64 answer = rz_config_get_integer(cfg, "universe.question");
|
||||
mu_assert_eq(answer, 42, "Integer variable 1");
|
||||
|
||||
|
|
@ -139,6 +153,9 @@ bool test_config_booleans() {
|
|||
ret = rz_config_add_bool(cfg, "true.or.false", "is true.or.false desc", true);
|
||||
mu_assert_true(ret, "added true.or.false");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "true.or.false", test_config_validator, &ret);
|
||||
mu_assert_true(ret, "can set validator for bool");
|
||||
|
||||
bool what = rz_config_get_bool(cfg, "true.or.false");
|
||||
mu_assert_true(what, "Boolean variable");
|
||||
|
||||
|
|
@ -197,6 +214,9 @@ bool test_config_lists() {
|
|||
ret = rz_config_add_list(cfg, "thy.list", "is thy.list desc", "r1", "r2", "r3", NULL);
|
||||
mu_assert_true(ret, "added thy.list");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "thy.list", test_config_validator, &ret);
|
||||
mu_assert_true(ret, "can set validator for list");
|
||||
|
||||
list = rz_config_get_list(cfg, "thy.list");
|
||||
mu_assert_notnull(list, "List is not null variable");
|
||||
mu_assert_eq(rz_list_length(list), 3, "List size is 3");
|
||||
|
|
@ -261,6 +281,9 @@ bool test_config_itv() {
|
|||
ret = rz_config_add_interval(cfg, "this.limit", "is this.limit desc", 0x230, 0x4fff);
|
||||
mu_assert_true(ret, "added this.limit [0x230, 0x4fff]");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "this.limit", test_config_validator, &ret);
|
||||
mu_assert_true(ret, "can set validator for itv");
|
||||
|
||||
itv = rz_config_get_interval(cfg, "this.limit");
|
||||
mu_assert_eq(rz_itv_begin(itv), 0x230, "interval starts at 0x230 (inclusive)");
|
||||
mu_assert_eq(rz_itv_end(itv), 0x4fff, "interval ends at 0x4fff (inclusive)");
|
||||
|
|
@ -340,6 +363,7 @@ bool test_config_invalid() {
|
|||
mu_assert_null(rz_config_get_list(cfg, "list.here"), "list.here does not exist");
|
||||
mu_assert_eq(rz_config_get_integer(cfg, "int.here"), 0, "int.here does not exist");
|
||||
mu_assert_false(rz_config_get_bool(cfg, "bool.here"), "bool.here does not exist");
|
||||
mu_assert_false(rz_config_set_validator(cfg, "self.validator", test_config_validator, &itv), "self.validator does not exist");
|
||||
itv = rz_config_get_interval(cfg, "itv.here");
|
||||
mu_assert_eq(rz_itv_begin(itv), 0, "itv.here does not exist (addr = 0)");
|
||||
mu_assert_eq(rz_itv_size(itv), 0, "itv.here does not exist (size = 0)");
|
||||
|
|
@ -462,22 +486,37 @@ bool test_config_binds() {
|
|||
ret = rz_config_add_bool_bind(cfg, "bind.bool", "is bind.bool desc", any_get, any_set, any_opts, &bt);
|
||||
mu_assert_true(ret, "added bind.bool");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "bind.bool", test_config_validator, &ret);
|
||||
mu_assert_false(ret, "cannot set validator when bind");
|
||||
|
||||
bt.bind = RZ_CONFIG_VAR_TYPE_INT;
|
||||
ret = rz_config_add_integer_bind(cfg, "bind.integer", "is bind.integer desc", any_get, any_set, any_opts, &bt);
|
||||
mu_assert_true(ret, "added bind.integer");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "bind.integer", test_config_validator, &ret);
|
||||
mu_assert_false(ret, "cannot set validator when bind");
|
||||
|
||||
bt.bind = RZ_CONFIG_VAR_TYPE_STR;
|
||||
ret = rz_config_add_string_bind(cfg, "bind.string", "is bind.string desc", any_get, any_set, any_opts, &bt);
|
||||
mu_assert_true(ret, "added bind.string");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "bind.string", test_config_validator, &ret);
|
||||
mu_assert_false(ret, "cannot set validator when bind");
|
||||
|
||||
bt.bind = RZ_CONFIG_VAR_TYPE_LIST;
|
||||
ret = rz_config_add_list_bind(cfg, "bind.list", "is bind.list desc", any_get, any_set, any_opts, &bt);
|
||||
mu_assert_true(ret, "added bind.list");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "bind.list", test_config_validator, &ret);
|
||||
mu_assert_false(ret, "cannot set validator when bind");
|
||||
|
||||
bt.bind = RZ_CONFIG_VAR_TYPE_ITV;
|
||||
ret = rz_config_add_interval_bind(cfg, "bind.interval", "is bind.interval desc", any_get, any_set, any_opts, &bt);
|
||||
mu_assert_true(ret, "added bind.interval");
|
||||
|
||||
ret = rz_config_set_validator(cfg, "bind.interval", test_config_validator, &ret);
|
||||
mu_assert_false(ret, "cannot set validator when bind");
|
||||
|
||||
bt.bind = RZ_CONFIG_VAR_TYPE_BOOL;
|
||||
mu_assert_true(rz_config_get_bool(cfg, "bind.bool"), "get bind.bool");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue