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