Git init
[framework/uifw/xorg/lib/libxt.git] / src / Convert.c
1 /***********************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice (including the next
12 paragraph) shall be included in all copies or substantial portions of the
13 Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22
23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                         All Rights Reserved
26
27 Permission to use, copy, modify, and distribute this software and its
28 documentation for any purpose and without fee is hereby granted,
29 provided that the above copyright notice appear in all copies and that
30 both that copyright notice and this permission notice appear in
31 supporting documentation, and that the name of Digital not be
32 used in advertising or publicity pertaining to distribution of the
33 software without specific, written prior permission.
34
35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41 SOFTWARE.
42
43 ******************************************************************/
44
45 /*
46
47 Copyright 1987, 1988, 1998  The Open Group
48
49 Permission to use, copy, modify, distribute, and sell this software and its
50 documentation for any purpose is hereby granted without fee, provided that
51 the above copyright notice appear in all copies and that both that
52 copyright notice and this permission notice appear in supporting
53 documentation.
54
55 The above copyright notice and this permission notice shall be included in
56 all copies or substantial portions of the Software.
57
58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65 Except as contained in this notice, the name of The Open Group shall not be
66 used in advertising or otherwise to promote the sale, use or other dealings
67 in this Software without prior written authorization from The Open Group.
68
69 */
70
71 #ifdef HAVE_CONFIG_H
72 #include <config.h>
73 #endif
74 #include        "IntrinsicI.h"
75 #include        "StringDefs.h"
76 #include        "Intrinsic.h"
77
78 /* Conversion procedure hash table */
79
80 #define CONVERTHASHSIZE ((unsigned)256)
81 #define CONVERTHASHMASK 255
82 #define ProcHash(from_type, to_type) (2 * (from_type) + to_type)
83
84 typedef struct _ConverterRec *ConverterPtr;
85 typedef struct _ConverterRec {
86     ConverterPtr        next;
87     XrmRepresentation   from, to;
88     XtTypeConverter     converter;
89     XtDestructor        destructor;
90     unsigned short      num_args;
91     unsigned int        do_ref_count:1;
92     unsigned int        new_style:1;
93     unsigned int        global:1;
94     char                cache_type;
95 } ConverterRec;
96
97 #define ConvertArgs(p) ((XtConvertArgList)((p)+1))
98
99 /* used for old-style type converter cache only */
100 static Heap globalHeap = {NULL, NULL, 0};
101
102 void _XtSetDefaultConverterTable(
103         ConverterTable *table)
104 {
105     register ConverterTable globalConverterTable;
106
107     LOCK_PROCESS;
108     globalConverterTable = _XtGetProcessContext()->globalConverterTable;
109
110     *table = (ConverterTable)
111         __XtCalloc(CONVERTHASHSIZE, (unsigned)sizeof(ConverterPtr));
112     _XtAddDefaultConverters(*table);
113
114     if (globalConverterTable) {
115         ConverterPtr rec;
116         int i;
117         XtCacheType cache_type;
118         for (i = CONVERTHASHSIZE; --i >= 0; ) {
119             for (rec = *globalConverterTable++; rec; rec = rec->next) {
120                 cache_type = rec->cache_type;
121                 if (rec->do_ref_count)
122                     cache_type |= XtCacheRefCount;
123                _XtTableAddConverter(*table, rec->from, rec->to, rec->converter,
124                                     ConvertArgs(rec), rec->num_args,
125                                     rec->new_style, cache_type,
126                                     rec->destructor, True);
127             }
128         }
129     }
130     UNLOCK_PROCESS;
131 }
132
133 void _XtFreeConverterTable(
134         ConverterTable table)
135 {
136         register Cardinal i;
137         register ConverterPtr p;
138
139         for (i = 0; i < CONVERTHASHSIZE; i++) {
140             for (p = table[i]; p; ) {
141                 register ConverterPtr next = p->next;
142                 XtFree((char*)p);
143                 p = next;
144             }
145         }
146         XtFree((char*)table);
147 }
148
149 /* Data cache hash table */
150
151 typedef struct _CacheRec *CachePtr;
152
153 typedef struct _CacheRec {
154     CachePtr    next;
155     XtPointer   tag;
156     int         hash;
157     XtTypeConverter converter;
158     unsigned short num_args;
159     unsigned int conversion_succeeded:1;
160     unsigned int has_ext:1;
161     unsigned int is_refcounted:1;
162     unsigned int must_be_freed:1;
163     unsigned int from_is_value:1;
164     unsigned int to_is_value:1;
165     XrmValue    from;
166     XrmValue    to;
167 } CacheRec;
168
169 typedef struct _CacheRecExt {
170     CachePtr    *prev;
171     XtDestructor destructor;
172     XtPointer    closure;
173     long         ref_count;
174 } CacheRecExt;
175
176 #define CEXT(p) ((CacheRecExt *)((p)+1))
177 #define CARGS(p) ((p)->has_ext ? (XrmValue *)(CEXT(p)+1) : (XrmValue *)((p)+1))
178
179 #define CACHEHASHSIZE   256
180 #define CACHEHASHMASK   255
181 typedef CachePtr CacheHashTable[CACHEHASHSIZE];
182
183 static CacheHashTable   cacheHashTable;
184
185 void _XtTableAddConverter(
186     ConverterTable      table,
187     XrmRepresentation   from_type,
188     XrmRepresentation   to_type,
189     XtTypeConverter     converter,
190     XtConvertArgList    convert_args,
191     Cardinal            num_args,
192     _XtBoolean          new_style,
193     XtCacheType         cache_type,
194     XtDestructor        destructor,
195     _XtBoolean          global)
196 {
197     register ConverterPtr       *pp;
198     register ConverterPtr       p;
199     XtConvertArgList args;
200
201     pp= &table[ProcHash(from_type, to_type) & CONVERTHASHMASK];
202     while ((p = *pp) && (p->from != from_type || p->to != to_type))
203         pp = &p->next;
204
205     if (p) {
206         *pp = p->next;
207         XtFree((char *)p);
208     }
209
210     p = (ConverterPtr) __XtMalloc(sizeof(ConverterRec) +
211                                 sizeof(XtConvertArgRec) * num_args);
212     p->next         = *pp;
213     *pp = p;
214     p->from         = from_type;
215     p->to           = to_type;
216     p->converter    = converter;
217     p->destructor   = destructor;
218     p->num_args     = num_args;
219     p->global       = global;
220     args = ConvertArgs(p);
221     while (num_args--)
222         *args++ = *convert_args++;
223     p->new_style    = new_style;
224     p->do_ref_count = False;
225     if (destructor || (cache_type & 0xff)) {
226         p->cache_type = cache_type & 0xff;
227         if (cache_type & XtCacheRefCount)
228             p->do_ref_count = True;
229     } else {
230         p->cache_type = XtCacheNone;
231     }
232 }
233
234 void XtSetTypeConverter(
235     register _Xconst char* from_type,
236     register _Xconst char* to_type,
237     XtTypeConverter     converter,
238     XtConvertArgList    convert_args,
239     Cardinal            num_args,
240     XtCacheType         cache_type,
241     XtDestructor        destructor
242     )
243 {
244     ProcessContext process;
245     XtAppContext app;
246     XrmRepresentation from;
247     XrmRepresentation to;
248
249     LOCK_PROCESS;
250     process = _XtGetProcessContext();
251     app = process->appContextList;
252     from = XrmStringToRepresentation(from_type);
253     to = XrmStringToRepresentation(to_type);
254
255     if (!process->globalConverterTable) {
256         process->globalConverterTable = (ConverterTable)
257             __XtCalloc(CONVERTHASHSIZE, (unsigned)sizeof(ConverterPtr));
258     }
259     _XtTableAddConverter(process->globalConverterTable, from, to,
260                          converter, convert_args,
261                          num_args, True, cache_type, destructor, True);
262     while (app) {
263         _XtTableAddConverter(app->converterTable, from, to,
264                              converter, convert_args,
265                              num_args, True, cache_type, destructor, True);
266         app = app->next;
267     }
268     UNLOCK_PROCESS;
269 }
270
271 void XtAppSetTypeConverter(
272     XtAppContext        app,
273     register _Xconst char* from_type,
274     register _Xconst char* to_type,
275     XtTypeConverter     converter,
276     XtConvertArgList    convert_args,
277     Cardinal            num_args,
278     XtCacheType         cache_type,
279     XtDestructor        destructor
280     )
281 {
282     LOCK_PROCESS;
283     _XtTableAddConverter(app->converterTable,
284         XrmStringToRepresentation(from_type),
285         XrmStringToRepresentation(to_type),
286         converter, convert_args, num_args,
287         True, cache_type, destructor, False);
288     UNLOCK_PROCESS;
289 }
290
291 /* old interface */
292 void XtAddConverter(
293     register _Xconst char* from_type,
294     register _Xconst char* to_type,
295     XtConverter         converter,
296     XtConvertArgList    convert_args,
297     Cardinal            num_args
298     )
299 {
300     ProcessContext process;
301     XtAppContext app;
302     XrmRepresentation from;
303     XrmRepresentation to;
304
305     LOCK_PROCESS;
306     process = _XtGetProcessContext();
307     app = process->appContextList;
308     from = XrmStringToRepresentation(from_type);
309     to = XrmStringToRepresentation(to_type);
310
311     if (!process->globalConverterTable) {
312         process->globalConverterTable = (ConverterTable)
313             __XtCalloc(CONVERTHASHSIZE, (unsigned)sizeof(ConverterPtr));
314     }
315     _XtTableAddConverter(process->globalConverterTable, from, to,
316                          (XtTypeConverter)converter, convert_args, num_args,
317                          False, XtCacheAll, (XtDestructor)NULL, True);
318     while (app) {
319         _XtTableAddConverter(app->converterTable, from, to,
320                              (XtTypeConverter)converter, convert_args,
321                              num_args, False, XtCacheAll, (XtDestructor)NULL,
322                              True);
323         app = app->next;
324     }
325     UNLOCK_PROCESS;
326 }
327
328 /* old interface */
329 void XtAppAddConverter(
330     XtAppContext        app,
331     register _Xconst char* from_type,
332     register _Xconst char* to_type,
333     XtConverter         converter,
334     XtConvertArgList    convert_args,
335     Cardinal            num_args
336     )
337 {
338     LOCK_PROCESS;
339     _XtTableAddConverter(app->converterTable,
340         XrmStringToRepresentation(from_type),
341         XrmStringToRepresentation(to_type),
342         (XtTypeConverter)converter, convert_args, num_args,
343         False, XtCacheAll, (XtDestructor)NULL, False);
344     UNLOCK_PROCESS;
345 }
346
347 static CachePtr
348 CacheEnter(
349     Heap*                   heap,
350     register XtTypeConverter converter,
351     register XrmValuePtr    args,
352     Cardinal                num_args,
353     XrmValuePtr             from,
354     XrmValuePtr             to,
355     Boolean                 succeeded,
356     register int            hash,
357     Boolean                 do_ref,
358     Boolean                 do_free,
359     XtDestructor            destructor,
360     XtPointer               closure)
361 {
362     register    CachePtr *pHashEntry;
363     register    CachePtr p;
364     register    Cardinal i;
365
366     LOCK_PROCESS;
367     pHashEntry = &cacheHashTable[hash & CACHEHASHMASK];
368
369     if ((succeeded && destructor) || do_ref) {
370         p = (CachePtr) _XtHeapAlloc(heap, (sizeof(CacheRec) +
371                                            sizeof(CacheRecExt) +
372                                            num_args * sizeof(XrmValue)));
373         CEXT(p)->prev = pHashEntry;
374         CEXT(p)->destructor = succeeded ? destructor : NULL;
375         CEXT(p)->closure = closure;
376         CEXT(p)->ref_count = 1;
377         p->has_ext = True;
378     }
379     else {
380         p = (CachePtr)_XtHeapAlloc(heap, (sizeof(CacheRec) +
381                                           num_args * sizeof(XrmValue)));
382         p->has_ext = False;
383     }
384     if (!to->addr)
385         succeeded = False;
386     p->conversion_succeeded = succeeded;
387     p->is_refcounted = do_ref;
388     p->must_be_freed = do_free;
389     p->next         = *pHashEntry;
390     if (p->next && p->next->has_ext)
391         CEXT(p->next)->prev = &p->next;
392
393     *pHashEntry     = p;
394     p->tag          = (XtPointer)heap;
395     p->hash         = hash;
396     p->converter    = converter;
397     p->from.size    = from->size;
398     if (from->size <= sizeof(p->from.addr)) {
399         p->from_is_value = True;
400         XtMemmove(&p->from.addr, from->addr, from->size);
401     } else {
402         p->from_is_value = False;
403         p->from.addr = (XPointer)_XtHeapAlloc(heap, from->size);
404         (void) memmove((char *)p->from.addr, (char *)from->addr, from->size);
405     }
406     p->num_args = num_args;
407     if (num_args) {
408         XrmValue *pargs = CARGS(p);
409         for (i = 0; i < num_args; i++) {
410             pargs[i].size = args[i].size;
411             pargs[i].addr = (XPointer)_XtHeapAlloc(heap, args[i].size);
412             XtMemmove(pargs[i].addr, args[i].addr, args[i].size);
413         }
414     }
415     p->to.size = to->size;
416     if (!succeeded) {
417         p->to_is_value = False;
418         p->to.addr = NULL;
419     } else if (to->size <= sizeof(p->to.addr)) {
420         p->to_is_value = True;
421         XtMemmove(&p->to.addr, to->addr, to->size);
422     } else {
423         p->to_is_value = False;
424         p->to.addr = (XPointer)_XtHeapAlloc(heap, to->size);
425         (void) memmove((char *)p->to.addr, (char *)to->addr, to->size);
426     }
427     UNLOCK_PROCESS;
428     return p;
429 }
430
431 static void FreeCacheRec(
432     XtAppContext app,
433     CachePtr p,
434     CachePtr *prev)
435 {
436     LOCK_PROCESS;
437     if (p->has_ext) {
438         if (CEXT(p)->destructor) {
439             Cardinal num_args = p->num_args;
440             XrmValue *args = NULL;
441             XrmValue toc;
442             if (num_args)
443                 args = CARGS(p);
444             toc.size = p->to.size;
445             if (p->to_is_value)
446                 toc.addr = (XPointer)&p->to.addr;
447             else
448                 toc.addr = p->to.addr;
449             (*CEXT(p)->destructor) (app, &toc, CEXT(p)->closure, args,
450                                     &num_args);
451         }
452         *(CEXT(p)->prev) = p->next;
453         if (p->next && p->next->has_ext)
454             CEXT(p->next)->prev = CEXT(p)->prev;
455     } else {
456         *prev = p->next;
457         if (p->next && p->next->has_ext)
458             CEXT(p->next)->prev = prev;
459     }
460     if (p->must_be_freed) {
461         register int i;
462         if (!p->from_is_value)
463             XtFree(p->from.addr);
464         if ((i = p->num_args)) {
465             XrmValue *pargs = CARGS(p);
466             while (i--)
467                 XtFree(pargs[i].addr);
468         }
469         if (!p->to_is_value)
470             XtFree(p->to.addr);
471         XtFree((char*)p);
472     }
473     /* else on private heap; will free entire heap later */
474     UNLOCK_PROCESS;
475 }
476
477
478 void _XtCacheFlushTag(
479     XtAppContext app,
480     XtPointer   tag)
481 {
482     int i;
483     register CachePtr *prev;
484     register CachePtr rec;
485
486     LOCK_PROCESS;
487     for (i = CACHEHASHSIZE; --i >= 0;) {
488         prev = &cacheHashTable[i];
489         while ((rec = *prev)) {
490             if (rec->tag == tag)
491                 FreeCacheRec(app, rec, prev);
492             else
493                 prev = &rec->next;
494         }
495     }
496     UNLOCK_PROCESS;
497 }
498
499 #ifdef DEBUG
500 #include        <stdio.h>
501
502 void _XtConverterCacheStats(void)
503 {
504     register Cardinal i;
505     register CachePtr p;
506     register Cardinal entries;
507
508     LOCK_PROCESS;
509     for (i = 0; i < CACHEHASHSIZE; i++) {
510         p = cacheHashTable[i];
511         if (p) {
512             for (entries = 0; p; p = p->next) {
513                 entries++;
514             }
515             (void) fprintf(stdout, "Index: %4d  Entries: %d\n", i, entries);
516             for (p = cacheHashTable[i]; p; p = p->next) {
517                 (void) fprintf(stdout, "    Size: %3d  Refs: %3d  '",
518                                p->from.size,
519                                p->has_ext ? CEXT(p)->ref_count : 0);
520                 (void) fprintf(stdout, "'\n");
521             }
522             (void) fprintf(stdout, "\n");
523         }
524     }
525     UNLOCK_PROCESS;
526 }
527 #endif /*DEBUG*/
528
529 static Boolean ResourceQuarkToOffset(
530     WidgetClass widget_class,
531     XrmName     name,
532     Cardinal    *offset)
533 {
534     register WidgetClass     wc;
535     register Cardinal        i;
536     register XrmResourceList res, *resources;
537
538     for (wc = widget_class; wc; wc = wc->core_class.superclass) {
539         resources = (XrmResourceList*) wc->core_class.resources;
540         for (i = 0; i < wc->core_class.num_resources; i++, resources++) {
541             res = *resources;
542             if (res->xrm_name == name) {
543                 *offset = -res->xrm_offset - 1;
544                 return True;
545             }
546         } /* for i in resources */
547     } /* for wc in widget classes */
548     (*offset) = 0;
549     return False;
550 }
551
552
553 static void ComputeArgs(
554     Widget              widget,
555     XtConvertArgList    convert_args,
556     Cardinal            num_args,
557     XrmValuePtr         args)
558 {
559     register Cardinal   i;
560     Cardinal            offset;
561     String              params[1];
562     Cardinal            num_params = 1;
563     Widget              ancestor = NULL;
564
565     for (i = 0; i < num_args; i++) {
566         args[i].size = convert_args[i].size;
567         switch (convert_args[i].address_mode) {
568         case XtAddress:
569             args[i].addr = convert_args[i].address_id;
570             break;
571
572         case XtBaseOffset:
573             args[i].addr =
574                 (XPointer)((char *)widget + (long)convert_args[i].address_id);
575             break;
576
577         case XtWidgetBaseOffset:
578             if (!ancestor) {
579                 if (XtIsWidget(widget))
580                     ancestor = widget;
581                 else
582                     ancestor = _XtWindowedAncestor(widget);
583             }
584
585             args[i].addr =
586                 (XPointer)((char *)ancestor + (long)convert_args[i].address_id);
587             break;
588
589         case XtImmediate:
590             args[i].addr = (XPointer) &(convert_args[i].address_id);
591             break;
592
593         case XtProcedureArg:
594             (*(XtConvertArgProc)convert_args[i].address_id)
595                 (widget, &convert_args[i].size, &args[i]);
596             break;
597
598         case XtResourceString:
599             /* Convert in place for next usage */
600             convert_args[i].address_mode = XtResourceQuark;
601             convert_args[i].address_id =
602                (XtPointer)(long)XrmStringToQuark((String)convert_args[i].address_id);
603             /* Fall through */
604
605         case XtResourceQuark:
606             if (! ResourceQuarkToOffset(widget->core.widget_class,
607                     (XrmQuark)(long) convert_args[i].address_id, &offset)) {
608                 params[0]=
609                   XrmQuarkToString((XrmQuark)(long) convert_args[i].address_id);
610                XtAppWarningMsg(XtWidgetToApplicationContext(widget),
611                     "invalidResourceName","computeArgs",XtCXtToolkitError,
612                     "Cannot find resource name %s as argument to conversion",
613                      params,&num_params);
614                 offset = 0;
615             }
616             args[i].addr = (XPointer)((char *)widget + offset);
617             break;
618         default:
619             params[0] = XtName(widget);
620             XtAppWarningMsg(XtWidgetToApplicationContext(widget),
621                 "invalidAddressMode", "computeArgs", XtCXtToolkitError,
622                 "Conversion arguments for widget '%s' contain an unsupported address mode",
623                         params,&num_params);
624             args[i].addr = NULL;
625             args[i].size = 0;
626         } /* switch */
627     } /* for */
628 } /* ComputeArgs */
629
630 void XtDirectConvert(
631     XtConverter     converter,
632     XrmValuePtr     args,
633     Cardinal        num_args,
634     register XrmValuePtr from,
635     XrmValuePtr     to)
636 {
637     register CachePtr   p;
638     register int        hash;
639     register Cardinal   i;
640
641     LOCK_PROCESS;
642     /* Try to find cache entry for conversion */
643     hash = ((long) converter >> 2) + from->size + *((char *) from->addr);
644     if (from->size > 1) hash += ((char *) from->addr)[1];
645
646     for (p = cacheHashTable[hash & CACHEHASHMASK]; p; p = p->next) {
647         if ((p->hash == hash)
648          && (p->converter == (XtTypeConverter)converter)
649          && (p->from.size == from->size)
650          && !(p->from_is_value ?
651               XtMemcmp(&p->from.addr, from->addr, from->size) :
652               memcmp((char *)p->from.addr, (char *)from->addr, from->size))
653          && (p->num_args == num_args)) {
654             if ((i = num_args)) {
655                 XrmValue *pargs = CARGS(p);
656                 /* Are all args the same data ? */
657                 while (i) {
658                     i--; /* do not move to while test, broken compilers */
659                     if (pargs[i].size != args[i].size ||
660                         XtMemcmp(pargs[i].addr, args[i].addr, args[i].size)) {
661                         i++;
662                         break;
663                     }
664                 }
665             }
666             if (!i) {
667                 /* Perfect match */
668                 to->size = p->to.size;
669                 if (p->to_is_value)
670                     to->addr = (XPointer)&p->to.addr;
671                 else
672                     to->addr = p->to.addr;
673                 UNLOCK_PROCESS;
674                 return;
675             }
676         }
677     }
678
679     /* Didn't find it, call converter procedure and entry result in cache */
680     (*to).size = 0;
681     (*to).addr = NULL;
682     (*converter)(args, &num_args, from, to);
683     /* This memory can never be freed since we don't know the Display
684      * or app context from which to compute the persistance */
685     {
686         CacheEnter(&globalHeap, (XtTypeConverter)converter, args, num_args,
687                    from, to, (to->addr != NULL), hash, False, False,
688                    (XtDestructor)NULL, NULL);
689     }
690     UNLOCK_PROCESS;
691 }
692
693
694 static ConverterPtr GetConverterEntry(
695     XtAppContext app,
696     XtTypeConverter converter)
697 {
698     Cardinal entry;
699     register ConverterPtr cP;
700     ConverterTable converterTable;
701
702     LOCK_PROCESS;
703     converterTable = app->converterTable;
704     cP = NULL;
705     for (entry = 0; (entry < CONVERTHASHSIZE) && !cP; entry++) {
706         cP = converterTable[entry];
707         while (cP && (cP->converter != converter)) cP = cP->next;
708     }
709     UNLOCK_PROCESS;
710     return cP;
711 }
712
713
714 static Boolean
715 CallConverter(
716     Display*        dpy,
717     XtTypeConverter converter,
718     XrmValuePtr     args,
719     Cardinal        num_args,
720     register XrmValuePtr from,
721     XrmValuePtr     to,
722     XtCacheRef      *cache_ref_return,
723     register ConverterPtr cP)
724 {
725     CachePtr p;
726     int hash;
727     Cardinal i;
728     Boolean retval;
729
730     if (!cP || ((cP->cache_type == XtCacheNone) && !cP->destructor)) {
731         XtPointer closure;
732         if (cache_ref_return) *cache_ref_return = NULL;
733         retval = (*(XtTypeConverter)converter)
734             (dpy, args, &num_args, from, to, &closure);
735         return retval;
736     }
737
738     LOCK_PROCESS;
739     /* Try to find cache entry for conversion */
740     hash = ((long)(converter) >> 2) + from->size + *((char *) from->addr);
741     if (from->size > 1) hash += ((char *) from->addr)[1];
742
743     if (cP->cache_type != XtCacheNone) {
744         for (p = cacheHashTable[hash & CACHEHASHMASK]; p; p = p->next){
745             if ((p->hash == hash)
746              && (p->converter == converter)
747              && (p->from.size == from->size)
748              && !(p->from_is_value ?
749                   XtMemcmp(&p->from.addr, from->addr, from->size) :
750                   memcmp((char *)p->from.addr, (char *)from->addr, from->size))
751              && (p->num_args == num_args)) {
752                 if ((i = num_args)) {
753                     XrmValue *pargs = CARGS(p);
754                     /* Are all args the same data ? */
755                     while (i) {
756                         i--; /* do not move to while test, broken compilers */
757                         if (pargs[i].size != args[i].size ||
758                             XtMemcmp(pargs[i].addr, args[i].addr, args[i].size)){
759                             i++;
760                             break;
761                         }
762                     }
763                 }
764                 if (!i) {
765                     /* Perfect match */
766                     if (p->conversion_succeeded) {
767                         if (to->addr) { /* new-style call */
768                             if (to->size < p->to.size) {
769                                 to->size = p->to.size;
770                                 UNLOCK_PROCESS;
771                                 return False;
772                             }
773                             to->size = p->to.size;
774                             if (p->to_is_value) {
775                                 XtMemmove(to->addr, &p->to.addr,
776                                           to->size);
777                             } else {
778                                 (void) memmove((char *)to->addr,
779                                                (char *)p->to.addr, to->size);
780                             }
781                         } else {        /* old-style call */
782                             to->size = p->to.size;
783                             if (p->to_is_value)
784                                 to->addr = (XPointer)&p->to.addr;
785                             else
786                                 to->addr = p->to.addr;
787                         }
788                     }
789                     if (p->is_refcounted) {
790                         CEXT(p)->ref_count++;
791                         if (cache_ref_return)
792                             *cache_ref_return = (XtCacheRef)p;
793                         else
794                             p->is_refcounted = False;
795                     }
796                     else {
797                         if (cache_ref_return)
798                             *cache_ref_return = NULL;
799                     }
800                     retval = (p->conversion_succeeded);
801                     UNLOCK_PROCESS;
802                     return retval;
803                 }
804             }
805         }
806     }
807
808     /* No cache entry, call converter procedure and enter result in cache */
809     {
810         Heap *heap;
811         XtPointer closure = NULL;
812         unsigned int supplied_size = to->size;
813         Boolean do_ref = cP->do_ref_count && cache_ref_return;
814         Boolean do_free = False;
815         Boolean retval =
816             (*(XtTypeConverter)converter)(dpy, args, &num_args, from, to, &closure);
817
818         if (retval == False && supplied_size < to->size) {
819             /* programmer error: caller must allocate sufficient storage */
820             if (cache_ref_return)
821                 *cache_ref_return = NULL;
822             UNLOCK_PROCESS;
823             return False;
824         }
825
826         if ((cP->cache_type == XtCacheNone) || do_ref) {
827             heap = NULL;
828             do_free = True;
829         }
830         else if (cP->cache_type == XtCacheByDisplay)
831             heap = &_XtGetPerDisplay(dpy)->heap;
832         else if (cP->global)
833             heap = &globalHeap;
834         else
835             heap = &XtDisplayToApplicationContext(dpy)->heap;
836
837         p = CacheEnter(heap, converter, args, num_args, from, to, retval,
838                        hash, do_ref, do_free, cP->destructor, closure);
839         if (do_ref)
840             *cache_ref_return = (XtCacheRef)p;
841         else if (cache_ref_return)
842             *cache_ref_return = NULL;
843         UNLOCK_PROCESS;
844         return retval;
845     }
846 }
847
848 Boolean
849 XtCallConverter(
850     Display*        dpy,
851     XtTypeConverter converter,
852     XrmValuePtr     args,
853     Cardinal        num_args,
854     register XrmValuePtr from,
855     XrmValuePtr     to,
856     XtCacheRef      *cache_ref_return)
857 {
858     ConverterPtr cP;
859     Boolean retval;
860     XtAppContext app = XtDisplayToApplicationContext(dpy);
861
862     LOCK_APP(app);
863     if ((cP = GetConverterEntry(app, converter)) == NULL) {
864         XtAppSetTypeConverter(XtDisplayToApplicationContext(dpy),
865                               "_XtUnk1", "_XtUnk2",
866                               converter, NULL, 0,
867                               XtCacheAll, NULL);
868         cP = GetConverterEntry(app, converter);
869     }
870     retval = CallConverter(dpy, converter, args, num_args, from, to,
871                             cache_ref_return, cP);
872     UNLOCK_APP(app);
873     return retval;
874 }
875
876 Boolean _XtConvert(
877              Widget             widget,
878     register XrmRepresentation  from_type,
879              XrmValuePtr        from,
880     register XrmRepresentation  to_type,
881     register XrmValuePtr        to,
882     XtCacheRef                  *cache_ref_return)
883 {
884     XtAppContext        app = XtWidgetToApplicationContext(widget);
885     register ConverterPtr       p;
886     Cardinal            num_args;
887     XrmValue            *args;
888
889     /* Look for type converter */
890     LOCK_PROCESS;
891     p = app->converterTable[ProcHash(from_type, to_type) & CONVERTHASHMASK];
892     for (; p; p = p->next) {
893         if (from_type == p->from && to_type == p->to) {
894             Boolean retval = False;
895             /* Compute actual arguments from widget and arg descriptor */
896             num_args = p->num_args;
897             if (num_args != 0) {
898                 args = (XrmValue*)
899                     ALLOCATE_LOCAL( num_args * sizeof (XrmValue) );
900                 if (!args) _XtAllocError("alloca");
901                 ComputeArgs(widget, ConvertArgs(p), num_args, args);
902             } else args = NULL;
903             if (p->new_style) {
904                 retval =
905                     CallConverter(XtDisplayOfObject(widget),
906                                      p->converter, args, num_args,
907                                      from, to, cache_ref_return, p);
908             }
909             else { /* is old-style (non-display) converter */
910                 XrmValue tempTo;
911                 XtDirectConvert((XtConverter)p->converter, args, num_args,
912                                 from, &tempTo);
913                 if (cache_ref_return)
914                     *cache_ref_return = NULL;
915                 if (tempTo.addr) {
916                     if (to->addr) {     /* new-style caller */
917                         if (to->size >= tempTo.size) {
918                             if (to_type == _XtQString)
919                                 *(String*)(to->addr) = tempTo.addr;
920                             else {
921                                 XtMemmove(to->addr, tempTo.addr,
922                                           tempTo.size);
923                             }
924                             retval = True;
925                         }
926                         to->size = tempTo.size;
927                     } else {            /* old-style caller */
928                         *to = tempTo;
929                         retval = True;
930                     }
931                 }
932             }
933             if (args) DEALLOCATE_LOCAL( (XtPointer)args );
934             UNLOCK_PROCESS;
935             return retval;
936         }
937     }
938
939     {
940         String params[2];
941         Cardinal num_params = 2;
942         params[0] = XrmRepresentationToString(from_type);
943         params[1] = XrmRepresentationToString(to_type);
944         XtAppWarningMsg(app, "typeConversionError", "noConverter", XtCXtToolkitError,
945              "No type converter registered for '%s' to '%s' conversion.",
946              params, &num_params);
947     }
948     UNLOCK_PROCESS;
949     return False;
950 }
951
952 void XtConvert(
953     Widget      widget,
954     _Xconst char* from_type_str,
955     XrmValuePtr from,
956     _Xconst char* to_type_str,
957     XrmValuePtr to)
958 {
959     XrmQuark    from_type, to_type;
960     WIDGET_TO_APPCON(widget);
961
962     LOCK_APP(app);
963     from_type = XrmStringToRepresentation(from_type_str);
964     to_type = XrmStringToRepresentation(to_type_str);
965     if (from_type != to_type) {
966         /*  It's not safe to ref count these resources, 'cause we
967             don't know what older clients may have assumed about
968             the resource lifetimes.
969         XtCacheRef ref;
970         */
971         to->addr = NULL;
972         to->size = 0;
973         _XtConvert(widget, from_type, from, to_type, to, /*&ref*/ NULL);
974         /*
975         if (ref) {
976             XtAddCallback( widget, XtNdestroyCallback,
977                            XtCallbackReleaseCacheRef, (XtPointer)ref );
978         }
979         */
980     }
981     else
982         (*to) = *from;
983     UNLOCK_APP(app);
984 }
985
986 Boolean XtConvertAndStore(
987     Widget      object,
988     _Xconst char* from_type_str,
989     XrmValuePtr from,
990     _Xconst char* to_type_str,
991     XrmValuePtr to)
992 {
993     XrmQuark    from_type, to_type;
994     WIDGET_TO_APPCON(object);
995
996     LOCK_APP(app);
997     LOCK_PROCESS;
998     from_type = XrmStringToRepresentation(from_type_str);
999     to_type = XrmStringToRepresentation(to_type_str);
1000     if (from_type != to_type) {
1001         static XtPointer local_valueP = NULL;
1002         static Cardinal local_valueS = 128;
1003         XtCacheRef ref;
1004         Boolean local = False;
1005         do {
1006             if (!to->addr) {
1007                 if (!local_valueP)
1008                     local_valueP = _XtHeapAlloc(&globalHeap, local_valueS);
1009                 to->addr = local_valueP;
1010                 to->size = local_valueS;
1011                 local = True;
1012             }
1013             if (!_XtConvert(object, from_type, from, to_type, to, &ref)) {
1014                 if (local && (to->size > local_valueS)) {
1015                     to->addr =
1016                         local_valueP = _XtHeapAlloc(&globalHeap, to->size);
1017                     local_valueS = to->size;
1018                     continue;
1019                 } else {
1020                     if (local) {
1021                         to->addr = NULL;
1022                         to->size = 0;
1023                     }
1024                     UNLOCK_PROCESS;
1025                     UNLOCK_APP(app);
1026                     return False;
1027                 }
1028             }
1029             if (ref) {
1030                 XtAddCallback( object, XtNdestroyCallback,
1031                                XtCallbackReleaseCacheRef, (XtPointer)ref );
1032             }
1033             UNLOCK_PROCESS;
1034             UNLOCK_APP(app);
1035             return True;
1036         } while (local /* && local_valueS < to->size */);
1037     }
1038     if (to->addr) {
1039         if (to->size < from->size) {
1040             to->size = from->size;
1041             UNLOCK_PROCESS;
1042             UNLOCK_APP(app);
1043             return False;
1044         }
1045         (void) memmove(to->addr, from->addr, from->size );
1046         to->size = from->size;
1047     } else                      /* from_type == to_type */
1048         *to = *from;
1049     UNLOCK_PROCESS;
1050     UNLOCK_APP(app);
1051     return True;
1052 }
1053
1054 void XtAppReleaseCacheRefs(
1055     XtAppContext app,
1056     XtCacheRef *refs)
1057 {
1058     register CachePtr *r;
1059     register CachePtr p;
1060
1061     LOCK_APP(app);
1062     LOCK_PROCESS;
1063     for (r = (CachePtr*)refs; (p = *r); r++) {
1064         if (p->is_refcounted && --(CEXT(p)->ref_count) == 0) {
1065             FreeCacheRec(app, p, NULL);
1066         }
1067     }
1068     UNLOCK_PROCESS;
1069     UNLOCK_APP(app);
1070 }
1071
1072
1073 /* ARGSUSED */
1074 void XtCallbackReleaseCacheRefList(
1075     Widget widget,              /* unused */
1076     XtPointer closure,
1077     XtPointer call_data)        /* unused */
1078 {
1079     XtAppReleaseCacheRefs( XtWidgetToApplicationContext(widget),
1080                            (XtCacheRef*)closure );
1081     XtFree(closure);
1082 }
1083
1084
1085 /* ARGSUSED */
1086 void XtCallbackReleaseCacheRef(
1087     Widget widget,              /* unused */
1088     XtPointer closure,
1089     XtPointer call_data)        /* unused */
1090 {
1091     XtCacheRef cache_refs[2];
1092     cache_refs[0] = (XtCacheRef)closure;
1093     cache_refs[1] = NULL;
1094     XtAppReleaseCacheRefs( XtWidgetToApplicationContext(widget), cache_refs );
1095 }