home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xt / Convert.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  28.6 KB  |  1,052 lines

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