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