/** add a key, value pair to a hash table. * each key can appear only once; the value of any * identical key will be replaced */ int hash_add(hash_t *table, const char * const key, void *data) { xmpp_ctx_t *ctx = table->ctx; hashentry_t *entry = NULL; int table_index = _hash_key(table, key); /* drop existing entry, if any */ hash_drop(table, key); /* allocate and fill a new entry */ entry = xmpp_alloc(ctx, sizeof(hashentry_t)); if (!entry) return -1; entry->key = xmpp_strdup(ctx, key); if (!entry->key) { xmpp_free(ctx, entry); return -1; } entry->value = data; /* insert ourselves in the linked list */ /* TODO: this leaks duplicate keys */ entry->next = table->entries[table_index]; table->entries[table_index] = entry; table->num_keys++; return 0; }
int hash_add(hash_t *table, const char *key, void *data) { hashentry_t *entry = NULL; int index = _hash_key(table, key); if (table->free) { hash_drop(table, key); } else { // 没有指定释放函数,有冲突的话插入失败 if (!hash_get(table, key)) { return -1; } } entry = safe_mem_calloc(sizeof(hashentry_t), NULL); if (!entry) return -1; entry->key = im_strndup(key, im_strlen(key)); if (!entry->key) { safe_mem_free(entry); return -1; } entry->value = data; entry->next = table->entries[index]; table->entries[index] = entry; table->num_keys++; return 0; }
/** Delete an id based stanza handler. * * @param conn a Strophe connection object * @param handler a function pointer to a stanza handler * @param id a string containing the id the handler is for * * @ingroup Handlers */ void xmpp_id_handler_delete(xmpp_conn_t * const conn, xmpp_handler handler, const char * const id) { xmpp_handlist_t *item, *prev; prev = NULL; item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); if (!item) return; while (item) { if (item->handler == (void *)handler) break; prev = item; item = item->next; } if (item) { if (prev) prev->next = item->next; else { hash_drop(conn->id_handlers, id); hash_add(conn->id_handlers, id, item->next); } xmpp_free(conn->ctx, item->id); xmpp_free(conn->ctx, item); } }
/** Delete an attribute from a stanza. * * @param stanza a Strophe stanza object * @param name a string containing attribute name * * @return XMPP_EOK (0) on success or a number less than 0 on failure * * @ingroup Stanza */ int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza, const char * const name) { if (stanza->type != XMPP_STANZA_TAG) return -1; if (!stanza->attributes) return -1; return hash_drop(stanza->attributes, name); }
int main(int argc, char **argv) { xmpp_ctx_t *ctx; hash_t *table, *clone; hash_iterator_t *iter; unsigned int seed; const char *key; char *result; int err = 0; int i; /* initialize random numbers */ if (argc > 2) { /* use a seed from the command line */ seed = (unsigned int)atoi(argv[1]); } else { seed = (unsigned int)clock(); } /* using random seed 'seed' */ srand(seed); /* allocate a default context */ ctx = xmpp_ctx_new(NULL, NULL); if (ctx == NULL) { /* ctx allocation failed! */ return -1; } /* allocate a hash table */ table = hash_new(ctx, TABLESIZE, NULL); if (table == NULL) { /* table allocation failed! */ return 1; } /* test insertion */ for (i = 0; i < nkeys; i++) { err = hash_add(table, keys[i], (void*)values[i]); if (err) return err; } /* test key count */ if (hash_num_keys(table) != nkeys) { /* wrong number of keys in table! */ return 1; } /* test cloning */ clone = hash_clone(table); /* test lookup */ for (i = 0; i < nkeys; i++) { result = hash_get(clone, keys[i]); if (result == NULL) { /* lookup failed! */ return 1; } if (strcmp(values[i], result)) { /* lookup returned incorrect value! */ return 1; } } /* test key iterator */ iter = hash_iter_new(clone); if (iter == NULL) { /* iterator allocation failed! */ return 1; } for (i = 0; i < nkeys; i++) { key = hash_iter_next(iter); printf("key: '%s'\n", key); } key = hash_iter_next(iter); if (key != NULL) { /* extra keys returned! */ return 1; } key = hash_iter_next(iter); if (key != NULL) { /* extra keys returned! */ return 1; } hash_iter_release(iter); /* release the hash table */ hash_release(table); /* test drops */ hash_drop(clone, keys[2]); if (hash_get(clone, keys[2]) != NULL) return 1; hash_drop(clone, keys[1]); hash_drop(clone, keys[4]); if (hash_get(clone, keys[4]) != NULL) return 1; if (hash_get(clone, keys[1]) != NULL) return 1; /* keys 0,3 should still be available */ if (hash_get(clone, keys[0]) == NULL) return 1; if (hash_get(clone, keys[3]) == NULL) return 1; /* release our clone */ hash_release(clone); /* release our library context */ xmpp_ctx_free(ctx); return err; }
/** Fire off all stanza handlers that match. * This function is called internally by the event loop whenever stanzas * are received from the XMPP server. * * @param conn a Strophe connection object * @param stanza a Strophe stanza object */ void handler_fire_stanza(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza) { xmpp_handlist_t *item, *prev; char *id, *ns, *name, *type; /* call id handlers */ id = xmpp_stanza_get_id(stanza); if (id) { prev = NULL; item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); while (item) { xmpp_handlist_t *next = item->next; if (item->user_handler && !conn->authenticated) { item = next; continue; } if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { /* handler is one-shot, so delete it */ if (prev) prev->next = next; else { hash_drop(conn->id_handlers, id); hash_add(conn->id_handlers, id, next); } xmpp_free(conn->ctx, item->id); xmpp_free(conn->ctx, item); item = NULL; } if (item) prev = item; item = next; } } /* call handlers */ ns = xmpp_stanza_get_ns(stanza); name = xmpp_stanza_get_name(stanza); type = xmpp_stanza_get_type(stanza); /* enable all added handlers */ for (item = conn->handlers; item; item = item->next) item->enabled = 1; prev = NULL; item = conn->handlers; while (item) { /* skip newly added handlers */ if (!item->enabled) { prev = item; item = item->next; continue; } /* don't call user handlers until authentication succeeds */ if (item->user_handler && !conn->authenticated) { prev = item; item = item->next; continue; } if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) || xmpp_stanza_get_child_by_ns(stanza, item->ns)) && (!item->name || (name && strcmp(name, item->name) == 0)) && (!item->type || (type && strcmp(type, item->type) == 0))) if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { /* handler is one-shot, so delete it */ if (prev) prev->next = item->next; else conn->handlers = item->next; if (item->ns) xmpp_free(conn->ctx, item->ns); if (item->name) xmpp_free(conn->ctx, item->name); if (item->type) xmpp_free(conn->ctx, item->type); xmpp_free(conn->ctx, item); item = NULL; } if (item) { prev = item; item = item->next; } else if (prev) item = prev->next; else item = conn->handlers; } }