rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmio/rpmhook.c
Go to the documentation of this file.

    00001 #include "system.h"
    00002
    00003 #include <stdlib.h>
    00004 #include <stdio.h>
    00005 #include <string.h>
    00006 #include <stdarg.h>
    00007
    00008 #include <rpmhook.h>
    00009 #include "debug.h"
    00010
    00011 #define RPMHOOK_TABLE_INITSIZE  256
    00012 #define RPMHOOK_BUCKET_INITSIZE 5
    00013
    00014 typedef struct rpmhookItem_s {
    00015     rpmhookFunc func;
    00016     void *data;
    00017     struct rpmhookItem_s *next;
    00018 } * rpmhookItem;
    00019
    00020 typedef struct rpmhookBucket_s {
    00021     unsigned long hash;
    00022 /*@relnull@*/
    00023     char *name;
    00024     rpmhookItem item;
    00025 } * rpmhookBucket;
    00026
    00027 typedef struct rpmhookTable_s {
    00028     int size;
    00029     int used;
    00030     struct rpmhookBucket_s bucket[1];
    00031 } * rpmhookTable;
    00032
    00033
    00034 rpmhookArgs rpmhookArgsNew(int argc)
    00035 {
    00036     rpmhookArgs args = (rpmhookArgs) xcalloc(1,
    00037                         sizeof(*args) + sizeof(args->argv) * (argc-1));
    00038     args->argc = argc;
    00039     return args;
    00040 }
    00041
    00042 rpmhookArgs rpmhookArgsFree(rpmhookArgs args)
    00043 {
    00044     if (args != NULL)
    00045         free(args);
    00046     return NULL;
    00047 }
    00048
    00049 /*@only@*/
    00050 static rpmhookTable rpmhookTableNew(int size)
    00051         /*@*/
    00052 {
    00053     rpmhookTable table = (rpmhookTable) xcalloc(1,
    00054                 sizeof(*table) + sizeof(table->bucket) * (size-1));
    00055     table->size = size;
    00056     return table;
    00057 }
    00058
    00059 #if 0
    00060 static rpmhookTable rpmhookTableFree(rpmhookTable table)
    00061         /*@*/
    00062 {
    00063     rpmhookItem item, nextItem;
    00064     int i;
    00065     for (i = 0; i != table->size; i++) {
    00066         if (table->bucket[i].name == NULL)
    00067             continue;
    00068         free(table->bucket[i].name);
    00069         item = table->bucket[i].item;
    00070         while (item) {
    00071             nextItem = item->next;
    00072             free(item);
    00073             item = nextItem;
    00074         }
    00075     }
    00076     free(table);
    00077     return NULL;
    00078 }
    00079 #endif
    00080
    00081 static void rpmhookTableRehash(rpmhookTable *table)
    00082         /*@modifies *table @*/;
    00083
    00084 static int rpmhookTableFindBucket(rpmhookTable *table, const char *name)
    00085         /*@modifies *table @*/
    00086 {
    00087     /* Hash based on http://www.isthe.com/chongo/tech/comp/fnv/ */
    00088     unsigned long perturb;
    00089     unsigned long hash = 0;
    00090     unsigned char *bp = (unsigned char *)name;
    00091     unsigned char *be = bp + strlen(name);
    00092     rpmhookBucket bucket;
    00093     int ret;
    00094
    00095     if (((*table)->used/2)*3 > (*table)->size)
    00096         rpmhookTableRehash(table);
    00097     while (bp < be) {
    00098         hash ^= (unsigned long)*bp++;
    00099         hash *= (unsigned long)0x01000193;
    00100     }
    00101     perturb = hash;
    00102     ret = hash % (*table)->size;
    00103     bucket = &(*table)->bucket[ret];
    00104     while (bucket->name &&
    00105             (bucket->hash != hash || strcmp(bucket->name, name) != 0)) {
    00106         /* Collision resolution based on Python's perturb scheme. */
    00107 /*@-shiftimplementation@*/
    00108         ret = ((ret << 2) + ret + perturb + 1) % (*table)->size;
    00109 /*@=shiftimplementation@*/
    00110         perturb >>= 5;
    00111         bucket = &(*table)->bucket[ret];
    00112     }
    00113     if (!bucket->name)
    00114         bucket->hash = hash;
    00115     return ret;
    00116 }
    00117
    00118 static void rpmhookTableRehash(rpmhookTable *table)
    00119         /*@modifies *table @*/
    00120 {
    00121     rpmhookTable newtable = rpmhookTableNew((*table)->size*2);
    00122     int n, i = 0;
    00123
    00124     for (; i != (*table)->size; i++) {
    00125         if ((*table)->bucket[i].name == NULL)
    00126             continue;
    00127         n = rpmhookTableFindBucket(&newtable, (*table)->bucket[i].name);
    00128         newtable->bucket[n].name = (*table)->bucket[i].name;
    00129         newtable->bucket[n].item = (*table)->bucket[i].item;
    00130     }
    00131     newtable->used = (*table)->used;
    00132 /*@-unqualifiedtrans@*/
    00133     free(*table);
    00134 /*@=unqualifiedtrans@*/
    00135     *table = newtable;
    00136 }
    00137
    00138 static void rpmhookTableAddItem(rpmhookTable *table, const char *name,
    00139                                 rpmhookFunc func, void *data)
    00140         /*@modifies *table @*/
    00141 {
    00142     int n = rpmhookTableFindBucket(table, name);
    00143     rpmhookBucket bucket = &(*table)->bucket[n];
    00144     rpmhookItem *item = &bucket->item;
    00145     if (!bucket->name) {
    00146         bucket->name = strdup(name);
    00147         (*table)->used++;
    00148     }
    00149     while (*item) item = &(*item)->next;
    00150     *item = xcalloc(1, sizeof(**item));
    00151     (*item)->func = func;
    00152 /*@-temptrans@*/
    00153     (*item)->data = data;
    00154 /*@=temptrans@*/
    00155 }
    00156
    00157 static void rpmhookTableDelItem(rpmhookTable *table, const char *name,
    00158                 /*@null@*/ rpmhookFunc func, /*@null@*/ void *data,
    00159                 int matchfunc, int matchdata)
    00160         /*@modifies *table @*/
    00161 {
    00162     int n = rpmhookTableFindBucket(table, name);
    00163     rpmhookBucket bucket = &(*table)->bucket[n];
    00164     rpmhookItem item = bucket->item;
    00165     rpmhookItem lastItem = NULL;
    00166     rpmhookItem nextItem;
    00167     while (item) {
    00168         nextItem = item->next;
    00169         if ((!matchfunc || item->func == func) &&
    00170             (!matchdata || item->data == data)) {
    00171             free(item);
    00172             if (lastItem)
    00173                 lastItem->next = nextItem;
    00174             else
    00175                 bucket->item = nextItem;
    00176         } else {
    00177             lastItem = item;
    00178         }
    00179 /*@-usereleased@*/
    00180         item = nextItem;
    00181     }
    00182     if (!bucket->item) {
    00183         free(bucket->name);
    00184         bucket->name = NULL;
    00185         (*table)->used--;
    00186     }
    00187 /*@=usereleased@*/
    00188 }
    00189
    00190 static rpmhookArgs rpmhookArgsParse(const char *argt, va_list ap)
    00191         /*@*/
    00192 {
    00193     rpmhookArgs args = rpmhookArgsNew((int)strlen(argt));
    00194     int i;
    00195
    00196 /*@-temptrans@*/
    00197     args->argt = argt;
    00198 /*@=temptrans@*/
    00199     for (i = 0; i != args->argc; i++) {
    00200         switch (argt[i]) {
    00201             case 's':
    00202                 args->argv[i].s = va_arg(ap, char *);
    00203                 /*@switchbreak@*/ break;
    00204             case 'i':
    00205                 args->argv[i].i = va_arg(ap, int);
    00206                 /*@switchbreak@*/ break;
    00207             case 'f':
    00208                 args->argv[i].f = (float)va_arg(ap, double);
    00209                 /*@switchbreak@*/ break;
    00210             case 'p':
    00211                 args->argv[i].p = va_arg(ap, void *);
    00212                 /*@switchbreak@*/ break;
    00213             default:
    00214 /*@-modfilesys @*/
    00215                 fprintf(stderr, "error: unsupported type '%c' as "
    00216                                 "a hook argument\n", argt[i]);
    00217 /*@=modfilesys @*/
    00218                 /*@switchbreak@*/ break;
    00219         }
    00220     }
    00221     return args;
    00222 }
    00223
    00224 static void rpmhookTableCallArgs(rpmhookTable *table, const char *name,
    00225                         rpmhookArgs args)
    00226         /*@modifies *table @*/
    00227 {
    00228     int n = rpmhookTableFindBucket(table, name);
    00229     rpmhookItem item = (*table)->bucket[n].item;
    00230     while (item) {
    00231         if (item->func(args, item->data) != 0)
    00232             break;
    00233         item = item->next;
    00234     }
    00235 }
    00236
    00237 /*@unchecked@*/ /*@only@*/ /*@null@*/
    00238 static rpmhookTable globalTable = NULL;
    00239
    00240 void rpmhookRegister(const char *name, rpmhookFunc func, void *data)
    00241         /*@globals globalTable @*/
    00242         /*@modifies globalTable @*/
    00243 {
    00244     if (globalTable == NULL)
    00245         globalTable = rpmhookTableNew(RPMHOOK_TABLE_INITSIZE);
    00246     rpmhookTableAddItem(&globalTable, name, func, data);
    00247 }
    00248
    00249 void rpmhookUnregister(const char *name, rpmhookFunc func, void *data)
    00250 {
    00251     if (globalTable != NULL)
    00252         rpmhookTableDelItem(&globalTable, name, func, data, 1, 1);
    00253 }
    00254
    00255 void rpmhookUnregisterAny(const char *name, rpmhookFunc func)
    00256 {
    00257     if (globalTable != NULL)
    00258         rpmhookTableDelItem(&globalTable, name, func, NULL, 1, 0);
    00259 }
    00260
    00261 void rpmhookUnregisterAll(const char *name)
    00262 {
    00263     if (globalTable != NULL)
    00264         rpmhookTableDelItem(&globalTable, name, NULL, NULL, 0, 0);
    00265 }
    00266
    00267 void rpmhookCall(const char *name, const char *argt, ...)
    00268 {
    00269     if (globalTable != NULL) {
    00270         rpmhookArgs args;
    00271         va_list ap;
    00272         va_start(ap, argt);
    00273         args = rpmhookArgsParse(argt, ap);
    00274 /*@-noeffect@*/
    00275         rpmhookTableCallArgs(&globalTable, name, args);
    00276 /*@=noeffect@*/
    00277         (void) rpmhookArgsFree(args);
    00278         va_end(ap);
    00279     }
    00280 }
    00281
    00282 void rpmhookCallArgs(const char *name, rpmhookArgs args)
    00283 {
    00284 /*@-noeffect@*/
    00285     if (globalTable != NULL)
    00286         rpmhookTableCallArgs(&globalTable, name, args);
    00287 /*@=noeffect@*/
    00288 }