* Initial import of the hashtable implementation of WayLand
- Kinda smart (150LOC) - Fork it for 64bit hash keys (make ht64 in libr/util) * Make RConfig use the RHashTable to resolve by name - Code cleanup resulting in -30LOC - O(1) access to config variables (speedup!) - Make r_list_free and r_list_destroy take sense
This commit is contained in:
parent
c6a579a291
commit
3d142e8ec1
1
TODO
1
TODO
|
@ -25,6 +25,7 @@ pancake
|
||||||
|
|
||||||
nibble
|
nibble
|
||||||
------
|
------
|
||||||
|
* Do not show XREF info if in the same function?
|
||||||
* r_anal
|
* r_anal
|
||||||
- Code analysis (detect when an argument is a flagmask or enum and display text format) (ollydbg)
|
- Code analysis (detect when an argument is a flagmask or enum and display text format) (ollydbg)
|
||||||
* r_bin
|
* r_bin
|
||||||
|
|
|
@ -1,45 +1,41 @@
|
||||||
/* radare - LGPL - Copyright 2006-2009 pancake<nopcode.org> */
|
/* radare - LGPL - Copyright 2006-2011 pancake<nopcode.org> */
|
||||||
|
|
||||||
#include "r_config.h"
|
#include "r_config.h"
|
||||||
|
|
||||||
// XXX spaguetti code lives here
|
// XXX spaguetti code lives here
|
||||||
|
|
||||||
static int r_config_callback_q(void *data) {
|
static int r_config_callback_q(void *data) {
|
||||||
struct r_config_node_t *node = data;
|
RConfigNode *node = data;
|
||||||
*(node->cb_ptr_q) = node->i_value;
|
*(node->cb_ptr_q) = node->i_value;
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_config_callback_i(void *data) {
|
static int r_config_callback_i(void *data) {
|
||||||
struct r_config_node_t *node = data;
|
RConfigNode *node = data;
|
||||||
*(node->cb_ptr_i) = node->i_value;
|
*(node->cb_ptr_i) = node->i_value;
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_config_callback_s(void *data) {
|
static int r_config_callback_s(void *data) {
|
||||||
struct r_config_node_t *node = data;
|
RConfigNode *node = data;
|
||||||
if (!node->value || node->value[0]=='\0') {
|
if (!node->value || !*node->value) {
|
||||||
free(*node->cb_ptr_s);
|
free (*node->cb_ptr_s);
|
||||||
*node->cb_ptr_s = NULL;
|
*node->cb_ptr_s = NULL;
|
||||||
} else *node->cb_ptr_s = r_str_dup(*node->cb_ptr_s, node->value);
|
} else *node->cb_ptr_s = r_str_dup (*node->cb_ptr_s, node->value);
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API int r_config_set_callback_q(struct r_config_t *cfg, const char *name, ut64 *ptr)
|
R_API int r_config_set_callback_q(RConfig *cfg, const char *name, ut64 *ptr) {
|
||||||
{
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
struct r_config_node_t *node;
|
|
||||||
node = r_config_node_get(cfg, name);
|
|
||||||
if (node) {
|
if (node) {
|
||||||
node->cb_ptr_q = ptr;
|
node->cb_ptr_q = ptr;
|
||||||
node->callback = (void *)&r_config_callback_q;
|
node->callback = (void *)&r_config_callback_q;
|
||||||
return 1;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
return 0;
|
return R_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API int r_config_set_callback_i(struct r_config_t *cfg, const char *name, int *ptr)
|
R_API int r_config_set_callback_i(RConfig *cfg, const char *name, int *ptr) {
|
||||||
{
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
struct r_config_node_t *node = r_config_node_get(cfg, name);
|
|
||||||
if (node) {
|
if (node) {
|
||||||
node->cb_ptr_i = ptr;
|
node->cb_ptr_i = ptr;
|
||||||
node->callback = (void *)&r_config_callback_i;
|
node->callback = (void *)&r_config_callback_i;
|
||||||
|
@ -48,9 +44,8 @@ R_API int r_config_set_callback_i(struct r_config_t *cfg, const char *name, int
|
||||||
return R_FALSE;
|
return R_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API int r_config_set_callback_s(struct r_config_t *cfg, const char *name, char **ptr)
|
R_API int r_config_set_callback_s(RConfig *cfg, const char *name, char **ptr) {
|
||||||
{
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
struct r_config_node_t *node = r_config_node_get(cfg, name);
|
|
||||||
if (node) {
|
if (node) {
|
||||||
node->cb_ptr_s = ptr;
|
node->cb_ptr_s = ptr;
|
||||||
node->callback = (void *)&r_config_callback_s;
|
node->callback = (void *)&r_config_callback_s;
|
||||||
|
|
|
@ -1,53 +1,42 @@
|
||||||
/* radare - LGPL - Copyright 2006-2009 pancake<nopcode.org> */
|
/* radare - LGPL - Copyright 2006-2011 pancake<nopcode.org> */
|
||||||
|
|
||||||
#include "r_config.h"
|
#include "r_config.h"
|
||||||
#include "r_util.h" // r_str_hash, r_str_chop, ...
|
#include "r_util.h" // r_str_hash, r_str_chop, ...
|
||||||
|
|
||||||
R_API RConfigNode* r_config_node_new(const char *name, const char *value) {
|
R_API RConfigNode* r_config_node_new(const char *name, const char *value) {
|
||||||
RConfigNode *node =
|
RConfigNode *node = R_NEW (RConfigNode);
|
||||||
(RConfigNode *)
|
node->name = strdup (name);
|
||||||
malloc(sizeof(RConfigNode));
|
node->hash = r_str_hash (name);
|
||||||
INIT_LIST_HEAD(&(node->list));
|
node->value = strdup (value?value:"");
|
||||||
node->name = strdup(name);
|
|
||||||
node->hash = r_str_hash(name);
|
|
||||||
node->value = value?strdup(value):strdup("");
|
|
||||||
node->flags = CN_RW | CN_STR;
|
node->flags = CN_RW | CN_STR;
|
||||||
node->i_value = 0;
|
node->i_value = 0;
|
||||||
node->callback = NULL;
|
node->callback = NULL;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API void r_config_list(RConfig *cfg, const char *str, int rad) {
|
R_API void r_config_list(RConfig *cfg, const char *str, boolt rad) {
|
||||||
struct list_head *i;
|
RConfigNode *node;
|
||||||
|
RListIter *iter;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
if (!strnull(str)) {
|
if (!strnull (str)) {
|
||||||
str = r_str_chop_ro(str);
|
str = r_str_chop_ro (str);
|
||||||
len = strlen(str);
|
len = strlen (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each(i, &(cfg->nodes)) {
|
r_list_foreach (cfg->nodes, iter, node) {
|
||||||
RConfigNode *bt = list_entry(i, RConfigNode, list);
|
|
||||||
if (str) {
|
if (str) {
|
||||||
if (strncmp(str, bt->name, len) == 0)
|
if (!strncmp (str, node->name, len))
|
||||||
cfg->printf ("%s%s = %s\n", rad?"e ":"",
|
cfg->printf ("%s%s = %s\n", rad?"e ":"",
|
||||||
bt->name, bt->value);
|
node->name, node->value);
|
||||||
} else cfg->printf ("%s%s = %s\n", rad?"e ":"", bt->name, bt->value);
|
} else cfg->printf ("%s%s = %s\n", rad?"e ":"", node->name, node->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API RConfigNode *r_config_node_get(RConfig *cfg, const char *name) {
|
R_API RConfigNode *r_config_node_get(RConfig *cfg, const char *name) {
|
||||||
struct list_head *i;
|
|
||||||
int hash;
|
|
||||||
if (strnull (name))
|
if (strnull (name))
|
||||||
return NULL;
|
return NULL;
|
||||||
hash = r_str_hash (name);
|
return r_hashtable_lookup (cfg->ht, r_str_hash (name));
|
||||||
list_for_each_prev (i, &(cfg->nodes)) {
|
|
||||||
RConfigNode *bt = list_entry (i, RConfigNode, list);
|
|
||||||
if (bt->hash == hash)
|
|
||||||
return bt;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API const char *r_config_get(RConfig *cfg, const char *name) {
|
R_API const char *r_config_get(RConfig *cfg, const char *name) {
|
||||||
|
@ -56,8 +45,8 @@ R_API const char *r_config_get(RConfig *cfg, const char *name) {
|
||||||
cfg->last_notfound = 0;
|
cfg->last_notfound = 0;
|
||||||
if (node->flags & CN_BOOL)
|
if (node->flags & CN_BOOL)
|
||||||
return (const char *)
|
return (const char *)
|
||||||
(((!strcmp("true", node->value))
|
(((!strcmp ("true", node->value))
|
||||||
|| (!strcmp("1", node->value)))?
|
|| (!strcmp ("1", node->value)))?
|
||||||
(const char *)"true":"false"); // XXX (char*)1 is ugly
|
(const char *)"true":"false"); // XXX (char*)1 is ugly
|
||||||
return node->value;
|
return node->value;
|
||||||
}
|
}
|
||||||
|
@ -66,32 +55,28 @@ R_API const char *r_config_get(RConfig *cfg, const char *name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API int r_config_swap(RConfig *cfg, const char *name) {
|
R_API int r_config_swap(RConfig *cfg, const char *name) {
|
||||||
RConfigNode *node = r_config_node_get(cfg, name);
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
if (node && node->flags & CN_BOOL) {
|
if (node && node->flags & CN_BOOL) {
|
||||||
r_config_set_i(cfg, name, !node->i_value);
|
r_config_set_i (cfg, name, !node->i_value);
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
return R_FALSE;
|
return R_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API ut64 r_config_get_i(RConfig *cfg, const char *name) {
|
R_API ut64 r_config_get_i(RConfig *cfg, const char *name) {
|
||||||
RConfigNode *node = r_config_node_get(cfg, name);
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
if (node) {
|
if (node) {
|
||||||
if (node->i_value != 0)
|
if (node->i_value != 0)
|
||||||
return node->i_value;
|
return node->i_value;
|
||||||
return (ut64)r_num_math(NULL, node->value);
|
return (ut64)r_num_math (NULL, node->value);
|
||||||
}
|
}
|
||||||
return (ut64)0LL;
|
return (ut64)0LL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use typedef declaration here
|
R_API RConfigNode *r_config_set_cb(RConfig *cfg, const char *name, const char *value, RConfigCallback cb) {
|
||||||
R_API RConfigNode *r_config_set_cb(RConfig *cfg, const char *name, const char *value, int (*callback)(void *user, void *data))
|
RConfigNode *node = r_config_set (cfg, name, value);
|
||||||
{
|
if ((node->callback = cb))
|
||||||
RConfigNode *node;
|
cb (cfg->user, node);
|
||||||
node = r_config_set(cfg, name, value);
|
|
||||||
node->callback = callback;
|
|
||||||
if (node->callback)
|
|
||||||
node->callback(cfg->user, node);
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +92,9 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
||||||
RConfigNode *node;
|
RConfigNode *node;
|
||||||
char *ov = NULL;
|
char *ov = NULL;
|
||||||
ut64 oi;
|
ut64 oi;
|
||||||
|
if (strnull (name))
|
||||||
if (name[0] == '\0')
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
node = r_config_node_get (cfg, name);
|
node = r_config_node_get (cfg, name);
|
||||||
|
|
||||||
// TODO: store old value somewhere..
|
// TODO: store old value somewhere..
|
||||||
if (node) {
|
if (node) {
|
||||||
if (node->flags & CN_RO) {
|
if (node->flags & CN_RO) {
|
||||||
|
@ -123,9 +105,9 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
||||||
if (node->value)
|
if (node->value)
|
||||||
ov = strdup (node->value);
|
ov = strdup (node->value);
|
||||||
else node->value = strdup ("");
|
else node->value = strdup ("");
|
||||||
free(node->value);
|
free (node->value);
|
||||||
if (node->flags & CN_BOOL) {
|
if (node->flags & CN_BOOL) {
|
||||||
int b = (!strcmp (value,"true")||!strcmp (value,"1"));
|
int b = (!strcmp (value,"true") || !strcmp (value,"1"));
|
||||||
node->i_value = (ut64)(b==0)?0:1;
|
node->i_value = (ut64)(b==0)?0:1;
|
||||||
node->value = strdup (b?"true":"false");
|
node->value = strdup (b?"true":"false");
|
||||||
} else {
|
} else {
|
||||||
|
@ -136,22 +118,21 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
||||||
node->value = strdup (value);
|
node->value = strdup (value);
|
||||||
if (strchr(value, '/'))
|
if (strchr(value, '/'))
|
||||||
node->i_value = r_num_get (NULL, value);
|
node->i_value = r_num_get (NULL, value);
|
||||||
else node->i_value = r_num_math (NULL, value);
|
else node->i_value = r_num_math (NULL, value);
|
||||||
node->flags |= CN_INT;
|
node->flags |= CN_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cfg->lock) {
|
if (!cfg->lock) {
|
||||||
eprintf ("config is locked: cannot create '%s'\n", name);
|
|
||||||
} else {
|
|
||||||
node = r_config_node_new (name, value);
|
node = r_config_node_new (name, value);
|
||||||
if (value && (!strcmp(value,"true")||!strcmp(value,"false"))) {
|
if (value && (!strcmp(value,"true")||!strcmp(value,"false"))) {
|
||||||
node->flags|=CN_BOOL;
|
node->flags|=CN_BOOL;
|
||||||
node->i_value = (!strcmp(value,"true"))?1:0;
|
node->i_value = (!strcmp(value,"true"))?1:0;
|
||||||
}
|
}
|
||||||
list_add_tail (&(node->list), &(cfg->nodes));
|
r_hashtable_insert (cfg->ht, node->hash, node);
|
||||||
|
r_list_append (cfg->nodes, node);
|
||||||
cfg->n_nodes++;
|
cfg->n_nodes++;
|
||||||
}
|
} else eprintf ("config is locked: cannot create '%s'\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node && node->callback) {
|
if (node && node->callback) {
|
||||||
|
@ -159,7 +140,7 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
||||||
if (ret == R_FALSE) {
|
if (ret == R_FALSE) {
|
||||||
node->i_value = oi;
|
node->i_value = oi;
|
||||||
free (node->value);
|
free (node->value);
|
||||||
node->value = strdup(ov);
|
node->value = strdup (ov);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free (ov);
|
free (ov);
|
||||||
|
@ -169,7 +150,8 @@ R_API RConfigNode *r_config_set(RConfig *cfg, const char *name, const char *valu
|
||||||
R_API int r_config_rm(RConfig *cfg, const char *name) {
|
R_API int r_config_rm(RConfig *cfg, const char *name) {
|
||||||
RConfigNode *node = r_config_node_get (cfg, name);
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
if (node) {
|
if (node) {
|
||||||
list_del (&(node->list));
|
r_hashtable_remove (cfg->ht, node->hash);
|
||||||
|
r_list_delete_data (cfg->nodes, node);
|
||||||
cfg->n_nodes--;
|
cfg->n_nodes--;
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -177,9 +159,8 @@ R_API int r_config_rm(RConfig *cfg, const char *name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API RConfigNode *r_config_set_i(RConfig *cfg, const char *name, const ut64 i) {
|
R_API RConfigNode *r_config_set_i(RConfig *cfg, const char *name, const ut64 i) {
|
||||||
char buf[128];
|
|
||||||
char *ov = NULL;
|
|
||||||
ut64 oi;
|
ut64 oi;
|
||||||
|
char buf[128], *ov = NULL;
|
||||||
RConfigNode *node = r_config_node_get (cfg, name);
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
|
@ -199,16 +180,16 @@ R_API RConfigNode *r_config_set_i(RConfig *cfg, const char *name, const ut64 i)
|
||||||
//node->flags = CN_RW | CN_INT;
|
//node->flags = CN_RW | CN_INT;
|
||||||
node->i_value = i;
|
node->i_value = i;
|
||||||
} else {
|
} else {
|
||||||
if (cfg->lock) {
|
if (!cfg->lock) {
|
||||||
eprintf ("(locked: no new keys can be created)");
|
if (i<1024) sprintf (buf, "%"PFMT64d"", i);
|
||||||
} else {
|
else sprintf (buf, "0x%08"PFMT64x"", i);
|
||||||
sprintf(buf, "0x%08"PFMT64x"", i);
|
node = r_config_node_new (name, buf);
|
||||||
node = r_config_node_new(name, buf);
|
|
||||||
node->flags = CN_RW | CN_OFFT;
|
node->flags = CN_RW | CN_OFFT;
|
||||||
node->i_value = i;
|
node->i_value = i;
|
||||||
list_add_tail(&(node->list), &(cfg->nodes));
|
r_hashtable_insert (cfg->ht, node->hash, node);
|
||||||
|
r_list_append (cfg->nodes, node);
|
||||||
cfg->n_nodes++;
|
cfg->n_nodes++;
|
||||||
}
|
} else eprintf ("(locked: no new keys can be created)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node && node->callback) {
|
if (node && node->callback) {
|
||||||
|
@ -274,28 +255,29 @@ R_API void r_config_lock(RConfig *cfg, int l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API RConfig *r_config_new(void *user) {
|
R_API RConfig *r_config_new(void *user) {
|
||||||
RConfig *cfg;
|
RConfig *cfg = R_NEW (RConfig);
|
||||||
|
|
||||||
cfg = R_NEW (RConfig);
|
|
||||||
if (cfg) {
|
if (cfg) {
|
||||||
|
cfg->ht = r_hashtable_new ();
|
||||||
|
cfg->nodes = r_list_new ();
|
||||||
|
cfg->nodes->free = free;
|
||||||
cfg->user = user;
|
cfg->user = user;
|
||||||
cfg->n_nodes = 0;
|
cfg->n_nodes = 0;
|
||||||
cfg->lock = 0;
|
cfg->lock = 0;
|
||||||
cfg->printf = (void *)printf;
|
cfg->printf = (void *)printf;
|
||||||
INIT_LIST_HEAD (&(cfg->nodes));
|
|
||||||
}
|
}
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API int r_config_free(RConfig *cfg) {
|
R_API int r_config_free(RConfig *cfg) {
|
||||||
// TODO: Free node list
|
// XXX: memory leak ! r_list_destroy (cfg->nodes);
|
||||||
|
r_list_free (cfg->nodes);
|
||||||
|
r_hashtable_free (cfg->ht);
|
||||||
free (cfg);
|
free (cfg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API void r_config_visual_hit_i(RConfig *cfg, const char *name, int delta) {
|
R_API void r_config_visual_hit_i(RConfig *cfg, const char *name, int delta) {
|
||||||
RConfigNode *node =
|
RConfigNode *node = r_config_node_get (cfg, name);
|
||||||
r_config_node_get(cfg, name);
|
|
||||||
if (node && (node->flags & CN_INT || node->flags & CN_OFFT))
|
if (node && (node->flags & CN_INT || node->flags & CN_OFFT))
|
||||||
r_config_set_i(cfg, name, r_config_get_i(cfg, name)+delta);
|
r_config_set_i(cfg, name, r_config_get_i(cfg, name)+delta);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,6 @@ static const char *radare_argv[] = {
|
||||||
static const char *tmp_argv[TMP_ARGV_SZ];
|
static const char *tmp_argv[TMP_ARGV_SZ];
|
||||||
static int autocomplete(RLine *line) {
|
static int autocomplete(RLine *line) {
|
||||||
RCore *core = line->user;
|
RCore *core = line->user;
|
||||||
struct list_head *pos;
|
|
||||||
RListIter *iter;
|
RListIter *iter;
|
||||||
RFlagItem *flag;
|
RFlagItem *flag;
|
||||||
if (core) {
|
if (core) {
|
||||||
|
@ -181,9 +180,10 @@ printf ("FILEN %d\n", n);
|
||||||
line->completion.argv = tmp_argv;
|
line->completion.argv = tmp_argv;
|
||||||
} else
|
} else
|
||||||
if (!memcmp (line->buffer.data, "e ", 2)) {
|
if (!memcmp (line->buffer.data, "e ", 2)) {
|
||||||
|
RConfigNode *bt;
|
||||||
|
RListIter *iter;
|
||||||
int i = 0, n = strlen (line->buffer.data+2);
|
int i = 0, n = strlen (line->buffer.data+2);
|
||||||
list_for_each_prev (pos, &core->config->nodes) {
|
r_list_foreach (core->config->nodes, iter, bt) {
|
||||||
RConfigNode *bt = list_entry(pos, RConfigNode, list);
|
|
||||||
if (!memcmp (bt->name, line->buffer.data+2, n)) {
|
if (!memcmp (bt->name, line->buffer.data+2, n)) {
|
||||||
tmp_argv[i++] = bt->name;
|
tmp_argv[i++] = bt->name;
|
||||||
if (i==TMP_ARGV_SZ)
|
if (i==TMP_ARGV_SZ)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* radare - LGPL - Copyright 2010 - nibble<develsec.org> */
|
/* radare - LGPL - Copyright 2010-2011 - nibble<develsec.org> */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -12,7 +12,6 @@ R_API int r_core_gdiff(RCore *c, RCore *c2) {
|
||||||
RAnalFcn *fcn;
|
RAnalFcn *fcn;
|
||||||
RAnalBlock *bb;
|
RAnalBlock *bb;
|
||||||
RListIter *iter, *iter2;
|
RListIter *iter, *iter2;
|
||||||
ut8 *buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
|
|
|
@ -303,8 +303,9 @@ static void config_visual_hit(RCore *core, const char *name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API void r_core_visual_config(RCore *core) {
|
R_API void r_core_visual_config(RCore *core) {
|
||||||
|
RListIter *iter;
|
||||||
|
RConfigNode *bt;
|
||||||
char cmd[1024];
|
char cmd[1024];
|
||||||
struct list_head *pos;
|
|
||||||
#define MAX_FORMAT 2
|
#define MAX_FORMAT 2
|
||||||
char *fs = NULL;
|
char *fs = NULL;
|
||||||
char *fs2 = NULL;
|
char *fs2 = NULL;
|
||||||
|
@ -327,8 +328,7 @@ R_API void r_core_visual_config(RCore *core) {
|
||||||
r_cons_printf ("\n Eval spaces:\n\n");
|
r_cons_printf ("\n Eval spaces:\n\n");
|
||||||
hit = 0;
|
hit = 0;
|
||||||
j = i = 0;
|
j = i = 0;
|
||||||
list_for_each(pos, &(core->config->nodes)) {
|
r_list_foreach (core->config->nodes, iter, bt) {
|
||||||
struct r_config_node_t *bt = list_entry(pos, struct r_config_node_t, list);
|
|
||||||
if (option==i) {
|
if (option==i) {
|
||||||
fs = bt->name;
|
fs = bt->name;
|
||||||
hit = 1;
|
hit = 1;
|
||||||
|
@ -360,8 +360,7 @@ R_API void r_core_visual_config(RCore *core) {
|
||||||
hit = 0;
|
hit = 0;
|
||||||
j = i = 0;
|
j = i = 0;
|
||||||
// TODO: cut -d '.' -f 1 | sort | uniq !!!
|
// TODO: cut -d '.' -f 1 | sort | uniq !!!
|
||||||
list_for_each (pos, &(core->config->nodes)) {
|
r_list_foreach (core->config->nodes, iter, bt) {
|
||||||
RConfigNode *bt = list_entry (pos, RConfigNode, list);
|
|
||||||
if (option==i) {
|
if (option==i) {
|
||||||
fs2 = bt->name;
|
fs2 = bt->name;
|
||||||
hit = 1;
|
hit = 1;
|
||||||
|
|
|
@ -23,3 +23,9 @@ DROP TABLE flags
|
||||||
INSERT INTO flags (name, offset) VALUES ("patata", 33)
|
INSERT INTO flags (name, offset) VALUES ("patata", 33)
|
||||||
|
|
||||||
UPDATE flags SET offset=33 WHERE offset==20
|
UPDATE flags SET offset=33 WHERE offset==20
|
||||||
|
|
||||||
|
STORE
|
||||||
|
- ut32
|
||||||
|
- ut64
|
||||||
|
- Endianness matterz
|
||||||
|
- RList *get_range (0, 4096)
|
||||||
|
|
30
libr/db/db.c
30
libr/db/db.c
|
@ -1,4 +1,4 @@
|
||||||
/* radare - LGPL - Copyright 2009-2010 pancake<nopcode.org> */
|
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
|
||||||
|
|
||||||
#include "r_db.h"
|
#include "r_db.h"
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ Configurable options:
|
||||||
R_API RDatabase *r_db_new() {
|
R_API RDatabase *r_db_new() {
|
||||||
RDatabase *db = R_NEW (RDatabase);
|
RDatabase *db = R_NEW (RDatabase);
|
||||||
if (db) {
|
if (db) {
|
||||||
memset(&db->blocks, '\0', sizeof(db->blocks));
|
memset (&db->blocks, '\0', sizeof (db->blocks));
|
||||||
db->id_min = -1;
|
db->id_min = -1;
|
||||||
db->id_max = -1;
|
db->id_max = -1;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ R_API RDatabase *r_db_new() {
|
||||||
R_API RDatabaseBlock *r_db_block_new() {
|
R_API RDatabaseBlock *r_db_block_new() {
|
||||||
RDatabaseBlock *ptr = R_NEW (RDatabaseBlock);
|
RDatabaseBlock *ptr = R_NEW (RDatabaseBlock);
|
||||||
ptr->data = NULL;
|
ptr->data = NULL;
|
||||||
memset(&ptr->childs, '\0', sizeof(ptr->childs));
|
memset (&ptr->childs, '\0', sizeof (ptr->childs));
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ R_API int r_db_add_id(struct r_db_t *db, int key, int size) {
|
||||||
db->id_max = key;
|
db->id_max = key;
|
||||||
if (key < db->id_min)
|
if (key < db->id_min)
|
||||||
db->id_min = key;
|
db->id_min = key;
|
||||||
db->blocks[key] = r_db_block_new();
|
db->blocks[key] = r_db_block_new ();
|
||||||
db->blocks_sz[key] = size;
|
db->blocks_sz[key] = size;
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ static int _r_db_add_internal(struct r_db_t *db, int key, void *b) {
|
||||||
size = db->blocks_sz[key];
|
size = db->blocks_sz[key];
|
||||||
block = db->blocks[key];
|
block = db->blocks[key];
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
block = r_db_block_new();
|
block = r_db_block_new ();
|
||||||
db->blocks[key] = block;
|
db->blocks[key] = block;
|
||||||
}
|
}
|
||||||
for (i=0;i<size;i++) {
|
for (i=0;i<size;i++) {
|
||||||
|
@ -112,7 +112,7 @@ UNNECESSARY LOOPZ
|
||||||
}
|
}
|
||||||
size = db->blocks_sz[key];
|
size = db->blocks_sz[key];
|
||||||
block = db->blocks[key];
|
block = db->blocks[key];
|
||||||
for (i=0;block&&i<size;i++)
|
for (i=0; block && i<size; i++)
|
||||||
block = block->childs[b[key+i]];
|
block = block->childs[b[key+i]];
|
||||||
if (block)
|
if (block)
|
||||||
return block->data;
|
return block->data;
|
||||||
|
@ -138,13 +138,13 @@ static int _r_db_delete_internal(struct r_db_t *db, int key, const ut8 *b) {
|
||||||
block = block->childs[b[key+i]];
|
block = block->childs[b[key+i]];
|
||||||
|
|
||||||
if (block && block->data) {
|
if (block && block->data) {
|
||||||
for(i=0;block->data[i]; i++) {
|
for (i=0;block->data[i]; i++) {
|
||||||
if (block->data[i] == b)
|
if (block->data[i] == b)
|
||||||
for(j=i;block->data[j]; j++)
|
for (j=i;block->data[j]; j++)
|
||||||
block->data[j] = block->data[j+1];
|
block->data[j] = block->data[j+1];
|
||||||
}
|
}
|
||||||
if (block->data[0] == NULL) {
|
if (block->data[0] == NULL) {
|
||||||
free(block->data);
|
free (block->data);
|
||||||
block->data = NULL;
|
block->data = NULL;
|
||||||
}
|
}
|
||||||
return R_TRUE;
|
return R_TRUE;
|
||||||
|
@ -154,13 +154,13 @@ static int _r_db_delete_internal(struct r_db_t *db, int key, const ut8 *b) {
|
||||||
|
|
||||||
R_API int r_db_delete(struct r_db_t *db, const void *ptr) {
|
R_API int r_db_delete(struct r_db_t *db, const void *ptr) {
|
||||||
int i;
|
int i;
|
||||||
for(i=db->id_min;i<=db->id_max;i++)
|
for (i=db->id_min; i<=db->id_max; i++)
|
||||||
if (db->blocks[i])
|
if (db->blocks[i])
|
||||||
if (!_r_db_delete_internal(db, i, ptr))
|
if (!_r_db_delete_internal (db, i, ptr))
|
||||||
eprintf ("failed to delete internal pointer\n");
|
eprintf ("failed to delete internal pointer\n");
|
||||||
/* TODO */
|
/* TODO */
|
||||||
if (db->cb_free && ptr)
|
if (db->cb_free && ptr)
|
||||||
return db->cb_free(db, ptr, db->cb_user);
|
return db->cb_free (db, ptr, db->cb_user);
|
||||||
return (ptr != NULL);
|
return (ptr != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ R_API RDatabaseIter *r_db_iter_new(RDatabase *db, int key) {
|
||||||
iter->db = db;
|
iter->db = db;
|
||||||
iter->key = key;
|
iter->key = key;
|
||||||
iter->size = db->blocks_sz[key];
|
iter->size = db->blocks_sz[key];
|
||||||
memset(&iter->path, 0, sizeof(iter->path));
|
memset (&iter->path, 0, sizeof (iter->path));
|
||||||
/* TODO: detect when no keys are found and return NULL */
|
/* TODO: detect when no keys are found and return NULL */
|
||||||
iter->ptr = 0;
|
iter->ptr = 0;
|
||||||
iter->cur = NULL;
|
iter->cur = NULL;
|
||||||
|
@ -235,7 +235,7 @@ R_API int r_db_iter_next(RDatabaseIter *iter) {
|
||||||
// if (something) return 1;
|
// if (something) return 1;
|
||||||
// depth = iter->size
|
// depth = iter->size
|
||||||
//
|
//
|
||||||
for (i=iter->ptr;i<iter->size;i++) {
|
for (i=iter->ptr; i<iter->size; i++) {
|
||||||
//block = block->childs[b[key+i]];
|
//block = block->childs[b[key+i]];
|
||||||
}
|
}
|
||||||
iter->ptr = i; // update pointer
|
iter->ptr = i; // update pointer
|
||||||
|
@ -257,7 +257,7 @@ R_API void *r_db_iter_prev(struct r_db_iter_t *iter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API struct r_db_iter_t *r_db_iter_free(struct r_db_iter_t *iter) {
|
R_API struct r_db_iter_t *r_db_iter_free(struct r_db_iter_t *iter) {
|
||||||
free(iter);
|
free (iter);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* radare - LGPL - Copyright 2009-2011 pancake<nopcode.org> */
|
||||||
|
|
||||||
#include "r_db.h"
|
#include "r_db.h"
|
||||||
#include "r_util.h"
|
#include "r_util.h"
|
||||||
/*
|
/*
|
||||||
|
@ -14,20 +16,20 @@ sizes['i'] = 4;
|
||||||
struct r_db_table_t *r_db_table_new(const char *name, const char *fmt, const char *fields) {
|
struct r_db_table_t *r_db_table_new(const char *name, const char *fmt, const char *fields) {
|
||||||
int i;
|
int i;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
struct r_db_table_t *table = R_NEW(struct r_db_table_t);
|
struct r_db_table_t *table = R_NEW (RDatabaseTable);
|
||||||
table->args = strdup(fields);
|
table->args = strdup (fields);
|
||||||
table->nelems = r_str_word_set0(table->args);
|
table->nelems = r_str_word_set0 (table->args);
|
||||||
if (table->nelems != strlen(fmt)) {
|
if (table->nelems != strlen (fmt)) {
|
||||||
fprintf(stderr, "Invalid arguments\n");
|
fprintf(stderr, "Invalid arguments\n");
|
||||||
/* XXX: refactor */
|
/* XXX: refactor */
|
||||||
free(table->args);
|
free (table->args);
|
||||||
free(table);
|
free (table);
|
||||||
table = NULL;
|
table = NULL;
|
||||||
} else {
|
} else {
|
||||||
table->fmt = strdup(fmt);
|
table->fmt = strdup (fmt);
|
||||||
table->name = strdup(name);
|
table->name = strdup (name);
|
||||||
table->offset = (int*)malloc(sizeof(int)*table->nelems);
|
table->offset = (int*)malloc (sizeof (int)*table->nelems);
|
||||||
for(i=0;i<table->nelems;i++) {
|
for (i=0; i<table->nelems; i++) {
|
||||||
table->offset[i] = offset;
|
table->offset[i] = offset;
|
||||||
offset += 4;
|
offset += 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ typedef int (*RConfigCallback)(void *user, void *data);
|
||||||
|
|
||||||
typedef struct r_config_node_t {
|
typedef struct r_config_node_t {
|
||||||
char *name;
|
char *name;
|
||||||
int hash;
|
ut32 hash;
|
||||||
int flags;
|
int flags;
|
||||||
char *value;
|
char *value;
|
||||||
ut64 i_value;
|
ut64 i_value;
|
||||||
|
@ -24,7 +24,6 @@ typedef struct r_config_node_t {
|
||||||
int *cb_ptr_i;
|
int *cb_ptr_i;
|
||||||
char **cb_ptr_s;
|
char **cb_ptr_s;
|
||||||
RConfigCallback callback;
|
RConfigCallback callback;
|
||||||
struct list_head list;
|
|
||||||
} RConfigNode;
|
} RConfigNode;
|
||||||
|
|
||||||
typedef struct r_config_t {
|
typedef struct r_config_t {
|
||||||
|
@ -32,8 +31,9 @@ typedef struct r_config_t {
|
||||||
int last_notfound;
|
int last_notfound;
|
||||||
int n_nodes;
|
int n_nodes;
|
||||||
void *user;
|
void *user;
|
||||||
void (*printf)(const char *str, ...);
|
PrintfCallback printf;
|
||||||
struct list_head nodes;
|
RList *nodes;
|
||||||
|
RHashTable *ht;
|
||||||
} RConfig;
|
} RConfig;
|
||||||
|
|
||||||
#ifdef R_API
|
#ifdef R_API
|
||||||
|
|
|
@ -49,6 +49,7 @@ R_API void r_list_sort(RList *list, RListComparator cmp);
|
||||||
|
|
||||||
R_API void r_list_init(RList *list);
|
R_API void r_list_init(RList *list);
|
||||||
R_API void r_list_delete (RList *list, RListIter *iter);
|
R_API void r_list_delete (RList *list, RListIter *iter);
|
||||||
|
R_API boolt r_list_delete_data (RList *list, void *ptr);
|
||||||
R_API void r_list_iter_init (RListIter *iter, RList *list);
|
R_API void r_list_iter_init (RListIter *iter, RList *list);
|
||||||
R_API void r_list_destroy (RList *list);
|
R_API void r_list_destroy (RList *list);
|
||||||
R_API void r_list_free (RList *list);
|
R_API void r_list_free (RList *list);
|
||||||
|
|
|
@ -243,7 +243,7 @@ R_API char *r_str_trim(char *str);
|
||||||
R_API char *r_str_trim_head(char *str);
|
R_API char *r_str_trim_head(char *str);
|
||||||
R_API char *r_str_trim_tail(char *str);
|
R_API char *r_str_trim_tail(char *str);
|
||||||
R_API char *r_str_trim_head_tail(char *str);
|
R_API char *r_str_trim_head_tail(char *str);
|
||||||
R_API int r_str_hash(const char *str);
|
R_API ut32 r_str_hash(const char *str);
|
||||||
R_API ut64 r_str_hash64(const char *str);
|
R_API ut64 r_str_hash64(const char *str);
|
||||||
R_API char *r_str_clean(char *str);
|
R_API char *r_str_clean(char *str);
|
||||||
R_API int r_str_nstr(char *from, char *to, int size);
|
R_API int r_str_nstr(char *from, char *to, int size);
|
||||||
|
@ -383,6 +383,50 @@ R_API void r_big_div(RNumBig *c, RNumBig *a, RNumBig *b);
|
||||||
R_API void r_big_div_ut(RNumBig *a, RNumBig *b, ut32 c);
|
R_API void r_big_div_ut(RNumBig *a, RNumBig *b, ut32 c);
|
||||||
R_API int r_big_divisible_ut(RNumBig *n, ut32 v);
|
R_API int r_big_divisible_ut(RNumBig *n, ut32 v);
|
||||||
R_API void r_big_mod(RNumBig *c, RNumBig *a, RNumBig *b);
|
R_API void r_big_mod(RNumBig *c, RNumBig *a, RNumBig *b);
|
||||||
|
|
||||||
|
/** hashtable **/
|
||||||
|
typedef struct r_hashtable_entry_t {
|
||||||
|
ut32 hash;
|
||||||
|
void *data;
|
||||||
|
} RHashTableEntry;
|
||||||
|
|
||||||
|
typedef struct r_hashtable_t {
|
||||||
|
RHashTableEntry *table;
|
||||||
|
ut32 size;
|
||||||
|
ut32 rehash;
|
||||||
|
ut32 max_entries;
|
||||||
|
ut32 size_index;
|
||||||
|
ut32 entries;
|
||||||
|
ut32 deleted_entries;
|
||||||
|
} RHashTable;
|
||||||
|
|
||||||
|
typedef struct r_hashtable64_entry_t {
|
||||||
|
ut64 hash;
|
||||||
|
void *data;
|
||||||
|
} RHashTable64Entry;
|
||||||
|
|
||||||
|
typedef struct r_hashtable64_t {
|
||||||
|
RHashTable64Entry *table;
|
||||||
|
ut64 size;
|
||||||
|
ut64 rehash;
|
||||||
|
ut64 max_entries;
|
||||||
|
ut64 size_index;
|
||||||
|
ut64 entries;
|
||||||
|
ut64 deleted_entries;
|
||||||
|
} RHashTable64;
|
||||||
|
|
||||||
|
|
||||||
|
R_API RHashTable* r_hashtable_new(void);
|
||||||
|
R_API void r_hashtable_free(RHashTable *ht);
|
||||||
|
R_API void *r_hashtable_lookup(RHashTable *ht, ut32 hash);
|
||||||
|
R_API boolt r_hashtable_insert(RHashTable *ht, ut32 hash, void *data);
|
||||||
|
R_API void r_hashtable_remove(RHashTable *ht, ut32 hash);
|
||||||
|
|
||||||
|
R_API RHashTable64* r_hashtable64_new(void);
|
||||||
|
R_API void r_hashtable64_free(RHashTable64 *ht);
|
||||||
|
R_API void *r_hashtable64_lookup(RHashTable64 *ht, ut64 hash);
|
||||||
|
R_API boolt r_hashtable64_insert(RHashTable64 *ht, ut64 hash, void *data);
|
||||||
|
R_API void r_hashtable64_remove(RHashTable64 *ht, ut64 hash);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,6 +3,7 @@ include ../config.mk
|
||||||
NAME=r_util
|
NAME=r_util
|
||||||
OBJ=mem.o pool.o num.o str.o re.o hex.o file.o alloca.o range.o log.o
|
OBJ=mem.o pool.o num.o str.o re.o hex.o file.o alloca.o range.o log.o
|
||||||
OBJ+=prof.o cache.o sys.o btree.o buf.o list.o flist.o w32-sys.o base64.o
|
OBJ+=prof.o cache.o sys.o btree.o buf.o list.o flist.o w32-sys.o base64.o
|
||||||
|
OBJ+=ht.o ht64.o
|
||||||
ifeq (${HAVE_LIB_GMP},1)
|
ifeq (${HAVE_LIB_GMP},1)
|
||||||
OBJ+=big-gmp.o
|
OBJ+=big-gmp.o
|
||||||
else
|
else
|
||||||
|
@ -16,3 +17,7 @@ endif
|
||||||
LDFLAGS+=${BN_LIBS}
|
LDFLAGS+=${BN_LIBS}
|
||||||
|
|
||||||
include ../rules.mk
|
include ../rules.mk
|
||||||
|
|
||||||
|
ht64:
|
||||||
|
cat ht.c | sed -e s,hashtable,hashtable64,g -e s,HashTable,HashTable64,g -e s,ut32,ut64,g > ht64.c
|
||||||
|
#cat ht.c ht64.c | sed -e 's,) {,);,'
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2009 Intel Corporation
|
||||||
|
* Copyright © 1988-2004 Keith Packard and Bart Massey.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Except as contained in this notice, the names of the authors
|
||||||
|
* or their institutions shall not be used in advertising or
|
||||||
|
* otherwise to promote the sale, use or other dealings in this
|
||||||
|
* Software without prior written authorization from the
|
||||||
|
* authors.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Anholt <eric@anholt.net>
|
||||||
|
* Keith Packard <keithp@keithp.com>
|
||||||
|
* Integration in r2 core api
|
||||||
|
* pancake <nopcode.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <r_util.h>
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From Knuth -- a good choice for hash/rehash values is p, p-2 where
|
||||||
|
* p and p-2 are both prime. These tables are sized to have an extra 10%
|
||||||
|
* free to avoid exponential performance degradation as the hash table fills
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const ut32 deleted_data;
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
ut32 max_entries, size, rehash;
|
||||||
|
} hash_sizes[] = {
|
||||||
|
{ 2, 5, 3 },
|
||||||
|
{ 4, 7, 5 },
|
||||||
|
{ 8, 13, 11 },
|
||||||
|
{ 16, 19, 17 },
|
||||||
|
{ 32, 43, 41 },
|
||||||
|
{ 64, 73, 71 },
|
||||||
|
{ 128, 151, 149 },
|
||||||
|
{ 256, 283, 281 },
|
||||||
|
{ 512, 571, 569 },
|
||||||
|
{ 1024, 1153, 1151 },
|
||||||
|
{ 2048, 2269, 2267 },
|
||||||
|
{ 4096, 4519, 4517 },
|
||||||
|
{ 8192, 9013, 9011 },
|
||||||
|
{ 16384, 18043, 18041 },
|
||||||
|
{ 32768, 36109, 36107 },
|
||||||
|
{ 65536, 72091, 72089 },
|
||||||
|
{ 131072, 144409, 144407 },
|
||||||
|
{ 262144, 288361, 288359 },
|
||||||
|
{ 524288, 576883, 576881 },
|
||||||
|
{ 1048576, 1153459, 1153457 },
|
||||||
|
{ 2097152, 2307163, 2307161 },
|
||||||
|
{ 4194304, 4613893, 4613891 },
|
||||||
|
{ 8388608, 9227641, 9227639 },
|
||||||
|
{ 16777216, 18455029, 18455027 },
|
||||||
|
{ 33554432, 36911011, 36911009 },
|
||||||
|
{ 67108864, 73819861, 73819859 },
|
||||||
|
{ 134217728, 147639589, 147639587 },
|
||||||
|
{ 268435456, 295279081, 295279079 },
|
||||||
|
{ 536870912, 590559793, 590559791 },
|
||||||
|
{ 1073741824, 1181116273, 1181116271},
|
||||||
|
{ 2147483648ul, 2362232233ul, 2362232231ul}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define entry_is_free(x) (!x->data)
|
||||||
|
#define entry_is_deleted(x) (x->data==&deleted_data)
|
||||||
|
#define entry_is_present(x) (x->data && x->data != &deleted_data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a hash table entry with the given key and hash of that key.
|
||||||
|
*
|
||||||
|
* Returns NULL if no entry is found. Note that the data pointer may be
|
||||||
|
* modified by the user.
|
||||||
|
*/
|
||||||
|
static RHashTableEntry* r_hashtable_search(RHashTable *ht, ut32 hash) {
|
||||||
|
ut32 double_hash, hash_address = hash % ht->size;
|
||||||
|
do {
|
||||||
|
RHashTableEntry *entry = ht->table + hash_address;
|
||||||
|
if (entry_is_free (entry))
|
||||||
|
return NULL;
|
||||||
|
if (entry_is_present (entry) && entry->hash == hash)
|
||||||
|
return entry;
|
||||||
|
double_hash = hash % ht->rehash;
|
||||||
|
if (double_hash == 0)
|
||||||
|
double_hash = 1;
|
||||||
|
hash_address = (hash_address + double_hash) % ht->size;
|
||||||
|
} while (hash_address != hash % ht->size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void r_hashtable_rehash(RHashTable *ht, int new_size_index) {
|
||||||
|
RHashTable old_ht = *ht;
|
||||||
|
RHashTableEntry *e;
|
||||||
|
if (new_size_index >= ARRAY_SIZE (hash_sizes))
|
||||||
|
return;
|
||||||
|
// XXX: This code is redupped! fuck't
|
||||||
|
ht->table = malloc (hash_sizes[new_size_index].size * sizeof (*ht->table));
|
||||||
|
if (!ht->table)
|
||||||
|
return;
|
||||||
|
ht->size_index = new_size_index;
|
||||||
|
ht->size = hash_sizes[ht->size_index].size;
|
||||||
|
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||||
|
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||||
|
ht->entries = 0;
|
||||||
|
ht->deleted_entries = 0;
|
||||||
|
for (e = old_ht.table; e != old_ht.table + old_ht.size; e++) {
|
||||||
|
if (entry_is_present (e))
|
||||||
|
r_hashtable_insert (ht, e->hash, e->data);
|
||||||
|
}
|
||||||
|
free (old_ht.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API RHashTable* r_hashtable_new(void) {
|
||||||
|
RHashTable *ht = malloc (sizeof (*ht));
|
||||||
|
if (!ht)
|
||||||
|
return NULL;
|
||||||
|
// TODO: use slices here
|
||||||
|
ht->table = malloc (ht->size * sizeof (*ht->table));
|
||||||
|
if (!ht->table) {
|
||||||
|
free (ht);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ht->size_index = 0;
|
||||||
|
ht->entries = 0;
|
||||||
|
ht->deleted_entries = 0;
|
||||||
|
ht->size = hash_sizes[ht->size_index].size;
|
||||||
|
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||||
|
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||||
|
return ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API void r_hashtable_free(RHashTable *ht) {
|
||||||
|
if (ht) free (ht->table), free (ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API void *r_hashtable_lookup(RHashTable *ht, ut32 hash) {
|
||||||
|
RHashTableEntry *entry = r_hashtable_search (ht, hash);
|
||||||
|
return entry? entry->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the data with the given hash into the table.
|
||||||
|
*
|
||||||
|
* Note that insertion may rearrange the table on a resize or rehash,
|
||||||
|
* so previously found hash_entries are no longer valid after this function.
|
||||||
|
*/
|
||||||
|
R_API boolt r_hashtable_insert(RHashTable *ht, ut32 hash, void *data) {
|
||||||
|
ut32 hash_address;
|
||||||
|
|
||||||
|
if (ht->entries >= ht->max_entries)
|
||||||
|
r_hashtable_rehash (ht, ht->size_index + 1);
|
||||||
|
else if (ht->deleted_entries + ht->entries >= ht->max_entries)
|
||||||
|
r_hashtable_rehash (ht, ht->size_index);
|
||||||
|
|
||||||
|
hash_address = hash % ht->size;
|
||||||
|
do {
|
||||||
|
RHashTableEntry *entry = ht->table + hash_address;
|
||||||
|
ut32 double_hash;
|
||||||
|
|
||||||
|
if (!entry_is_present (entry)) {
|
||||||
|
if (entry_is_deleted (entry))
|
||||||
|
ht->deleted_entries--;
|
||||||
|
entry->hash = hash;
|
||||||
|
entry->data = data;
|
||||||
|
ht->entries++;
|
||||||
|
return R_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
double_hash = hash % ht->rehash;
|
||||||
|
if (double_hash == 0)
|
||||||
|
double_hash = 1;
|
||||||
|
hash_address = (hash_address + double_hash) % ht->size;
|
||||||
|
} while (hash_address != hash % ht->size);
|
||||||
|
|
||||||
|
/* We could hit here if a required resize failed. An unchecked-malloc
|
||||||
|
* application could ignore this result.
|
||||||
|
*/
|
||||||
|
return R_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API void r_hashtable_remove(RHashTable *ht, ut32 hash) {
|
||||||
|
RHashTableEntry *entry = r_hashtable_search (ht, hash);
|
||||||
|
if (entry) {
|
||||||
|
entry->data = (void *) &deleted_data;
|
||||||
|
ht->entries--;
|
||||||
|
ht->deleted_entries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
int main () {
|
||||||
|
const char *str;
|
||||||
|
int ret;
|
||||||
|
RHashTable *ht = r_hashtable_new ();
|
||||||
|
#define HASH 268453705
|
||||||
|
|
||||||
|
ret = r_hashtable_insert (ht, HASH, "patata");
|
||||||
|
if (!ret)
|
||||||
|
printf ("Cannot reinsert !!1\n");
|
||||||
|
|
||||||
|
str = r_hashtable_lookup (ht, HASH);
|
||||||
|
if (str) printf ("String is (%s)\n", str);
|
||||||
|
else printf ("Cannot find string\n");
|
||||||
|
|
||||||
|
r_hashtable_remove (ht, HASH);
|
||||||
|
|
||||||
|
str = r_hashtable_lookup (ht, HASH);
|
||||||
|
if (str) printf ("String is (%s)\n", str);
|
||||||
|
else printf("Cannot find string which is ok :)\n");
|
||||||
|
|
||||||
|
r_hashtable_search (ht, HASH);
|
||||||
|
|
||||||
|
r_hashtable_free (ht);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,234 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2009 Intel Corporation
|
||||||
|
* Copyright © 1988-2004 Keith Packard and Bart Massey.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Except as contained in this notice, the names of the authors
|
||||||
|
* or their institutions shall not be used in advertising or
|
||||||
|
* otherwise to promote the sale, use or other dealings in this
|
||||||
|
* Software without prior written authorization from the
|
||||||
|
* authors.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Anholt <eric@anholt.net>
|
||||||
|
* Keith Packard <keithp@keithp.com>
|
||||||
|
* Integration in r2 core api
|
||||||
|
* pancake <nopcode.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <r_util.h>
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From Knuth -- a good choice for hash/rehash values is p, p-2 where
|
||||||
|
* p and p-2 are both prime. These tables are sized to have an extra 10%
|
||||||
|
* free to avoid exponential performance degradation as the hash table fills
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const ut64 deleted_data;
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
ut64 max_entries, size, rehash;
|
||||||
|
} hash_sizes[] = {
|
||||||
|
{ 2, 5, 3 },
|
||||||
|
{ 4, 7, 5 },
|
||||||
|
{ 8, 13, 11 },
|
||||||
|
{ 16, 19, 17 },
|
||||||
|
{ 32, 43, 41 },
|
||||||
|
{ 64, 73, 71 },
|
||||||
|
{ 128, 151, 149 },
|
||||||
|
{ 256, 283, 281 },
|
||||||
|
{ 512, 571, 569 },
|
||||||
|
{ 1024, 1153, 1151 },
|
||||||
|
{ 2048, 2269, 2267 },
|
||||||
|
{ 4096, 4519, 4517 },
|
||||||
|
{ 8192, 9013, 9011 },
|
||||||
|
{ 16384, 18043, 18041 },
|
||||||
|
{ 32768, 36109, 36107 },
|
||||||
|
{ 65536, 72091, 72089 },
|
||||||
|
{ 131072, 144409, 144407 },
|
||||||
|
{ 262144, 288361, 288359 },
|
||||||
|
{ 524288, 576883, 576881 },
|
||||||
|
{ 1048576, 1153459, 1153457 },
|
||||||
|
{ 2097152, 2307163, 2307161 },
|
||||||
|
{ 4194304, 4613893, 4613891 },
|
||||||
|
{ 8388608, 9227641, 9227639 },
|
||||||
|
{ 16777216, 18455029, 18455027 },
|
||||||
|
{ 33554432, 36911011, 36911009 },
|
||||||
|
{ 67108864, 73819861, 73819859 },
|
||||||
|
{ 134217728, 147639589, 147639587 },
|
||||||
|
{ 268435456, 295279081, 295279079 },
|
||||||
|
{ 536870912, 590559793, 590559791 },
|
||||||
|
{ 1073741824, 1181116273, 1181116271},
|
||||||
|
{ 2147483648ul, 2362232233ul, 2362232231ul}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define entry_is_free(x) (!x->data)
|
||||||
|
#define entry_is_deleted(x) (x->data==&deleted_data)
|
||||||
|
#define entry_is_present(x) (x->data && x->data != &deleted_data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a hash table entry with the given key and hash of that key.
|
||||||
|
*
|
||||||
|
* Returns NULL if no entry is found. Note that the data pointer may be
|
||||||
|
* modified by the user.
|
||||||
|
*/
|
||||||
|
static RHashTable64Entry* r_hashtable64_search(RHashTable64 *ht, ut64 hash) {
|
||||||
|
ut64 double_hash, hash_address = hash % ht->size;
|
||||||
|
do {
|
||||||
|
RHashTable64Entry *entry = ht->table + hash_address;
|
||||||
|
if (entry_is_free (entry))
|
||||||
|
return NULL;
|
||||||
|
if (entry_is_present (entry) && entry->hash == hash)
|
||||||
|
return entry;
|
||||||
|
double_hash = hash % ht->rehash;
|
||||||
|
if (double_hash == 0)
|
||||||
|
double_hash = 1;
|
||||||
|
hash_address = (hash_address + double_hash) % ht->size;
|
||||||
|
} while (hash_address != hash % ht->size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void r_hashtable64_rehash(RHashTable64 *ht, int new_size_index) {
|
||||||
|
RHashTable64 old_ht = *ht;
|
||||||
|
RHashTable64Entry *e;
|
||||||
|
if (new_size_index >= ARRAY_SIZE (hash_sizes))
|
||||||
|
return;
|
||||||
|
// XXX: This code is redupped! fuck't
|
||||||
|
ht->table = malloc (hash_sizes[new_size_index].size * sizeof (*ht->table));
|
||||||
|
if (!ht->table)
|
||||||
|
return;
|
||||||
|
ht->size_index = new_size_index;
|
||||||
|
ht->size = hash_sizes[ht->size_index].size;
|
||||||
|
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||||
|
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||||
|
ht->entries = 0;
|
||||||
|
ht->deleted_entries = 0;
|
||||||
|
for (e = old_ht.table; e != old_ht.table + old_ht.size; e++) {
|
||||||
|
if (entry_is_present (e))
|
||||||
|
r_hashtable64_insert (ht, e->hash, e->data);
|
||||||
|
}
|
||||||
|
free (old_ht.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API RHashTable64* r_hashtable64_new(void) {
|
||||||
|
RHashTable64 *ht = malloc (sizeof (*ht));
|
||||||
|
if (!ht)
|
||||||
|
return NULL;
|
||||||
|
// TODO: use slices here
|
||||||
|
ht->table = malloc (ht->size * sizeof (*ht->table));
|
||||||
|
if (!ht->table) {
|
||||||
|
free (ht);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ht->size_index = 0;
|
||||||
|
ht->entries = 0;
|
||||||
|
ht->deleted_entries = 0;
|
||||||
|
ht->size = hash_sizes[ht->size_index].size;
|
||||||
|
ht->rehash = hash_sizes[ht->size_index].rehash;
|
||||||
|
ht->max_entries = hash_sizes[ht->size_index].max_entries;
|
||||||
|
return ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API void r_hashtable64_free(RHashTable64 *ht) {
|
||||||
|
if (ht) free (ht->table), free (ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API void *r_hashtable64_lookup(RHashTable64 *ht, ut64 hash) {
|
||||||
|
RHashTable64Entry *entry = r_hashtable64_search (ht, hash);
|
||||||
|
return entry? entry->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the data with the given hash into the table.
|
||||||
|
*
|
||||||
|
* Note that insertion may rearrange the table on a resize or rehash,
|
||||||
|
* so previously found hash_entries are no longer valid after this function.
|
||||||
|
*/
|
||||||
|
R_API boolt r_hashtable64_insert(RHashTable64 *ht, ut64 hash, void *data) {
|
||||||
|
ut64 hash_address;
|
||||||
|
|
||||||
|
if (ht->entries >= ht->max_entries)
|
||||||
|
r_hashtable64_rehash (ht, ht->size_index + 1);
|
||||||
|
else if (ht->deleted_entries + ht->entries >= ht->max_entries)
|
||||||
|
r_hashtable64_rehash (ht, ht->size_index);
|
||||||
|
|
||||||
|
hash_address = hash % ht->size;
|
||||||
|
do {
|
||||||
|
RHashTable64Entry *entry = ht->table + hash_address;
|
||||||
|
ut64 double_hash;
|
||||||
|
|
||||||
|
if (!entry_is_present (entry)) {
|
||||||
|
if (entry_is_deleted (entry))
|
||||||
|
ht->deleted_entries--;
|
||||||
|
entry->hash = hash;
|
||||||
|
entry->data = data;
|
||||||
|
ht->entries++;
|
||||||
|
return R_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
double_hash = hash % ht->rehash;
|
||||||
|
if (double_hash == 0)
|
||||||
|
double_hash = 1;
|
||||||
|
hash_address = (hash_address + double_hash) % ht->size;
|
||||||
|
} while (hash_address != hash % ht->size);
|
||||||
|
|
||||||
|
/* We could hit here if a required resize failed. An unchecked-malloc
|
||||||
|
* application could ignore this result.
|
||||||
|
*/
|
||||||
|
return R_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
R_API void r_hashtable64_remove(RHashTable64 *ht, ut64 hash) {
|
||||||
|
RHashTable64Entry *entry = r_hashtable64_search (ht, hash);
|
||||||
|
if (entry) {
|
||||||
|
entry->data = (void *) &deleted_data;
|
||||||
|
ht->entries--;
|
||||||
|
ht->deleted_entries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
int main () {
|
||||||
|
const char *str;
|
||||||
|
int ret;
|
||||||
|
RHashTable64 *ht = r_hashtable64_new ();
|
||||||
|
|
||||||
|
ret = r_hashtable64_insert (ht, 33, "patata");
|
||||||
|
if (!ret)
|
||||||
|
printf ("Cannot reinsert !!1\n");
|
||||||
|
|
||||||
|
str = r_hashtable64_lookup (ht, 33);
|
||||||
|
if (str) printf ("String is (%s)\n", str);
|
||||||
|
else printf ("Cannot find string\n");
|
||||||
|
|
||||||
|
r_hashtable64_remove (ht, 33);
|
||||||
|
|
||||||
|
str = r_hashtable64_lookup (ht, 33);
|
||||||
|
if (str) printf ("String is (%s)\n", str);
|
||||||
|
else printf("Cannot find string\n");
|
||||||
|
|
||||||
|
r_hashtable64_search (ht, 33);
|
||||||
|
|
||||||
|
r_hashtable64_free (ht);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* radare - LGPL - Copyright 2007-2011 pancake<nopcode.org> */
|
||||||
|
|
||||||
#include "r_util.h"
|
#include "r_util.h"
|
||||||
|
|
||||||
R_API void r_list_init(RList *list) {
|
R_API void r_list_init(RList *list) {
|
||||||
|
@ -42,14 +44,22 @@ R_API void r_list_split (RList *list, void *ptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API void r_list_split_iter (RList *list, RListIter *iter) {
|
R_API void r_list_split_iter (RList *list, RListIter *iter) {
|
||||||
if (list->head == iter)
|
if (list->head == iter) list->head = iter->n;
|
||||||
list->head = iter->n;
|
if (list->tail == iter) list->tail = iter->p;
|
||||||
if (list->tail == iter)
|
if (iter->p) iter->p->n = iter->n;
|
||||||
list->tail = iter->p;
|
if (iter->n) iter->n->p = iter->p;
|
||||||
if (iter->p)
|
}
|
||||||
iter->p->n = iter->n;
|
|
||||||
if (iter->n)
|
R_API boolt r_list_delete_data (RList *list, void *ptr) {
|
||||||
iter->n->p = iter->p;
|
void *p;
|
||||||
|
RListIter *iter;
|
||||||
|
r_list_foreach (list, iter, p) {
|
||||||
|
if (ptr == p) {
|
||||||
|
r_list_delete (list, iter);
|
||||||
|
return R_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return R_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API void r_list_delete (RList *list, RListIter *iter) {
|
R_API void r_list_delete (RList *list, RListIter *iter) {
|
||||||
|
@ -75,12 +85,15 @@ R_API void r_list_destroy (RList *list) {
|
||||||
RListIter *next = it->n;
|
RListIter *next = it->n;
|
||||||
r_list_delete (list, it);
|
r_list_delete (list, it);
|
||||||
it = next;
|
it = next;
|
||||||
|
// free (it);
|
||||||
}
|
}
|
||||||
list->head = list->tail = NULL;
|
list->head = list->tail = NULL;
|
||||||
}
|
}
|
||||||
|
//free (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API void r_list_free (RList *list) {
|
R_API void r_list_free (RList *list) {
|
||||||
|
list->free = NULL;
|
||||||
r_list_destroy (list);
|
r_list_destroy (list);
|
||||||
free (list);
|
free (list);
|
||||||
}
|
}
|
||||||
|
@ -362,7 +375,7 @@ int main () {
|
||||||
}
|
}
|
||||||
|
|
||||||
r_list_free (l);
|
r_list_free (l);
|
||||||
r_list_free (list);
|
//r_list_free (l);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,8 +174,8 @@ R_API ut64 r_str_hash64(const char *str) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
R_API int r_str_hash(const char *str) {
|
R_API ut32 r_str_hash(const char *str) {
|
||||||
int ret = 0;
|
ut32 ret = 0;
|
||||||
for (;*str; str++)
|
for (;*str; str++)
|
||||||
ret ^= (ret<<7 | *str);
|
ret ^= (ret<<7 | *str);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue