"Fossies" - the Fresh Open Source Software Archive

Member "rpm-4.15.0/rpmio/rpmhook.c" (26 Jun 2019, 6198 Bytes) of package /linux/misc/rpm-4.15.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rpmhook.c" see the Fossies "Dox" file reference documentation.

    1 #include "system.h"
    2 
    3 #include <stdlib.h>
    4 #include <stdio.h>
    5 #include <string.h>
    6 #include <stdarg.h>
    7 
    8 #include <rpm/rpmstring.h>
    9 #include "rpmio/rpmhook.h"
   10 
   11 #include "debug.h"
   12 
   13 #define RPMHOOK_TABLE_INITSIZE  256
   14 #define RPMHOOK_BUCKET_INITSIZE 5
   15 
   16 typedef struct rpmhookItem_s {
   17     rpmhookFunc func;
   18     void *data;
   19     struct rpmhookItem_s *next;
   20 } * rpmhookItem;
   21 
   22 typedef struct rpmhookBucket_s {
   23     unsigned long hash;
   24     char *name;
   25     rpmhookItem item;
   26 } * rpmhookBucket;
   27 
   28 typedef struct rpmhookTable_s {
   29     int size;
   30     int used;
   31     struct rpmhookBucket_s bucket[1];
   32 } * rpmhookTable;
   33 
   34 
   35 rpmhookArgs rpmhookArgsNew(int argc)
   36 {
   37     rpmhookArgs args = (rpmhookArgs) xcalloc(1,
   38             sizeof(*args) + sizeof(args->argv) * (argc-1));
   39     args->argc = argc;
   40     return args;
   41 }
   42 
   43 rpmhookArgs rpmhookArgsFree(rpmhookArgs args)
   44 {
   45     if (args != NULL)
   46     free(args);
   47     return NULL;
   48 }
   49 
   50 static rpmhookTable rpmhookTableNew(int size)
   51 {
   52     rpmhookTable table = (rpmhookTable) xcalloc(1,
   53         sizeof(*table) + sizeof(table->bucket) * (size-1));
   54     table->size = size;
   55     return table;
   56 }
   57 
   58 #if 0
   59 static rpmhookTable rpmhookTableFree(rpmhookTable table)
   60 {
   61     rpmhookItem item, nextItem;
   62     int i;
   63     for (i = 0; i != table->size; i++) {
   64     if (table->bucket[i].name == NULL)
   65         continue;
   66     free(table->bucket[i].name);
   67     item = table->bucket[i].item;
   68     while (item) {
   69         nextItem = item->next;
   70         free(item);
   71         item = nextItem;
   72     }
   73     }
   74     free(table);
   75     return NULL;
   76 }
   77 #endif
   78 
   79 static void rpmhookTableRehash(rpmhookTable *table);
   80 
   81 static int rpmhookTableFindBucket(rpmhookTable *table, const char *name)
   82 {
   83     /* Hash based on http://www.isthe.com/chongo/tech/comp/fnv/ */
   84     unsigned long perturb;
   85     unsigned long hash = 0;
   86     unsigned char *bp = (unsigned char *)name;
   87     unsigned char *be = bp + strlen(name);
   88     rpmhookBucket bucket;
   89     int ret;
   90 
   91     if (((*table)->used/2)*3 > (*table)->size)
   92     rpmhookTableRehash(table);
   93     while (bp < be) {
   94     hash ^= (unsigned long)*bp++;
   95     hash *= (unsigned long)0x01000193;
   96     }
   97     perturb = hash;
   98     ret = hash % (*table)->size;
   99     bucket = &(*table)->bucket[ret];
  100     while (bucket->name &&
  101         (bucket->hash != hash || !rstreq(bucket->name, name))) {
  102     /* Collision resolution based on Python's perturb scheme. */
  103     ret = ((ret << 2) + ret + perturb + 1) % (*table)->size;
  104     perturb >>= 5;
  105     bucket = &(*table)->bucket[ret];
  106     }
  107     if (!bucket->name)
  108     bucket->hash = hash;
  109     return ret;
  110 }
  111 
  112 static void rpmhookTableRehash(rpmhookTable *table)
  113 {
  114     rpmhookTable newtable = rpmhookTableNew((*table)->size*2);
  115     int n, i = 0;
  116 
  117     for (; i != (*table)->size; i++) {
  118     if ((*table)->bucket[i].name == NULL)
  119         continue;
  120     n = rpmhookTableFindBucket(&newtable, (*table)->bucket[i].name);
  121     newtable->bucket[n].name = (*table)->bucket[i].name;
  122     newtable->bucket[n].item = (*table)->bucket[i].item;
  123     }
  124     newtable->used = (*table)->used;
  125     free(*table);
  126     *table = newtable;
  127 }
  128 
  129 static void rpmhookTableAddItem(rpmhookTable *table, const char *name,
  130                 rpmhookFunc func, void *data)
  131 {
  132     int n = rpmhookTableFindBucket(table, name);
  133     rpmhookBucket bucket = &(*table)->bucket[n];
  134     rpmhookItem *item = &bucket->item;
  135     if (!bucket->name) {
  136     bucket->name = xstrdup(name);
  137     (*table)->used++;
  138     }
  139     while (*item) item = &(*item)->next;
  140     *item = xcalloc(1, sizeof(**item));
  141     (*item)->func = func;
  142     (*item)->data = data;
  143 }
  144 
  145 static void rpmhookTableDelItem(rpmhookTable *table, const char *name,
  146         rpmhookFunc func, void *data,
  147         int matchfunc, int matchdata)
  148 {
  149     int n = rpmhookTableFindBucket(table, name);
  150     rpmhookBucket bucket = &(*table)->bucket[n];
  151     rpmhookItem item = bucket->item;
  152     rpmhookItem lastItem = NULL;
  153     rpmhookItem nextItem;
  154     while (item) {
  155     nextItem = item->next;
  156     if ((!matchfunc || item->func == func) &&
  157         (!matchdata || item->data == data)) {
  158         free(item);
  159         if (lastItem)
  160         lastItem->next = nextItem;
  161         else
  162         bucket->item = nextItem;
  163     } else {
  164         lastItem = item;
  165     }
  166     item = nextItem;
  167     }
  168     if (!bucket->item) {
  169     free(bucket->name);
  170     bucket->name = NULL;
  171     (*table)->used--;
  172     }
  173 }
  174 
  175 static rpmhookArgs rpmhookArgsParse(const char *argt, va_list ap)
  176 {
  177     rpmhookArgs args = rpmhookArgsNew(strlen(argt));
  178     int i;
  179 
  180     args->argt = argt;
  181     for (i = 0; i != args->argc; i++) {
  182     switch (argt[i]) {
  183         case 's':
  184         args->argv[i].s = va_arg(ap, char *);
  185         break;
  186         case 'i':
  187         args->argv[i].i = va_arg(ap, int);
  188         break;
  189         case 'f':
  190         args->argv[i].f = (float)va_arg(ap, double);
  191         break;
  192         case 'p':
  193         args->argv[i].p = va_arg(ap, void *);
  194         break;
  195         default:
  196         fprintf(stderr, "error: unsupported type '%c' as "
  197                 "a hook argument\n", argt[i]);
  198         break;
  199     }
  200     }
  201     return args;
  202 }
  203 
  204 static void rpmhookTableCallArgs(rpmhookTable *table, const char *name,
  205             rpmhookArgs args)
  206 {
  207     int n = rpmhookTableFindBucket(table, name);
  208     rpmhookItem item = (*table)->bucket[n].item;
  209     rpmhookItem next;
  210     while (item) {
  211     next = item->next;
  212     if (item->func(args, item->data) != 0)
  213         break;
  214     item = next;
  215     }
  216 }
  217 
  218 static rpmhookTable globalTable = NULL;
  219 
  220 void rpmhookRegister(const char *name, rpmhookFunc func, void *data)
  221 {
  222     if (globalTable == NULL)
  223     globalTable = rpmhookTableNew(RPMHOOK_TABLE_INITSIZE);
  224     rpmhookTableAddItem(&globalTable, name, func, data);
  225 }
  226 
  227 void rpmhookUnregister(const char *name, rpmhookFunc func, void *data)
  228 {
  229     if (globalTable != NULL)
  230     rpmhookTableDelItem(&globalTable, name, func, data, 1, 1);
  231 }
  232 
  233 void rpmhookUnregisterAny(const char *name, rpmhookFunc func)
  234 {
  235     if (globalTable != NULL)
  236     rpmhookTableDelItem(&globalTable, name, func, NULL, 1, 0);
  237 }
  238 
  239 void rpmhookUnregisterAll(const char *name)
  240 {
  241     if (globalTable != NULL)
  242     rpmhookTableDelItem(&globalTable, name, NULL, NULL, 0, 0);
  243 }
  244 
  245 void rpmhookCall(const char *name, const char *argt, ...)
  246 {
  247     if (globalTable != NULL) {
  248     rpmhookArgs args;
  249     va_list ap;
  250     va_start(ap, argt);
  251     args = rpmhookArgsParse(argt, ap);
  252     rpmhookTableCallArgs(&globalTable, name, args);
  253     (void) rpmhookArgsFree(args);
  254     va_end(ap);
  255     }
  256 }
  257 
  258 void rpmhookCallArgs(const char *name, rpmhookArgs args)
  259 {
  260     if (globalTable != NULL)
  261     rpmhookTableCallArgs(&globalTable, name, args);
  262 }