First step in tidying up the LHASH code. The callback prototypes (and
[openssl.git] / crypto / objects / o_names.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include <openssl/lhash.h>
6 #include <openssl/objects.h>
7 #include <openssl/safestack.h>
8
9 /* I use the ex_data stuff to manage the identifiers for the obj_name_types
10  * that applications may define.  I only really use the free function field.
11  */
12 static LHASH *names_lh=NULL;
13 static int names_type_num=OBJ_NAME_TYPE_NUM;
14
15 typedef struct name_funcs_st
16         {
17         unsigned long (*hash_func)(const char *name);
18         int (*cmp_func)(const char *a,const char *b);
19         void (*free_func)(const char *, int, const char *);
20         } NAME_FUNCS;
21
22 DECLARE_STACK_OF(NAME_FUNCS)
23 IMPLEMENT_STACK_OF(NAME_FUNCS)
24
25 static STACK_OF(NAME_FUNCS) *name_funcs_stack;
26
27 static unsigned long obj_name_hash(OBJ_NAME *a);
28 static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b);
29
30 int OBJ_NAME_init(void)
31         {
32         if (names_lh != NULL) return(1);
33         MemCheck_off();
34         names_lh=lh_new((LHASH_HASH_FN_TYPE)obj_name_hash,
35                         (LHASH_COMP_FN_TYPE)obj_name_cmp);
36         MemCheck_on();
37         return(names_lh != NULL);
38         }
39
40 int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *),
41         int (*cmp_func)(const char *, const char *),
42         void (*free_func)(const char *, int, const char *))
43         {
44         int ret;
45         int i;
46         NAME_FUNCS *name_funcs;
47
48         if (name_funcs_stack == NULL)
49                 {
50                 MemCheck_off();
51                 name_funcs_stack=sk_NAME_FUNCS_new_null();
52                 MemCheck_on();
53                 }
54         if ((name_funcs_stack == NULL))
55                 {
56                 /* ERROR */
57                 return(0);
58                 }
59         ret=names_type_num;
60         names_type_num++;
61         for (i=sk_NAME_FUNCS_num(name_funcs_stack); i<names_type_num; i++)
62                 {
63                 MemCheck_off();
64                 name_funcs = OPENSSL_malloc(sizeof(NAME_FUNCS));
65                 name_funcs->hash_func = lh_strhash;
66                 name_funcs->cmp_func = strcmp;
67                 name_funcs->free_func = 0; /* NULL is often declared to
68                                                 * ((void *)0), which according
69                                                 * to Compaq C is not really
70                                                 * compatible with a function
71                                                 * pointer.      -- Richard Levitte*/
72                 sk_NAME_FUNCS_push(name_funcs_stack,name_funcs);
73                 MemCheck_on();
74                 }
75         name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
76         if (hash_func != NULL)
77                 name_funcs->hash_func = hash_func;
78         if (cmp_func != NULL)
79                 name_funcs->cmp_func = cmp_func;
80         if (free_func != NULL)
81                 name_funcs->free_func = free_func;
82         return(ret);
83         }
84
85 static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b)
86         {
87         int ret;
88
89         ret=a->type-b->type;
90         if (ret == 0)
91                 {
92                 if ((name_funcs_stack != NULL)
93                         && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type))
94                         {
95                         ret=sk_NAME_FUNCS_value(name_funcs_stack,a->type)
96                                 ->cmp_func(a->name,b->name);
97                         }
98                 else
99                         ret=strcmp(a->name,b->name);
100                 }
101         return(ret);
102         }
103
104 static unsigned long obj_name_hash(OBJ_NAME *a)
105         {
106         unsigned long ret;
107
108         if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type))
109                 {
110                 ret=sk_NAME_FUNCS_value(name_funcs_stack,a->type)
111                         ->hash_func(a->name);
112                 }
113         else
114                 {
115                 ret=lh_strhash(a->name);
116                 }
117         ret^=a->type;
118         return(ret);
119         }
120
121 const char *OBJ_NAME_get(const char *name, int type)
122         {
123         OBJ_NAME on,*ret;
124         int num=0,alias;
125
126         if (name == NULL) return(NULL);
127         if ((names_lh == NULL) && !OBJ_NAME_init()) return(NULL);
128
129         alias=type&OBJ_NAME_ALIAS;
130         type&= ~OBJ_NAME_ALIAS;
131
132         on.name=name;
133         on.type=type;
134
135         for (;;)
136         {
137                 ret=(OBJ_NAME *)lh_retrieve(names_lh,&on);
138                 if (ret == NULL) return(NULL);
139                 if ((ret->alias) && !alias)
140                         {
141                         if (++num > 10) return(NULL);
142                         on.name=ret->data;
143                         }
144                 else
145                         {
146                         return(ret->data);
147                         }
148                 }
149         }
150
151 int OBJ_NAME_add(const char *name, int type, const char *data)
152         {
153         OBJ_NAME *onp,*ret;
154         int alias;
155
156         if ((names_lh == NULL) && !OBJ_NAME_init()) return(0);
157
158         alias=type&OBJ_NAME_ALIAS;
159         type&= ~OBJ_NAME_ALIAS;
160
161         onp=(OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME));
162         if (onp == NULL)
163                 {
164                 /* ERROR */
165                 return(0);
166                 }
167
168         onp->name=name;
169         onp->alias=alias;
170         onp->type=type;
171         onp->data=data;
172
173         ret=(OBJ_NAME *)lh_insert(names_lh,onp);
174         if (ret != NULL)
175                 {
176                 /* free things */
177                 if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
178                         {
179                         /* XXX: I'm not sure I understand why the free
180                          * function should get three arguments...
181                          * -- Richard Levitte
182                          */
183                         sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
184                                 ->free_func(ret->name,ret->type,ret->data);
185                         }
186                 OPENSSL_free(ret);
187                 }
188         else
189                 {
190                 if (lh_error(names_lh))
191                         {
192                         /* ERROR */
193                         return(0);
194                         }
195                 }
196         return(1);
197         }
198
199 int OBJ_NAME_remove(const char *name, int type)
200         {
201         OBJ_NAME on,*ret;
202
203         if (names_lh == NULL) return(0);
204
205         type&= ~OBJ_NAME_ALIAS;
206         on.name=name;
207         on.type=type;
208         ret=(OBJ_NAME *)lh_delete(names_lh,&on);
209         if (ret != NULL)
210                 {
211                 /* free things */
212                 if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
213                         {
214                         /* XXX: I'm not sure I understand why the free
215                          * function should get three arguments...
216                          * -- Richard Levitte
217                          */
218                         sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
219                                 ->free_func(ret->name,ret->type,ret->data);
220                         }
221                 OPENSSL_free(ret);
222                 return(1);
223                 }
224         else
225                 return(0);
226         }
227
228 struct doall
229         {
230         int type;
231         void (*fn)(const OBJ_NAME *,void *arg);
232         void *arg;
233         };
234
235 static void do_all_fn(const OBJ_NAME *name,struct doall *d)
236         {
237         if(name->type == d->type)
238                 d->fn(name,d->arg);
239         }
240
241 void OBJ_NAME_do_all(int type,void (*fn)(const OBJ_NAME *,void *arg),void *arg)
242         {
243         struct doall d;
244
245         d.type=type;
246         d.fn=fn;
247         d.arg=arg;
248
249         lh_doall_arg(names_lh,(LHASH_DOALL_ARG_FN_TYPE)do_all_fn,&d);
250         }
251
252 struct doall_sorted
253         {
254         int type;
255         int n;
256         const OBJ_NAME **names;
257         };
258
259 static void do_all_sorted_fn(const OBJ_NAME *name,void *d_)
260         {
261         struct doall_sorted *d=d_;
262
263         if(name->type != d->type)
264                 return;
265
266         d->names[d->n++]=name;
267         }
268
269 static int do_all_sorted_cmp(const void *n1_,const void *n2_)
270         {
271         const OBJ_NAME * const *n1=n1_;
272         const OBJ_NAME * const *n2=n2_;
273
274         return strcmp((*n1)->name,(*n2)->name);
275         }
276
277 void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg),
278                                 void *arg)
279         {
280         struct doall_sorted d;
281         int n;
282
283         d.type=type;
284         d.names=OPENSSL_malloc(lh_num_items(names_lh)*sizeof *d.names);
285         d.n=0;
286         OBJ_NAME_do_all(type,do_all_sorted_fn,&d);
287
288         qsort(d.names,d.n,sizeof *d.names,do_all_sorted_cmp);
289
290         for(n=0 ; n < d.n ; ++n)
291                 fn(d.names[n],arg);
292
293         OPENSSL_free(d.names);
294         }
295
296 static int free_type;
297
298 static void names_lh_free(OBJ_NAME *onp, int type)
299 {
300         if(onp == NULL)
301                 return;
302
303         if ((free_type < 0) || (free_type == onp->type))
304                 {
305                 OBJ_NAME_remove(onp->name,onp->type);
306                 }
307         }
308
309 static void name_funcs_free(NAME_FUNCS *ptr)
310         {
311         OPENSSL_free(ptr);
312         }
313
314 void OBJ_NAME_cleanup(int type)
315         {
316         unsigned long down_load;
317
318         if (names_lh == NULL) return;
319
320         free_type=type;
321         down_load=names_lh->down_load;
322         names_lh->down_load=0;
323
324         lh_doall(names_lh,(LHASH_DOALL_FN_TYPE)names_lh_free);
325         if (type < 0)
326                 {
327                 lh_free(names_lh);
328                 sk_NAME_FUNCS_pop_free(name_funcs_stack,name_funcs_free);
329                 names_lh=NULL;
330                 name_funcs_stack = NULL;
331                 }
332         else
333                 names_lh->down_load=down_load;
334         }
335