remove OSF1 support
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / Symbolic.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * File:         Symbolic.c $XConsortium: Symbolic.c /main/5 1996/09/27 19:00:23 drk $
25  * Language:     C
26  *
27  * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
28  *
29  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
30  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
31  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
32  * (c) Copyright 1993, 1994 Novell, Inc.                                *
33  */
34
35 #include <Dt/UserMsg.h>
36
37 #include <bms/sbport.h>         /* NOTE: sbport.h must be the first include. */
38
39 #include <assert.h>
40
41 #include <bms/bms.h>
42 #include <bms/XeUserMsg.h>
43 #include <bms/MemoryMgr.h>
44 #include <bms/Symbolic.h>
45
46 #include <codelibs/stringx.h>   /* strhash */
47 #include "DtSvcLock.h"
48
49 /******************************************************************************/
50 /* HASHING */
51
52 /* This is the default symbol table to use */
53 /* --------------------------------------- */
54 #define XE_END_OF_HASH_TABLE (XeSymtabList) -1
55
56 static XeSymTable D_sym_table = NULL;
57
58 typedef struct _unknown_entry_data {
59     XeString name;
60 } *unknown_entry_data;
61
62
63 /******************************************************************************/
64 /*  Symbol (hash) Table                                                       */
65
66 /*------------------------------------------------------------------------+*/
67 static unsigned int
68 keyhash(XeSymTable t, void *key)
69 /*------------------------------------------------------------------------+*/
70 {
71     unsigned int hash;
72     
73     if (t->hash_fn)
74     {
75         hash = t->hash_fn( key, t->hashsize );
76         if (hash >= t->hashsize)
77             _DtSimpleError(XeProgName, XeInternalError, NULL, 
78                           (XeString) "Symbolic.c: Hash value from user hash function out of range",
79                           NULL);
80             /* We don't come back from the error routine */
81     }
82     else
83     {
84         hash = strhash( (const char *) key );
85         hash =  hash & (t->hashsize - 1);
86     }
87     
88     return hash;
89 }
90
91
92
93 /*------------------------------------------------------------------------+*/
94 static unsigned int
95 trap_bad_hash_fn(void * UNUSED_PARM(ptr), unsigned int UNUSED_PARM(size))
96 /*------------------------------------------------------------------------+*/
97 {
98     _DtSimpleError(XeProgName, XeInternalError, NULL, 
99                   (XeString) "Symbolic.c: Hash table at must be power of 2",
100                   NULL);
101     /* We don't come back from the error routine */
102     return 1;
103 }
104
105 /*------------------------------------------------------------------------+*/
106 XeSymTable
107 Xe_new_symtab(unsigned int  hashsize)
108 /*------------------------------------------------------------------------+*/
109
110 /* Note, hashsize must be power of 2 if using default hash function */
111
112 {
113     int i;
114
115     XeSymTable t = (XeSymTable) XeMalloc( sizeof (struct _XeSymTable) );
116     t->hashsize = hashsize;
117
118     t->list     = (XeSymtabList *)XeMalloc( sizeof( XeSymtabList ) * hashsize );
119    
120     for (i = 0; i < hashsize; i++)
121         t->list[i] = (XeSymtabList)NULL;
122
123     t->curr_list = XE_END_OF_HASH_TABLE;
124     t->curr_hash = 0;
125
126     Xe_set_sym_fns(t,
127                    (XeSymFn_cmp)NULL,
128                    (XeSymFn_init)NULL,
129                    (XeSymFn_clean)NULL,
130                    (XeSymFn_hash)NULL);
131     
132     /* If not a power of two, user better have a hash function   */
133     /* that handles that.  Install hash function trap so that if */
134     /* he does not install one, we catch it.                     */
135     /* --------------------------------------------------------- */
136     if (hashsize & (hashsize - 1))
137         t->hash_fn = trap_bad_hash_fn;
138     
139     return t;
140 }
141
142 /*------------------------------------------------------------------------+*/
143 XeSymTable
144 Xe_default_symtab(void)
145 /*------------------------------------------------------------------------+*/
146 {
147 #define D_HASHSIZE 256
148
149     _DtSvcProcessLock();
150     if (D_sym_table) {
151         _DtSvcProcessUnlock();
152         return D_sym_table;
153     }
154
155     D_sym_table = Xe_new_symtab(D_HASHSIZE);
156     _DtSvcProcessUnlock();
157     return(D_sym_table);
158 }
159 /*------------------------------------------------------------------------+*/
160 static XeSymtabList
161 NukeOneItem(XeSymTable t, XeSymtabList l)
162 /*------------------------------------------------------------------------+*/
163 {
164     XeSymtabList next;
165     
166     /* For standard XeSymbols:                  */
167     /* 1) Free the name                         */
168     /* 2) Call free function if configured      */
169     /* 3) Free the XeSymbol entry               */
170     /* ---------------------------------------- */
171     if (l->data_is_XeSymbol)
172     {
173         XeFree( ((XeSymbol)l->data)->name );
174         if (t->clean_fn)
175             t->clean_fn( ((XeSymbol)l->data)->value );
176         XeFree( l->data );
177     }
178     /* For "anysym" symbols:                    */
179     /* 1) Call free function if configured      */
180     /* 2) If we malloced the data, free it      */
181     /* ---------------------------------------- */
182     else 
183     {
184         if (t->clean_fn)
185             t->clean_fn( l->data );
186         
187         if (l->data_is_malloc_mem)
188             XeFree(l->data);
189     }
190     
191     next = l->rest;
192     XeFree(l);
193     return next;
194 }
195
196 /*------------------------------------------------------------------------+*/
197 XeSymTable
198 Xe_set_sym_fns(XeSymTable       t,
199                XeSymFn_cmp      cmp_fn, 
200                XeSymFn_init     init_fn,
201                XeSymFn_clean    clean_fn, 
202                XeSymFn_hash     hash_fn)
203 /*------------------------------------------------------------------------+*/
204
205 {
206     if (!t) t = Xe_default_symtab();
207
208     t->cmp_fn    = cmp_fn;
209     t->init_fn   = init_fn;
210     t->clean_fn  = clean_fn;
211     t->hash_fn   = hash_fn;
212     return(t);
213 }
214
215 /*------------------------------------------------------------------------+*/
216 static XeSymbol 
217 make_sym(XeString name)
218 /*------------------------------------------------------------------------+*/
219 {
220     XeSymbol sym = Xe_make_struct(_XeSymbol);
221     
222     sym->name  = strdup( name );
223     sym->value = (void*)NULL;
224     return sym;
225 }
226
227 /*------------------------------------------------------------------------+*/
228 static void *
229 intern_something(XeSymTable   t, 
230                  void *       data, 
231                  unsigned int size, 
232                  Boolean      is_XeSymbol,
233                  Boolean      lookup_only,
234                  int           *bucket)
235 /*------------------------------------------------------------------------+*/
236
237 {
238    unsigned int hash;
239    XeSymtabList l;
240    XeSymtabList l0;
241    Boolean      match;
242    void *       hash_key;
243
244    /* If no cmp function assume first item of "data" is a string pointer */
245    /* ------------------------------------------------------------------ */
246    if (is_XeSymbol)
247        hash_key = data;
248    else
249        hash_key = (t->hash_fn) ? data : ((unknown_entry_data) data)->name;
250    
251    hash = keyhash( t, hash_key );
252    l = t->list[hash];
253
254    if (bucket)
255        *bucket = hash;
256    
257    for (l0 = NULL; l; l0 = l, l = l->rest)
258    {
259        void *   cmp_key;
260        void *   cmp_key2;
261
262        if (is_XeSymbol)
263            cmp_key = data;
264        else
265            cmp_key = (t->cmp_fn) ? data : ((unknown_entry_data) data)->name;
266
267        if (l->data_is_XeSymbol)
268            cmp_key2 = ((XeSymbol) l->data)->name;
269        else
270            cmp_key2 = (t->cmp_fn) ? l->data : ((unknown_entry_data) l->data)->name;
271
272        /* Use the "compare" function to see if we have a match on our key */
273        /* --------------------------------------------------------------- */
274        if (t->cmp_fn)
275            match = (t->cmp_fn( cmp_key, cmp_key2 ) == 0);
276        else
277            match = (strcmp((const char *) cmp_key, (const char *)cmp_key2 ) == 0);
278
279        if (match)
280            return l->data;
281    }
282
283    /* If just doing a lookup, don't add a new symbol */
284    /* ---------------------------------------------- */
285    if (lookup_only) return (void *) NULL;
286    
287    /* There was no match.  We need to create an entry in the hash table. */
288    /* ------------------------------------------------------------------ */
289    l = (XeSymtabList) XeMalloc( sizeof(struct _XeSymtabList) );
290    l->rest = (XeSymtabList)NULL;
291    l->data_is_XeSymbol = is_XeSymbol;
292    l->data_is_malloc_mem = FALSE;
293    
294
295    if (l0)
296        l0->rest = l;
297    else
298        t->list[hash] = l;
299
300    /* If we have a standard symbol, make the XeSymbol entry.   */
301    /* -------------------------------------------------------- */
302    if (is_XeSymbol)
303    {
304        XeSymbol sym = make_sym((XeString)data);
305        l->data = (void*) sym;
306        if (t->init_fn)
307          sym->value = t->init_fn( l->data, size /* will be 0 */ );
308    }
309    else
310    {
311        /*     1) If "size" != 0,                                             */
312        /*        - malloc "size" bytes,                                      */
313        /*        - copy "data" into malloced space,                          */
314        /*        - Save pointer to malloc space as user's data pointer       */
315        /*        Else                                                        */
316        /*        - Save "data" as pointer to user's data                     */
317        /*     2) If a "init_fn" is configured,                               */
318        /*        - call init_fn( user's data pointer, "size" )               */
319        /*        - set user's data pointer to return value of init_fn        */
320        /*          ONLY if "size" was zero.                                  */
321        /*                                                                    */
322        /*         If size is non zero AND there is a user's malloc function, */
323        /*        beware that the return value from the malloc function is not*/
324        /*        save anywhere by these routines.  If size was zero, the     */
325        /*        return value of the user's function is kept.                */
326        /* ------------------------------------------------------------------ */
327        if (size)
328        {
329            l->data = XeMalloc( size );
330            memcpy(l->data, data, size);
331            l->data_is_malloc_mem = TRUE;
332        }
333        else
334            l->data = data;
335
336        if (t->init_fn)
337        {
338            void * new_data = t->init_fn( l->data, size );
339
340            if (!size)
341                l->data = new_data;
342        }
343        
344    }
345
346    
347    /* appended to the end of the hash chain (if any).                 */
348    /* --------------------------------------------------------------- */
349    
350    t->curr_list = l;
351    t->curr_hash = hash;
352
353 #ifdef DEBUG
354    printf("Added data %p in list[%d] @ %p\n", l->data, hash, l);
355 #endif
356
357    return l->data;
358 }
359
360 /*------------------------------------------------------------------------+*/
361 XeSymbol 
362 Xe_intern(XeSymTable t, ConstXeString const name)
363 /*------------------------------------------------------------------------+*/
364 {
365     if (!name) return (XeSymbol)NULL;
366
367     if (!t) t = Xe_default_symtab();
368
369     return (XeSymbol)intern_something(t, (void *)name, 0, TRUE, FALSE, (int*)NULL);
370 }
371
372 /*------------------------------------------------------------------------+*/
373 XeSymbol 
374 Xe_lookup(XeSymTable t, ConstXeString const name)
375 /*------------------------------------------------------------------------+*/
376 {
377     if (!name) return (XeSymbol)NULL;
378
379     if (!t) t = Xe_default_symtab();
380
381     return (XeSymbol)intern_something(t, (void *)name, 0, TRUE, TRUE, (int*)NULL);
382 }
383
384 /******************************************************************************/
385 /*  LISTS                                                                     */
386
387 /*------------------------------------------------------------------------+*/
388 XeList 
389 Xe_make_list(void * data, XeList rest)
390 /*------------------------------------------------------------------------+*/
391 {
392    XeList            temp = Xe_make_struct(_XeList);
393
394    temp->data = data;
395    temp->rest = rest;
396    return temp;
397 }
398
399
400 /******************************************************************************/
401 /* QUEUES                                                                     */
402
403 /*------------------------------------------------------------------------+*/
404 XeQueue 
405 Xe_init_queue(XeQueue q, void * nullval)
406 /*------------------------------------------------------------------------+*/
407 {
408    q->head = 0;
409    q->null = nullval;
410    return q;
411 }
412
413 /*------------------------------------------------------------------------+*/
414 XeQueue 
415 Xe_make_queue(void * nullval)
416 /*------------------------------------------------------------------------+*/
417 {
418    return Xe_init_queue(Xe_make_struct(_XeQueue), nullval);
419 }
420
421 /*------------------------------------------------------------------------+*/
422 void *
423 Xe_pop_queue(XeQueue q)
424 /*------------------------------------------------------------------------+*/
425 {
426    XeList            head = q->head;
427
428    if (head) {
429       void *         val = head->data;
430
431       q->head = head->rest;
432       XeFree(head);
433       return val;
434    } else
435       return q->null;
436 }
437
438 /*------------------------------------------------------------------------+*/
439 void *
440 Xe_delete_queue_element(XeQueue q, void * val)
441 /*------------------------------------------------------------------------+*/
442 {
443    XeList            last = 0, head = q->head;
444
445    while (head)
446       if (head->data == val) {
447          if (last)
448             last->rest = head->rest;
449          else
450             q->head = head->rest;
451          if (q->tail == head)
452             q->tail = last;
453          XeFree(head);
454          return val;
455       } else
456          last = head, head = head->rest;
457    return q->null;
458 }
459
460 /*------------------------------------------------------------------------+*/
461 void 
462 Xe_push_queue(XeQueue q, void * val)
463 /*------------------------------------------------------------------------+*/
464 {
465   XeList new_ptr = Xe_make_list(val, 0);
466   
467   if (q->head)
468     q->tail->rest = new_ptr;
469   else
470     q->head = new_ptr;
471   q->tail = new_ptr;
472 }
473
474 /*------------------------------------------------------------------------+*/
475 void 
476 Xe_release_queue(XeQueue q)
477 /*------------------------------------------------------------------------+*/
478 {
479    if (q) {
480       while (q->head)
481          Xe_pop_queue(q);
482       XeFree(q);
483    }
484 }