Convert.c revision 362b94d5
1/*********************************************************** 2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved. 3 4Permission is hereby granted, free of charge, to any person obtaining a 5copy of this software and associated documentation files (the "Software"), 6to deal in the Software without restriction, including without limitation 7the rights to use, copy, modify, merge, publish, distribute, sublicense, 8and/or sell copies of the Software, and to permit persons to whom the 9Software is furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice (including the next 12paragraph) shall be included in all copies or substantial portions of the 13Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21DEALINGS IN THE SOFTWARE. 22 23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. 24 25 All Rights Reserved 26 27Permission to use, copy, modify, and distribute this software and its 28documentation for any purpose and without fee is hereby granted, 29provided that the above copyright notice appear in all copies and that 30both that copyright notice and this permission notice appear in 31supporting documentation, and that the name of Digital not be 32used in advertising or publicity pertaining to distribution of the 33software without specific, written prior permission. 34 35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 41SOFTWARE. 42 43******************************************************************/ 44 45/* 46 47Copyright 1987, 1988, 1998 The Open Group 48 49Permission to use, copy, modify, distribute, and sell this software and its 50documentation for any purpose is hereby granted without fee, provided that 51the above copyright notice appear in all copies and that both that 52copyright notice and this permission notice appear in supporting 53documentation. 54 55The above copyright notice and this permission notice shall be included in 56all copies or substantial portions of the Software. 57 58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 65Except as contained in this notice, the name of The Open Group shall not be 66used in advertising or otherwise to promote the sale, use or other dealings 67in 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 85typedef struct _ConverterRec *ConverterPtr; 86typedef 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 */ 101static Heap globalHeap = { NULL, NULL, 0 }; 102 103void 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 135void 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 154typedef struct _CacheRec *CachePtr; 155 156typedef 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 172typedef 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 184typedef CachePtr CacheHashTable[CACHEHASHSIZE]; 185 186static CacheHashTable cacheHashTable; 187 188void 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 240void 241XtSetTypeConverter(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 276void 277XtAppSetTypeConverter(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 */ 295void 296XtAddConverter(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 */ 331void 332XtAppAddConverter(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 348static CachePtr 349CacheEnter(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 437static void 438FreeCacheRec(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 485void 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 508void 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 536static Boolean 537ResourceQuarkToOffset(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 560static void 561ComputeArgs(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 644void 645XtDirectConvert(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 710static ConverterPtr 711GetConverterEntry(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 729static Boolean 730CallConverter(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 872Boolean 873XtCallConverter(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 898Boolean 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 982void 983XtConvert(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 1017Boolean 1018XtConvertAndStore(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 1089void 1090XtAppReleaseCacheRefs(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 1106void 1107XtCallbackReleaseCacheRefList(Widget widget, 1108 XtPointer closure, 1109 XtPointer call_data _X_UNUSED) 1110{ 1111 XtAppReleaseCacheRefs(XtWidgetToApplicationContext(widget), 1112 (XtCacheRef *) closure); 1113 XtFree(closure); 1114} 1115 1116void 1117XtCallbackReleaseCacheRef(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