Add new implementation of RzConfig (#5820)

This commit is contained in:
Giovanni 2026-05-03 15:34:48 +08:00 committed by GitHub
parent d3a97d5ef8
commit bd44250fd6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 3853 additions and 1321 deletions

View file

@ -141,54 +141,46 @@ static struct {
};
int disass_6502(ut64 pc, RzAsmOp *op, const ut8 *buf, ut64 len) {
int i;
for (i = 0; ops[i].name != NULL; i++) {
if (ops[i].op == buf[0]) {
int len = ops[i].len;
switch (ops[i].len) {
case 1:
rz_asm_op_setf_asm(op, "%s", ops[i].name);
break;
case 2:
if (len > 1) {
rz_asm_op_setf_asm(op, ops[i].name, buf[1]);
} else {
rz_asm_op_set_asm(op, "truncated");
len = -1;
}
break;
case 3:
if (len > 2) {
rz_asm_op_setf_asm(op, ops[i].name, buf[1] + 0x100 * buf[2]);
} else {
rz_asm_op_set_asm(op, "truncated");
len = -1;
}
break;
case 4:
if (len > 3) {
rz_asm_op_setf_asm(op, ops[i].name, buf[1] + 0x100 * buf[2] + 0x10000 * buf[3]);
} else {
rz_asm_op_set_asm(op, "truncated");
len = -1;
}
break;
default:
rz_asm_op_set_asm(op, "invalid");
goto beach;
}
return len;
for (size_t i = 0; ops[i].name != NULL; i++) {
if (ops[i].op != buf[0]) {
continue;
}
int len = ops[i].len;
switch (len) {
case 1:
rz_asm_op_set_asm(op, ops[i].name);
break;
case 2:
if (len > 1) {
rz_asm_op_setf_asm(op, ops[i].name, buf[1]);
} else {
rz_asm_op_set_asm(op, "truncated");
len = -1;
}
break;
case 3:
if (len > 2) {
rz_asm_op_setf_asm(op, ops[i].name, buf[1] + 0x100 * buf[2]);
} else {
rz_asm_op_set_asm(op, "truncated");
len = -1;
}
break;
case 4:
if (len > 3) {
rz_asm_op_setf_asm(op, ops[i].name, buf[1] + 0x100 * buf[2] + 0x10000 * buf[3]);
} else {
rz_asm_op_set_asm(op, "truncated");
len = -1;
}
break;
default:
rz_asm_op_set_asm(op, "invalid");
goto beach;
}
return len;
}
beach:
return snesDisass(1, 1, pc, op, buf, len);
}
_6502State *_6502_state_new() {
_6502State *state = RZ_NEW0(_6502State);
if (!state) {
RZ_LOG_ERROR("Could not allocate memory for _6502State!");
return NULL;
}
return state;
}

View file

@ -5,10 +5,9 @@
#define DISASSEMBLE_6502_H
typedef struct {
RzConfig *cfg;
ut8 magic;
} _6502State;
_6502State *_6502_state_new();
int disass_6502(ut64 pc, RzAsmOp *op, const ut8 *buf, ut64 len);
#endif /* DISASSEMBLE_6502_H */

View file

@ -266,10 +266,14 @@ typedef struct {
bool just_init; ///< Flag indicates if IL VM was just initialized.
HexPkt pkts[HEXAGON_STATE_PKTS]; // buffered instructions
RzList /*<HexConstExt *>*/ *const_ext_l; // Constant extender values.
RzConfig *cfg;
RzPVector /*<RzAsmTokenPattern *>*/ *token_patterns; ///< PVector with token patterns. Priority ordered.
bool utf8_enabled; ///< If set, print UTF-8 characters.
bool might_have_jumped; ///< Is set if a previous IL packet was a branch. Indicates the next decoded packet is valid.
bool imm_hash; ///< Display ## before 32bit immediates and # before immidiates with other width.
bool imm_sign; ///< True: Print them with sign. False: Print signed immediates in unsigned representation.
bool sdk; ///< Print packet syntax in objdump style.
bool reg_alias; ///< Print the alias of registers (Alias from C0 = SA0).
} HexState;
/**

View file

@ -27,7 +27,6 @@ RZ_IPI void hexagon_state_fini(RZ_NULLABLE HexState *state) {
if (!state) {
return;
}
rz_config_free(state->cfg);
rz_pvector_free(state->token_patterns);
rz_list_free(state->const_ext_l);
for (size_t i = 0; i < HEXAGON_STATE_PKTS; ++i) {
@ -537,7 +536,7 @@ static void hex_set_pkt_info(RZ_INOUT HexInsnContainer *hic, const HexPkt *pkt,
rz_return_if_fail(hic && pkt && state);
bool is_first = (k == 0);
HexPktInfo *hi_pi = &hic->pkt_info;
bool sdk_form = rz_config_get_b(state->cfg, "plugins.hexagon.sdk");
bool sdk_form = state->sdk;
strncpy(hi_pi->text_postfix, "", 16);
// Parse instr. position in pkt

View file

@ -36562,9 +36562,9 @@ static int get_jmp_target_imm_op_index(const HexInsnTemplate *tpl) {
}
static void hex_disasm_with_templates(const HexInsnTemplate *tpl, HexState *state, ut32 hi_u32, RZ_INOUT HexInsn *hi, HexInsnContainer *hic, ut64 addr, HexPkt *pkt) {
bool print_reg_alias = rz_config_get_b(state->cfg, "plugins.hexagon.reg.alias");
bool show_hash = rz_config_get_b(state->cfg, "plugins.hexagon.imm.hash");
bool sign_nums = rz_config_get_b(state->cfg, "plugins.hexagon.imm.sign");
bool print_reg_alias = state->reg_alias;
bool show_hash = state->imm_hash;
bool sign_nums = state->imm_sign;
char signed_imm[HEX_MAX_OPERANDS][32];
// Find the right template
for (; tpl->id; tpl++) {

View file

@ -439,6 +439,7 @@ static int _6502_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8
_6502ILAddr il_addr = { 0 };
_6502ILAddr *il_addr_ptr = (mask & RZ_ANALYSIS_OP_MASK_IL) ? &il_addr : NULL;
_6502State *cfg_state = (_6502State *)analysis->plugin_data;
ut8 magic = cfg_state ? cfg_state->magic : 0xee;
switch (data[0]) {
// SLO
@ -838,12 +839,8 @@ static int _6502_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8
op->cycles = 2;
op->size = 2;
if (mask & RZ_ANALYSIS_OP_MASK_IL) {
ut8 magic = 0xee;
_6502ILAddr addr;
_6502_il_immediate(&addr, data[1]);
if (cfg_state && cfg_state->cfg) {
magic = (ut8)rz_config_get_i(cfg_state->cfg, "plugins.6502.magic");
}
op->il_op = _6502_il_op_laximm(&addr, magic);
}
break;
@ -1132,12 +1129,8 @@ static int _6502_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8
op->size = 2;
op->cycles = 2;
if (mask & RZ_ANALYSIS_OP_MASK_IL) {
ut8 magic = 0xee;
_6502ILAddr addr;
_6502_il_immediate(&addr, data[1]);
if (cfg_state && cfg_state->cfg) {
magic = (ut8)rz_config_get_i(cfg_state->cfg, "plugins.6502.magic");
}
op->il_op = _6502_il_op_ane(&addr, magic);
}
break;

View file

@ -15,52 +15,57 @@ static int _6520_disassemble(const RzAsm *a, RzAsmOp *op, const ut8 *buf, int le
return op->size = RZ_MAX(dlen, 0);
}
RzConfig *_6502_get_config(void *plugin_data) {
rz_return_val_if_fail(plugin_data, NULL);
_6502State *state = (_6502State *)plugin_data;
return rz_config_clone(state->cfg);
static bool _6520_config_magic_get(void *user, void *data) {
ut64 *value = data;
_6502State *state = user;
if (!state) {
return false;
}
*value = state->magic;
return true;
}
static bool _6502_cfg_set(void *user, void *data) {
rz_return_val_if_fail(user && data, false);
static bool _6520_config_magic_set(void *user, const void *data) {
const ut64 *value = data;
_6502State *state = user;
RzConfig *pcfg = state->cfg;
if (!state) {
return false;
}
state->magic = *value;
return true;
}
RzConfigNode *cnode = (RzConfigNode *)data; // Config node from core.
RzConfigNode *pnode = rz_config_node_get(pcfg, cnode->name); // Config node of plugin.
if (pnode == cnode) {
return true;
static RzConfig *_6502_get_config(void *plugin_data) {
rz_return_val_if_fail(plugin_data, NULL);
_6502State *state = (_6502State *)plugin_data;
RzConfig *cfg = rz_config_new(NULL);
if (!cfg) {
return NULL;
}
if (cnode) {
pnode->i_value = cnode->i_value;
free(pnode->value);
pnode->value = rz_str_dup(cnode->value);
return true;
}
return false;
// Add nodes
rz_config_add_integer_bind(cfg,
"plugins.6502.magic",
"Determines the magic number certain illegal opcodes use.",
_6520_config_magic_get,
_6520_config_magic_set,
NULL, state);
return cfg;
}
static bool _6502_init(void **user) {
_6502State *state = _6502_state_new();
rz_return_val_if_fail(state, false);
RzConfig *cfg = state->cfg = rz_config_new(state);
rz_return_val_if_fail(state->cfg, false);
SETICB("plugins.6502.magic", 0xee, &_6502_cfg_set, "Determines the magic number certain illegal opcodes use.");
_6502State *state = RZ_NEW0(_6502State);
if (!state) {
return false;
}
state->magic = 0xee;
*user = state;
return true;
}
void _6502State_fini(_6502State *state) {
if (!state) {
return;
}
rz_config_free(state->cfg);
return;
}
static bool _6502_fini(void *user) {
_6502State_fini(user);
free(user);
return true;
}

View file

@ -85,53 +85,51 @@ static RZ_OWN RzPVector /*<RzAsmTokenPattern *>*/ *get_token_patterns() {
return pvec;
}
/**
* \brief Setter for the plugins RzConfig nodes.
*
* \param user The user of the RzConfig node. If this callback is called by Core \p user = RzCore.
* If it is called by the plugins config setup \p user = HexState.
* \param data The node to set. Again, if called by RzCore \p date = Node from RzCore config.
* If it is called by the plugins config setup \p data = a plugins config node.
* \return bool True if the config was set. False otherwise.
*/
static bool hex_cfg_set(void *user, void *data) {
rz_return_val_if_fail(user && data, false);
HexState *state = user;
RzConfig *pcfg = state->cfg;
RzConfigNode *cnode = (RzConfigNode *)data; // Config node from core.
RzConfigNode *pnode = rz_config_node_get(pcfg, cnode->name); // Config node of plugin.
if (pnode == cnode) {
return true;
}
if (cnode) {
pnode->i_value = cnode->i_value;
free(pnode->value);
pnode->value = rz_str_dup(cnode->value);
return true;
}
return false;
}
static bool hexagon_fini(void *user) {
hexagon_state_fini(user);
free(user);
return true;
}
#define hexagon_getter_config(name, variable) \
static bool hexagon_##name(void *user, void *data) { \
bool *value = data; \
HexState *state = user; \
if (!state) { \
return false; \
} \
*value = state->variable; \
return true; \
}
#define hexagon_setter_config(name, variable) \
static bool hexagon_##name(void *user, const void *data) { \
const bool *value = data; \
HexState *state = user; \
if (!state) { \
return false; \
} \
state->variable = *value; \
return true; \
}
#define hexagon_config_callbacks(variable) \
hexagon_setter_config(config_##variable##_set, variable); \
hexagon_getter_config(config_##variable##_get, variable)
hexagon_config_callbacks(imm_hash);
hexagon_config_callbacks(imm_sign);
hexagon_config_callbacks(sdk);
hexagon_config_callbacks(reg_alias);
static bool hexagon_init(void **plugin_data) {
HexState *state = hexagon_state_new();
rz_return_val_if_fail(state, false);
state->cfg = rz_config_new(state);
rz_return_val_if_fail(state->cfg, false);
RzConfig *cfg = state->cfg; // Rename for SETCB macros.
// Add nodes
SETCB("plugins.hexagon.imm.hash", "true", &hex_cfg_set, "Display ## before 32bit immediates and # before immidiates with other width.");
SETCB("plugins.hexagon.imm.sign", "true", &hex_cfg_set, "True: Print them with sign. False: Print signed immediates in unsigned representation.");
SETCB("plugins.hexagon.sdk", "false", &hex_cfg_set, "Print packet syntax in objdump style.");
SETCB("plugins.hexagon.reg.alias", "true", &hex_cfg_set, "Print the alias of registers (Alias from C0 = SA0).");
state->imm_hash = true;
state->imm_sign = true;
state->sdk = false;
state->reg_alias = true;
if (!state->token_patterns) {
state->token_patterns = get_token_patterns();
@ -145,7 +143,35 @@ static bool hexagon_init(void **plugin_data) {
RZ_API RZ_OWN RzConfig *hexagon_get_config(void *plugin_data) {
rz_return_val_if_fail(plugin_data, NULL);
HexState *state = plugin_data;
return rz_config_clone(state->cfg);
RzConfig *cfg = rz_config_new(NULL);
if (!cfg) {
return NULL;
}
// Add nodes
rz_config_add_bool_bind(cfg, "plugins.hexagon.imm.hash",
"Display ## before 32bit immediates and # before immidiates with other width.",
hexagon_config_imm_hash_get,
hexagon_config_imm_hash_set,
NULL, state);
rz_config_add_bool_bind(cfg, "plugins.hexagon.imm.sign",
"True: Print them with sign. False: Print signed immediates in unsigned representation.",
hexagon_config_imm_sign_get,
hexagon_config_imm_sign_set,
NULL, state);
rz_config_add_bool_bind(cfg, "plugins.hexagon.sdk",
"Print packet syntax in objdump style.",
hexagon_config_sdk_get,
hexagon_config_sdk_set,
NULL, state);
rz_config_add_bool_bind(cfg, "plugins.hexagon.reg.alias",
"Print the alias of registers (Alias from C0 = SA0).",
hexagon_config_reg_alias_get,
hexagon_config_reg_alias_set,
NULL, state);
return cfg;
}
/**

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,76 @@
// SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef CONFIG_INTERNAL_H
#define CONFIG_INTERNAL_H
#include <rz_config.h>
#include <rz_util.h>
#include <rz_vector.h>
typedef struct config_value_t {
const char *name; ///< Variable name
ut32 flags; ///< Copy of the variable flags (see RzConfigVarFlags)
union {
char *string;
ut64 integer;
bool boolean;
RzList /*<char *>*/ *list;
RzInterval interval;
} value; ///< Copy of the variable value
} ConfigValue;
struct rz_config_hold_t {
RzConfig *cfg;
RzVector /*<ConfigValue>*/ variables;
};
static int find_variable(const char *a_name, const RzConfigEntry *b, void *user) {
const char *b_name = rz_config_entry_get_name(b);
return strcmp(a_name, b_name);
}
static inline RzConfigEntry *config_find_entry(RzConfig *cfg, const char *name) {
size_t length = rz_vector_len(&cfg->sorted_vars);
size_t index = rz_vector_find_sorted(&cfg->sorted_vars, (void *)name, (RzVectorComparator)find_variable, NULL);
if (index >= length) {
return NULL;
}
return rz_vector_index_ptr(&cfg->sorted_vars, index);
}
#define config_find_entry_ro(cfg, name) ((const RzConfigEntry *)config_find_entry((RzConfig *)cfg, name))
static int sort_variables(const RzConfigEntry *a, const RzConfigEntry *b, void *user) {
const char *a_name = rz_config_entry_get_name(a);
const char *b_name = rz_config_entry_get_name(b);
return strcmp(a_name, b_name);
}
static inline void config_add_entry(RzConfig *cfg, const char *name, RzConfigEntry *entry, bool is_var) {
entry->is_variable = is_var;
rz_vector_insert_sorted(&cfg->sorted_vars, entry, (RzVectorComparator)sort_variables, NULL);
}
RZ_IPI RZ_OWN RzList /*<char *>*/ *rz_config_dup_list(RZ_NULLABLE const RzList /*<const char *>*/ *list);
RZ_IPI bool rz_config_var_set_bool(RzConfigVar *var, bool value);
RZ_IPI bool rz_config_var_set_integer(RzConfigVar *var, ut64 value);
RZ_IPI bool rz_config_var_set_string(RzConfigVar *var, const char *value);
RZ_IPI bool rz_config_var_set_list(RzConfigVar *var, const RzList /*<const char *>*/ *value);
RZ_IPI bool rz_config_var_set_list2(RzConfigVar *var, RZ_OWN RzList /*<char *>*/ *value);
RZ_IPI bool rz_config_var_set_interval(RzConfigVar *var, RzInterval value);
RZ_IPI bool rz_config_var_set_any(RzConfigVar *var, const char *value);
RZ_IPI bool rz_config_toggle_var_bool(RzConfigVar *var);
/* old implementation */
RZ_IPI void rz_config_node_fini(RZ_NULLABLE RzConfigNode *node);
RZ_IPI bool rz_config_node_is_readonly(const RzConfigNode *node);
RZ_IPI bool rz_config_node_set_readonly(RzConfigNode *node, bool read_only);
RZ_IPI bool rz_config_node_set_string(RzConfigNode *node, const char *value, void *user);
RZ_IPI bool rz_config_node_set_integer(RzConfigNode *node, ut64 i, void *user);
RZ_IPI bool rz_config_node_set_bool(RzConfigNode *node, bool value, void *user);
#endif /* CONFIG_INTERNAL_H */

View file

@ -1,110 +1,112 @@
// SPDX-FileCopyrightText: 2006-2021 pancake <pancake@nopcode.org>
// SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_config.h>
#include "config_internal.h"
static void rz_config_hold_char_free(RzConfigHoldChar *hc) {
free(hc->key);
free(hc->value);
free(hc);
static RzList /*<char *>*/ *config_hold_dup_safe_list(RzConfigVar *var) {
// we do not know if the strings returned are
// safe or not to be owned, so we just dup them
RzList /*<const char *>*/ *list = rz_config_var_get_list(var);
RzList *safe_list = rz_config_dup_list(list);
rz_list_free(list);
return safe_list;
}
static void rz_config_hold_num_free(RzConfigHoldNum *hc) {
free(hc->key);
free(hc);
static void config_hold_value_init_from_node(ConfigValue *cv, RzConfigNode *node) {
cv->name = node->name;
if (rz_config_node_is_bool(node)) {
cv->flags = RZ_CONFIG_VAR_TYPE_BOOL;
cv->value.boolean = rz_str_is_true(node->value);
return;
} else if (rz_config_node_is_int(node)) {
cv->flags = RZ_CONFIG_VAR_TYPE_INT;
cv->value.integer = node->i_value;
return;
}
cv->flags = RZ_CONFIG_VAR_TYPE_STR;
cv->value.string = rz_str_dup(node->value);
}
static int key_cmp_hold_s(const void *a, const void *b, void *user) {
const char *a_s = (const char *)a;
const RzConfigHoldChar *b_s = (const RzConfigHoldChar *)b;
return strcmp(a_s, b_s->key);
static void config_hold_value_init_from_var(ConfigValue *cv, RzConfigVar *var) {
cv->name = var->name;
cv->flags = var->flags & RZ_CONFIG_VAR_TYPE_MASK;
if (RZ_CONFIG_VAR_IS_TYPE(var->flags, RZ_CONFIG_VAR_TYPE_BOOL)) {
cv->value.boolean = rz_config_var_get_bool(var);
} else if (RZ_CONFIG_VAR_IS_TYPE(var->flags, RZ_CONFIG_VAR_TYPE_STR)) {
const char *str = rz_config_var_get_string(var);
cv->value.string = rz_str_dup(str);
} else if (RZ_CONFIG_VAR_IS_TYPE(var->flags, RZ_CONFIG_VAR_TYPE_LIST)) {
cv->value.list = config_hold_dup_safe_list(var);
} else if (RZ_CONFIG_VAR_IS_TYPE(var->flags, RZ_CONFIG_VAR_TYPE_INT)) {
cv->value.integer = rz_config_var_get_integer(var);
} else {
cv->value.interval = rz_config_var_get_interval(var);
}
}
static int key_cmp_hold_i(const void *a, const void *b, void *user) {
const char *a_s = (const char *)a;
const RzConfigHoldNum *b_s = (const RzConfigHoldNum *)b;
return strcmp(a_s, b_s->key);
static bool config_hold_is_readonly(const RzConfigEntry *entry) {
if (entry->is_variable) {
return rz_config_var_is_readonly(&entry->var);
}
return rz_config_node_is_readonly(&entry->node);
}
static void config_hold_variable_add(RzConfigHold *hold, const char *name) {
RzConfigEntry *entry = config_find_entry(hold->cfg, name);
if (!entry) {
RZ_LOG_WARN("config-hold: failed to get '%s'\n", name);
return;
}
if (config_hold_is_readonly(entry)) {
return;
}
ConfigValue cv = { 0 };
if (entry->is_variable) {
config_hold_value_init_from_var(&cv, &entry->var);
} else {
config_hold_value_init_from_node(&cv, &entry->node);
}
rz_vector_push(&hold->variables, &cv);
}
/**
* \brief Save the current values of a list of config options that have string values.
* \brief Save a copy of the current config options.
*
* Get the current values of a list of config variables (terminated by NULL) and
* save them in the RzConfigHold object \p h . \p rz_config_get is used to
* retrieve the current config values.
* Get the current values of the config and save them in the RzConfigHold object \p h .
*
* \param h Reference to RzConfigHold instance
* \param ... List of config variables to save, terminated by NULL.
* \return true if at least one variable is correctly saved, false otherwise
* \param hold Reference to RzConfigHold instance
* \param ... List of config variables to save, terminated by NULL.
* \return Returns true if at least one variable is correctly saved, false otherwise
*/
RZ_API bool rz_config_hold_s(RzConfigHold *h, ...) {
RZ_API bool rz_config_hold_var(RZ_NONNULL RzConfigHold *hold, ...) {
rz_return_val_if_fail(hold, false);
va_list ap;
char *key;
va_start(ap, h);
if (!h->list_char) {
h->list_char = rz_list_newf((RzListFree)rz_config_hold_char_free);
if (!h->list_char) {
va_end(ap);
return false;
}
}
while ((key = va_arg(ap, char *))) {
if (rz_list_find(h->list_char, key, key_cmp_hold_s, NULL)) {
continue;
}
const char *val = rz_config_get(h->cfg, key);
if (!val) {
continue;
}
RzConfigHoldChar *hc = RZ_NEW0(RzConfigHoldChar);
if (hc) {
hc->key = rz_str_dup(key);
hc->value = rz_str_dup(val);
rz_list_append(h->list_char, hc);
}
const char *name;
va_start(ap, hold);
while ((name = va_arg(ap, const char *))) {
config_hold_variable_add(hold, name);
}
va_end(ap);
return true;
return rz_vector_len(&hold->variables) > 0;
}
/**
* \brief Save the current values of a list of config options that have integer values.
*
* Get the current values of a list of config variables (terminated by NULL) and
* save them in the RzConfigHold object \p h . \p rz_config_get_i is used to
* retrieve the current config values.
*
* \param h Reference to RzConfigHold instance
* \param ... List of config variables to save, terminated by NULL.
* \return true if at least one variable is correctly saved, false otherwise
*/
RZ_API bool rz_config_hold_i(RzConfigHold *h, ...) {
va_list ap;
char *key;
if (!h) {
return false;
static void config_hold_value_fini(void *e, void *user) {
if (!e) {
return;
}
if (!h->list_num) {
h->list_num = rz_list_newf((RzListFree)rz_config_hold_num_free);
if (!h->list_num) {
return false;
}
ConfigValue *cv = (ConfigValue *)e;
if (RZ_CONFIG_VAR_IS_TYPE(cv->flags, RZ_CONFIG_VAR_TYPE_STR)) {
free(cv->value.string);
} else if (RZ_CONFIG_VAR_IS_TYPE(cv->flags, RZ_CONFIG_VAR_TYPE_LIST)) {
rz_list_free(cv->value.list);
}
va_start(ap, h);
while ((key = va_arg(ap, char *))) {
if (rz_list_find(h->list_num, key, key_cmp_hold_i, NULL)) {
continue;
}
RzConfigHoldNum *hc = RZ_NEW0(RzConfigHoldNum);
if (!hc) {
continue;
}
hc->key = rz_str_dup(key);
hc->value = rz_config_get_i(h->cfg, key);
rz_list_append(h->list_num, hc);
}
va_end(ap);
return true;
}
/**
@ -113,15 +115,69 @@ RZ_API bool rz_config_hold_i(RzConfigHold *h, ...) {
* \param cfg RzConfig reference
* \return RzConfigHold allocated object
*/
RZ_API RzConfigHold *rz_config_hold_new(RzConfig *cfg) {
if (cfg) {
RzConfigHold *hold = RZ_NEW0(RzConfigHold);
if (hold) {
hold->cfg = cfg;
return hold;
}
RZ_API RzConfigHold *rz_config_hold_new(RZ_NONNULL RzConfig *cfg) {
rz_return_val_if_fail(cfg, NULL);
RzConfigHold *hold = RZ_NEW0(RzConfigHold);
if (!hold) {
return false;
}
return NULL;
hold->cfg = cfg;
rz_vector_init(&hold->variables, sizeof(ConfigValue), config_hold_value_fini, NULL);
return hold;
}
/**
* \brief Create an opaque object to save/restore some configuration options and saves the given variables.
*
* \param cfg RzConfig reference
* \param ... List of config variables to save, terminated by NULL.
* \return RzConfigHold allocated object
*/
RZ_API RzConfigHold *rz_config_hold_new2(RZ_NONNULL RzConfig *cfg, ...) {
rz_return_val_if_fail(cfg, NULL);
RzConfigHold *hold = rz_config_hold_new(cfg);
if (!hold) {
return NULL;
}
va_list ap;
const char *name;
va_start(ap, cfg);
while ((name = va_arg(ap, const char *))) {
config_hold_variable_add(hold, name);
}
va_end(ap);
if (rz_vector_len(&hold->variables) < 1) {
rz_config_hold_free(hold);
return NULL;
}
return hold;
}
static bool config_hold_set_bool(RzConfigEntry *entry, bool value, void *user) {
if (entry->is_variable) {
return rz_config_var_set_bool(&entry->var, value);
}
return rz_config_node_set_bool(&entry->node, value, user);
}
static bool config_hold_set_integer(RzConfigEntry *entry, ut64 value, void *user) {
if (entry->is_variable) {
return rz_config_var_set_integer(&entry->var, value);
}
return rz_config_node_set_integer(&entry->node, value, user);
}
static bool config_hold_set_string(RzConfigEntry *entry, const char *value, void *user) {
if (entry->is_variable) {
return rz_config_var_set_string(&entry->var, value);
}
return rz_config_node_set_string(&entry->node, value, user);
}
/**
@ -129,17 +185,38 @@ RZ_API RzConfigHold *rz_config_hold_new(RzConfig *cfg) {
*
* \param h Reference to RzConfigHold
*/
RZ_API void rz_config_hold_restore(RzConfigHold *h) {
RzListIter *iter;
RzConfigHoldChar *hchar;
RzConfigHoldNum *hnum;
if (h) {
RzConfig *cfg = h->cfg;
rz_list_foreach (h->list_num, iter, hnum) {
(void)rz_config_set_i(cfg, hnum->key, hnum->value);
RZ_API void rz_config_hold_restore(RZ_NULLABLE RzConfigHold *hold) {
if (!hold) {
return;
}
void *cfg_user = hold->cfg->user;
ConfigValue *cv;
// we iterate from the last to the first as order matters.
rz_vector_foreach_prev (&hold->variables, cv) {
if (!cv->name) {
continue;
}
rz_list_foreach (h->list_char, iter, hchar) {
(void)rz_config_set(cfg, hchar->key, hchar->value);
RzConfigEntry *entry = config_find_entry(hold->cfg, cv->name);
if (!entry) {
RZ_LOG_WARN("config-hold: failed to get node named '%s'\n", cv->name);
continue;
}
if (RZ_CONFIG_VAR_IS_TYPE(cv->flags, RZ_CONFIG_VAR_TYPE_BOOL)) {
config_hold_set_bool(entry, cv->value.boolean, cfg_user);
} else if (RZ_CONFIG_VAR_IS_TYPE(cv->flags, RZ_CONFIG_VAR_TYPE_INT)) {
config_hold_set_integer(entry, cv->value.integer, cfg_user);
} else if (RZ_CONFIG_VAR_IS_TYPE(cv->flags, RZ_CONFIG_VAR_TYPE_STR)) {
config_hold_set_string(entry, cv->value.string, cfg_user);
} else if (RZ_CONFIG_VAR_IS_TYPE(cv->flags, RZ_CONFIG_VAR_TYPE_LIST)) {
// ownership of list moved to var.
rz_config_var_set_list(&entry->var, cv->value.list);
cv->value.list = NULL;
} else { /// RZ_CONFIG_VAR_TYPE_ITV
rz_config_var_set_interval(&entry->var, cv->value.interval);
}
}
}
@ -149,10 +226,18 @@ RZ_API void rz_config_hold_restore(RzConfigHold *h) {
*
* \param h Reference to RzConfigHold
*/
RZ_API void rz_config_hold_free(RzConfigHold *h) {
if (h) {
rz_list_free(h->list_num);
rz_list_free(h->list_char);
RZ_FREE(h);
RZ_API void rz_config_hold_free(RZ_NULLABLE RzConfigHold *h) {
if (!h) {
return;
}
rz_vector_fini(&h->variables);
free(h);
}
RZ_API void rz_config_hold_restore_and_free(RZ_NULLABLE RzConfigHold *hold) {
if (!hold) {
return;
}
rz_config_hold_restore(hold);
rz_config_hold_free(hold);
}

View file

@ -1,7 +1,8 @@
rz_config_sources = [
'old_config.c',
'serialize_config.c',
'config.c',
'hold.c',
'serialize_config.c'
]
rz_config = library('rz_config', rz_config_sources,

526
librz/config/old_config.c Normal file
View file

@ -0,0 +1,526 @@
// SPDX-FileCopyrightText: 2006-2021 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include "config_internal.h"
static bool config_node_init(RzConfigNode *node, RZ_NONNULL const char *name, RZ_NONNULL const char *value) {
if (RZ_STR_ISEMPTY(name) || !value) {
return false;
}
node->name = rz_str_dup(name);
node->value = rz_str_dup(value);
node->flags = CN_STR;
node->i_value = rz_num_get(NULL, value);
node->options = rz_list_new();
return node->name && node->value && node->options;
}
RZ_IPI void rz_config_node_fini(RZ_NULLABLE RzConfigNode *node) {
if (!node) {
return;
}
free(node->name);
free(node->desc);
free(node->value);
rz_list_free(node->options);
}
RZ_API RZ_BORROW RzConfigNode *rz_config_node_get(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), NULL);
RzConfigEntry *entry = config_find_entry(cfg, name);
if (!entry || entry->is_variable) {
return NULL;
}
return &entry->node;
}
static const char *config_node_get(RzConfigNode *node) {
if (rz_config_node_is_bool(node)) {
return rz_str_bool(rz_str_is_true(node->value));
}
return node->value;
}
static ut64 config_node_get_i(RzConfigNode *node) {
if (node->i_value || !strcmp(node->value, "false")) {
return node->i_value;
}
// TODO: Remove it once the switch to `rz_config_get_b()` is complete
if (!strcmp(node->value, "true")) {
return 1;
}
return (ut64)rz_num_math(NULL, node->value);
}
static bool config_node_get_b(RzConfigNode *node) {
if (!rz_config_node_is_bool(node)) {
RZ_LOG_DEBUG("error: '%s' is not a boolean variable\n", node->name);
return false;
}
return rz_str_is_true(node->value);
}
static bool config_node_toggle(RzConfigNode *node, void *user) {
if (!rz_config_node_is_bool(node)) {
RZ_LOG_DEBUG("error: '%s' is not a boolean variable\n", node->name);
return false;
} else if (rz_config_node_is_ro(node)) {
RZ_LOG_DEBUG("error: '%s' config key is read only\n", node->name);
return false;
}
(void)rz_config_node_set_integer(node, !node->i_value, user);
return true;
}
/**
* Returns the value of the config variable of \p name as a string
*/
RZ_API RZ_BORROW const char *rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), NULL);
RzConfigEntry *entry = config_find_entry(cfg, name);
if (!entry) {
RZ_LOG_DEBUG("config: variable '%s' not found\n", name);
return NULL;
} else if (entry->is_variable) {
return rz_config_var_get_string(&entry->var);
}
return config_node_get(&entry->node);
}
/**
* Reads the value of the config variable of \p name only and only if
* the variable is boolean, then tries to write back the inverted value.
* Returns true in case of success.
*/
RZ_API bool rz_config_toggle(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), false);
RzConfigEntry *entry = config_find_entry(cfg, name);
if (!entry) {
return false;
} else if (entry->is_variable) {
return rz_config_toggle_var_bool(&entry->var);
}
return config_node_toggle(&entry->node, cfg->user);
}
/**
* Reads the value of the config variable of \p name only and only if
* the variable is integer.
*/
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), 0);
RzConfigEntry *entry = config_find_entry(cfg, name);
if (!entry) {
RZ_LOG_DEBUG("config: variable '%s' not found\n", name);
return 0;
} else if (entry->is_variable) {
return rz_config_var_get_integer(&entry->var);
}
return config_node_get_i(&entry->node);
}
/**
* Reads the value of the config variable of \p name only and only if
* the variable is boolean. Returns false in case of the failure.
*/
RZ_API bool rz_config_get_b(RzConfig *cfg, RZ_NONNULL const char *name) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), false);
RzConfigEntry *entry = config_find_entry(cfg, name);
if (!entry) {
RZ_LOG_DEBUG("config: variable '%s' not found\n", name);
return NULL;
} else if (entry->is_variable) {
return rz_config_var_get_integer(&entry->var);
}
return config_node_get_b(&entry->node);
}
RZ_API const char *rz_config_node_type(RzConfigNode *node) {
rz_return_val_if_fail(node, "");
if (rz_config_node_is_bool(node)) {
return "bool";
}
if (rz_config_node_is_str(node)) {
return "str";
}
if (rz_config_node_is_int(node)) {
return "int";
}
return "";
}
RZ_API RZ_BORROW RzConfigNode *rz_config_set_cb(RZ_BORROW RzConfig *cfg, const char *name, const char *value, RzConfigCallback cb) {
RzConfigNode *node = rz_config_set(cfg, name, value);
if (node && (node->setter = cb)) {
node->setter(cfg->user, node);
}
// it's not guaranteed that node is still pointing to the same object.
// as this old config method will call the callback which may add new
// config variables which will move or realloc the entry in the vector.
return rz_config_node_get(cfg, name);
}
RZ_API RZ_BORROW RzConfigNode *rz_config_set_i_cb(RZ_BORROW RzConfig *cfg, const char *name, st64 ivalue, RzConfigCallback cb) {
RzConfigNode *node = rz_config_set_i(cfg, name, ivalue);
if (node && (node->setter = cb)) {
node->setter(cfg->user, node);
}
// it's not guaranteed that node is still pointing to the same object.
// as this old config method will call the callback which may add new
// config variables which will move or realloc the entry in the vector.
return rz_config_node_get(cfg, name);
}
static bool __is_true_or_false(const char *s) {
return s && (!rz_str_casecmp(s, "true") || !rz_str_casecmp(s, "false"));
}
RZ_IPI bool rz_config_node_set_bool(RzConfigNode *node, bool value, void *user) {
char *ov = NULL;
ut64 oi = 0;
if (rz_config_node_is_ro(node)) {
RZ_LOG_ERROR("error: '%s' config key is read only\n", node->name);
return false;
}
oi = node->i_value;
if (node->value) {
ov = rz_str_dup(node->value);
}
if (rz_config_node_is_bool(node)) {
node->i_value = value ? 1 : 0;
char *svalue = rz_str_dup(rz_str_bool(value));
if (svalue) {
free(node->value);
node->value = svalue;
}
} else {
RZ_LOG_ERROR("error: '%s' is not a boolean variable\n", node->name);
free(ov);
return false;
}
if (node && node->setter) {
if (!node->setter(user, node)) {
if (oi != UT64_MAX) {
node->i_value = oi;
}
free(node->value);
node->value = rz_str_dup(ov ? ov : "");
}
}
free(ov);
return true;
}
RZ_IPI bool rz_config_node_set_integer(RzConfigNode *node, ut64 i, void *user) {
char buf[128], *ov = NULL;
if (rz_config_node_is_ro(node)) {
return false;
}
if (node->value) {
ov = rz_str_dup(node->value);
}
rz_config_node_value_format_i(buf, sizeof(buf), i, NULL);
free(node->value);
node->value = rz_str_dup(buf);
if (!node->value) {
free(ov);
return false;
}
node->i_value = i;
if (node && node->setter) {
ut64 oi = node->i_value;
if (!node->setter(user, node)) {
node->i_value = oi;
free(node->value);
node->value = rz_str_dup(ov ? ov : "");
free(ov);
return false;
}
}
free(ov);
return true;
}
RZ_IPI bool rz_config_node_set_string(RzConfigNode *node, const char *value, void *user) {
char *ov = NULL;
ut64 oi;
if (rz_config_node_is_ro(node)) {
RZ_LOG_ERROR("error: '%s' config key is read only\n", node->name);
return false;
}
if (node->value == value) {
return true;
}
oi = node->i_value;
if (node->value) {
ov = rz_str_dup(node->value);
if (!ov) {
free(ov);
return false;
}
} else {
free(node->value);
node->value = rz_str_dup("");
}
if (rz_config_node_is_bool(node)) {
bool b = rz_str_is_true(value);
node->i_value = b ? 1 : 0;
char *value = rz_str_dup(rz_str_bool(b));
if (value) {
free(node->value);
node->value = value;
}
} else if (rz_config_node_is_str(node)) {
free(node->value);
node->value = rz_str_dup(rz_str_get(value));
} else {
if (!value) {
free(node->value);
node->value = rz_str_dup("0");
node->i_value = 0;
} else {
free(node->value);
node->value = rz_str_dup(value);
if (IS_DIGIT(*value) || (value[0] == '-' && IS_DIGIT(value[1]))) {
if (strchr(value, '/')) {
node->i_value = rz_num_get(NULL, value);
} else {
node->i_value = rz_num_math(NULL, value);
}
} else {
node->i_value = 0;
}
}
}
if (node && node->setter) {
if (!node->setter(user, node)) {
if (oi != UT64_MAX) {
node->i_value = oi;
}
free(node->value);
node->value = rz_str_dup(ov ? ov : "");
free(ov);
return false;
}
}
free(ov);
return true;
}
/**
* Writes the boolean \p value in the config variable of \p name only and only if
* the variable is boolean.
*/
RZ_API RZ_BORROW RzConfigNode *rz_config_set_b(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name, bool value) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), NULL);
RzConfigNode *node = NULL;
RzConfigEntry *entry = config_find_entry(cfg, name);
if (entry) {
if (entry->is_variable) {
rz_config_var_set_bool(&entry->var, value);
return NULL;
}
node = &entry->node;
} else {
if (cfg->lock) {
return NULL;
}
RzConfigEntry new_entry = { 0 };
if (!config_node_init(&new_entry.node, name, rz_str_bool(value))) {
rz_config_node_fini(&new_entry.node);
return NULL;
}
new_entry.node.flags = CN_BOOL;
new_entry.node.i_value = value ? 1 : 0;
config_add_entry(cfg, name, &new_entry, false);
node = rz_config_node_get(cfg, name);
}
if (!rz_config_node_set_bool(node, value, cfg->user)) {
return NULL;
}
return node;
}
/* TODO: reduce number of strdups here */
/**
* Writes the string \p value in the config variable of \p name.
*/
RZ_API RZ_BORROW RzConfigNode *rz_config_set(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name, const char *value) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), NULL);
RzConfigNode *node = NULL;
RzConfigEntry *entry = config_find_entry(cfg, name);
if (entry) {
if (entry->is_variable) {
rz_config_var_set_any(&entry->var, value);
return NULL;
}
node = &entry->node;
} else {
if (cfg->lock) {
return NULL;
}
RzConfigEntry new_entry = { 0 };
if (!config_node_init(&new_entry.node, name, value)) {
rz_config_node_fini(&new_entry.node);
return NULL;
}
if (__is_true_or_false(value)) {
new_entry.node.flags = CN_BOOL;
new_entry.node.i_value = rz_str_is_true(value) ? 1 : 0;
}
config_add_entry(cfg, name, &new_entry, false);
node = rz_config_node_get(cfg, name);
}
if (!rz_config_node_set_string(node, value, cfg->user)) {
return NULL;
}
return node;
}
/* rz_config_desc takes a RzConfig and a name,
* rz_config_node_desc takes a RzConfigNode
* Both set and return node->desc */
RZ_API const char *rz_config_desc(RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc) {
rz_return_val_if_fail(RZ_STR_ISNOTEMPTY(name), NULL);
RzConfigNode *node = rz_config_node_get(cfg, name);
return rz_config_node_desc(node, desc);
}
RZ_API const char *rz_config_node_desc(RzConfigNode *node, RZ_NULLABLE const char *desc) {
rz_return_val_if_fail(node, NULL);
if (desc) {
free(node->desc);
node->desc = rz_str_dup(desc);
}
return node->desc;
}
RZ_API void rz_config_node_value_format_i(RZ_OUT char *buf, size_t buf_size, const ut64 i, RZ_NULLABLE RzConfigNode *node) {
if (node && rz_config_node_is_bool(node)) {
rz_str_ncpy(buf, rz_str_bool((int)i), buf_size);
return;
}
if (i < 1024) {
snprintf(buf, buf_size, "%" PFMT64d, i);
} else {
snprintf(buf, buf_size, "0x%08" PFMT64x, i);
}
}
/**
* Writes the integer \p value in the config variable of \p name only and only if
* the variable is integer.
*/
RZ_API RZ_BORROW RzConfigNode *rz_config_set_i(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i) {
rz_return_val_if_fail(cfg && RZ_STR_ISNOTEMPTY(name), NULL);
RzConfigNode *node = NULL;
RzConfigEntry *entry = config_find_entry(cfg, name);
if (entry) {
if (entry->is_variable) {
rz_config_var_set_integer(&entry->var, i);
return NULL;
}
node = &entry->node;
} else {
if (cfg->lock) {
return NULL;
}
char buf[128];
RzConfigEntry new_entry = { 0 };
rz_config_node_value_format_i(buf, sizeof(buf), i, NULL);
if (!config_node_init(&new_entry.node, name, buf)) {
rz_config_node_fini(&new_entry.node);
return NULL;
}
new_entry.node.flags = CN_INT;
new_entry.node.i_value = i;
config_add_entry(cfg, name, &new_entry, false);
node = rz_config_node_get(cfg, name);
}
if (!rz_config_node_set_integer(node, i, cfg->user)) {
return NULL;
}
return node;
}
RZ_IPI bool rz_config_node_is_readonly(const RzConfigNode *n) {
return n->flags & CN_RO;
}
RZ_IPI bool rz_config_node_set_readonly(RzConfigNode *n, bool read_only) {
if (read_only) {
n->flags |= CN_RO;
} else {
n->flags &= ~CN_RO;
}
return true;
}
RZ_API void rz_config_visual_hit_i(RzConfig *cfg, const char *name, int delta) {
RzConfigNode *node = rz_config_node_get(cfg, name);
if (node && rz_config_node_is_int(node)) {
(void)rz_config_set_i(cfg, name, rz_config_get_i(cfg, name) + delta);
}
}
/**
* \brief Sets the configuration variable and its value passed as argument
*
* \param cfg reference to RzConfig
* \param str reference the configuration variable string (eg, 'asm.arch=x86')
*/
RZ_API bool rz_config_eval(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *str) {
rz_return_val_if_fail(str, false);
char *name = rz_str_trim_dup(str);
char *value = strchr(name, '=');
if (!value) {
free(name);
return false;
}
*value++ = 0;
rz_config_set(cfg, name, value);
free(name);
return true;
}
RZ_API ut32 rz_config_node_get_var_flags(RZ_NONNULL const RzConfigNode *node) {
rz_return_val_if_fail(node, 0);
ut32 flags = 0;
if (!(node->flags & CN_RO)) {
flags |= RZ_CONFIG_VAR_FLAG_WRITABLE;
}
if (node->flags & CN_BOOL) {
flags |= RZ_CONFIG_VAR_TYPE_BOOL;
}
if (node->flags & CN_INT) {
flags |= RZ_CONFIG_VAR_TYPE_INT;
}
if (node->flags & CN_STR) {
flags |= RZ_CONFIG_VAR_TYPE_STR;
}
if (node->setter) {
flags |= RZ_CONFIG_VAR_FLAG_BIND;
}
return flags;
}

View file

@ -1,8 +1,22 @@
// SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-FileCopyrightText: 2020 Florian Märkl <info@florianmaerkl.de>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util/rz_serialize.h>
#include <rz_config.h>
#include "config_internal.h"
static bool config_serialize_to_sdb(const RzConfigEntry *entry, void *user) {
Sdb *db = user;
if (entry->is_variable) {
char *value = rz_config_var_as_string(&entry->var);
sdb_set(db, entry->var.name, value);
free(value);
} else {
const RzConfigNode *node = &entry->node;
sdb_set(db, node->name, node->value);
}
return true;
}
/*
*
@ -15,39 +29,43 @@
* ...
*
*/
RZ_API void rz_serialize_config_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config) {
RzListIter *iter;
RzConfigNode *node;
rz_list_foreach (config->nodes, iter, node) {
sdb_set(db, node->name, node->value);
}
rz_config_iterate_over(config, config_serialize_to_sdb, db);
}
typedef struct load_config_ctx_t {
typedef struct deserialize_ctx_s {
RzConfig *config;
HtSP *exclude;
} LoadConfigCtx;
} DeserializeCtx;
static bool load_config_cb(void *user, const SdbKv *kv) {
LoadConfigCtx *ctx = user;
if (ctx->exclude && ht_sp_find_kv(ctx->exclude, sdbkv_key(kv), NULL)) {
static bool config_deserialize_from_sdb(void *user, const SdbKv *kv) {
DeserializeCtx *ctx = user;
const char *key = sdbkv_key(kv);
if (ctx->exclude && ht_sp_find_kv(ctx->exclude, key, NULL)) {
return true;
}
RzConfigNode *node = rz_config_node_get(ctx->config, sdbkv_key(kv));
if (!node) {
return 1;
RzConfigEntry *entry = config_find_entry(ctx->config, key);
if (!entry) {
return true;
}
rz_config_set(ctx->config, sdbkv_key(kv), sdbkv_value(kv));
return 1;
const char *value = sdbkv_value(kv);
if (entry->is_variable) {
rz_config_var_set_any(&entry->var, value);
} else {
rz_config_set(ctx->config, key, value);
}
return true;
}
/**
* \param exclude NULL-terminated array of keys to not load from the sdb.
*/
RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config,
RZ_NULLABLE const char *const *exclude, RZ_NULLABLE RzSerializeResultInfo *res) {
LoadConfigCtx ctx = { config, NULL };
RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config, RZ_NULLABLE const char **exclude) {
rz_return_val_if_fail(db && config, false);
DeserializeCtx ctx = { config, NULL };
if (exclude) {
ctx.exclude = ht_sp_new(HT_STR_DUP, NULL, NULL);
if (!ctx.exclude) {
@ -57,7 +75,7 @@ RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *co
ht_sp_insert(ctx.exclude, *exclude, NULL);
}
}
sdb_foreach(db, load_config_cb, &ctx);
sdb_foreach(db, config_deserialize_from_sdb, &ctx);
ht_sp_free(ctx.exclude);
return true;
}

View file

@ -2844,7 +2844,7 @@ static char *get_body(RzCore *core, ut64 addr, int size, int opts) {
if (!hc) {
return NULL;
}
rz_config_hold_i(hc, "asm.lines", "asm.bytes",
rz_config_hold_var(hc, "asm.lines", "asm.bytes",
"asm.cmt.col", "asm.marks", "asm.offset",
"asm.comments", "asm.cmt.right", "asm.bb.line", NULL);
const bool o_comments = rz_config_get_i(core->config, "graph.comments");
@ -5103,7 +5103,7 @@ RZ_IPI int rz_core_visual_graph(RzCore *core, RzAGraph *g, RzAnalysisFunction *_
if (!hc) {
return false;
}
rz_config_hold_i(hc, "asm.pseudo", "asm.esil", "asm.cmt.right", NULL);
rz_config_hold_var(hc, "asm.pseudo", "asm.esil", "asm.cmt.right", NULL);
int h, w = rz_cons_get_size(&h);
can = rz_cons_canvas_new(w, h);

View file

@ -21,7 +21,7 @@ static bool analysis_emul_init(RzCore *core, RzConfigHold *hc, RzDebugTrace **dt
core->dbg->trace = rz_debug_trace_new();
esil->trace = rz_analysis_esil_trace_new(esil);
rz_config_hold_i(hc, "esil.romem", "dbg.trace",
rz_config_hold_var(hc, "esil.romem", "dbg.trace",
"esil.nonull", "dbg.follow", NULL);
rz_config_set(core->config, "esil.romem", "true");
rz_config_set(core->config, "dbg.trace", "true");

View file

@ -4559,7 +4559,7 @@ RZ_IPI bool rz_core_analysis_types_propagation(RzCore *core) {
return false;
}
RzConfigHold *hold = rz_config_hold_new(core->config);
rz_config_hold_i(hold, "io.va", "io.pcache.write", NULL);
rz_config_hold_var(hold, "io.va", "io.pcache.write", NULL);
bool io_cache = rz_config_get_b(core->config, "io.pcache.write");
if (!io_cache) {
// XXX. we shouldnt need this, but it breaks 'rizin -c aaa -w ls'
@ -4854,7 +4854,7 @@ static void sdb_concat_by_path(Sdb *s, const char *path) {
}
RZ_API void rz_core_analysis_cc_init_by_path(RzCore *core, RZ_NULLABLE const char *path, RZ_NULLABLE const char *homepath) {
const char *analysis_arch = rz_config_get(core->config, "analysis.arch");
const char *analysis_arch = rz_analysis_get_arch(core->analysis);
Sdb *cc = rz_analysis_get_sdb_cc(core->analysis);
if (!strcmp(analysis_arch, "null")) {
sdb_reset(cc);

View file

@ -325,7 +325,6 @@ static void core_set_asm_plugin_configs(RZ_BORROW RzCore *core) {
return;
}
rz_config_lock(pcfg, 1);
if (!ht_sp_insert(core->plugin_configs, arch, pcfg)) {
RZ_LOG_WARN("core: plugin '%s' was already added.\n", arch);
}

View file

@ -549,22 +549,33 @@ static void autocmplt_cmd_arg_choices(RzCore *core, RzLineNSCompletionResult *re
}
}
static void autocmplt_cmd_arg_eval_key(RzCore *core, RzLineNSCompletionResult *res, const char *s, size_t len) {
RzListIter *iter;
RzConfigNode *bt;
rz_list_foreach (core->config->nodes, iter, bt) {
if (!strncmp(bt->name, s, len)) {
rz_line_ns_completion_result_add(res, bt->name);
}
typedef struct autocmplt_context_s {
RzLineNSCompletionResult *res;
const char *prefix; ///< Prefix to search
size_t len; ///< Prefix length
} autocmplt_ctx_t;
static bool autocmplt_cmd_arg_eval_key_iterator(const RzConfigEntry *entry, void *user) {
autocmplt_ctx_t *ctx = user;
const char *e_name = rz_config_entry_get_name(entry);
if (!strncmp(ctx->prefix, e_name, ctx->len)) {
rz_line_ns_completion_result_add(ctx->res, e_name);
}
return true;
}
static void autocmplt_cmd_arg_eval_key(RzCore *core, RzLineNSCompletionResult *res, const char *prefix, size_t len) {
autocmplt_ctx_t ctx = {
res,
prefix,
len,
};
rz_config_iterate_over(core->config, autocmplt_cmd_arg_eval_key_iterator, &ctx);
RzConfig **plugin_cfg;
RzIterator *it = ht_sp_as_iter(core->plugin_configs);
rz_iterator_foreach(it, plugin_cfg) {
rz_list_foreach ((*plugin_cfg)->nodes, iter, bt) {
if (!strncmp(bt->name, s, len)) {
rz_line_ns_completion_result_add(res, bt->name);
}
}
rz_config_iterate_over((*plugin_cfg), autocmplt_cmd_arg_eval_key_iterator, &ctx);
}
rz_iterator_free(it);
}
@ -580,25 +591,26 @@ static void autocmplt_cmd_arg_eval_full(RzCore *core, RzLineNSCompletionResult *
char *k = rz_str_ndup(s, eq - s);
char *v = NULL;
RzConfigNode *node = rz_config_node_get(core->config, k);
if (!node) {
const RzList *options = rz_config_get_options(core->config, k);
if (!options) {
goto err;
}
const ut32 flags = rz_config_get_flags(core->config, k);
v = rz_str_ndup(eq + 1, len - (eq - s) - 1);
len = strlen(v);
res->start += strlen(k) + 1;
if (node->options && rz_list_length(node->options)) {
RzListIter *iter;
char *opt;
rz_list_foreach (node->options, iter, opt) {
if (rz_list_length(options) > 0) {
const RzListIter *iter;
const char *opt;
rz_list_foreach (options, iter, opt) {
if (!strncmp(opt, v, len)) {
rz_line_ns_completion_result_add(res, opt);
}
}
} else if (rz_config_node_is_bool(node)) {
} else if (RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_BOOL)) {
if (!strncmp("true", v, len)) {
rz_line_ns_completion_result_add(res, "true");
}

View file

@ -1135,36 +1135,30 @@ static bool cb_scrnull(void *user, void *data) {
return true;
}
static bool cb_color(void *user, void *data) {
static bool core_scr_color_set(void *user, const void *pvalue) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
if (node->i_value) {
ut64 value = *((const ut64 *)pvalue);
// ensure is never greater than COLOR_MODE_16M
value = RZ_MIN(value, COLOR_MODE_16M);
if (value > 0) {
core->print->flags |= RZ_PRINT_FLAGS_COLOR;
} else {
core->print->flags &= (~RZ_PRINT_FLAGS_COLOR);
}
if (!strcmp(node->value, "true")) {
node->i_value = 1;
} else if (!strcmp(node->value, "false")) {
node->i_value = 0;
}
rz_cons_singleton()->context->color_mode = (node->i_value > COLOR_MODE_16M)
? COLOR_MODE_16M
: node->i_value;
core->cons->context->color_mode = value;
rz_cons_pal_update_event();
rz_print_set_flags(core->print, core->print->flags);
return true;
}
static bool cb_color_getter(void *user, RzConfigNode *node) {
(void)user;
node->i_value = rz_cons_singleton()->context->color_mode;
char buf[128];
rz_config_node_value_format_i(buf, sizeof(buf), rz_cons_singleton()->context->color_mode, node);
if (!node->value || strcmp(node->value, buf) != 0) {
free(node->value);
node->value = rz_str_dup(buf);
}
static bool core_scr_color_get(void *user, void *pvalue) {
RzCore *core = (RzCore *)user;
ut64 *value = (ut64 *)pvalue;
*value = core->cons->context->color_mode;
return true;
}
@ -1613,124 +1607,177 @@ static bool cb_iopcachewrite(void *user, void *data) {
return true;
}
RZ_API bool rz_core_esil_cmd(RzAnalysisEsil *esil, const char *cmd, ut64 a1, ut64 a2) {
if (cmd && *cmd) {
RzCore *core = (RzCore *)esil->pcore;
rz_core_cmdf(core, "%s %" PFMT64d " %" PFMT64d, cmd, a1, a2);
return core->num->value;
static void config_print_options_as_json(PJ *pj, const RzList /*<char *>*/ *options) {
RzListIter *iter;
const char *option;
pj_ka(pj, "options");
rz_list_foreach (options, iter, option) {
pj_s(pj, option);
}
return false;
pj_end(pj);
}
static void config_print_node(RzConfig *cfg, RzConfigNode *node, RzCmdStateOutput *state) {
rz_return_if_fail(cfg && node && state);
char *option;
bool isFirst;
RzOutputMode mode = state->mode;
PJ *pj = state->d.pj;
RzListIter *iter;
char *es = NULL;
static void config_print_node_value_as_json(const RzConfigNode *node, PJ *pj, const char *key) {
if (rz_str_isnumber(node->value)) {
pj_kn(pj, key, rz_num_math(NULL, node->value));
return;
} else if (rz_str_is_bool(node->value)) {
pj_kb(pj, key, (node->value));
return;
} else {
pj_ks(pj, key, node->value);
}
}
static void config_print_long_json(PJ *pj, const char *name, const char *desc, ut32 flags) {
char *s_flags = rz_config_var_flags_as_string(flags);
pj_ks(pj, "name", name);
pj_ks(pj, "desc", rz_str_get(desc));
pj_ks(pj, "flags", rz_str_get(s_flags));
free(s_flags);
}
static void config_print_node_as_long_json(const RzConfigNode *node, PJ *pj) {
ut32 flags = rz_config_node_get_var_flags(node);
pj_o(pj);
config_print_long_json(pj, node->name, node->desc, flags);
config_print_options_as_json(pj, node->options);
config_print_node_value_as_json(node, pj, "value");
pj_end(pj);
}
static void config_print_var_as_long_json(const RzConfigVar *var, PJ *pj) {
const char *name = rz_config_var_get_name(var);
const char *desc = rz_config_var_get_desc(var);
const RzList *options = rz_config_var_get_options(var);
ut32 flags = rz_config_var_get_flags(var);
pj_o(pj);
config_print_long_json(pj, name, desc, flags);
config_print_options_as_json(pj, options);
rz_config_var_as_json(var, pj, "value");
pj_end(pj);
}
typedef struct core_config_print_s {
RzCmdStateOutput *state;
const char *str;
char color_name[32];
char color_value[32];
char color_meta[32];
char reset_str[32];
} CoreConfigPrint;
static void core_config_print_array_as_string(const RzList /*<char *>*/ *list, bool allow_empty) {
const char *entry;
const RzListIter *it;
if (rz_list_empty(list) && !allow_empty) {
return;
}
rz_cons_print("[");
rz_list_foreach (list, it, entry) {
if (rz_list_head(list) != it) {
rz_cons_printf(", %s", entry);
} else {
rz_cons_print(entry);
}
}
rz_cons_print("]");
}
static void core_config_print_var_as_string(const RzConfigEntry *entry, ut32 flags) {
if (RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_INT)) {
ut64 value = rz_config_entry_get_integer(entry);
if (value > 0x1000) {
rz_cons_printf("0x%" PFMT64x, value);
} else {
rz_cons_printf("%" PFMT64u, value);
}
} else if (RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_BOOL)) {
bool value = rz_config_entry_get_bool(entry);
rz_cons_print(rz_str_bool(value));
} else if (RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_STR)) {
const char *value = rz_config_entry_get_string(entry);
rz_cons_print(value);
} else if (RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_LIST)) {
RzList *list = rz_config_var_get_list(&entry->var);
core_config_print_array_as_string(list, true);
rz_list_free(list);
} else if (RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_ITV)) {
RzInterval itv = rz_config_var_get_interval(&entry->var);
rz_cons_printf("[0x%08" PFMT64x ",0x%08" PFMT64x "]", rz_itv_begin(itv), rz_itv_end(itv));
}
}
static bool core_config_print_iterator(const RzConfigEntry *entry, void *user) {
CoreConfigPrint *ccp = (CoreConfigPrint *)user;
const char *e_name = rz_config_entry_get_name(entry);
if (RZ_STR_ISNOTEMPTY(ccp->str) && !rz_str_startswith(e_name, ccp->str)) {
return true;
}
const char *name = NULL;
const char *desc = "";
const RzList *options = NULL;
ut32 e_flags = 0;
RzOutputMode mode = ccp->state->mode;
PJ *pj = ccp->state->d.pj;
if (entry->is_variable) {
name = rz_config_var_get_name(&entry->var);
desc = rz_config_var_get_desc(&entry->var);
options = rz_config_var_get_options(&entry->var);
e_flags = rz_config_var_get_flags(&entry->var);
} else {
name = entry->node.name;
desc = rz_str_get(entry->node.desc);
options = entry->node.options;
e_flags = rz_config_node_get_var_flags(&entry->node);
}
char *s_flags = rz_config_var_flags_as_string(e_flags);
switch (mode) {
case RZ_OUTPUT_MODE_JSON:
if (rz_str_isnumber(node->value)) {
pj_kn(pj, node->name, rz_num_math(NULL, node->value));
return;
} else if (rz_str_is_bool(node->value)) {
pj_kb(pj, node->name, (node->value));
return;
if (entry->is_variable) {
rz_config_var_as_json(&entry->var, pj, name);
} else {
pj_ks(pj, node->name, node->value);
config_print_node_value_as_json(&entry->node, pj, name);
}
break;
case RZ_OUTPUT_MODE_LONG_JSON:
pj_o(pj);
pj_ks(pj, "name", node->name);
if (rz_str_isnumber(node->value)) {
pj_kn(pj, "value", rz_num_math(NULL, node->value));
} else if (rz_str_is_bool(node->value)) {
pj_kb(pj, "value", (node->value));
if (entry->is_variable) {
config_print_var_as_long_json(&entry->var, pj);
} else {
pj_ks(pj, "value", node->value);
config_print_node_as_long_json(&entry->node, pj);
}
pj_ks(pj, "type", rz_config_node_type(node));
es = rz_str_escape(node->desc);
if (es) {
pj_ks(pj, "desc", es);
free(es);
}
pj_kb(pj, "ro", rz_config_node_is_ro(node));
if (!rz_list_empty(node->options)) {
pj_ka(pj, "options");
rz_list_foreach (node->options, iter, option) {
pj_s(pj, option);
}
pj_end(pj);
}
pj_end(pj);
break;
case RZ_OUTPUT_MODE_LONG: {
bool color_enabled = rz_config_get_i(cfg, "scr.color") > 0;
char color_name[32], color_value[32], color_meta[32], reset_str[32];
if (color_enabled) {
RzColor color_name_val = rz_cons_pal_get("label");
RzColor color_value_val = rz_cons_pal_get("args");
RzColor color_meta_val = rz_cons_pal_get("comment");
RzColor reset_val = rz_cons_pal_get("help");
rz_cons_rgb_str(color_name, sizeof(color_name), &color_name_val);
rz_cons_rgb_str(color_value, sizeof(color_value), &color_value_val);
rz_cons_rgb_str(color_meta, sizeof(color_meta), &color_meta_val);
rz_cons_rgb_str(reset_str, sizeof(reset_str), &reset_val);
} else {
color_name[0] = color_value[0] = color_meta[0] = reset_str[0] = '\0';
}
const char *ro_str = rz_config_node_is_ro(node) ? "(ro)" : "";
rz_cons_printf("%s%20s = %s%s %s%s; %s%s", color_name, node->name, color_value, node->value, color_meta, ro_str, reset_str, node->desc);
if (!rz_list_empty(node->options)) {
isFirst = true;
rz_cons_printf(" [");
rz_list_foreach (node->options, iter, option) {
if (isFirst) {
isFirst = false;
} else {
rz_cons_printf(", ");
}
rz_cons_printf("%s", option);
}
rz_cons_printf("]");
}
rz_cons_printf("%s%20s = %s", ccp->color_name, name, ccp->color_value);
core_config_print_var_as_string(entry, e_flags);
rz_cons_printf(" %s(%s); %s%s ", ccp->color_meta, s_flags, ccp->reset_str, desc);
core_config_print_array_as_string(options, false);
rz_cons_println("");
break;
}
case RZ_OUTPUT_MODE_QUIET:
rz_cons_printf("%s=%s\n", node->name, node->value);
rz_cons_printf("%s=", name);
core_config_print_var_as_string(entry, e_flags);
rz_cons_println("");
break;
case RZ_OUTPUT_MODE_STANDARD: {
bool color_enabled = rz_config_get_i(cfg, "scr.color") > 0;
char color_str[32], reset_str[32];
if (color_enabled) {
RzColor color_val = rz_cons_pal_get("label");
RzColor reset_val = rz_cons_pal_get("help");
rz_cons_rgb_str(color_str, sizeof(color_str), &color_val);
rz_cons_rgb_str(reset_str, sizeof(reset_str), &reset_val);
} else {
color_str[0] = reset_str[0] = '\0';
}
rz_cons_printf("%s%20s: %s%s\n", color_str, node->name, reset_str, node->desc ? node->desc : "");
rz_cons_printf("%s%20s: %s%s\n", ccp->color_name, name, ccp->reset_str, desc);
break;
}
case RZ_OUTPUT_MODE_STR_BUF:
rz_strbuf_appendf(state->d.sbuf, "%20s: %10s - %s\n", node->name,
rz_config_node_type(node),
node->desc ? node->desc : "");
rz_strbuf_appendf(ccp->state->d.sbuf, "%20s: %10s - %s\n", name, s_flags, desc);
break;
default:
rz_warn_if_reached();
break;
}
free(s_flags);
return true;
}
/**
@ -1742,25 +1789,47 @@ static void config_print_node(RzConfig *cfg, RzConfigNode *node, RzCmdStateOutpu
*/
RZ_API void rz_core_config_print_all(RzConfig *cfg, const char *str, RzCmdStateOutput *state) {
rz_return_if_fail(cfg);
RzConfigNode *node;
RzListIter *iter;
PJ *pj = state->d.pj;
RzOutputMode mode = state->mode;
CoreConfigPrint ccp = { 0 };
ccp.state = state;
ccp.str = str;
const bool color_enabled = rz_config_get_i(cfg, "scr.color") > 0;
if (mode == RZ_OUTPUT_MODE_LONG_JSON) {
pj_a(pj);
} else if (mode == RZ_OUTPUT_MODE_JSON) {
pj_o(pj);
}
rz_list_foreach (cfg->nodes, iter, node) {
if (rz_str_startswith(node->name, str)) {
config_print_node(cfg, node, state);
// begin
switch (state->mode) {
case RZ_OUTPUT_MODE_LONG_JSON:
pj_a(state->d.pj);
break;
case RZ_OUTPUT_MODE_JSON:
pj_o(state->d.pj);
break;
case RZ_OUTPUT_MODE_LONG:
if (color_enabled) {
RzColor color_name_val = rz_cons_pal_get("label");
RzColor color_value_val = rz_cons_pal_get("args");
RzColor color_meta_val = rz_cons_pal_get("comment");
RzColor reset_val = rz_cons_pal_get("help");
rz_cons_rgb_str(ccp.color_name, sizeof(ccp.color_name), &color_name_val);
rz_cons_rgb_str(ccp.color_value, sizeof(ccp.color_value), &color_value_val);
rz_cons_rgb_str(ccp.color_meta, sizeof(ccp.color_meta), &color_meta_val);
rz_cons_rgb_str(ccp.reset_str, sizeof(ccp.reset_str), &reset_val);
}
break;
case RZ_OUTPUT_MODE_STANDARD:
if (color_enabled) {
RzColor color_val = rz_cons_pal_get("label");
RzColor reset_val = rz_cons_pal_get("help");
rz_cons_rgb_str(ccp.color_name, sizeof(ccp.color_name), &color_val);
rz_cons_rgb_str(ccp.reset_str, sizeof(ccp.reset_str), &reset_val);
}
break;
default:
break;
}
if (mode == RZ_OUTPUT_MODE_LONG_JSON || mode == RZ_OUTPUT_MODE_JSON) {
pj_end(pj);
rz_config_iterate_over(cfg, core_config_print_iterator, &ccp);
if (state->mode == RZ_OUTPUT_MODE_LONG_JSON || state->mode == RZ_OUTPUT_MODE_JSON) {
pj_end(state->d.pj);
}
}
@ -2247,14 +2316,6 @@ static bool cb_scrprompt(void *user, void *data) {
return true;
}
static bool cb_scrrows(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
int n = atoi(node->value);
core->cons->force_rows = n;
return true;
}
static bool cb_contiguous(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
@ -2307,10 +2368,16 @@ static bool cb_scr_prompt_popup(void *user, void *data) {
return true;
}
static bool cb_swstep(void *user, void *data) {
static bool core_dbg_swstep_set(void *user, const void *pvalue) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
core->dbg->swstep = node->i_value;
core->dbg->swstep = *((const bool *)pvalue);
return true;
}
static bool core_dbg_swstep_get(void *user, void *pvalue) {
RzCore *core = (RzCore *)user;
bool *value = (bool *)pvalue;
*value = core->dbg->swstep;
return true;
}
@ -2557,12 +2624,6 @@ static bool cb_zoom_in(void *user, void *data) {
return false;
}
static int __dbg_swstep_getter(void *user, RzConfigNode *node) {
RzCore *core = (RzCore *)user;
node->i_value = core->dbg->swstep;
return true;
}
static bool cb_analysis_roregs(RzCore *core, RzConfigNode *node) {
RzReg *rreg = rz_analysis_get_reg(core->analysis);
if (rreg) {
@ -2873,7 +2934,6 @@ RZ_API int rz_core_config_init(RzCore *core) {
if (!cfg) {
return 0;
}
cfg->num = core->num;
/* dir.prefix is used in other modules, set it first */
{
char *pfx = rz_sys_getenv("RZ_PREFIX");
@ -3403,7 +3463,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
}
rz_config_desc(cfg, "dbg.follow", "Follow program counter when pc >= core->offset + dbg.follow");
SETBPREF("dbg.rebase", "true", "Rebase analysis/meta/comments/flags when reopening file in debugger");
SETCB("dbg.swstep", "false", &cb_swstep, "Force use of software steps (code analysis+breakpoint)");
rz_config_add_bool_bind(cfg, "dbg.swstep", "Force use of software steps (code analysis+breakpoint)", core_dbg_swstep_get, core_dbg_swstep_set, NULL, core);
SETBPREF("dbg.trace.inrange", "false", "While tracing, avoid following calls outside specified range");
SETBPREF("dbg.trace.libs", "true", "Trace library code too");
SETBPREF("dbg.exitkills", "true", "Kill process on exit");
@ -3413,8 +3473,6 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETICB("dbg.gdb.retries", 10, &cb_dbg_gdb_retries, "Number of retries before gdb packet read times out");
SETCB("dbg.consbreak", "false", &cb_consbreak, "SIGINT handle for attached processes");
rz_config_set_getter(cfg, "dbg.swstep", (RzConfigCallback)__dbg_swstep_getter);
SETBPREF("dbg.bpsysign", "false", "Ignore system breakpoints");
SETICB("dbg.btdepth", 128, &cb_dbgbtdepth, "Depth of backtrace");
SETCB("dbg.trace", "false", &cb_trace, "Trace program execution (see asm.trace)");
@ -3599,8 +3657,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETBPREF("scr.panelborder", "false", "Specify panels border active area (0 by default)");
SETICB("scr.columns", 0, &cb_scrcolumns, "Force console column count (width)");
SETBPREF("scr.dumpcols", "false", "Prefer pC commands before p ones");
SETCB("scr.rows", "0", &cb_scrrows, "Force console row count (height) ");
SETICB("scr.rows", 0, &cb_rows, "Force console row count (height) (duplicate?)");
SETICB("scr.rows", 0, &cb_rows, "Force console row count (height)");
SETICB("scr.fix.rows", 0, &cb_fixrows, "Workaround for Linux TTY");
SETICB("scr.fix.columns", 0, &cb_fixcolumns, "Workaround for Prompt iOS SSH client");
SETCB("scr.highlight", "", &cb_scrhighlight, "Highlight that word at RzCons level");
@ -3624,8 +3681,10 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETCB("scr.prompt", "true", &cb_scrprompt, "Show user prompt (used by rizin -q)");
SETCB("scr.tee", "", &cb_teefile, "Pipe output to file of this name");
SETPREF("scr.seek", "", "Seek to the specified address on startup");
SETICB("scr.color", (core->print->flags & RZ_PRINT_FLAGS_COLOR) ? COLOR_MODE_16 : COLOR_MODE_DISABLED, &cb_color, "Enable colors (0: none, 1: ansi, 2: 256 colors, 3: truecolor)");
rz_config_set_getter(cfg, "scr.color", (RzConfigCallback)cb_color_getter);
rz_config_add_integer_bind(cfg, "scr.color", "Enable colors (0: none, 1: ansi, 2: 256 colors, 3: truecolor)", core_scr_color_get, core_scr_color_set, NULL, core);
rz_config_set_i(cfg, "scr.color", (core->print->flags & RZ_PRINT_FLAGS_COLOR) ? COLOR_MODE_16 : COLOR_MODE_DISABLED);
SETCB("scr.color.grep", "false", &cb_scr_color_grep, "Enable colors when using ~grep");
SETBPREF("scr.color.pipe", "false", "Enable colors when using pipes");
SETBPREF("scr.color.ops", "true", "Colorize numbers and registers in opcodes");
@ -3803,7 +3862,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETB("flirt.sigdb.load.extra", true, "Load signatures from the extra path");
SETB("flirt.sigdb.load.home", true, "Load signatures from the home path");
rz_config_lock(cfg, true);
cfg->lock = 1;
return true;
}
@ -3856,6 +3915,38 @@ RZ_API void rz_core_parse_rizinrc(RzCore *r) {
}
}
typedef struct cconfig_space_s {
RzList /*<char *>*/ *list;
const char *space;
} cconfig_space_t;
static bool core_config_in_space(const RzConfigEntry *entry, void *user) {
cconfig_space_t *ctx = user;
const char *e_name = rz_config_entry_get_name(entry);
char *name = rz_str_dup(e_name);
if (!name) {
return false;
}
char *dot = strchr(name, '.');
if (dot) {
*dot = 0;
}
if (RZ_STR_ISNOTEMPTY(ctx->space)) {
if (0 == strcmp(name, ctx->space) && dot && !rz_list_find(ctx->list, dot + 1, (RzListComparator)strcmp, NULL)) {
rz_list_append(ctx->list, rz_str_dup(dot + 1));
}
} else {
if (!rz_list_find(ctx->list, name, (RzListComparator)strcmp, NULL)) {
rz_list_append(ctx->list, rz_str_dup(name));
}
}
free(name);
return true;
}
/**
* \brief Get config variable spaces
* \param core The RzCore instance
@ -3868,28 +3959,9 @@ RZ_API RZ_OWN RzList /*<char *>*/ *rz_core_config_in_space(RZ_NONNULL RzCore *co
if (!list) {
return NULL;
}
RzConfigNode *node;
RzListIter *iter;
rz_list_foreach (core->config->nodes, iter, node) {
char *name = rz_str_dup(node->name);
if (!name) {
continue;
}
char *dot = strchr(name, '.');
if (dot) {
*dot = 0;
}
if (RZ_STR_ISNOTEMPTY(space)) {
if (0 == strcmp(name, space) && dot && !rz_list_find(list, dot + 1, (RzListComparator)strcmp, NULL)) {
rz_list_append(list, rz_str_dup(dot + 1));
}
} else {
if (!rz_list_find(list, name, (RzListComparator)strcmp, NULL)) {
rz_list_append(list, rz_str_dup(name));
}
}
free(name);
}
cconfig_space_t ctx = { list, space };
rz_config_iterate_over(core->config, core_config_in_space, &ctx);
return list;
}

View file

@ -12,6 +12,15 @@
#include <rz_util/rz_graph_drawable.h>
#include "core_private.h"
RZ_API bool rz_core_esil_cmd(RzAnalysisEsil *esil, const char *cmd, ut64 a1, ut64 a2) {
if (cmd && *cmd) {
RzCore *core = (RzCore *)esil->pcore;
rz_core_cmdf(core, "%s %" PFMT64d " %" PFMT64d, cmd, a1, a2);
return core->num->value;
}
return false;
}
static ut64 initializeEsil(RzCore *core) {
ut64 addr = 0;
int romem = rz_config_get_i(core->config, "esil.romem");

View file

@ -617,7 +617,7 @@ RZ_API void rz_core_sysenv_begin(RzCore *core) {
}
Sdb *config_sdb = sdb_new(NULL, config_sdb_path, 0);
rz_config_serialize(core->config, config_sdb);
rz_serialize_config_save(config_sdb, core->config);
sdb_sync(config_sdb);
sdb_free(config_sdb);
rz_sys_setenv("RZ_CONFIG", config_sdb_path);
@ -1295,7 +1295,7 @@ RZ_API RZ_BORROW RzCoreFile *rz_core_file_open(RZ_NONNULL RzCore *r, RZ_NONNULL
if (r->dbg->cur && r->dbg->cur->canstep) {
swstep = false;
}
rz_config_set_i(r->config, "dbg.swstep", swstep);
rz_config_set_bool(r->config, "dbg.swstep", swstep);
// Set the correct debug handle
if (fd->plugin && fd->plugin->isdbg) {
char *dh = rz_str_ndup(file, (strstr(file, "://") - file));

View file

@ -363,7 +363,7 @@ static RZ_OWN RzGraph /*<RzGraphNodeInfo *, None *>*/ *rz_core_graph_function_bb
goto fail;
}
rz_config_hold_i(hc, "asm.xrefs.max", "asm.lines", "asm.lines.fcn", "asm.bytes", "asm.debuginfo", "asm.offset", "asm.marks",
rz_config_hold_var(hc, "asm.xrefs.max", "asm.lines", "asm.lines.fcn", "asm.bytes", "asm.debuginfo", "asm.offset", "asm.marks",
"asm.cmt.right", "asm.cmt.col", "asm.bb.middle", NULL);
rz_config_set_i(core->config, "asm.xrefs.max", 3);
rz_config_set_i(core->config, "asm.lines", 0);

View file

@ -28,7 +28,7 @@ RZ_API int rz_core_setup_debugger(RzCore *r, const char *debugbackend, bool atta
rz_debug_attach(r->dbg, pid);
rz_debug_select(r->dbg, r->dbg->pid, r->dbg->tid);
}
rz_config_set_i(r->config, "dbg.swstep", (r->dbg->cur && !r->dbg->cur->canstep));
rz_config_set_bool(r->config, "dbg.swstep", (r->dbg->cur && !r->dbg->cur->canstep));
rz_io_system(r->io, rz_strf(buf, "pid %d", r->dbg->pid));
// this makes to attach twice showing warnings in the output

View file

@ -1597,11 +1597,11 @@ DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_fromto_op) {
RzConfigHold *hc = rz_config_hold_new(core->config);
int i;
for (i = 0; fromvars[i]; i++) {
rz_config_hold_i(hc, fromvars[i], NULL);
rz_config_hold_var(hc, fromvars[i], NULL);
rz_config_set_i(core->config, fromvars[i], from_val);
}
for (i = 0; tovars[i]; i++) {
rz_config_hold_i(hc, tovars[i], NULL);
rz_config_hold_var(hc, tovars[i], NULL);
rz_config_set_i(core->config, tovars[i], to_val);
}
@ -1724,8 +1724,8 @@ DEFINE_HANDLE_TS_FCN_AND_SYMBOL(tmp_eval_op) {
char *eq = strchr(arg_str, '=');
if (eq) {
*eq = 0;
rz_config_hold_s(hc, arg_str, NULL);
rz_config_set(core->config, arg_str, eq + 1);
rz_config_hold_var(hc, arg_str, NULL);
rz_config_set_any(core->config, arg_str, eq + 1);
} else {
RZ_LOG_ERROR("core: Missing '=' in e: expression (%s)\n", arg_str);
}

View file

@ -5358,7 +5358,7 @@ RZ_IPI RzCmdStatus rz_analyze_cycles_handler(RzCore *core, int argc, const char
st32 ccl = 0;
RzConfigHold *hc = rz_config_hold_new(core->config);
rz_config_hold_i(hc, "asm.cmt.right", "asm.functions", "asm.lines", "asm.xrefs", NULL);
rz_config_hold_var(hc, "asm.cmt.right", "asm.functions", "asm.lines", "asm.xrefs", NULL);
if (argc > 1) {
ccl = (st32)rz_num_get(core->num, argv[1]);

View file

@ -2806,7 +2806,7 @@ RZ_IPI RzCmdStatus rz_cmd_debug_process_profile_handler(RzCore *core, int argc,
rz_list_append(list, (void *)argv[i]);
rz_list_free(l);
}
char *str = rz_list_to_str(list, '\n');
char *str = rz_list_to_str(list, '\n', true);
set_profile_string(core, str);
free(str);
rz_list_free(list);

View file

@ -504,16 +504,17 @@ RZ_IPI RzCmdStatus rz_eval_getset_handler(RzCore *core, int argc, const char **a
rz_cmd_state_output_fini(&state);
} else if (llen == 1) {
// no value was set, show the value of the key
const char *v = rz_config_get(cfg, key);
char *v = rz_config_get_as_string(cfg, key);
if (!v) {
RZ_LOG_ERROR("core: Invalid config key '%s'\n", key);
rz_list_free(l);
return RZ_CMD_STATUS_ERROR;
}
rz_cons_printf("%s\n", v);
free(v);
} else if (llen == 2) {
char *value = rz_list_get_n(l, 1);
rz_config_set(cfg, key, value);
rz_config_set_any(cfg, key, value);
}
rz_list_free(l);
}
@ -554,7 +555,7 @@ RZ_IPI RzCmdStatus rz_eval_editor_handler(RzCore *core, int argc, const char **a
print_all_plugin_configs(core);
return RZ_CMD_STATUS_OK;
}
const char *val = rz_config_get(cfg, argv[1]);
char *val = rz_config_get_as_string(cfg, argv[1]);
if (!val) {
RZ_LOG_ERROR("core: Invalid config key '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
@ -564,7 +565,8 @@ RZ_IPI RzCmdStatus rz_eval_editor_handler(RzCore *core, int argc, const char **a
return RZ_CMD_STATUS_ERROR;
}
rz_str_replace_char(p, '\n', ';');
rz_config_set(cfg, argv[1], p);
rz_config_set_any(cfg, argv[1], p);
free(val);
return RZ_CMD_STATUS_OK;
}
@ -574,7 +576,8 @@ RZ_IPI RzCmdStatus rz_eval_readonly_handler(RzCore *core, int argc, const char *
print_all_plugin_configs(core);
return RZ_CMD_STATUS_OK;
}
if (!rz_config_readonly(cfg, argv[1])) {
if (!rz_config_set_readonly(cfg, argv[1], true)) {
RZ_LOG_ERROR("core: Cannot make eval '%s' readonly.\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}

View file

@ -4268,11 +4268,11 @@ RZ_IPI RzCmdStatus rz_print_calls_function_handler(RzCore *core, int argc, const
// store current configurations
RzConfigHold *hc = rz_config_hold_new(core->config);
rz_config_hold_i(hc, "asm.offset", NULL);
rz_config_hold_i(hc, "asm.comments", NULL);
rz_config_hold_i(hc, "asm.tabs", NULL);
rz_config_hold_i(hc, "asm.bytes", NULL);
rz_config_hold_i(hc, "emu.str", NULL);
rz_config_hold_var(hc, "asm.offset", NULL);
rz_config_hold_var(hc, "asm.comments", NULL);
rz_config_hold_var(hc, "asm.tabs", NULL);
rz_config_hold_var(hc, "asm.bytes", NULL);
rz_config_hold_var(hc, "emu.str", NULL);
// temporarily replace configurations
rz_config_set_i(core->config, "asm.offset", false);
@ -4616,7 +4616,7 @@ RZ_IPI RzCmdStatus rz_print_columns_disassembly_handler(RzCore *core, int argc,
int rows = user_rows > 0 ? user_rows : h - 2;
RzConfigHold *ch = rz_config_hold_new(core->config);
rz_config_hold_i(ch, "asm.offset", "asm.bytes", NULL);
rz_config_hold_var(ch, "asm.offset", "asm.bytes", NULL);
if (rz_config_get_i(core->config, "asm.minicols")) {
rz_config_set_b(core->config, "asm.offset", false);
}
@ -4756,7 +4756,7 @@ static bool print_hexdump_columns(RzCore *core, int user_rows, bool has_header,
int rows = user_rows > 0 ? user_rows : h - 2;
RzConfigHold *ch = rz_config_hold_new(core->config);
rz_config_hold_i(ch, "hex.cols", NULL);
rz_config_hold_var(ch, "hex.cols", NULL);
rz_config_set_i(core->config, "hex.cols", colwidth / 5);
// Add one more line for the hexdump header
@ -5136,7 +5136,7 @@ static RzCmdStatus print_visual_bytes(RzCore *core, RZ_NONNULL const unsigned ch
if (!hc) {
return false;
}
rz_config_hold_i(hc, "asm.pseudo", "asm.esil", "asm.cmt.right", NULL);
rz_config_hold_var(hc, "asm.pseudo", "asm.esil", "asm.cmt.right", NULL);
int h, w = rz_cons_get_size(&h);
can = rz_cons_canvas_new(w, h);

View file

@ -28,7 +28,7 @@ static char *config_path(RzCore *core) {
free(path);
return NULL;
}
rz_config_serialize(core->config, sdb);
rz_serialize_config_save(sdb, core->config);
sdb_sync(sdb);
sdb_free(sdb);
@ -55,15 +55,15 @@ static int system_exec(RzCore *core, int argc, const char **argv, char **output,
char file_size[32];
char core_offset[32];
char block_size[32];
const char *file_path = rz_config_get(core->config, "file.path");
const char *asm_arch = rz_config_get(core->config, "asm.arch");
const char *asm_bits = rz_config_get(core->config, "asm.bits");
const char *bin_demangle = rz_config_get(core->config, "bin.demangle");
const char *bin_lang = rz_config_get(core->config, "bin.lang");
const char *cfg_debug = rz_config_get(core->config, "cfg.debug");
const char *io_va = rz_config_get(core->config, "io.va");
const char *pdb_server = rz_config_get(core->config, "pdb.server");
const char *scr_color = rz_config_get(core->config, "scr.color");
char *file_path = rz_config_get_as_string(core->config, "file.path");
char *asm_arch = rz_config_get_as_string(core->config, "asm.arch");
char *asm_bits = rz_config_get_as_string(core->config, "asm.bits");
char *bin_demangle = rz_config_get_as_string(core->config, "bin.demangle");
char *bin_lang = rz_config_get_as_string(core->config, "bin.lang");
char *cfg_debug = rz_config_get_as_string(core->config, "cfg.debug");
char *io_va = rz_config_get_as_string(core->config, "io.va");
char *pdb_server = rz_config_get_as_string(core->config, "pdb.server");
char *scr_color = rz_config_get_as_string(core->config, "scr.color");
const char *endian = rz_str_bool(rz_asm_is_big_endian_set(core->rasm));
char *cfg_path = config_path(core);
@ -180,6 +180,15 @@ args_err:
alloc_err:
rz_file_rm(cfg_path);
free(cfg_path);
free(file_path);
free(asm_arch);
free(asm_bits);
free(bin_demangle);
free(bin_lang);
free(cfg_debug);
free(io_va);
free(pdb_server);
free(scr_color);
return success;
}

View file

@ -629,7 +629,7 @@ RZ_API RZ_OWN char *rz_core_print_disasm_strings(RZ_NONNULL RzCore *core, RzCore
rz_config_hold_free(hc);
return NULL;
}
rz_config_hold_i(hc,
rz_config_hold_var(hc,
"asm.offset",
"asm.debuginfo",
"asm.tabs",

View file

@ -4727,7 +4727,7 @@ static void ds_print_esil_analysis(RzDisasmState *ds) {
rz_analysis_esil_parse(esil, esilstr);
}
rz_analysis_esil_stack_free(esil);
rz_config_hold_i(hc, "io.cache", NULL);
rz_config_hold_var(hc, "io.cache", NULL);
rz_config_set(core->config, "io.cache", "true");
if (!ds->show_comments) {
goto beach;
@ -5263,8 +5263,7 @@ RZ_API int rz_core_print_disasm(RZ_NONNULL RzCore *core, ut64 addr, RZ_NONNULL u
if (!rch) {
return 0;
}
rz_config_hold_s(rch, "asm.arch", NULL);
rz_config_hold_i(rch, "asm.bits", NULL);
rz_config_hold_var(rch, "asm.arch", "asm.bits", NULL);
// TODO: All those ds must be print flags
RzReg *rreg = rz_analysis_get_reg(core->analysis);
@ -6457,7 +6456,7 @@ RZ_API int rz_core_disasm_pde(RzCore *core, int nb_opcodes, RzCmdStateOutput *st
}
rz_reg_arena_push(reg);
RzConfigHold *chold = rz_config_hold_new(core->config);
rz_config_hold_i(chold, "io.cache", "asm.lines", NULL);
rz_config_hold_var(chold, "io.cache", "asm.lines", NULL);
rz_config_set_i(core->config, "io.cache", true);
rz_config_set_i(core->config, "asm.lines", false);
const char *strip = rz_config_get(core->config, "asm.strip");

View file

@ -389,7 +389,7 @@ static int rz_core_rtr_http_run(RzCore *core, bool open_browser) {
if (!hc) {
return 0;
}
rz_config_hold_i(hc, "scr.color", "scr.html", "scr.interactive", "asm.cmt.right", "asm.bytes", NULL);
rz_config_hold_var(hc, "scr.color", "scr.html", "scr.interactive", "asm.cmt.right", "asm.bytes", NULL);
// set new configs
rz_config_set(core->config, "asm.cmt.right", "false");

View file

@ -43,7 +43,7 @@ RZ_API void rz_serialize_core_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core,
sdb_set(db, "blocksize", buf);
}
static const char *const config_exclude[] = {
static const char *config_exclude[] = {
"dir.home",
"dir.libs",
"dir.magic",
@ -79,7 +79,7 @@ RZ_API bool rz_serialize_core_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzCore *core,
if (load_bin_io) {
SUB("file", file_load(subdb, core, prj_file, res));
}
SUB("config", rz_serialize_config_load(subdb, core->config, config_exclude, res));
SUB("config", rz_serialize_config_load(subdb, core->config, config_exclude));
SUB("flags", rz_serialize_flag_load(subdb, core->flags, res));
SUB("marks", rz_serialize_mark_load(subdb, core->marks, res));
SUB("analysis", rz_serialize_analysis_load(subdb, core->analysis, res));

View file

@ -12,156 +12,189 @@
#include <rz_util/rz_strbuf.h>
#include <cmd_descs.h>
typedef struct config_visual_ctx {
const char *fs;
const char *fs2;
const char *desc;
int i;
int j;
int hit;
int show;
int option;
int _option;
char old[1024];
int delta;
int menu;
RzCore *core;
} ConfigVisualCtx;
static void config_visual_hit_i(RzCore *core, const char *name, int delta) {
struct rz_config_node_t *node;
node = rz_config_node_get(core->config, name);
if (node && rz_config_node_is_int(node)) {
int hitDelta = rz_config_get_i(core->config, name) + delta;
(void)rz_config_set_i(core->config, name, hitDelta);
const ut32 flags = rz_config_get_flags(core->config, name);
if (!(RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_INT))) {
return;
}
ut64 value = rz_config_get_i(core->config, name);
value += delta;
rz_config_set_i(core->config, name, value);
}
/* Visually activate the config variable */
static void config_visual_hit(RzCore *core, const char *name, int editor) {
char buf[1024];
RzConfigNode *node;
RzLine *line = core->cons->line;
if (!(node = rz_config_node_get(core->config, name))) {
const ut32 flags = rz_config_get_flags(core->config, name);
if (!flags) {
return;
}
if (rz_config_node_is_bool(node)) {
rz_config_set_i(core->config, name, node->i_value ? 0 : 1);
} else {
// XXX: must use config_set () to run callbacks!
if (editor) {
char *buf = rz_core_editor(core, NULL, node->value);
char *tmp = rz_str_dup(buf);
free(node->value);
node->value = tmp;
free(buf);
} else {
// FGETS AND SO
rz_cons_printf("New value (old=%s): \n", node->value);
rz_cons_show_cursor(true);
rz_cons_flush();
rz_cons_set_raw(0);
rz_line_set_prompt(line, ":> ");
rz_cons_fgets(buf, sizeof(buf), 0, 0);
rz_cons_set_raw(1);
rz_cons_show_cursor(false);
rz_config_set(core->config, name, buf);
// node->value = rz_str_dup (node->value, buf);
}
if ((RZ_CONFIG_VAR_IS_TYPE(flags, RZ_CONFIG_VAR_TYPE_BOOL))) {
rz_config_toggle_bool(core->config, name);
return;
}
char *value = rz_config_get_as_string(core->config, name);
if (editor) {
char *buf = rz_core_editor(core, NULL, value);
rz_config_set_any(core->config, name, buf);
free(buf);
free(value);
return;
}
rz_cons_printf("New value (old=%s): \n", value);
rz_cons_show_cursor(true);
rz_cons_flush();
rz_cons_set_raw(0);
rz_line_set_prompt(line, ":> ");
rz_cons_fgets(buf, sizeof(buf), 0, 0);
rz_cons_set_raw(1);
rz_cons_show_cursor(false);
rz_config_set_any(core->config, name, buf);
free(value);
}
static void show_config_options(RzCore *core, const char *opt) {
RzConfigNode *node = rz_config_node_get(core->config, opt);
if (node && !rz_list_empty(node->options)) {
int h, w = rz_cons_get_size(&h);
const char *item;
RzListIter *iter;
RzStrBuf *sb = rz_strbuf_new(" Options: ");
rz_list_foreach (node->options, iter, item) {
rz_strbuf_appendf(sb, "%s%s", rz_list_has_prev(iter) ? ", " : "", item);
if (rz_strbuf_length(sb) + 5 >= w) {
char *s = rz_strbuf_drain(sb);
rz_cons_println(s);
free(s);
sb = rz_strbuf_new("");
}
}
char *s = rz_strbuf_drain(sb);
rz_cons_println(s);
free(s);
static void show_config_options(RzCore *core, const char *name) {
const RzList *options = rz_config_get_options(core->config, name);
if (rz_list_empty(options)) {
return;
}
int w = rz_cons_get_size(NULL);
const char *item;
const RzListIter *iter;
RzStrBuf *sb = rz_strbuf_new(" Options: ");
rz_list_foreach (options, iter, item) {
rz_strbuf_appendf(sb, "%s%s", rz_list_val(iter) ? ", " : "", item);
if (rz_strbuf_length(sb) + 5 >= w) {
char *s = rz_strbuf_drain(sb);
rz_cons_println(s);
free(s);
sb = rz_strbuf_new("");
}
}
char *s = rz_strbuf_drain(sb);
rz_cons_println(s);
free(s);
}
static bool core_visual_config_flag_space(const RzConfigEntry *entry, void *user) {
ConfigVisualCtx *ctx = (ConfigVisualCtx *)user;
const char *name = rz_config_entry_get_name(entry);
if (ctx->option == ctx->i) {
ctx->fs = name;
}
if (!ctx->old[0]) {
rz_str_ccpy(ctx->old, name, '.');
ctx->show = 1;
} else if (rz_str_ccmp(ctx->old, name, '.')) {
rz_str_ccpy(ctx->old, name, '.');
ctx->show = 1;
} else {
ctx->show = 0;
}
if (ctx->show) {
if (ctx->option == ctx->i) {
ctx->hit = 1;
}
if ((ctx->i >= ctx->option - ctx->delta) &&
((ctx->i < ctx->option + ctx->delta) || ((ctx->option < ctx->delta) && (ctx->i < (ctx->delta << 1))))) {
rz_cons_printf(" %c %s\n", (ctx->option == ctx->i) ? '>' : ' ', ctx->old);
ctx->j++;
}
ctx->i++;
}
return true;
}
static bool core_visual_config_flag_selection(const RzConfigEntry *entry, void *user) {
ConfigVisualCtx *ctx = (ConfigVisualCtx *)user;
const char *name = rz_config_entry_get_name(entry);
const char *desc = rz_config_entry_get_desc(entry);
if (!rz_str_ccmp(name, ctx->fs, '.')) {
if (ctx->option == ctx->i) {
ctx->fs2 = name;
ctx->desc = desc;
ctx->hit = 1;
}
if ((ctx->i >= ctx->option - ctx->delta) &&
((ctx->i < ctx->option + ctx->delta) || ((ctx->option < ctx->delta) && (ctx->i < (ctx->delta << 1))))) {
// TODO: Better align
char *value = rz_config_get_as_string(ctx->core->config, name);
rz_cons_printf(" %c %s = %s\n", (ctx->option == ctx->i) ? '>' : ' ', name, value);
free(value);
ctx->j++;
}
ctx->i++;
}
return true;
}
RZ_IPI void rz_core_visual_config(RzCore *core) {
char *fs = NULL, *fs2 = NULL, *desc = NULL;
int i, j, ch, hit, show;
int option, _option = 0;
RzListIter *iter;
RzConfigNode *bt;
char old[1024];
int delta = 9;
int menu = 0;
old[0] = '\0';
int ch = 0;
ConfigVisualCtx ctx = { 0 };
ctx._option = 0;
ctx.delta = 9;
ctx.menu = 0;
ctx.core = core;
option = 0;
for (;;) {
rz_cons_clear00();
rz_cons_get_size(&delta);
delta /= 4;
rz_cons_get_size(&ctx.delta);
ctx.delta /= 4;
switch (menu) {
switch (ctx.menu) {
case 0: // flag space
rz_cons_printf("[EvalSpace]\n\n");
hit = j = i = 0;
rz_list_foreach (core->config->nodes, iter, bt) {
if (option == i) {
fs = bt->name;
}
if (!old[0]) {
rz_str_ccpy(old, bt->name, '.');
show = 1;
} else if (rz_str_ccmp(old, bt->name, '.')) {
rz_str_ccpy(old, bt->name, '.');
show = 1;
} else {
show = 0;
}
if (show) {
if (option == i) {
hit = 1;
}
if ((i >= option - delta) && ((i < option + delta) || ((option < delta) && (i < (delta << 1))))) {
rz_cons_printf(" %c %s\n", (option == i) ? '>' : ' ', old);
j++;
}
i++;
}
}
if (!hit && j > 0) {
option--;
ctx.hit = ctx.j = ctx.i = 0;
rz_config_iterate_over(core->config, core_visual_config_flag_space, &ctx);
if (!ctx.hit && ctx.j > 0) {
ctx.option--;
continue;
}
rz_cons_printf("\n Sel: %s \n\n", fs);
rz_cons_printf("\n Sel: %s \n\n", ctx.fs);
break;
case 1: // flag selection
rz_cons_printf("[EvalSpace < Variables: %s]\n\n", fs);
hit = 0;
j = i = 0;
// TODO: cut -d '.' -f 1 | sort | uniq !!!
rz_list_foreach (core->config->nodes, iter, bt) {
if (!rz_str_ccmp(bt->name, fs, '.')) {
if (option == i) {
fs2 = bt->name;
desc = bt->desc;
hit = 1;
}
if ((i >= option - delta) && ((i < option + delta) || ((option < delta) && (i < (delta << 1))))) {
// TODO: Better align
rz_cons_printf(" %c %s = %s\n", (option == i) ? '>' : ' ', bt->name, bt->value);
j++;
}
i++;
}
}
if (!hit && j > 0) {
option = i - 1;
rz_cons_printf("[EvalSpace < Variables: %s]\n\n", ctx.fs);
ctx.hit = 0;
ctx.j = ctx.i = 0;
rz_config_iterate_over(core->config, core_visual_config_flag_selection, &ctx);
if (!ctx.hit && ctx.j > 0) {
ctx.option = ctx.i - 1;
continue;
}
if (fs2) {
if (ctx.fs2) {
// TODO: Break long lines.
rz_cons_printf("\n Selected: %s (%s)\n", fs2, desc);
show_config_options(core, fs2);
rz_cons_printf("\n Selected: %s (%s)\n", ctx.fs2, ctx.desc);
show_config_options(core, ctx.fs2);
rz_cons_newline();
}
}
if (fs && !strncmp(fs, "asm.", 4)) {
if (ctx.fs && !strncmp(ctx.fs, "asm.", 4)) {
rz_core_cmd(core, "pd $r", 0);
}
rz_cons_visual_flush();
@ -172,25 +205,25 @@ RZ_IPI void rz_core_visual_config(RzCore *core) {
ch = rz_cons_arrow_to_hjkl(ch); // get ESC+char, return 'hjkl' char
switch (ch) {
case 'j': option++; break;
case 'k': option = (option <= 0) ? 0 : option - 1; break;
case 'J': option += 4; break;
case 'K': option = (option <= 3) ? 0 : option - 4; break;
case 'j': ctx.option++; break;
case 'k': ctx.option = (ctx.option <= 0) ? 0 : ctx.option - 1; break;
case 'J': ctx.option += 4; break;
case 'K': ctx.option = (ctx.option <= 3) ? 0 : ctx.option - 4; break;
case 'h':
case 'b': // back
menu = 0;
option = _option;
ctx.menu = 0;
ctx.option = ctx._option;
break;
case '_':
rz_core_visual_config_hud(core);
break;
case 'Q':
case 'q':
if (menu <= 0) {
if (ctx.menu <= 0) {
return;
}
menu--;
option = _option;
ctx.menu--;
ctx.option = ctx._option;
break;
case '$':
rz_list_rizin_vars_handler(core, 0, NULL);
@ -198,11 +231,11 @@ RZ_IPI void rz_core_visual_config(RzCore *core) {
break;
case '*':
case '+':
fs2 ? config_visual_hit_i(core, fs2, +1) : 0;
ctx.fs2 ? config_visual_hit_i(core, ctx.fs2, +1) : 0;
continue;
case '/':
case '-':
fs2 ? config_visual_hit_i(core, fs2, -1) : 0;
ctx.fs2 ? config_visual_hit_i(core, ctx.fs2, -1) : 0;
continue;
case 'l':
case 'E': // edit value
@ -210,12 +243,12 @@ RZ_IPI void rz_core_visual_config(RzCore *core) {
case ' ':
case '\r':
case '\n': // never happens
if (menu == 1) {
fs2 ? config_visual_hit(core, fs2, (ch == 'E')) : 0;
if (ctx.menu == 1) {
ctx.fs2 ? config_visual_hit(core, ctx.fs2, (ch == 'E')) : 0;
} else {
menu = 1;
_option = option;
option = 0;
ctx.menu = 1;
ctx._option = ctx.option;
ctx.option = 0;
}
break;
case '?':

View file

@ -64,11 +64,10 @@ RZ_IPI bool rz_core_visual_hudclasses(RzCore *core) {
RzBinSymbol *m;
ut64 addr;
char *res;
RzList *list = rz_list_new();
RzList *list = rz_list_newf(free);
if (!list) {
return false;
}
list->free = free;
RzBinObject *bin_obj = rz_bin_cur_object(core->bin);
const RzPVector *classes = rz_bin_object_get_classes(bin_obj);
if (!classes) {
@ -110,11 +109,10 @@ static bool hudstuff_append(RzFlagItem *fi, void *user) {
RZ_IPI bool rz_core_visual_hudstuff(RzCore *core) {
ut64 addr;
char *res;
RzList *list = rz_list_new();
RzList *list = rz_list_newf(free);
if (!list) {
return false;
}
list->free = free;
rz_flag_foreach(core->flags, hudstuff_append, list);
RzIntervalTreeIter it;
RzAnalysisMetaItem *mi;
@ -141,17 +139,26 @@ RZ_IPI bool rz_core_visual_hudstuff(RzCore *core) {
return res != NULL;
}
bool core_visual_config_hud_append(const RzConfigEntry *entry, void *user) {
RzList *list = (RzList *)user;
const char *name = rz_config_entry_get_name(entry);
char *value = rz_config_entry_get_as_string(entry);
char *str = rz_str_newf("%s %s", name, value);
if (!str || !rz_list_append(list, str)) {
free(str);
}
free(value);
return true;
}
RZ_IPI bool rz_core_visual_config_hud(RzCore *core) {
RzListIter *iter;
RzConfigNode *bt;
RzList *list = rz_list_new();
RzList *list = rz_list_newf(free);
if (!list) {
return false;
}
list->free = free;
rz_list_foreach (core->config->nodes, iter, bt) {
rz_list_append(list, rz_str_newf("%s %s", bt->name, bt->value));
}
rz_config_iterate_over(core->config, core_visual_config_hud_append, list);
char *res = rz_cons_hud(list, NULL);
if (res) {
const char *oldvalue = NULL;

View file

@ -4417,7 +4417,9 @@ void __init_menu_disasm_settings_layout(void *_core, const char *parent) {
} else {
rz_strbuf_set(rsb, pos);
rz_strbuf_append(rsb, ": ");
rz_strbuf_append(rsb, rz_config_get(core->config, pos));
char *val = rz_config_get_as_string(core->config, pos);
rz_strbuf_append(rsb, val);
free(val);
__add_menu(core, parent, rz_strbuf_get(rsb), __config_toggle_cb);
}
}
@ -4434,7 +4436,9 @@ static void __init_menu_disasm_asm_settings_layout(void *_core, const char *pare
char *pos = *iter;
rz_strbuf_set(rsb, pos);
rz_strbuf_append(rsb, ": ");
rz_strbuf_append(rsb, rz_config_get(core->config, pos));
char *val = rz_config_get_as_string(core->config, pos);
rz_strbuf_append(rsb, val);
free(val);
if (!strcmp(pos, "asm.var.summary") ||
!strcmp(pos, "asm.arch") ||
!strcmp(pos, "asm.bits") ||
@ -4456,7 +4460,9 @@ static void __init_menu_screen_settings_layout(void *_core, const char *parent)
const char *menu = menus_settings_screen[i];
rz_strbuf_set(rsb, menu);
rz_strbuf_append(rsb, ": ");
rz_strbuf_append(rsb, rz_config_get(core->config, menu));
char *val = rz_config_get_as_string(core->config, menu);
rz_strbuf_append(rsb, val);
free(val);
if (!strcmp(menus_settings_screen[i], "scr.color")) {
__add_menu(core, parent, rz_strbuf_get(rsb), __config_value_cb);
} else {

View file

@ -105,7 +105,7 @@ RZ_IPI void rz_core_visual_toggle_decompiler_disasm(RzCore *core, bool for_graph
return;
}
hold = rz_config_hold_new(core->config);
rz_config_hold_s(hold, "asm.hint.pos", "asm.cmt.col", "asm.offset", "asm.lines",
rz_config_hold_var(hold, "asm.hint.pos", "asm.cmt.col", "asm.offset", "asm.lines",
"asm.indent", "asm.bytes", "asm.comments", "asm.debuginfo", "asm.usercomments", "asm.instr", NULL);
if (for_graph) {
rz_config_set(core->config, "asm.hint.pos", "-2");
@ -1264,7 +1264,7 @@ repeat:
if (!hc) {
return RZ_CMD_STATUS_ERROR;
}
rz_config_hold_i(hc, "asm.flags.limit", NULL);
rz_config_hold_var(hc, "asm.flags.limit", NULL);
rz_config_set_i(core->config, "asm.flags.limit", 1);
char *res = rz_core_print_cons_disassembly(core, xaddr2, 4, 0);
rz_config_hold_restore(hc);

View file

@ -248,7 +248,7 @@ RZ_IPI int __core_visual_view_graph_update(RzCore *core, RzCoreVisualViewGraph *
if (!hc) {
return 0;
}
rz_config_hold_i(hc, "asm.flags", NULL);
rz_config_hold_var(hc, "asm.flags", NULL);
rz_config_set_i(core->config, "asm.flags", 0);
char *output1 = rz_core_print_cons_disassembly(core, status->addr, 32, 0);
rz_config_hold_restore(hc);

View file

@ -393,7 +393,6 @@ static RzDebugReasonType rz_debug_gdb_wait(RzDebug *dbg, int pid) {
static int rz_debug_gdb_attach(RzDebug *dbg, int pid) {
RzDebugGdbCtx *ctx = dbg->plugin_data;
RzIODesc *d = dbg->iob.io->desc;
// TODO: the core must update the dbg.swstep config var when this var is changed
dbg->swstep = false;
// eprintf ("XWJSTEP TOFALSE\n");
if (!(d && d->plugin && d->plugin->name && d->data)) {

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-FileCopyrightText: 2006-2021 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_CONFIG_H
#define RZ_CONFIG_H
@ -13,12 +17,8 @@ RZ_LIB_VERSION_HEADER(rz_config);
#define CN_BOOL 0x000001
#define CN_INT 0x000002
// NOTE: removed because this is redundant and it does not add any value
// compared to CN_INT. Use that instead for consistency
// #define CN_OFFT 0x000004
#define CN_STR 0x000008
#define CN_RO 0x000010
#define CN_RW 0x000020
#define CN_STR 0x000008
#define CN_RO 0x000010
#define NODECB(w, x, y) rz_config_set_cb(cfg, w, x, y)
#define NODEICB(w, x, y) rz_config_set_i_cb(cfg, w, x, y)
@ -41,97 +41,193 @@ typedef struct rz_config_node_t {
ut64 *cb_ptr_q;
int *cb_ptr_i;
char **cb_ptr_s;
RzConfigCallback getter;
RzConfigCallback setter;
char *desc;
RzList /*<char *>*/ *options;
} RzConfigNode;
RZ_API const char *rz_config_node_type(RzConfigNode *node);
typedef enum {
RZ_CONFIG_VAR_TYPE_NONE = 0,
// these are types
RZ_CONFIG_VAR_TYPE_BOOL = 1,
RZ_CONFIG_VAR_TYPE_INT = 2,
RZ_CONFIG_VAR_TYPE_STR = 3,
RZ_CONFIG_VAR_TYPE_LIST = 4,
RZ_CONFIG_VAR_TYPE_ITV = 5,
// these are flags
RZ_CONFIG_VAR_FLAG_BIND = 0x40000000,
RZ_CONFIG_VAR_FLAG_WRITABLE = 0x80000000,
} RzConfigVarFlags;
#define RZ_CONFIG_VAR_TYPE_MASK 0x0000ffff
#define RZ_CONFIG_VAR_FLAGS_MASK 0xffff0000
#define RZ_CONFIG_VAR_IS_TYPE(flags, expected) (((flags) & RZ_CONFIG_VAR_TYPE_MASK) == (expected))
#define RZ_CONFIG_VAR_HAS_FLAG(flags, expected) (((flags) & RZ_CONFIG_VAR_FLAGS_MASK) & (expected))
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_bind_t {
void *user;
RzConfigBindGet get_value;
RzConfigBindSet set_value;
RzConfigBindOpts get_options;
} RzConfigBind;
typedef struct rz_config_var_t {
char *name; ///< Variable name
char *desc; ///< Description of the variable
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
RzConfigBind bind; ///< bind value
};
} RzConfigVar;
typedef struct rz_config_entry_t {
bool is_variable;
union {
RzConfigVar var;
RzConfigNode node;
};
} RzConfigEntry;
typedef struct rz_config_t {
int lock;
void *user;
RzNum *num;
RzList /*<RzConfigNode *>*/ *nodes;
HtSP *ht;
void *user; ///< DEPRECATED
bool lock; ///< DEPRECATED
RzVector /*<RzConfigEntry>*/ sorted_vars; ///< Sorted owned variables
} RzConfig;
typedef struct rz_config_hold_num_t {
char *key;
ut64 value;
} RzConfigHoldNum;
typedef struct rz_config_hold_char_t {
char *key;
char *value;
} RzConfigHoldChar;
typedef struct rz_config_hold_t {
RzConfig *cfg;
RzList /*<RzConfigHoldNum *>*/ *list_num; // holds numeric values
RzList /*<RzConfigHoldChar *>*/ *list_char; // holds char values
} RzConfigHold;
typedef struct rz_config_hold_t RzConfigHold;
typedef bool (*RzConfigIterator)(const RzConfigEntry *entry, void *user);
#ifdef RZ_API
RZ_API RzConfigHold *rz_config_hold_new(RzConfig *cfg);
RZ_API void rz_config_hold_free(RzConfigHold *h);
RZ_API bool rz_config_hold_i(RzConfigHold *h, ...);
RZ_API bool rz_config_hold_s(RzConfigHold *h, ...);
RZ_API bool rz_config_hold_var(RZ_NONNULL RzConfigHold *hold, ...);
RZ_API RzConfigHold *rz_config_hold_new(RZ_NONNULL RzConfig *cfg);
RZ_API RzConfigHold *rz_config_hold_new2(RZ_NONNULL RzConfig *cfg, ...);
RZ_API void rz_config_hold_restore(RZ_NULLABLE RzConfigHold *hold);
RZ_API void rz_config_hold_free(RZ_NULLABLE RzConfigHold *h);
RZ_API void rz_config_hold_restore_and_free(RZ_NULLABLE RzConfigHold *hold);
RZ_API void rz_config_hold_restore(RzConfigHold *h);
RZ_API RZ_OWN RzConfig *rz_config_new(RZ_DEPRECATE RZ_BORROW void *user);
RZ_API void rz_config_free(RZ_NULLABLE RzConfig *cfg);
RZ_API RZ_OWN RzConfig *rz_config_new(RZ_BORROW void *user);
RZ_API RZ_OWN RzConfig *rz_config_clone(RZ_BORROW RzConfig *cfg);
RZ_API void rz_config_free(RZ_OWN RzConfig *cfg);
RZ_API void rz_config_lock(RZ_BORROW RzConfig *cfg, int l);
RZ_API void rz_config_bump(RZ_BORROW RzConfig *cfg, const char *key);
RZ_API bool rz_config_set_readonly(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, bool read_only);
RZ_API bool rz_config_is_readonly(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API void rz_config_iterate_over(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL RzConfigIterator iterator, RZ_NULLABLE void *user);
RZ_API bool rz_config_add_bool(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, bool value);
RZ_API bool rz_config_add_integer(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, ut64 value);
RZ_API bool rz_config_add_string(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, RZ_NULLABLE const char *value);
RZ_API bool rz_config_add_options(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, ...);
RZ_API bool rz_config_add_list(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, ...);
RZ_API bool rz_config_add_interval(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, ut64 from, ut64 to);
RZ_API bool rz_config_add_bind(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc, ut32 type, RZ_NONNULL RzConfigBindGet get, RZ_NULLABLE RzConfigBindSet set, RZ_NULLABLE RzConfigBindOpts opts, RZ_NULLABLE void *user);
#define rz_config_add_bool_bind(cfg, name, desc, get, set, opts, user) rz_config_add_bind(cfg, name, desc, RZ_CONFIG_VAR_TYPE_BOOL, get, set, opts, user)
#define rz_config_add_integer_bind(cfg, name, desc, get, set, opts, user) rz_config_add_bind(cfg, name, desc, RZ_CONFIG_VAR_TYPE_INT, get, set, opts, user)
#define rz_config_add_string_bind(cfg, name, desc, get, set, opts, user) rz_config_add_bind(cfg, name, desc, RZ_CONFIG_VAR_TYPE_STR, get, set, opts, user)
#define rz_config_add_list_bind(cfg, name, desc, get, set, opts, user) rz_config_add_bind(cfg, name, desc, RZ_CONFIG_VAR_TYPE_LIST, get, set, opts, user)
#define rz_config_add_interval_bind(cfg, name, desc, get, set, opts, user) rz_config_add_bind(cfg, name, desc, RZ_CONFIG_VAR_TYPE_ITV, get, set, opts, user)
RZ_API bool rz_config_set_string(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *value);
RZ_API bool rz_config_set_integer(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, ut64 value);
RZ_API bool rz_config_set_bool(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, bool value);
RZ_API bool rz_config_toggle_bool(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API bool rz_config_set_list(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const RzList /*<const char *>*/ *value);
RZ_API bool rz_config_set_list2(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, ...);
RZ_API bool rz_config_set_list3(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *comma_list);
RZ_API bool rz_config_set_interval(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RzInterval value);
RZ_API bool rz_config_set_interval2(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, ut64 from, ut64 to);
RZ_API bool rz_config_set_interval3(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *comma_itv);
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_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);
RZ_API const char *rz_config_get_string(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API RZ_OWN RzList /*<const char *>*/ *rz_config_get_list(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API RzInterval rz_config_get_interval(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API RZ_OWN char *rz_config_get_as_string(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API const RzList /*<char *>*/ *rz_config_get_options(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API ut32 rz_config_get_flags(RZ_NONNULL const RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API bool rz_config_var_as_json(RZ_NONNULL const RzConfigVar *var, RZ_NONNULL PJ *pj, RZ_NONNULL const char *key);
RZ_API RZ_OWN char *rz_config_var_as_string(RZ_NONNULL const RzConfigVar *var);
RZ_API bool rz_config_var_is_readonly(RZ_NONNULL const RzConfigVar *var);
RZ_API bool rz_config_var_get_bool(RZ_NONNULL const RzConfigVar *var);
RZ_API ut64 rz_config_var_get_integer(RZ_NONNULL const RzConfigVar *var);
RZ_API const char *rz_config_var_get_string(RZ_NONNULL const RzConfigVar *var);
RZ_API RZ_OWN RzList /*<const char *>*/ *rz_config_var_get_list(RZ_NONNULL const RzConfigVar *var);
RZ_API RzInterval rz_config_var_get_interval(RZ_NONNULL const RzConfigVar *var);
RZ_API bool rz_config_var_has_type(RZ_NONNULL const RzConfigVar *var, ut32 etype);
RZ_API bool rz_config_var_has_flags(RZ_NONNULL const RzConfigVar *var, ut32 eflags);
RZ_API RZ_OWN char *rz_config_var_flags_as_string(ut32 flags);
RZ_API ut32 rz_config_var_get_flags(RZ_NONNULL const RzConfigVar *var);
RZ_API const char *rz_config_var_get_name(RZ_NONNULL const RzConfigVar *var);
RZ_API const char *rz_config_var_get_desc(RZ_NONNULL const RzConfigVar *var);
RZ_API const RzList /*<char *>*/ *rz_config_var_get_options(RZ_NONNULL const RzConfigVar *var);
/* to deprecate */
RZ_API const char *rz_config_entry_get_name(RZ_NONNULL const RzConfigEntry *entry);
RZ_API const char *rz_config_entry_get_desc(RZ_NONNULL const RzConfigEntry *entry);
RZ_API ut64 rz_config_entry_get_integer(RZ_NONNULL const RzConfigEntry *entry);
RZ_API bool rz_config_entry_get_bool(RZ_NONNULL const RzConfigEntry *entry);
RZ_API const char *rz_config_entry_get_string(RZ_NONNULL const RzConfigEntry *entry);
RZ_API RZ_OWN char *rz_config_entry_get_as_string(RZ_NONNULL const RzConfigEntry *entry);
/* old apis, deprecated */
RZ_API const char *rz_config_node_type(RzConfigNode *node);
RZ_API RZ_BORROW RzConfigNode *rz_config_set_i(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i);
RZ_API RZ_BORROW RzConfigNode *rz_config_set_b(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name, bool value);
RZ_API RZ_BORROW RzConfigNode *rz_config_set_cb(RZ_BORROW RzConfig *cfg, const char *name, const char *value, bool (*callback)(void *user, void *data));
RZ_API RZ_BORROW RzConfigNode *rz_config_set_i_cb(RZ_BORROW RzConfig *cfg, const char *name, st64 ivalue, bool (*callback)(void *user, void *data));
RZ_API RZ_BORROW RzConfigNode *rz_config_set(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name, const char *value);
RZ_API bool rz_config_add_node(RZ_BORROW RzConfig *cfg, RZ_OWN RzConfigNode *node);
RZ_API bool rz_config_rm(RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API bool rz_config_get_b(RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API RZ_BORROW const char *rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API const char *rz_config_desc(RzConfig *cfg, RZ_NONNULL const char *name, RZ_NULLABLE const char *desc);
RZ_API const char *rz_config_node_desc(RzConfigNode *node, RZ_NULLABLE const char *desc);
RZ_API RZ_BORROW RzConfigNode *rz_config_node_get(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API RZ_OWN RzConfigNode *rz_config_node_new(RZ_NONNULL const char *name, RZ_NONNULL const char *value);
RZ_API RZ_OWN RzConfigNode *rz_config_node_clone(RZ_BORROW RzConfigNode *n);
RZ_API void rz_config_node_free(RZ_NULLABLE void *n);
RZ_API void rz_config_node_value_format_i(RZ_OUT char *buf, size_t buf_size, const ut64 i, RZ_NULLABLE RzConfigNode *node);
RZ_API bool rz_config_toggle(RZ_BORROW RzConfig *cfg, RZ_NONNULL const char *name);
RZ_API bool rz_config_readonly(RZ_BORROW RzConfig *cfg, const char *key);
RZ_API bool rz_config_eval(RZ_NONNULL RzConfig *cfg, RZ_NONNULL const char *str);
RZ_API ut32 rz_config_node_get_var_flags(RZ_NONNULL const RzConfigNode *node);
RZ_API bool rz_config_set_setter(RzConfig *cfg, const char *key, RzConfigCallback cb);
RZ_API bool rz_config_set_getter(RzConfig *cfg, const char *key, RzConfigCallback cb);
RZ_API void rz_config_serialize(RZ_NONNULL RzConfig *config, RZ_NONNULL Sdb *db);
RZ_API bool rz_config_unserialize(RZ_NONNULL RzConfig *config, RZ_NONNULL Sdb *db, RZ_NULLABLE char **err);
static inline bool rz_config_node_is_bool(RzConfigNode *node) {
static inline bool rz_config_node_is_bool(const RzConfigNode *node) {
return node->flags & CN_BOOL;
}
static inline bool rz_config_node_is_int(RzConfigNode *node) {
static inline bool rz_config_node_is_int(const RzConfigNode *node) {
return node->flags & CN_INT;
}
static inline bool rz_config_node_is_ro(RzConfigNode *node) {
static inline bool rz_config_node_is_ro(const RzConfigNode *node) {
return node->flags & CN_RO;
}
static inline bool rz_config_node_is_str(RzConfigNode *node) {
static inline bool rz_config_node_is_str(const RzConfigNode *node) {
return node->flags & CN_STR;
}
/* serialize */
RZ_API void rz_serialize_config_save(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config);
RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config,
RZ_NULLABLE const char *const *exclude, RZ_NULLABLE RzSerializeResultInfo *res);
RZ_API bool rz_serialize_config_load(RZ_NONNULL Sdb *db, RZ_NONNULL RzConfig *config, RZ_NULLABLE const char **exclude);
#endif
#ifdef __cplusplus

View file

@ -255,7 +255,7 @@ typedef struct rz_debug_t {
char *btalgo; /* select backtrace algorithm */
int btdepth; /* backtrace depth */
int regcols; /* display columns */
int swstep; /* steps with software traps */
bool swstep; /* when true, steps with software traps */
int stop_all_threads; /* stop all threads at any stop */
int trace_forks; /* stop on new children */
int trace_execs; /* stop on new execs */

View file

@ -135,7 +135,7 @@ RZ_API RZ_OWN void *rz_list_pop(RZ_NONNULL RzList *list);
RZ_API RZ_OWN void *rz_list_pop_head(RZ_NONNULL RzList *list);
RZ_API void rz_list_reverse(RZ_NONNULL RzList *list);
RZ_API RZ_OWN RzList *rz_list_clone(RZ_NONNULL const RzList *list);
RZ_API RZ_OWN char *rz_list_to_str(RZ_NONNULL RzList *list, char ch);
RZ_API RZ_OWN char *rz_list_to_str(RZ_NONNULL RzList /*<const char *>*/ *list, char ch, bool append_last);
/* hashlike api */
RZ_API RZ_BORROW bool rz_list_contains(RZ_NONNULL const RzList *list, RZ_NONNULL const void *val);

View file

@ -204,7 +204,7 @@ RZ_API bool rz_str_cmp_list(const char *list, const char *item, char sep);
RZ_API int rz_str_cmp(RZ_NULLABLE const char *dst, RZ_NULLABLE const char *orig, int len);
RZ_API int rz_str_casecmp(const char *dst, const char *orig);
RZ_API int rz_str_ncasecmp(const char *dst, const char *orig, size_t n);
RZ_API int rz_str_ccpy(char *dst, char *orig, int ch);
RZ_API int rz_str_ccpy(char *dst, const char *orig, int ch);
static inline const char *rz_str_get(const char *str) {
return str ? str : "";
}

View file

@ -736,7 +736,7 @@ RZ_API int rz_main_rz_bin(int argc, const char **argv) {
if ((tmp = rz_sys_getenv("RZ_CONFIG"))) {
Sdb *config_sdb = sdb_new(NULL, tmp, 0);
if (config_sdb) {
rz_config_unserialize(core.config, config_sdb, NULL);
rz_serialize_config_load(config_sdb, core.config, NULL);
sdb_free(config_sdb);
} else {
eprintf("Cannot open file specified in RZ_CONFIG\n");

View file

@ -1513,10 +1513,10 @@ static char *basic_block_opcodes(RzCore *core, RzAnalysisBlock *bbi) {
RzConfigHold *hc = NULL;
ut8 *block = NULL;
if (!(hc = rz_config_hold_new(core->config))) {
hc = rz_config_hold_new2(core->config, "scr.color", "scr.utf8", "asm.offset", "asm.lines", "asm.cmt.right", "asm.lines.fcn", "asm.bytes", "asm.comments", NULL);
if (!hc) {
return NULL;
}
rz_config_hold_i(hc, "scr.color", "scr.utf8", "asm.offset", "asm.lines", "asm.cmt.right", "asm.lines.fcn", "asm.bytes", "asm.comments", NULL);
rz_config_set_i(core->config, "scr.utf8", 0);
rz_config_set_i(core->config, "asm.offset", 0);
rz_config_set_i(core->config, "asm.lines", 0);

View file

@ -871,20 +871,30 @@ RZ_API void rz_list_sorted_uniq(RZ_NONNULL RzList *list, RZ_NONNULL RzListCompar
/**
* \brief Casts a RzList containing strings into a concatenated string
*
* \param list The list of strings to concatenate.
* \param ch char to separate the match strings.
* \param list The list of strings to concatenate.
* \param ch Char to separate the match strings.
* \param append_last When true appends `ch` at the end.
*
* \return The concatenated string.
**/
RZ_API RZ_OWN char *rz_list_to_str(RZ_NONNULL RzList *list, char ch) {
RZ_API RZ_OWN char *rz_list_to_str(RZ_NONNULL RzList /*<const char *>*/ *list, char ch, bool append_last) {
rz_return_val_if_fail(list && ch > 0, NULL);
RzListIter *iter;
RzStrBuf *buf = rz_strbuf_new("");
if (!buf) {
return NULL;
}
char *item;
const char *item;
rz_list_foreach (list, iter, item) {
rz_strbuf_appendf(buf, "%s%c", item, ch);
if (rz_strbuf_length(buf) > 0) {
rz_strbuf_appendf(buf, "%c%s", ch, item);
} else {
rz_strbuf_append(buf, item);
}
}
if (append_last) {
rz_strbuf_appendf(buf, "%c", ch);
}
return rz_strbuf_drain(buf);
}

View file

@ -1070,7 +1070,7 @@ RZ_API int rz_str_cmp(RZ_NULLABLE const char *a, RZ_NULLABLE const char *b, int
}
// Copies all characters from src to dst up until the character 'ch'.
RZ_API int rz_str_ccpy(char *dst, char *src, int ch) {
RZ_API int rz_str_ccpy(char *dst, const char *src, int ch) {
int i;
for (i = 0; src[i] && src[i] != ch; i++) {
dst[i] = src[i];

View file

@ -87,7 +87,7 @@ RZ_API RZ_OWN char *rz_syscmd_sort_str(RZ_NONNULL const char *input) {
rz_list_sort(list, cmpstr, NULL);
rz_list_del_n(list, 0);
char *sorted_str = rz_list_to_str(list, '\n');
char *sorted_str = rz_list_to_str(list, '\n', true);
rz_list_free(list);
free(data);
@ -224,7 +224,7 @@ RZ_API RZ_OWN char *rz_syscmd_uniq_str(RZ_NONNULL const char *input) {
return NULL;
}
rz_list_del_n(uniq_list, rz_list_length(uniq_list) - 1);
char *return_str = rz_list_to_str(uniq_list, '\n');
char *return_str = rz_list_to_str(uniq_list, '\n', true);
rz_list_free(uniq_list);
rz_list_free(list);
@ -293,7 +293,7 @@ RZ_API RZ_OWN char *rz_syscmd_join(RZ_NONNULL const char *file1, RZ_NONNULL cons
}
free(field);
}
data = rz_list_to_str(list, '\n');
data = rz_list_to_str(list, '\n', true);
rz_list_free(list2);
rz_list_free(list1);
rz_list_free(list);

View file

@ -380,7 +380,9 @@ static bool bin_search_range(RZ_NONNULL RzVector *vec, RZ_NONNULL void *elem, Rz
*/
RZ_API void *rz_vector_insert_sorted(RZ_NONNULL RzVector *vec, RZ_NONNULL void *elem, RzVectorComparator cmp, void *user) {
rz_return_val_if_fail(vec && elem, NULL);
if (rz_vector_empty(vec)) {
size_t len = rz_vector_len(vec);
if (len < 1) {
return rz_vector_push(vec, elem);
}

View file

@ -39,7 +39,7 @@ nodup
false
true
false
true
1
false
EOF
RUN

View file

@ -174,17 +174,17 @@ elq zoom
EOF
EXPECT=<<EOF
{"zoom.byte":"h","zoom.from":0,"zoom.in":"io.map","zoom.maxsz":512,"zoom.to":0}
[{"name":"zoom.byte","value":"h","type":"str","desc":"Zoom callback to calculate each byte (See pz? for help)","ro":false},{"name":"zoom.from","value":0,"type":"int","desc":"Zoom start address","ro":false},{"name":"zoom.in","value":"io.map","type":"str","desc":"Specify boundaries for zoom","ro":false,"options":["raw","block","bin.section","bin.sections","bin.sections.rwx","bin.sections.r","bin.sections.rw","bin.sections.rx","bin.sections.wx","bin.sections.x","io.map","io.maps","io.maps.rwx","io.maps.r","io.maps.rw","io.maps.rx","io.maps.wx","io.maps.x","dbg.stack","dbg.heap","dbg.map","dbg.maps","dbg.maps.rwx","dbg.maps.r","dbg.maps.rw","dbg.maps.rx","dbg.maps.wx","dbg.maps.x","analysis.fcn","analysis.bb"]},{"name":"zoom.maxsz","value":512,"type":"int","desc":"Zoom max size of block","ro":false},{"name":"zoom.to","value":0,"type":"int","desc":"Zoom end address","ro":false}]
[{"name":"zoom.byte","desc":"Zoom callback to calculate each byte (See pz? for help)","flags":"string,bind","options":[],"value":"h"},{"name":"zoom.from","desc":"Zoom start address","flags":"integer","options":[],"value":0},{"name":"zoom.in","desc":"Specify boundaries for zoom","flags":"string,bind","options":["raw","block","bin.section","bin.sections","bin.sections.rwx","bin.sections.r","bin.sections.rw","bin.sections.rx","bin.sections.wx","bin.sections.x","io.map","io.maps","io.maps.rwx","io.maps.r","io.maps.rw","io.maps.rx","io.maps.wx","io.maps.x","dbg.stack","dbg.heap","dbg.map","dbg.maps","dbg.maps.rwx","dbg.maps.r","dbg.maps.rw","dbg.maps.rx","dbg.maps.wx","dbg.maps.x","analysis.fcn","analysis.bb"],"value":"io.map"},{"name":"zoom.maxsz","desc":"Zoom max size of block","flags":"integer","options":[],"value":512},{"name":"zoom.to","desc":"Zoom end address","flags":"integer","options":[],"value":0}]
zoom.byte: Zoom callback to calculate each byte (See pz? for help)
zoom.from: Zoom start address
zoom.in: Specify boundaries for zoom
zoom.maxsz: Zoom max size of block
zoom.to: Zoom end address
zoom.byte = h ; Zoom callback to calculate each byte (See pz? for help)
zoom.from = 0 ; Zoom start address
zoom.in = io.map ; Specify boundaries for zoom [raw, block, bin.section, bin.sections, bin.sections.rwx, bin.sections.r, bin.sections.rw, bin.sections.rx, bin.sections.wx, bin.sections.x, io.map, io.maps, io.maps.rwx, io.maps.r, io.maps.rw, io.maps.rx, io.maps.wx, io.maps.x, dbg.stack, dbg.heap, dbg.map, dbg.maps, dbg.maps.rwx, dbg.maps.r, dbg.maps.rw, dbg.maps.rx, dbg.maps.wx, dbg.maps.x, analysis.fcn, analysis.bb]
zoom.maxsz = 512 ; Zoom max size of block
zoom.to = 0 ; Zoom end address
zoom.byte = h (string,bind); Zoom callback to calculate each byte (See pz? for help)
zoom.from = 0 (integer); Zoom start address
zoom.in = io.map (string,bind); Specify boundaries for zoom [raw, block, bin.section, bin.sections, bin.sections.rwx, bin.sections.r, bin.sections.rw, bin.sections.rx, bin.sections.wx, bin.sections.x, io.map, io.maps, io.maps.rwx, io.maps.r, io.maps.rw, io.maps.rx, io.maps.wx, io.maps.x, dbg.stack, dbg.heap, dbg.map, dbg.maps, dbg.maps.rwx, dbg.maps.r, dbg.maps.rw, dbg.maps.rx, dbg.maps.wx, dbg.maps.x, analysis.fcn, analysis.bb]
zoom.maxsz = 512 (integer); Zoom max size of block
zoom.to = 0 (integer); Zoom end address
zoom.byte=h
zoom.from=0
zoom.in=io.map

View file

@ -106,7 +106,7 @@ EOF
EXPECT=<<EOF
[?25l 0> |  0> |
- analysis.apply.signature: bool - enables/disables auto-applying signatures to the loaded binary (see also flirt 
analysis.arch: str - Select the architecture to use [?25h
analysis.arch: string,bind - Select the architecture to use [?25h
EOF
RUN

View file

@ -13,7 +13,7 @@ NAME=@e:
FILE==
CMDS=<<EOF
e scr.color=false
e scr.color @e:scr.color=true
e scr.color @e:scr.color=1
EOF
EXPECT=<<EOF
1
@ -36,8 +36,8 @@ FILE==
CMDS=<<EOF
e scr.color=false
s 0
e scr.color @e:scr.color=true @ 0x1337
s @e:scr.color=true @ 0x1337
e scr.color @e:scr.color=1 @ 0x1337
s @e:scr.color=1 @ 0x1337
EOF
EXPECT=<<EOF
1
@ -49,9 +49,9 @@ NAME=@ addr @e
FILE==
CMDS=<<EOF
e scr.color @ 0x42 @e:scr.color=false
e scr.color @ 0x1337 @e:scr.color=true
e scr.color @ 0x1337 @e:scr.color=1
s @ 0x42 @e:scr.color=false
s @ 0x1337 @e:scr.color=true
s @ 0x1337 @e:scr.color=1
EOF
EXPECT=<<EOF
0
@ -65,11 +65,11 @@ NAME=@a: @ addr @e:
FILE==
CMDS=<<EOF
e asm.arch @a:x86 @ 0x42 @e:scr.color=false
e asm.arch @a:arm @ 0x1337 @e:scr.color=true
e asm.arch @a:arm @ 0x1337 @e:scr.color=1
s @a:x86 @ 0x42 @e:scr.color=false
s @a:arm @ 0x1337 @e:scr.color=true
s @a:arm @ 0x1337 @e:scr.color=1
e scr.color @a:x86 @ 0x42 @e:scr.color=false
e scr.color @a:arm @ 0x1337 @e:scr.color=true
e scr.color @a:arm @ 0x1337 @e:scr.color=1
EOF
EXPECT=<<EOF
x86

View file

@ -86,13 +86,13 @@ void snprint_mem(char *out, size_t out_size, const ut8 *buf, size_t len) {
#define mu_ignore \
do { \
printf(TYELLOW "IGN\n" TRESET); \
printf(TYELLOW "IGN" TRESET "\n"); \
return MU_PASSED; \
} while (0)
#define mu_end \
do { \
printf(TGREEN "OK\n" TRESET); \
printf(TGREEN "OK" TRESET "\n"); \
return MU_PASSED; \
} while (0)

View file

@ -1,60 +1,544 @@
// SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-FileCopyrightText: 2021 Anton Kochkov <anton.kochkov@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_config.h>
#include "minunit.h"
bool test_config() {
bool test_config_strings() {
RzConfig *cfg = rz_config_new(NULL);
bool ret = false;
const char *bla = NULL;
// string variables
rz_config_set(cfg, "foo.bar", "bla");
const char *bla = rz_config_get(cfg, "foo.bar");
mu_assert_streq(bla, "bla", "String variable");
// normal string
ret = rz_config_add_string(cfg, "foo.bar", "is foo.bar desc", "bla");
mu_assert_true(ret, "added foo.bar");
// integer variables
rz_config_set_i(cfg, "universe.question", 42);
int answer = rz_config_get_i(cfg, "universe.question");
mu_assert_eq(answer, 42, "Integer variable");
ret = rz_config_is_readonly(cfg, "foo.bar");
mu_assert_false(ret, "foo.bar is not readonly");
// boolean variables
rz_config_set_b(cfg, "true.or.false", true);
bool what = rz_config_get_b(cfg, "true.or.false");
mu_assert_eq(what, true, "Boolean variable");
rz_config_toggle(cfg, "true.or.false");
what = rz_config_get_b(cfg, "true.or.false");
mu_assert_eq(what, false, "Boolean variable (toggle)");
bla = rz_config_get_string(cfg, "foo.bar");
mu_assert_streq(bla, "bla", "String variable 1");
ret = rz_config_set_string(cfg, "foo.bar", "woff");
mu_assert_true(ret, "set foo.bar (rw)");
bla = rz_config_get_string(cfg, "foo.bar");
mu_assert_streq(bla, "woff", "String variable 2");
ret = rz_config_set_readonly(cfg, "foo.bar", true);
mu_assert_true(ret, "foo.bar set as readonly");
ret = rz_config_is_readonly(cfg, "foo.bar");
mu_assert_true(ret, "foo.bar is readonly");
ret = rz_config_set_string(cfg, "foo.bar", "oink");
mu_assert_false(ret, "set foo.bar (ro) 1");
bla = rz_config_get_string(cfg, "foo.bar");
mu_assert_streq(bla, "woff", "String variable 3");
ret = rz_config_set_readonly(cfg, "foo.bar", false);
mu_assert_true(ret, "foo.bar set not readonly");
ret = rz_config_set_string(cfg, "foo.bar", NULL);
mu_assert_true(ret, "set foo.bar (rw) 2");
bla = rz_config_get_string(cfg, "foo.bar");
mu_assert_notnull(bla, "foo.bar is not null");
mu_assert_streq(bla, "", "String variable 4");
ret = rz_config_set_any(cfg, "foo.bar", "this is a string");
mu_assert_true(ret, "set ANY foo.bar");
bla = rz_config_get_string(cfg, "foo.bar");
mu_assert_streq(bla, "this is a string", "String variable 5");
// options string
ret = rz_config_add_options(cfg, "foo.options", "is foo.options desc", "option1", "option2", "option3", "option4", NULL);
mu_assert_true(ret, "added foo.options");
bla = rz_config_get_string(cfg, "foo.options");
mu_assert_streq(bla, "option1", "options variable 1");
ret = rz_config_set_string(cfg, "foo.options", "jjjjjjj");
mu_assert_false(ret, "set foo.options to invalid");
ret = rz_config_set_string(cfg, "foo.options", "");
mu_assert_false(ret, "set foo.options to invalid");
ret = rz_config_set_string(cfg, "foo.options", "option2");
mu_assert_true(ret, "set foo.options to option2");
bla = rz_config_get_string(cfg, "foo.options");
mu_assert_streq(bla, "option2", "options variable 2");
ret = rz_config_set_any(cfg, "foo.options", "option3");
mu_assert_true(ret, "set ANY foo.options");
bla = rz_config_get_string(cfg, "foo.options");
mu_assert_streq(bla, "option3", "options variable 3");
char *s = rz_config_get_as_string(cfg, "foo.options");
mu_assert_streq(s, "option3", "get as string foo.options");
free(s);
rz_config_free(cfg);
mu_end;
}
bool test_config_lock() {
bool test_config_intergers() {
RzConfig *cfg = rz_config_new(NULL);
cfg->lock = 1;
// string variables
rz_config_set(cfg, "foo.bar", "bla");
const char *bla = rz_config_get(cfg, "foo.bar");
mu_assert_null(bla, "String variable (locked)");
bool ret = false;
// integer variables
rz_config_set_i(cfg, "universe.question", 42);
int answer = rz_config_get_i(cfg, "universe.question");
mu_assert_neq(answer, 42, "Integer variable (locked)");
ret = rz_config_add_integer(cfg, "universe.question", "is universe.question desc", 42);
mu_assert_true(ret, "added universe.question");
// boolean variables
rz_config_set_b(cfg, "true.or.false", true);
bool what = rz_config_get_b(cfg, "true.or.false");
mu_assert_false(what, "Boolean variable (locked)");
ut64 answer = rz_config_get_integer(cfg, "universe.question");
mu_assert_eq(answer, 42, "Integer variable 1");
ret = rz_config_is_readonly(cfg, "universe.question");
mu_assert_false(ret, "universe.question is not readonly");
ret = rz_config_set_readonly(cfg, "universe.question", true);
mu_assert_true(ret, "universe.question set as readonly");
ret = rz_config_is_readonly(cfg, "universe.question");
mu_assert_true(ret, "universe.question is readonly");
ret = rz_config_set_integer(cfg, "universe.question", 99);
mu_assert_false(ret, "set universe.question (ro)");
answer = rz_config_get_integer(cfg, "universe.question");
mu_assert_eq(answer, 42, "Integer variable 2");
ret = rz_config_set_readonly(cfg, "universe.question", false);
mu_assert_true(ret, "universe.question is not readonly");
ret = rz_config_set_any(cfg, "universe.question", "2000");
mu_assert_true(ret, "set ANY universe.question");
answer = rz_config_get_integer(cfg, "universe.question");
mu_assert_eq(answer, 2000, "Integer variable 3");
char *s = rz_config_get_as_string(cfg, "universe.question");
mu_assert_streq(s, "2000", "get as string universe.question");
free(s);
rz_config_free(cfg);
mu_end;
}
bool test_config_booleans() {
RzConfig *cfg = rz_config_new(NULL);
bool ret = false;
// boolean variables
ret = rz_config_add_bool(cfg, "true.or.false", "is true.or.false desc", true);
mu_assert_true(ret, "added true.or.false");
bool what = rz_config_get_bool(cfg, "true.or.false");
mu_assert_true(what, "Boolean variable");
ret = rz_config_toggle_bool(cfg, "true.or.false");
mu_assert_true(ret, "toggle true.or.false");
what = rz_config_get_bool(cfg, "true.or.false");
mu_assert_false(what, "Boolean variable (toggle)");
ret = rz_config_is_readonly(cfg, "true.or.false");
mu_assert_false(ret, "true.or.false is not readonly");
ret = rz_config_set_readonly(cfg, "true.or.false", true);
mu_assert_true(ret, "true.or.false set as readonly");
ret = rz_config_is_readonly(cfg, "true.or.false");
mu_assert_true(ret, "true.or.false is readonly");
ret = rz_config_set_b(cfg, "true.or.false", true);
mu_assert_false(ret, "set true.or.false (ro)");
what = rz_config_get_bool(cfg, "true.or.false");
mu_assert_false(what, "Boolean variable 2");
ret = rz_config_toggle_bool(cfg, "true.or.false");
mu_assert_false(ret, "toggle fails true.or.false");
what = rz_config_get_bool(cfg, "true.or.false");
mu_assert_false(what, "Boolean variable 2");
ret = rz_config_set_readonly(cfg, "true.or.false", false);
mu_assert_true(ret, "true.or.false is not readonly");
ret = rz_config_set_any(cfg, "true.or.false", "yes");
mu_assert_true(ret, "set ANY true.or.false");
what = rz_config_get_bool(cfg, "true.or.false");
mu_assert_true(what, "Boolean variable 2");
char *s = rz_config_get_as_string(cfg, "true.or.false");
mu_assert_streq(s, "true", "get as string true.or.false");
free(s);
rz_config_free(cfg);
mu_end;
}
bool test_config_lists() {
RzConfig *cfg = rz_config_new(NULL);
bool ret = false;
const char *elem = NULL;
RzList *list = NULL;
RzListIter *it;
// list variables
ret = rz_config_add_list(cfg, "thy.list", "is thy.list desc", "r1", "r2", "r3", NULL);
mu_assert_true(ret, "added thy.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");
it = rz_list_head(list);
elem = rz_list_val(it);
mu_assert_streq(elem, "r1", "list[0] is r1");
it = rz_list_next(it);
elem = rz_list_val(it);
mu_assert_streq(elem, "r2", "list[1] is r2");
it = rz_list_next(it);
elem = rz_list_val(it);
mu_assert_streq(elem, "r3", "list[2] is r3");
rz_list_free(list);
ret = rz_config_set_list2(cfg, "thy.list", "x0", "x1", "x2", "x3", "x4", NULL);
mu_assert_true(ret, "set thy.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), 5, "List size is 5");
char *s = rz_config_get_as_string(cfg, "thy.list");
mu_assert_streq(s, "x0,x1,x2,x3,x4", "get as string thy.list");
free(s);
elem = rz_list_first_val(list);
mu_assert_streq(elem, "x0", "list[first] is x0");
elem = rz_list_last_val(list);
mu_assert_streq(elem, "x4", "list[last] is x4");
rz_list_free(list);
ret = rz_config_set_list3(cfg, "thy.list", "rax,rbx");
mu_assert_true(ret, "set thy.list as string");
list = rz_config_get_list(cfg, "thy.list");
mu_assert_notnull(list, "List is not null variable");
mu_assert_eq(rz_list_length(list), 2, "List size is 2");
rz_list_free(list);
ret = rz_config_set_list(cfg, "thy.list", NULL);
mu_assert_true(ret, "set thy.list as string");
list = rz_config_get_list(cfg, "thy.list");
mu_assert_notnull(list, "List is not null variable");
mu_assert_eq(rz_list_length(list), 0, "List is empty");
rz_list_free(list);
rz_config_free(cfg);
mu_end;
}
bool test_config_itv() {
RzConfig *cfg = rz_config_new(NULL);
bool ret = false;
RzInterval itv = { 0 };
// interval variables
ret = rz_config_add_interval(cfg, "this.limit", "is this.limit desc", 0x230, 0x4fff);
mu_assert_true(ret, "added this.limit [0x230, 0x4fff]");
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)");
mu_assert_eq(rz_itv_size(itv), 0x4dcf, "interval size at 0x4dcf");
itv.addr = 0x1000;
itv.size = 0x4f;
ret = rz_config_set_interval(cfg, "this.limit", itv);
mu_assert_true(ret, "set this.limit [0x1000, 0x104f]");
itv = rz_config_get_interval(cfg, "this.limit");
mu_assert_eq(rz_itv_begin(itv), 0x1000, "interval starts at 0x1000 (inclusive)");
mu_assert_eq(rz_itv_end(itv), 0x104f, "interval ends at 0x104f (inclusive)");
mu_assert_eq(rz_itv_size(itv), 0x4f, "interval size at 0x4f");
ret = rz_config_set_interval2(cfg, "this.limit", 0x80000000, 0x8fffffff);
mu_assert_true(ret, "set this.limit [0x80000000, 0x8fffffff]");
itv = rz_config_get_interval(cfg, "this.limit");
mu_assert_eq(rz_itv_begin(itv), 0x80000000, "interval starts at 0x80000000 (inclusive)");
mu_assert_eq(rz_itv_end(itv), 0x8fffffff, "interval ends at 0x8fffffff (inclusive)");
mu_assert_eq(rz_itv_size(itv), 0xfffffff, "interval size at 0xfffffff");
ret = rz_config_is_readonly(cfg, "this.limit");
mu_assert_false(ret, "this.limit is not readonly");
ret = rz_config_set_readonly(cfg, "this.limit", true);
mu_assert_true(ret, "this.limit set as readonly");
ret = rz_config_is_readonly(cfg, "this.limit");
mu_assert_true(ret, "this.limit is readonly");
ret = rz_config_set_interval2(cfg, "this.limit", 0, 1);
mu_assert_false(ret, "set this.limit [0, 1] RO");
itv = rz_config_get_interval(cfg, "this.limit");
mu_assert_eq(rz_itv_begin(itv), 0x80000000, "interval starts at 0x80000000 (inclusive)");
mu_assert_eq(rz_itv_end(itv), 0x8fffffff, "interval ends at 0x8fffffff (inclusive)");
mu_assert_eq(rz_itv_size(itv), 0xfffffff, "interval size at 0xfffffff");
ret = rz_config_set_readonly(cfg, "this.limit", false);
mu_assert_true(ret, "this.limit set as readonly");
ret = rz_config_is_readonly(cfg, "this.limit");
mu_assert_false(ret, "this.limit is not readonly");
ret = rz_config_set_interval3(cfg, "this.limit", " 0x11111 , 0x22222 ");
mu_assert_true(ret, "set this.limit [0x11111, 0x22222]");
itv = rz_config_get_interval(cfg, "this.limit");
mu_assert_eq(rz_itv_begin(itv), 0x11111, "interval starts at 0x11111 (inclusive)");
mu_assert_eq(rz_itv_end(itv), 0x22222, "interval ends at 0x22222 (inclusive)");
mu_assert_eq(rz_itv_size(itv), 0x11111, "interval size at 0x11111");
ret = rz_config_set_interval2(cfg, "this.limit", 0x80000000, 0x100);
mu_assert_false(ret, "cannot set this.limit [0x80000000, 0x100]");
ret = rz_config_set_interval3(cfg, "this.limit", "0x500000,0x8888");
mu_assert_false(ret, "cannot set this.limit [0x500000, 0x8888]");
ret = rz_config_add_interval(cfg, "bad.limit", NULL, 0x9999, 0);
mu_assert_false(ret, "cannot set bad.limit [0x9999, 0]");
char *s = rz_config_get_as_string(cfg, "this.limit");
mu_assert_streq(s, "0x00011111,0x00022222", "get as string this.limit");
free(s);
rz_config_free(cfg);
mu_end;
}
bool test_config_invalid() {
RzInterval itv = { 0x1000, 0x2000 };
RzConfig *cfg = rz_config_new(NULL);
mu_assert_null(rz_config_get_string(cfg, "string.here"), "string.here does not exist");
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");
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)");
rz_config_free(cfg);
mu_end;
}
typedef struct bind_test_s {
ut32 get;
ut32 set;
ut32 opts;
ut32 bind;
const void *set_val;
RzList *list;
} bind_test_t;
static bool any_get(void *user, void *p) {
bind_test_t *bt = user;
switch (bt->bind) {
case RZ_CONFIG_VAR_TYPE_BOOL: {
bool *value = p;
*value = true;
bt->get++;
return true;
}
case RZ_CONFIG_VAR_TYPE_INT: {
ut64 *value = p;
*value = 42;
bt->get++;
return true;
}
case RZ_CONFIG_VAR_TYPE_STR: {
const char **value = p;
*value = "what";
bt->get++;
return true;
}
case RZ_CONFIG_VAR_TYPE_LIST: {
const RzList **value = p;
*value = bt->list;
bt->get++;
return true;
}
case RZ_CONFIG_VAR_TYPE_ITV: {
RzInterval *value = p;
value->addr = 0x2222;
value->size = 0x1111;
bt->get++;
return true;
}
default:
return false;
}
}
static bool any_set(void *user, const void *p) {
bind_test_t *bt = user;
switch (bt->bind) {
case RZ_CONFIG_VAR_TYPE_BOOL:
bt->set_val = NULL;
bt->set++;
return true;
case RZ_CONFIG_VAR_TYPE_INT:
bt->set_val = (void *)5555;
bt->set++;
return true;
case RZ_CONFIG_VAR_TYPE_STR:
/* fall-thru */
case RZ_CONFIG_VAR_TYPE_LIST:
bt->set_val = p;
bt->set++;
return true;
case RZ_CONFIG_VAR_TYPE_ITV: {
const RzInterval *itv = p;
RzInterval *v = (void *)bt->set_val;
*v = *itv;
bt->set++;
return true;
}
default:
return false;
}
}
static bool any_opts(void *user, RzList /*<char *>*/ **options) {
bind_test_t *bt = user;
switch (bt->bind) {
case RZ_CONFIG_VAR_TYPE_STR:
*options = rz_str_split_duplist("foo,bar", ",", true);
bt->opts++;
return true;
case RZ_CONFIG_VAR_TYPE_BOOL:
/* fall-thru */
case RZ_CONFIG_VAR_TYPE_INT:
/* fall-thru */
case RZ_CONFIG_VAR_TYPE_LIST:
/* fall-thru */
case RZ_CONFIG_VAR_TYPE_ITV:
bt->opts++;
return true;
default:
return false;
}
}
bool test_config_binds() {
bool ret = false;
bind_test_t bt = { 0 };
RzInterval itv = { 0x1000, 0x2000 };
RzConfig *cfg = rz_config_new(NULL);
mu_assert_notnull(cfg, "alloc RzConfig");
bt.list = rz_str_split_duplist("init,fini", ",", true);
mu_assert_notnull(bt.list, "alloc list");
// add binds
bt.bind = RZ_CONFIG_VAR_TYPE_BOOL;
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");
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");
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");
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");
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");
bt.bind = RZ_CONFIG_VAR_TYPE_BOOL;
mu_assert_true(rz_config_get_bool(cfg, "bind.bool"), "get bind.bool");
bt.bind = RZ_CONFIG_VAR_TYPE_INT;
mu_assert_eq(rz_config_get_integer(cfg, "bind.integer"), 42, "get bind.integer");
bt.bind = RZ_CONFIG_VAR_TYPE_STR;
mu_assert_streq(rz_config_get_string(cfg, "bind.string"), "what", "get bind.string");
bt.bind = RZ_CONFIG_VAR_TYPE_LIST;
mu_assert_ptreq(rz_config_get_list(cfg, "bind.list"), bt.list, "get bind.list");
bt.bind = RZ_CONFIG_VAR_TYPE_ITV;
itv = rz_config_get_interval(cfg, "bind.interval");
mu_assert_eq(rz_itv_begin(itv), 0x2222, "bind.interval does not exist (addr = 0x2222)");
mu_assert_eq(rz_itv_size(itv), 0x1111, "bind.interval does not exist (size = 0x1111)");
bt.bind = RZ_CONFIG_VAR_TYPE_BOOL;
ret = rz_config_set_bool(cfg, "bind.bool", false);
mu_assert_true(ret, "set bind.bool");
mu_assert_null(bt.set_val, "has actually set bind.bool");
bt.bind = RZ_CONFIG_VAR_TYPE_INT;
ret = rz_config_set_integer(cfg, "bind.integer", 5555);
mu_assert_true(ret, "set bind.integer");
mu_assert_ptreq(bt.set_val, (void *)5555, "has actually set bind.integer");
bt.bind = RZ_CONFIG_VAR_TYPE_STR;
ret = rz_config_set_string(cfg, "bind.string", "foo");
mu_assert_true(ret, "set bind.string");
mu_assert_streq(bt.set_val, "foo", "has actually set bind.string");
bt.bind = RZ_CONFIG_VAR_TYPE_LIST;
ret = rz_config_set_list(cfg, "bind.list", bt.list);
mu_assert_true(ret, "set bind.list");
mu_assert_ptreq(bt.set_val, bt.list, "has actually set bind.list");
bt.bind = RZ_CONFIG_VAR_TYPE_ITV;
bt.set_val = &itv;
ret = rz_config_set_interval2(cfg, "bind.interval", 0x80000000, 0x8fffffff);
mu_assert_true(ret, "set bind.interval");
mu_assert_eq(rz_itv_begin(itv), 0x80000000, "bind.interval does not exist (beg = 0x80000000)");
mu_assert_eq(rz_itv_end(itv), 0x8fffffff, "bind.interval does not exist (end = 0x8fffffff)");
mu_assert_eq(bt.opts, 5, "called bind.get_options");
mu_assert_eq(bt.get, 5, "called bind.get_value");
mu_assert_eq(bt.set, 5, "called bind.set_value");
rz_config_free(cfg);
rz_list_free(bt.list);
mu_end;
}
bool all_tests() {
mu_run_test(test_config);
mu_run_test(test_config_lock);
mu_run_test(test_config_strings);
mu_run_test(test_config_intergers);
mu_run_test(test_config_booleans);
mu_run_test(test_config_lists);
mu_run_test(test_config_itv);
mu_run_test(test_config_invalid);
mu_run_test(test_config_binds);
return tests_passed != tests_run;
}

View file

@ -18,7 +18,6 @@ bool test_config_save() {
rz_config_set(config, "somestring", "somevalue");
rz_config_set_i(config, "someint", 42);
rz_config_set_i(config, "somebiggerint", 0x1337);
rz_config_lock(config, true);
Sdb *db = sdb_new0();
rz_serialize_config_save(db, config);
@ -36,15 +35,14 @@ bool test_config_load() {
rz_config_set(config, "somestring", "someoldvalue");
rz_config_set_i(config, "someint", 0);
rz_config_set_i(config, "somebiggerint", 0);
rz_config_lock(config, true);
Sdb *db = ref_db();
sdb_set(db, "sneaky", "not part of config");
bool loaded = rz_serialize_config_load(db, config, NULL, NULL);
bool loaded = rz_serialize_config_load(db, config, NULL);
sdb_free(db);
mu_assert("load success", loaded);
mu_assert_eq(rz_list_length(config->nodes), 3, "count after load");
mu_assert_eq(rz_vector_len(&config->sorted_vars), 3, "count after load");
mu_assert_streq(rz_config_get(config, "somestring"), "somevalue", "loaded config string");
mu_assert_eq_fmt(rz_config_get_i(config, "someint"), (ut64)42, "loaded config int", "%" PFMT64u);
mu_assert_eq_fmt(rz_config_get_i(config, "somebiggerint"), (ut64)0x1337, "loaded config bigger int", "0x%" PFMT64x);
@ -53,7 +51,7 @@ bool test_config_load() {
}
bool test_config_load_exclude() {
static const char *const exclude[] = {
static const char *exclude[] = {
"somestring",
"someint",
NULL
@ -62,14 +60,13 @@ bool test_config_load_exclude() {
rz_config_set(config, "somestring", "someoldvalue");
rz_config_set_i(config, "someint", 123);
rz_config_set_i(config, "somebiggerint", 0);
rz_config_lock(config, true);
Sdb *db = ref_db();
bool loaded = rz_serialize_config_load(db, config, exclude, NULL);
bool loaded = rz_serialize_config_load(db, config, exclude);
sdb_free(db);
mu_assert("load success", loaded);
mu_assert_eq(rz_list_length(config->nodes), 3, "count after load");
mu_assert_eq(rz_vector_len(&config->sorted_vars), 3, "count after load");
mu_assert_streq(rz_config_get(config, "somestring"), "someoldvalue", "excluded config string");
mu_assert_eq_fmt(rz_config_get_i(config, "someint"), (ut64)123, "excluded config int", "%" PFMT64u);
mu_assert_eq_fmt(rz_config_get_i(config, "somebiggerint"), (ut64)0x1337, "loaded config bigger int", "0x%" PFMT64x);