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