diff options
author | niemeyer <devnull@localhost> | 2004-04-18 03:23:39 +0000 |
---|---|---|
committer | niemeyer <devnull@localhost> | 2004-04-18 03:23:39 +0000 |
commit | e0c6886a5478c9e1b1721312973c49758ad171b4 (patch) | |
tree | b7a4565e4f322952478dccab8518351def678427 /rpmio/rpmhook.c | |
parent | a7722ac9939189915d8863779af95d8a10c583f8 (diff) | |
download | rpm-e0c6886a5478c9e1b1721312973c49758ad171b4.tar.gz rpm-e0c6886a5478c9e1b1721312973c49758ad171b4.tar.bz2 rpm-e0c6886a5478c9e1b1721312973c49758ad171b4.zip |
Adding in-development hooking system into the repository.
CVS patchset: 7237
CVS date: 2004/04/18 03:23:39
Diffstat (limited to 'rpmio/rpmhook.c')
-rw-r--r-- | rpmio/rpmhook.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/rpmio/rpmhook.c b/rpmio/rpmhook.c new file mode 100644 index 000000000..1323117ba --- /dev/null +++ b/rpmio/rpmhook.c @@ -0,0 +1,238 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#define RPMHOOK_TABLE_INITSIZE 256 +#define RPMHOOK_BUCKET_INITSIZE 5 + +typedef union { + char *s; + int i; + float f; + void *p; +} rpmhookArgv; + +typedef struct { + int argc; + const char *argt; + rpmhookArgv argv[1]; +} rpmhookArgs; + +typedef int (*rpmhookFunc)(rpmhookArgs *args, void *data); + +typedef struct _rpmhookItem { + rpmhookFunc func; + void *data; + struct _rpmhookItem *next; +} rpmhookItem; + +typedef struct { + unsigned long hash; + char *name; + rpmhookItem *item; +} rpmhookBucket; + +typedef struct { + int size; + int used; + rpmhookBucket bucket[1]; +} rpmhookTable; + +rpmhookTable *rpmhookTableNew(int size) +{ + rpmhookTable *table = (rpmhookTable *)calloc(1, sizeof(rpmhookTable)+ + sizeof(rpmhookBucket)* + (size-1)); + table->size = size; + return table; +} + +rpmhookTable *rpmhookTableFree(rpmhookTable *table) +{ + rpmhookItem *item, *nextItem; + int i; + for (i = 0; i != table->size; i++) { + if (table->bucket[i].name) { + free(table->bucket[i].name); + item = table->bucket[i].item; + while (item) { + nextItem = item->next; + free(item); + item = nextItem; + } + } + } + free(table); +} + +void rpmhookTableRehash(rpmhookTable **table); + +int rpmhookTableFindBucket(rpmhookTable **table, const char *name) +{ + /* Hash based on http://www.isthe.com/chongo/tech/comp/fnv/ */ + unsigned long perturb; + unsigned long hash = 0; + unsigned char *bp = (unsigned char *)name; + unsigned char *be = bp + strlen(name); + rpmhookBucket *bucket; + if (((*table)->used/2)*3 > (*table)->size) + rpmhookTableRehash(table); + int ret; + while (bp < be) { + hash ^= (unsigned long)*bp++; + hash *= (unsigned long)0x01000193; + } + perturb = hash; + ret = hash % (*table)->size; + bucket = &(*table)->bucket[ret]; + while (bucket->name && + (bucket->hash != hash || strcmp(bucket->name, name) != 0)) { + /* Collision resolution based on Python's perturb scheme. */ + ret = ((ret << 2) + ret + perturb + 1) % (*table)->size; + perturb >>= 5; + bucket = &(*table)->bucket[ret]; + } + if (!bucket->name) + bucket->hash = hash; + return ret; +} + +void rpmhookTableRehash(rpmhookTable **table) +{ + rpmhookTable *newtable = rpmhookTableNew((*table)->size*2); + int n, i = 0; + for (; i != (*table)->size; i++) { + if ((*table)->bucket[i].name) { + n = rpmhookTableFindBucket(&newtable, (*table)->bucket[i].name); + newtable->bucket[n].name = (*table)->bucket[i].name; + newtable->bucket[n].item = (*table)->bucket[i].item; + } + } + newtable->used = (*table)->used; + free(*table); + *table = newtable; +} + +void rpmhookTableAddItem(rpmhookTable **table, const char *name, + rpmhookFunc func, void *data) +{ + int n = rpmhookTableFindBucket(table, name); + rpmhookBucket *bucket = &(*table)->bucket[n]; + rpmhookItem **item = &bucket->item; + if (!bucket->name) { + bucket->name = strdup(name); + (*table)->used++; + } + while (*item) item = &(*item)->next; + *item = calloc(1, sizeof(rpmhookItem)); + (*item)->func = func; + (*item)->data = data; +} + +void rpmhookTableDelItem(rpmhookTable **table, const char *name, + rpmhookFunc func, void *data) +{ + int n = rpmhookTableFindBucket(table, name); + rpmhookBucket *bucket = &(*table)->bucket[n]; + rpmhookItem *item = bucket->item; + rpmhookItem *lastItem = NULL; + while (item && item->func != func + && (data == NULL || item->data == data)) { + lastItem = item; + item = item->next; + } + if (item) { + if (lastItem) + lastItem->next = item->next; + else + bucket->item = item->next; + free(item); + if (!bucket->item) { + free(bucket->name); + bucket->name = NULL; + (*table)->used--; + } + } +} + +rpmhookArgs *rpmhookArgsParse(const char *argt, va_list ap) +{ + int argc = strlen(argt); + int i; + rpmhookArgs *args = + (rpmhookArgs *)malloc(sizeof(rpmhookArgs)+ + (argc-1)*sizeof(rpmhookArgv)); + args->argc = argc; + args->argt = argt; + for (i = 0; i != argc; i++) { + switch (argt[i]) { + case 's': + args->argv[i].s = va_arg(ap, char *); + break; + case 'i': + args->argv[i].i = va_arg(ap, int); + break; + case 'f': + args->argv[i].f = (float)va_arg(ap, double); + break; + case 'p': + args->argv[i].p = va_arg(ap, void *); + break; + default: + fprintf(stderr, + "error: unsupported type '%c' as " + "a hook argument\n"); + break; + } + } + return args; +} + +void rpmhookTableCall(rpmhookTable **table, const char *name, + const char *argt, ...) +{ + rpmhookItem *item; + rpmhookArgs *args; + int n; + va_list ap; + va_start(ap, argt); + args = rpmhookArgsParse(argt, ap); + va_end(ap); + n = rpmhookTableFindBucket(table, name); + item = (*table)->bucket[n].item; + while (item) { + item->func(args, item->data); + item = item->next; + } + free(args); +} + +int myhook(rpmhookArgs *args, void *data) +{ + printf("%s: %d\n", args->argv[0].s, data); +} + +int main() +{ + rpmhookTable *table = rpmhookTableNew(RPMHOOK_TABLE_INITSIZE); + int i; + char buf[BUFSIZ]; + for (i = 0; i != 100000; i++) { + sprintf(buf, "%d", i); + rpmhookTableAddItem(&table, buf, myhook, (void *)i); + } + for (i = 0; i != 100000; i++) { + sprintf(buf, "%d", i); + rpmhookTableCall(&table, buf, "s", "Hello world!"); + } + for (i = 0; i != 100000; i++) { + sprintf(buf, "%d", i); + rpmhookTableDelItem(&table, buf, myhook, (void *)i); + } + rpmhookTableFree(table); + return 0; +} + +/* vim:ts=4:sw=4:et + */ |