Corrected small bug that could add ',L' when it shouldn't
[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)();
18         int (*cmp_func)();
19         void (*free_func)();
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(obj_name_hash,obj_name_cmp);
35         MemCheck_on();
36         return(names_lh != NULL);
37         }
38
39 int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *),
40         int (*cmp_func)(const void *, const void *),
41         void (*free_func)(const char *, int, const char *))
42         {
43         int ret;
44         int i;
45         NAME_FUNCS *name_funcs;
46
47         if (name_funcs_stack == NULL)
48                 {
49                 MemCheck_off();
50                 name_funcs_stack=sk_NAME_FUNCS_new_null();
51                 MemCheck_on();
52                 }
53         if ((name_funcs_stack == NULL))
54                 {
55                 /* ERROR */
56                 return(0);
57                 }
58         ret=names_type_num;
59         names_type_num++;
60         for (i=sk_NAME_FUNCS_num(name_funcs_stack); i<names_type_num; i++)
61                 {
62                 MemCheck_off();
63                 name_funcs = OPENSSL_malloc(sizeof(NAME_FUNCS));
64                 name_funcs->hash_func = lh_strhash;
65                 name_funcs->cmp_func = (int (*)())strcmp;
66                 name_funcs->free_func = 0; /* NULL is often declared to
67                                             * ((void *)0), which according
68                                             * to Compaq C is not really
69                                             * compatible with a function
70                                             * pointer.  -- Richard Levitte*/
71                 sk_NAME_FUNCS_push(name_funcs_stack,name_funcs);
72                 MemCheck_on();
73                 }
74         name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
75         if (hash_func != NULL)
76                 name_funcs->hash_func = hash_func;
77         if (cmp_func != NULL)
78                 name_funcs->cmp_func = cmp_func;
79         if (free_func != NULL)
80                 name_funcs->free_func = free_func;
81         return(ret);
82         }
83
84 static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b)
85         {
86         int ret;
87
88         ret=a->type-b->type;
89         if (ret == 0)
90                 {
91                 if ((name_funcs_stack != NULL)
92                         && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type))
93                         {
94                         ret=sk_NAME_FUNCS_value(name_funcs_stack,a->type)
95                                 ->cmp_func(a->name,b->name);
96                         }
97                 else
98                         ret=strcmp(a->name,b->name);
99                 }
100         return(ret);
101         }
102
103 static unsigned long obj_name_hash(OBJ_NAME *a)
104         {
105         unsigned long ret;
106
107         if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type))
108                 {
109                 ret=sk_NAME_FUNCS_value(name_funcs_stack,a->type)
110                         ->hash_func(a->name);
111                 }
112         else
113                 {
114                 ret=lh_strhash(a->name);
115                 }
116         ret^=a->type;
117         return(ret);
118         }
119
120 const char *OBJ_NAME_get(const char *name, int type)
121         {
122         OBJ_NAME on,*ret;
123         int num=0,alias;
124
125         if (name == NULL) return(NULL);
126         if ((names_lh == NULL) && !OBJ_NAME_init()) return(NULL);
127
128         alias=type&OBJ_NAME_ALIAS;
129         type&= ~OBJ_NAME_ALIAS;
130
131         on.name=name;
132         on.type=type;
133
134         for (;;)
135                 {
136                 ret=(OBJ_NAME *)lh_retrieve(names_lh,&on);
137                 if (ret == NULL) return(NULL);
138                 if ((ret->alias) && !alias)
139                         {
140                         if (++num > 10) return(NULL);
141                         on.name=ret->data;
142                         }
143                 else
144                         {
145                         return(ret->data);
146                         }
147                 }
148         }
149
150 int OBJ_NAME_add(const char *name, int type, const char *data)
151         {
152         OBJ_NAME *onp,*ret;
153         int alias;
154
155         if ((names_lh == NULL) && !OBJ_NAME_init()) return(0);
156
157         alias=type&OBJ_NAME_ALIAS;
158         type&= ~OBJ_NAME_ALIAS;
159
160         onp=(OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME));
161         if (onp == NULL)
162                 {
163                 /* ERROR */
164                 return(0);
165                 }
166
167         onp->name=name;
168         onp->alias=alias;
169         onp->type=type;
170         onp->data=data;
171
172         ret=(OBJ_NAME *)lh_insert(names_lh,onp);
173         if (ret != NULL)
174                 {
175                 /* free things */
176                 if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
177                         {
178                         /* XXX: I'm not sure I understand why the free
179                          * function should get three arguments...
180                          * -- Richard Levitte
181                          */
182                         sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
183                                 ->free_func(ret->name,ret->type,ret->data);
184                         }
185                 OPENSSL_free(ret);
186                 }
187         else
188                 {
189                 if (lh_error(names_lh))
190                         {
191                         /* ERROR */
192                         return(0);
193                         }
194                 }
195         return(1);
196         }
197
198 int OBJ_NAME_remove(const char *name, int type)
199         {
200         OBJ_NAME on,*ret;
201
202         if (names_lh == NULL) return(0);
203
204         type&= ~OBJ_NAME_ALIAS;
205         on.name=name;
206         on.type=type;
207         ret=(OBJ_NAME *)lh_delete(names_lh,&on);
208         if (ret != NULL)
209                 {
210                 /* free things */
211                 if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
212                         {
213                         /* XXX: I'm not sure I understand why the free
214                          * function should get three arguments...
215                          * -- Richard Levitte
216                          */
217                         sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
218                                 ->free_func(ret->name,ret->type,ret->data);
219                         }
220                 OPENSSL_free(ret);
221                 return(1);
222                 }
223         else
224                 return(0);
225         }
226
227 static int free_type;
228
229 static void names_lh_free(OBJ_NAME *onp, int type)
230 {
231         if(onp == NULL)
232             return;
233
234         if ((free_type < 0) || (free_type == onp->type))
235                 {
236                 OBJ_NAME_remove(onp->name,onp->type);
237                 }
238         }
239
240 static void name_funcs_free(NAME_FUNCS *ptr)
241         {
242         OPENSSL_free(ptr);
243         }
244
245 void OBJ_NAME_cleanup(int type)
246         {
247         unsigned long down_load;
248
249         if (names_lh == NULL) return;
250
251         free_type=type;
252         down_load=names_lh->down_load;
253         names_lh->down_load=0;
254
255         lh_doall(names_lh,names_lh_free);
256         if (type < 0)
257                 {
258                 lh_free(names_lh);
259                 sk_NAME_FUNCS_pop_free(name_funcs_stack,name_funcs_free);
260                 names_lh=NULL;
261                 name_funcs_stack = NULL;
262                 }
263         else
264                 names_lh->down_load=down_load;
265         }
266