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