rpm 5.2.1

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

- File List
- Globals

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 {
15 rpmhookFunc func;
16 void *data;
17 struct rpmhookItem_s *next;
18 } * rpmhookItem;
19
20 typedef struct rpmhookBucket_s {
21 unsigned long hash;
22 /*@relnull@*/
23 char *name;
24 rpmhookItem item;
25 } * rpmhookBucket;
26
27 typedef struct rpmhookTable_s {
28 int size;
29 int used;
30 struct rpmhookBucket_s bucket[1];
31 } * rpmhookTable;
32
33
34 rpmhookArgs rpmhookArgsNew(int argc)
35 {
36 rpmhookArgs args = (rpmhookArgs) xcalloc(1,
37 sizeof(*args) + sizeof(args->argv) * (argc-1));
38 args->argc = argc;
39 return args;
40 }
41
42 rpmhookArgs rpmhookArgsFree(rpmhookArgs args)
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 = 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)
245 globalTable = rpmhookTableNew(RPMHOOK_TABLE_INITSIZE);
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
255 void rpmhookUnregisterAny(const char *name, rpmhookFunc func)
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 }