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