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