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