X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=lib%2Fhashtable.c;h=e3be563565174fadb1fb434d56ca50e6cce17195;hb=09140113108541b95d340f3c7b6ee597d31ccc73;hp=50ff40a397431aac6abc5742352f6b63625f274a;hpb=748ad078eefea2ee5a3c8e53ca46e9e93c2fc7f1;p=oweals%2Fu-boot.git diff --git a/lib/hashtable.c b/lib/hashtable.c index 50ff40a397..e3be563565 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -14,6 +14,7 @@ #include #include +#include #ifdef USE_HOSTCC /* HOST build */ # include @@ -40,6 +41,9 @@ #define CONFIG_ENV_MAX_ENTRIES 512 #endif +#define USED_FREE 0 +#define USED_DELETED -1 + #include #include #include @@ -56,14 +60,14 @@ * which describes the current status. */ -typedef struct _ENTRY { +struct env_entry_node { int used; - ENTRY entry; -} _ENTRY; + struct env_entry entry; +}; -static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, - int idx); +static void _hdelete(const char *key, struct hsearch_data *htab, + struct env_entry *ep, int idx); /* * hcreate() @@ -117,7 +121,8 @@ int hcreate_r(size_t nel, struct hsearch_data *htab) htab->filled = 0; /* allocate memory and zero out */ - htab->table = (_ENTRY *) calloc(htab->size + 1, sizeof(_ENTRY)); + htab->table = (struct env_entry_node *)calloc(htab->size + 1, + sizeof(struct env_entry_node)); if (htab->table == NULL) return 0; @@ -148,7 +153,7 @@ void hdestroy_r(struct hsearch_data *htab) /* free used memory */ for (i = 1; i <= htab->size; ++i) { if (htab->table[i].used > 0) { - ENTRY *ep = &htab->table[i].entry; + struct env_entry *ep = &htab->table[i].entry; free((void *)ep->key); free(ep->data); @@ -190,14 +195,14 @@ void hdestroy_r(struct hsearch_data *htab) * data any more. * - The standard implementation does not provide a way to update an * existing entry. This version will create a new entry or update an - * existing one when both "action == ENTER" and "item.data != NULL". + * existing one when both "action == ENV_ENTER" and "item.data != NULL". * - Instead of returning 1 on success, we return the index into the * internal hash table, which is also guaranteed to be positive. * This allows us direct access to the found hash table slot for * example for functions like hdelete(). */ -int hmatch_r(const char *match, int last_idx, ENTRY ** retval, +int hmatch_r(const char *match, int last_idx, struct env_entry **retval, struct hsearch_data *htab) { unsigned int idx; @@ -217,18 +222,30 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval, return 0; } +static int +do_callback(const struct env_entry *e, const char *name, const char *value, + enum env_op op, int flags) +{ +#ifndef CONFIG_SPL_BUILD + if (e->callback) + return e->callback(name, value, op, flags); +#endif + return 0; +} + /* * Compare an existing entry with the desired key, and overwrite if the action - * is ENTER. This is simply a helper function for hsearch_r(). + * is ENV_ENTER. This is simply a helper function for hsearch_r(). */ -static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, - ENTRY **retval, struct hsearch_data *htab, int flag, - unsigned int hval, unsigned int idx) +static inline int _compare_and_overwrite_entry(struct env_entry item, + enum env_action action, struct env_entry **retval, + struct hsearch_data *htab, int flag, unsigned int hval, + unsigned int idx) { if (htab->table[idx].used == hval && strcmp(item.key, htab->table[idx].entry.key) == 0) { /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { + if (action == ENV_ENTER && item.data) { /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( &htab->table[idx].entry, item.data, @@ -241,9 +258,8 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, } /* If there is a callback, call it */ - if (htab->table[idx].entry.callback && - htab->table[idx].entry.callback(item.key, - item.data, env_op_overwrite, flag)) { + if (do_callback(&htab->table[idx].entry, item.key, + item.data, env_op_overwrite, flag)) { debug("callback() rejected setting variable " "%s, skipping it!\n", item.key); __set_errno(EINVAL); @@ -267,8 +283,8 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, return -1; } -int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, - struct hsearch_data *htab, int flag) +int hsearch_r(struct env_entry item, enum env_action action, + struct env_entry **retval, struct hsearch_data *htab, int flag) { unsigned int hval; unsigned int count; @@ -303,7 +319,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, */ unsigned hval2; - if (htab->table[idx].used == -1 + if (htab->table[idx].used == USED_DELETED && !first_deleted) first_deleted = idx; @@ -335,17 +351,21 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, if (idx == hval) break; + if (htab->table[idx].used == USED_DELETED + && !first_deleted) + first_deleted = idx; + /* If entry is found use it. */ ret = _compare_and_overwrite_entry(item, action, retval, htab, flag, hval, idx); if (ret != -1) return ret; } - while (htab->table[idx].used); + while (htab->table[idx].used != USED_FREE); } /* An empty bucket has been found. */ - if (action == ENTER) { + if (action == ENV_ENTER) { /* * If table is full and another entry should be * entered return with error. @@ -392,9 +412,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, } /* If there is a callback, call it */ - if (htab->table[idx].entry.callback && - htab->table[idx].entry.callback(item.key, item.data, - env_op_create, flag)) { + if (do_callback(&htab->table[idx].entry, item.key, item.data, + env_op_create, flag)) { debug("callback() rejected setting variable " "%s, skipping it!\n", item.key); _hdelete(item.key, htab, &htab->table[idx].entry, idx); @@ -424,30 +443,29 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ -static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, - int idx) +static void _hdelete(const char *key, struct hsearch_data *htab, + struct env_entry *ep, int idx) { - /* free used ENTRY */ + /* free used entry */ debug("hdelete: DELETING key \"%s\"\n", key); free((void *)ep->key); free(ep->data); - ep->callback = NULL; ep->flags = 0; - htab->table[idx].used = -1; + htab->table[idx].used = USED_DELETED; --htab->filled; } int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { - ENTRY e, *ep; + struct env_entry e, *ep; int idx; debug("hdelete: DELETE key \"%s\"\n", key); e.key = (char *)key; - idx = hsearch_r(e, FIND, &ep, htab, 0); + idx = hsearch_r(e, ENV_FIND, &ep, htab, 0); if (idx == 0) { __set_errno(ESRCH); return 0; /* not found */ @@ -463,8 +481,8 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) } /* If there is a callback, call it */ - if (htab->table[idx].entry.callback && - htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) { + if (do_callback(&htab->table[idx].entry, key, NULL, + env_op_delete, flag)) { debug("callback() rejected deleting variable " "%s, skipping it!\n", key); __set_errno(EINVAL); @@ -521,8 +539,8 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) static int cmpkey(const void *p1, const void *p2) { - ENTRY *e1 = *(ENTRY **) p1; - ENTRY *e2 = *(ENTRY **) p2; + struct env_entry *e1 = *(struct env_entry **)p1; + struct env_entry *e2 = *(struct env_entry **)p2; return (strcmp(e1->key, e2->key)); } @@ -556,8 +574,8 @@ static int match_string(int flag, const char *str, const char *pat, void *priv) return 0; } -static int match_entry(ENTRY *ep, int flag, - int argc, char * const argv[]) +static int match_entry(struct env_entry *ep, int flag, int argc, + char *const argv[]) { int arg; void *priv = NULL; @@ -587,9 +605,9 @@ static int match_entry(ENTRY *ep, int flag, ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, char **resp, size_t size, - int argc, char * const argv[]) + int argc, char *const argv[]) { - ENTRY *list[htab->size]; + struct env_entry *list[htab->size]; char *res, *p; size_t totlen; int i, n; @@ -610,7 +628,7 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) { if (htab->table[i].used > 0) { - ENTRY *ep = &htab->table[i].entry; + struct env_entry *ep = &htab->table[i].entry; int found = match_entry(ep, flag, argc, argv); if ((argc > 0) && (found == 0)) @@ -650,7 +668,7 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, #endif /* Sort list by keys */ - qsort(list, n, sizeof(ENTRY *), cmpkey); + qsort(list, n, sizeof(struct env_entry *), cmpkey); /* Check if the user supplied buffer size is sufficient */ if (size) { @@ -862,7 +880,7 @@ int himport_r(struct hsearch_data *htab, } /* Parse environment; allow for '\0' and 'sep' as separators */ do { - ENTRY e, *rv; + struct env_entry e, *rv; /* skip leading white space */ while (isblank(*dp)) @@ -922,7 +940,7 @@ int himport_r(struct hsearch_data *htab, e.key = name; e.data = value; - hsearch_r(e, ENTER, &rv, htab, flag); + hsearch_r(e, ENV_ENTER, &rv, htab, flag); if (rv == NULL) printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); @@ -969,7 +987,7 @@ end: * Walk all of the entries in the hash, calling the callback for each one. * this allows some generic operation to be performed on each element. */ -int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *)) +int hwalk_r(struct hsearch_data *htab, int (*callback)(struct env_entry *entry)) { int i; int retval;