Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright (c) 1998 by The XFree86 Project, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  *
     22  * Except as contained in this notice, the name of the XFree86 Project shall
     23  * not be used in advertising or otherwise to promote the sale, use or other
     24  * dealings in this Software without prior written authorization from the
     25  * XFree86 Project.
     26  */
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include <config.h>
     30 #endif
     31 #include <ctype.h>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <X11/Xmd.h>
     36 #include <X11/IntrinsicP.h>
     37 #include <X11/StringDefs.h>
     38 #include <X11/CoreP.h>
     39 #include <X11/Constraint.h>
     40 #include <X11/Xmu/CharSet.h>
     41 #include <X11/Xfuncs.h>
     42 #include "Private.h"
     43 
     44 
     45 #ifndef OLDXAW
     46 
     47 /*
     48  * Definitions
     49  */
     50 #define ERROR   -2
     51 #define END     -1
     52 #define BOOLEAN 0
     53 #define AND     '&'
     54 #define OR      '|'
     55 #define XOR     '^'
     56 #define NOT     '~'
     57 #define LP      '('
     58 #define RP      ')'
     59 
     60 /*
     61  * Types
     62  */
     63 /* boolean expressions */
     64 typedef struct _XawEvalInfo {
     65   Widget widget;
     66   XawActionResList *rlist;
     67   XawActionVarList *vlist;
     68   XawParseBooleanProc parse_proc;
     69   XEvent *event;
     70   char *cp, *lp;
     71   int token;
     72   Bool value;
     73 } XawEvalInfo;
     74 
     75 /* resources */
     76 typedef struct _XawActionRes {
     77   XrmQuark qname;
     78   XrmQuark qtype;
     79   Cardinal size;
     80 } XawActionRes;
     81 
     82 struct _XawActionResList {
     83   WidgetClass widget_class;
     84   XawActionRes **resources;
     85   Cardinal num_common_resources;
     86   Cardinal num_constraint_resources;
     87 };
     88 
     89 /* variables */
     90 typedef struct _XawActionVar {
     91   XrmQuark qname;
     92   XrmQuark qvalue;
     93 } XawActionVar;
     94 
     95 struct _XawActionVarList {
     96   Widget widget;
     97   Cardinal num_variables;
     98   XawActionVar **variables;
     99 };
    100 
    101 /*
    102  * Private methods
    103  */
    104 /* expressions */
    105 static int get_token(XawEvalInfo*);
    106 static Bool expr(XawEvalInfo*);
    107 static Bool and(XawEvalInfo*);
    108 static Bool prim(XawEvalInfo*);
    109 
    110 /* resources */
    111 static String XawConvertActionRes(XawActionResList*, Widget w, String);
    112 
    113 static char * _XawEscapeActionVarValue(String);
    114 static char * _XawUnescapeActionVarValue(String);
    115 static XawActionResList *_XawCreateActionResList(WidgetClass);
    116 static XawActionResList *_XawFindActionResList(WidgetClass);
    117 static void _XawBindActionResList(XawActionResList*);
    118 static XawActionRes *_XawFindActionRes(XawActionResList*, Widget, String);
    119 static int qcmp_action_resource_list(_Xconst void*, _Xconst void*);
    120 static int bcmp_action_resource_list(_Xconst void*, _Xconst void*);
    121 static int qcmp_action_resource(_Xconst void*, _Xconst void*);
    122 static int bcmp_action_resource(_Xconst void*, _Xconst void*);
    123 
    124 /* variables */
    125 static String XawConvertActionVar(XawActionVarList*, String);
    126 static void XawDeclareActionVar(XawActionVarList*, String, String);
    127 
    128 static XawActionVarList *_XawCreateActionVarList(Widget);
    129 static XawActionVarList *_XawFindActionVarList(Widget);
    130 static XawActionVar *_XawCreateActionVar(XawActionVarList*, String);
    131 static XawActionVar *_XawFindActionVar(XawActionVarList*, String);
    132 static void _XawDestroyActionVarList(Widget, XtPointer, XtPointer);
    133 
    134 /*
    135  * Initialization
    136  */
    137 /* resources */
    138 static XawActionResList **resource_list;
    139 static Cardinal num_resource_list;
    140 
    141 /* variables */
    142 static XawActionVarList **variable_list;
    143 static Cardinal num_variable_list;
    144 
    145 /*
    146  * Implementation
    147  */
    148 /*
    149  * Start of Boolean Expression Evaluation Implementation Code
    150  */
    151 Bool
    152 XawParseBoolean(Widget w, String param, XEvent *event, Bool *succeed)
    153 {
    154   if (!param)
    155     return (False);
    156   else
    157     {
    158       char *tmp = (char *)param;
    159       double dd = strtod(param, &tmp);
    160       int value = (int) dd;
    161 
    162       if (*tmp == '\0')
    163         return (value);
    164     }
    165 
    166   if (XmuCompareISOLatin1(param, "true") == 0
    167       || XmuCompareISOLatin1(param, "yes") == 0
    168       || XmuCompareISOLatin1(param, "on") == 0
    169       || XmuCompareISOLatin1(param, "in") == 0
    170       || XmuCompareISOLatin1(param, "up") == 0)
    171     return (True);
    172   else if (XmuCompareISOLatin1(param, "false") == 0
    173 	  || XmuCompareISOLatin1(param, "no") == 0
    174 	  || XmuCompareISOLatin1(param, "off") == 0
    175 	  || XmuCompareISOLatin1(param, "out") == 0
    176 	  || XmuCompareISOLatin1(param, "down") == 0)
    177       ;
    178   else if (XmuCompareISOLatin1(param, "my") == 0
    179 	   || XmuCompareISOLatin1(param, "mine") == 0)
    180     return (event->xany.window == XtWindow(w));
    181   else if (XmuCompareISOLatin1(param, "faked") == 0)
    182     return (event->xany.send_event != 0);
    183   else
    184     *succeed = False;
    185 
    186   return (False);
    187 }
    188 
    189 Bool
    190 XawBooleanExpression(Widget w, String param, XEvent *event)
    191 {
    192   XawEvalInfo info;
    193 
    194   if (!param)
    195     return (False);
    196 
    197   info.widget = w;
    198 
    199   info.rlist = XawGetActionResList(XtClass(w));
    200   info.vlist = XawGetActionVarList(w);
    201 
    202   /*
    203    * Verify widget class, in case we will allow the parse proc procedure
    204    * as a widget class element, or if we allow overriding the default
    205    * parse boolean proc.
    206    */
    207   info.parse_proc = XawParseBoolean;
    208 
    209   info.event = event;
    210   info.cp = info.lp = (char *)param;
    211 
    212 #ifdef DIAGNOSTIC
    213   fprintf(stderr, "(*) Parsing expression \"%s\"\n", param);
    214 #endif
    215 
    216   (void)get_token(&info);
    217   if (info.token == ERROR)
    218     return (False);
    219   else
    220     {
    221       Bool retval = expr(&info);
    222 
    223       return (info.token != ERROR ? retval : False);
    224     }
    225 }
    226 
    227 static int
    228 get_token(XawEvalInfo *info)
    229 {
    230   int ch;
    231 
    232   info->lp = info->cp;
    233 
    234   /*COSTCOND*/
    235   while (1)	/* eat white spaces */
    236     {
    237       ch = *info->cp++;
    238       if (isspace(ch))
    239 	continue;
    240       break;
    241     }
    242 
    243   switch (ch)
    244     {
    245     case AND: case OR: case XOR: case NOT: case LP: case RP:
    246       return (info->token = ch);
    247     }
    248 
    249   /* It's a symbol name, resolve it. */
    250   if (ch == XAW_PRIV_VAR_PREFIX || isalnum(ch) || ch == '_' || ch == '\\')
    251     {
    252       Bool succeed = True;
    253 
    254       char *p = info->cp - 1;
    255       char name[256];
    256 
    257       while ((ch = *info->cp) && (isalnum(ch) || ch == '_'))
    258 	++info->cp;
    259 
    260       strncpy(name, p, XawMin((int)sizeof(name) - 1,
    261 			      (unsigned)(info->cp - p)));
    262       name[XawMin((int)sizeof(name) -1, info->cp - p)] = '\0';
    263 
    264       if (name[0] == XAW_PRIV_VAR_PREFIX)
    265 	{
    266 	  String value = XawConvertActionVar(info->vlist, name);
    267 
    268 	  info->value = info->parse_proc(info->widget, value, info->event,
    269 					 &succeed) & 1;
    270 	}
    271       else
    272 	{
    273 	  info->value = info->parse_proc(info->widget, name, info->event,
    274 					 &succeed) & 1;
    275 	  if (!succeed)
    276 	    {
    277 	      String value =
    278 		XawConvertActionRes(info->rlist, info->widget,
    279 				    name[0] == '\\' ? &name[1] : name);
    280 	      /* '\\' may have been used to escape a resource name.
    281 	       */
    282 
    283 	      succeed = True;
    284 	      info->value = info->parse_proc(info->widget, value, info->event,
    285 					     &succeed) & 1;
    286 	      if (!succeed)
    287 		{
    288 		  /* not a numeric value or boolean string */
    289 		  info->value = True;
    290 		  succeed = True;
    291 		}
    292 	    }
    293 	}
    294       if (succeed)
    295 	return (info->token = BOOLEAN);
    296     }
    297   else if (ch == '\0')
    298     return (info->token = END);
    299 
    300   {
    301     char msg[256];
    302 
    303     snprintf(msg, sizeof(msg), "evaluate(): bad token \"%c\" at \"%s\"",
    304 	     ch, info->cp - 1);
    305 
    306     XtAppWarning(XtWidgetToApplicationContext(info->widget), msg);
    307   }
    308 
    309   return (info->token = ERROR);
    310 }
    311 
    312 static Bool
    313 expr(XawEvalInfo *info)
    314 {
    315   Bool left = and(info);
    316 
    317   for (;;)
    318     switch (info->token)
    319       {
    320       case OR:
    321 	(void)get_token(info);
    322 	left |= and(info);
    323 	break;
    324       case XOR:
    325 	(void)get_token(info);
    326 	left ^= and(info);
    327 	break;
    328       default:
    329 	return (left);
    330       }
    331   /* NOTREACHED */
    332 }
    333 
    334 static Bool
    335 and(XawEvalInfo *info)
    336 {
    337   Bool left = prim(info);
    338 
    339   for (;;)
    340     switch (info->token)
    341       {
    342       case AND:
    343 	(void)get_token(info);
    344 	left &= prim(info);
    345 	break;
    346       default:
    347 	return (left);
    348       }
    349   /* NOTREACHED */
    350 }
    351 
    352 static Bool
    353 prim(XawEvalInfo *info)
    354 {
    355   Bool e;
    356 
    357   switch (info->token)
    358     {
    359     case BOOLEAN:
    360       e = info->value;
    361       (void)get_token(info);
    362       return (e);
    363     case NOT:
    364       (void)get_token(info);
    365       return (!prim(info));
    366     case LP:
    367       (void)get_token(info);
    368       e = expr(info);
    369       if (info->token != RP)
    370 	{
    371 	  char msg[256];
    372 
    373 	  info->token = ERROR;
    374 	  snprintf(msg, sizeof(msg), "evaluate(): expecting ), at \"%s\"",
    375 		   info->lp);
    376 	  XtAppWarning(XtWidgetToApplicationContext(info->widget), msg);
    377 	  return (False);
    378 	}
    379       (void)get_token(info);
    380       return (e);
    381     case END:
    382       return (True);
    383     default:
    384       {
    385 	char msg[256];
    386 
    387 	info->token = ERROR;
    388 	snprintf(msg, sizeof(msg), "evaluate(): syntax error, at \"%s\"",
    389 		 info->lp);
    390 	XtAppWarning(XtWidgetToApplicationContext(info->widget), msg);
    391       } return (False);
    392     }
    393   /* NOTREACHED */
    394 }
    395 
    396 /*
    397  * Start of Resources Implementation Code
    398  */
    399 void
    400 XawSetValuesAction(Widget w, XEvent *event,
    401 		   String *params, Cardinal *num_params)
    402 {
    403   Arg *arglist;
    404   Cardinal num_args, count;
    405   XawActionResList *rlist;
    406   XawActionVarList *vlist;
    407   XawActionRes *resource;
    408   XrmValue from, to;
    409   String value;
    410   char  c_1;
    411   short c_2;
    412   int   c_4;
    413 #ifdef LONG64
    414   long  c_8;
    415 #endif
    416   unsigned use_size;
    417 
    418   if (!(*num_params & 1))
    419     {
    420       XawPrintActionErrorMsg("set-values", w, params, num_params);
    421       return;
    422     }
    423 
    424   if (!XawBooleanExpression(w, params[0], event))
    425     return;
    426 
    427   rlist = XawGetActionResList(XtClass(w));
    428   vlist = XawGetActionVarList(w);
    429 
    430   num_args = 0;
    431   arglist = (Arg *)XtMalloc((Cardinal)sizeof(Arg) * ((*num_params) >> 1));
    432 
    433   for (count = 1; count < *num_params; count += 2)
    434     {
    435       if ((resource = _XawFindActionRes(rlist, w, params[count])) == NULL)
    436 	{
    437 	  char msg[256];
    438 
    439 	  snprintf(msg, sizeof(msg), "set-values(): bad resource name \"%s\"",
    440 		   params[count]);
    441 	  XtAppWarning(XtWidgetToApplicationContext(w), msg);
    442           continue;
    443 	}
    444       value = XawConvertActionVar(vlist, params[count + 1]);
    445       from.size = (Cardinal) strlen(value) + 1;
    446       from.addr = (char *)value;
    447       to.size = resource->size;
    448       use_size = resource->size;
    449       switch (use_size)
    450 	{
    451 	case 1: to.addr = (XPointer)&c_1; c_1 = 0; break;
    452 	case 2: to.addr = (XPointer)&c_2; c_2 = 0; break;
    453 	case 4: to.addr = (XPointer)&c_4; c_4 = 0; break;
    454 #ifdef LONG64
    455 	case 8: to.addr = (XPointer)&c_8; c_8 = 0; break;
    456 #endif
    457 	default:
    458 	  {
    459 	    char msg[256];
    460 
    461 	    snprintf(msg, sizeof(msg),
    462 		     "set-values(): bad resource size for \"%s\"",
    463 		     params[count]);
    464 	    XtAppWarning(XtWidgetToApplicationContext(w), msg);
    465 	  } continue;
    466 	}
    467 
    468       if (strcmp(XtRString, XrmQuarkToString(resource->qtype)) == 0)
    469 #ifdef LONG64
    470 	c_8 = (long)from.addr;
    471 #else
    472 	c_4 = (int)from.addr;
    473 #endif
    474       else if (!XtConvertAndStore(w, XtRString, &from,
    475 				  XrmQuarkToString(resource->qtype), &to)
    476 	       || to.size != use_size)
    477 	continue;
    478 
    479       switch (use_size)
    480 	{
    481 	case 1:
    482 	  XtSetArg(arglist[num_args], XrmQuarkToString(resource->qname), c_1);
    483 	  break;
    484 	case 2:
    485 	  XtSetArg(arglist[num_args], XrmQuarkToString(resource->qname), c_2);
    486 	  break;
    487 	case 4:
    488 	  XtSetArg(arglist[num_args], XrmQuarkToString(resource->qname), c_4);
    489 	  break;
    490 #ifdef LONG64
    491 	case 8:
    492 	  XtSetArg(arglist[num_args], XrmQuarkToString(resource->qname), c_8);
    493 	  break;
    494 #endif
    495 	}
    496       ++num_args;
    497     }
    498 
    499   XtSetValues(w, arglist, num_args);
    500   XtFree((char *)arglist);
    501 }
    502 
    503 void
    504 XawGetValuesAction(Widget w, XEvent *event,
    505 		   String *params, Cardinal *num_params)
    506 {
    507   XawActionResList *rlist;
    508   XawActionVarList *vlist;
    509   Cardinal count;
    510 
    511   if (!(*num_params & 1))
    512     {
    513       XawPrintActionErrorMsg("get-values", w, params, num_params);
    514       return;
    515     }
    516   if (!XawBooleanExpression(w, params[0], event))
    517     return;
    518 
    519   rlist = XawGetActionResList(XtClass(w));
    520   vlist = XawGetActionVarList(w);
    521 
    522   for (count = 1; count < *num_params; count += 2)
    523     {
    524       String value = XawConvertActionRes(rlist, w, params[count + 1]);
    525       if (value == NULL)
    526 	continue;
    527       XawDeclareActionVar(vlist, params[count], value);
    528     }
    529 }
    530 
    531 void
    532 XawDeclareAction(Widget w, XEvent *event,
    533 		 String *params, Cardinal *num_params)
    534 {
    535   XawActionVarList *vlist;
    536   Cardinal count;
    537 
    538   if (!(*num_params & 1))
    539     {
    540       XawPrintActionErrorMsg("declare", w, params, num_params);
    541       return;
    542     }
    543   if (!XawBooleanExpression(w, params[0], event))
    544     return;
    545 
    546   vlist = XawGetActionVarList(w);
    547 
    548   for (count = 1; count < *num_params; count += 2)
    549     XawDeclareActionVar(vlist, params[count], params[count + 1]);
    550 }
    551 
    552 void
    553 XawCallProcAction(Widget w, XEvent *event,
    554 		  String *params, Cardinal *num_params)
    555 {
    556   String *args;
    557   Cardinal num_args;
    558 
    559   if (*num_params < 2)
    560     {
    561       XawPrintActionErrorMsg("call-proc", w, params, num_params);
    562       return;
    563     }
    564 
    565   if (*num_params && !XawBooleanExpression(w, params[0], event))
    566     return;
    567 
    568   if (*num_params > 2)
    569     {
    570       args = &params[2];
    571       num_args = *num_params - 2;
    572     }
    573   else
    574     {
    575       args = NULL;
    576       num_args = 0;
    577     }
    578 
    579   XtCallActionProc(w, params[1], event, args, num_args);
    580 }
    581 
    582 static String
    583 XawConvertActionRes(XawActionResList *list, Widget w, String name)
    584 {
    585   XawActionRes *resource;
    586   XrmValue from, to;
    587   Arg arg;
    588   char  c_1;
    589   short c_2;
    590   int   c_4;
    591 #ifdef LONG64
    592   long  c_8;
    593 #endif
    594 
    595   if ((resource = _XawFindActionRes(list, w, name)) == NULL)
    596     {
    597       char msg[256];
    598 
    599       snprintf(msg, sizeof(msg), "convert(): bad resource name \"%s\"",
    600 	       name);
    601       XtAppWarning(XtWidgetToApplicationContext(w), msg);
    602       return (NULL);
    603     }
    604 
    605   from.size = resource->size;
    606   switch (from.size)
    607     {
    608     case 1:
    609       XtSetArg(arg, XrmQuarkToString(resource->qname),
    610 	       from.addr = (XPointer)&c_1);
    611       break;
    612     case 2:
    613       XtSetArg(arg, XrmQuarkToString(resource->qname),
    614                from.addr = (XPointer)&c_2);
    615       break;
    616     case 4:
    617       XtSetArg(arg, XrmQuarkToString(resource->qname),
    618                from.addr = (XPointer)&c_4);
    619       break;
    620 #ifdef LONG64
    621     case 8:
    622       XtSetArg(arg, XrmQuarkToString(resource->qname),
    623 	       from.addr = (XPointer)&c_8);
    624       break;
    625 #endif
    626     default:
    627       {
    628         char msg[256];
    629 
    630         snprintf(msg, sizeof(msg), "convert(): bad resource size for \"%s\"",
    631 		 name);
    632 	XtAppWarning(XtWidgetToApplicationContext(w), name);
    633       } return (NULL);
    634     }
    635 
    636   XtGetValues(w, &arg, 1);
    637   to.size = sizeof(String);
    638   to.addr = NULL;
    639 
    640   if (strcmp(XtRString, XrmQuarkToString(resource->qtype)) == 0)
    641     to.addr = *(char **)from.addr;
    642   else if (!XtConvertAndStore(w, XrmQuarkToString(resource->qtype),
    643 			      &from, XtRString, &to))
    644     return (NULL);
    645 
    646   return ((String)to.addr);
    647 }
    648 
    649 void
    650 XawPrintActionErrorMsg(String action_name, Widget w,
    651 		       String *params, Cardinal *num_params)
    652 {
    653   char msg[1024];
    654   unsigned int size, idx;
    655 
    656   size = (unsigned)snprintf(msg,
    657 			    sizeof(msg),
    658 			    "%s(): bad number of parameters.\n\t(",
    659 			    action_name);
    660 
    661   idx = 0;
    662   while (idx < *num_params - 1 && size < sizeof(msg))
    663     size += (unsigned)snprintf(&msg[size], sizeof(msg) - size, "%s, ",
    664 			       params[idx++]);
    665   if (*num_params)
    666     snprintf(&msg[size], sizeof(msg) - size, "%s)", params[idx]);
    667   else
    668     snprintf(&msg[size], sizeof(msg) - size, ")");
    669   XtAppWarning(XtWidgetToApplicationContext(w), msg);
    670 }
    671 
    672 XawActionResList *
    673 XawGetActionResList(WidgetClass wc)
    674 {
    675   XawActionResList *list;
    676 
    677   list = _XawFindActionResList(wc);
    678 
    679   if (!list)
    680     list = _XawCreateActionResList(wc);
    681 
    682   return (list);
    683 }
    684 
    685 static int
    686 qcmp_action_resource_list(register _Xconst void *left,
    687 			  register _Xconst void *right)
    688 {
    689   return (int)((char *)((*(XawActionResList **)left)->widget_class) -
    690 	       (char *)((*(XawActionResList **)right)->widget_class));
    691 }
    692 
    693 static XawActionResList *
    694 _XawCreateActionResList(WidgetClass wc)
    695 {
    696   XawActionResList *list;
    697 
    698   list = (XawActionResList *)XtMalloc((Cardinal)sizeof(XawActionResList));
    699   list->widget_class = wc;
    700   list->num_common_resources = list->num_constraint_resources = 0;
    701   list->resources = NULL;
    702 
    703   if (!resource_list)
    704     {
    705       num_resource_list = 1;
    706       resource_list = (XawActionResList **)XtMalloc((Cardinal)sizeof(XawActionResList*));
    707       resource_list[0] = list;
    708     }
    709   else
    710     {
    711       ++num_resource_list;
    712       resource_list = (XawActionResList **)XtRealloc((char *)resource_list,
    713 						     (Cardinal) sizeof(XawActionResList*)
    714 						     * num_resource_list);
    715       resource_list[num_resource_list - 1] = list;
    716       qsort(resource_list, num_resource_list, sizeof(XawActionResList*),
    717 	    qcmp_action_resource_list);
    718     }
    719 
    720   _XawBindActionResList(list);
    721 
    722   return (list);
    723 }
    724 
    725 static int
    726 bcmp_action_resource_list(register _Xconst void *wc,
    727 			  register _Xconst void *list)
    728 {
    729   return (int)((char *)wc
    730              - (char *)((*(XawActionResList **)list)->widget_class));
    731 }
    732 
    733 static XawActionResList *
    734 _XawFindActionResList(WidgetClass wc)
    735 {
    736   XawActionResList **list;
    737 
    738   if (!resource_list)
    739     return (NULL);
    740 
    741   list = (XawActionResList **)bsearch(wc, resource_list,
    742 				      num_resource_list,
    743 				      sizeof(XawActionResList*),
    744 				      bcmp_action_resource_list);
    745 
    746   return (list ? *list : NULL);
    747 }
    748 
    749 static int
    750 qcmp_action_resource(register _Xconst void *left,
    751 		     register _Xconst void *right)
    752 {
    753   return (strcmp(XrmQuarkToString((*(XawActionRes **)left)->qname),
    754 		 XrmQuarkToString((*(XawActionRes **)right)->qname)));
    755 }
    756 
    757 static void
    758 _XawBindActionResList(XawActionResList *list)
    759 {
    760   XtResourceList xt_list, cons_list;
    761   Cardinal i, num_xt, num_cons;
    762 
    763 #ifdef DIAGNOSTIC
    764   fprintf(stderr, "(*) Creating resource list for class \'%s\'\n---------\n",
    765 	  list->widget_class->core_class.class_name);
    766 #endif
    767 
    768   XtGetResourceList(list->widget_class, &xt_list, &num_xt);
    769   XtGetConstraintResourceList(list->widget_class, &cons_list, &num_cons);
    770   list->num_common_resources = num_xt;
    771   list->num_constraint_resources = num_cons;
    772 
    773   list->resources = (XawActionRes **)
    774     XtMalloc((Cardinal)sizeof(XawActionRes*) * (num_xt + num_cons));
    775 
    776 #ifdef DIAGNOSTIC
    777   fprintf(stderr, "Common resources\n---\n");
    778 #endif
    779 
    780   for (i = 0; i < num_xt; i++)
    781     {
    782       list->resources[i] = (XawActionRes *)XtMalloc((Cardinal)sizeof(XawActionRes));
    783       list->resources[i]->qname =
    784 	XrmPermStringToQuark(xt_list[i].resource_name);
    785       list->resources[i]->qtype =
    786 	XrmPermStringToQuark(xt_list[i].resource_type);
    787       list->resources[i]->size = xt_list[i].resource_size;
    788 
    789 #ifdef DIAGNOSTIC
    790       fprintf(stderr, "%-20s\t%-20s\t(%d)\n",
    791 	      xt_list[i].resource_name,
    792 	      xt_list[i].resource_type,
    793 	      xt_list[i].resource_size);
    794 #endif
    795     }
    796 
    797 #ifdef DIAGNOSTIC
    798   fprintf(stderr, "---\nContraint resources\n---");
    799 #endif
    800 
    801   for (; i < num_xt + num_cons; i++)
    802     {
    803       list->resources[i] = (XawActionRes *)XtMalloc((Cardinal)sizeof(XawActionRes));
    804       list->resources[i]->qname =
    805 	XrmPermStringToQuark(cons_list[i - num_xt].resource_name);
    806       list->resources[i]->qtype =
    807 	XrmPermStringToQuark(cons_list[i - num_xt].resource_type);
    808       list->resources[i]->size = cons_list[i - num_xt].resource_size;
    809 
    810 #ifdef DIAGNOSTIC
    811       fprintf(stderr, "%-20s\t%-20s\t(%d)\n",
    812 	      cons_list[i - num_xt].resource_name,
    813 	      cons_list[i - num_xt].resource_type,
    814 	      cons_list[i - num_xt].resource_size);
    815 #endif
    816     }
    817 
    818 #ifdef DIAGNOSTIC
    819   fprintf(stderr, "---\n");
    820 #endif
    821 
    822   XtFree((char *)xt_list);
    823   if (cons_list)
    824     XtFree((char *)cons_list);
    825 
    826   qsort(list->resources, list->num_common_resources, sizeof(XawActionRes*),
    827 	qcmp_action_resource);
    828   if (num_cons)
    829     qsort(&list->resources[num_xt], list->num_constraint_resources,
    830 	  sizeof(XawActionRes*), qcmp_action_resource);
    831 }
    832 
    833 static int
    834 bcmp_action_resource(register _Xconst void *string,
    835 		     register _Xconst void *resource)
    836 {
    837   return (strcmp((String)string,
    838 		 XrmQuarkToString((*(XawActionRes **)resource)->qname)));
    839 }
    840 
    841 static XawActionRes *
    842 _XawFindActionRes(XawActionResList *list, Widget detail, String name)
    843 {
    844   XawActionRes **res;
    845 
    846   if (!list->resources)
    847     return (NULL);
    848 
    849   res = (XawActionRes **)bsearch(name, list->resources,
    850 				 list->num_common_resources,
    851 				 sizeof(XawActionRes*), bcmp_action_resource);
    852 
    853   if (!res && XtParent(detail)
    854       && XtIsSubclass(XtParent(detail), constraintWidgetClass))
    855     {
    856       XawActionResList *cons = XawGetActionResList(XtClass(XtParent(detail)));
    857 
    858       if (cons)
    859 	res = (XawActionRes **)
    860 	  bsearch(name, &cons->resources[cons->num_common_resources],
    861 		  cons->num_constraint_resources,
    862 		  sizeof(XawActionRes*), bcmp_action_resource);
    863     }
    864 
    865   return (res ? *res : NULL);
    866 }
    867 
    868 /*
    869  * Start of Variables Implementation Code
    870  */
    871 /* For speed, only does memory allocation when really required */
    872 static char *
    873 _XawEscapeActionVarValue(String value)
    874 {
    875   if (value[0] == '$' || value[0] == '\\')
    876     {
    877       char *escape = XtMalloc((Cardinal)strlen(value) + 2);
    878       escape[0] = '\\';
    879       strcpy(escape + 1, value);
    880       return (escape);
    881     }
    882   return (NULL);
    883 }
    884 
    885 /* For speed, only does memory allocation when really required */
    886 static char *
    887 _XawUnescapeActionVarValue(String value)
    888 {
    889   if (value[0] == '\\')
    890     {
    891       char *unescape = XtMalloc((Cardinal)strlen(value));
    892       strcpy(unescape, value + 1);
    893       return (unescape);
    894     }
    895   return (NULL);
    896 }
    897 
    898 static void
    899 XawDeclareActionVar(XawActionVarList *list, String name, String value)
    900 {
    901   XawActionVar *variable;
    902   char * escape = NULL;
    903 
    904   if (name[0] != XAW_PRIV_VAR_PREFIX)
    905     {
    906       char msg[256];
    907 
    908       snprintf(msg, sizeof(msg),
    909 	       "declare(): variable name must begin with \'%c\', at %s = %s",
    910 	       XAW_PRIV_VAR_PREFIX, name, value);
    911       XtAppWarning(XtWidgetToApplicationContext(list->widget), msg);
    912       return;
    913     }
    914   variable = _XawFindActionVar(list, name);
    915   if (!variable)
    916     variable = _XawCreateActionVar(list, name);
    917   if (value)
    918     escape = _XawEscapeActionVarValue(value);
    919 
    920   if (variable->qvalue)
    921     {
    922       String val = escape ? escape : value;
    923 
    924       if (val != NULL && strcmp(XrmQuarkToString(variable->qvalue), val) == 0)
    925 	{
    926 	  if (escape)
    927 	    XtFree(escape);
    928 	  return;
    929 	}
    930     }
    931   variable->qvalue = (escape ? XrmStringToQuark(escape) :
    932 		      (value ? XrmStringToQuark(value) : NULLQUARK));
    933   if (escape)
    934     XtFree(escape);
    935 }
    936 
    937 static String
    938 XawConvertActionVar(XawActionVarList *list, String name)
    939 {
    940   XawActionVar *variable;
    941   char * unescape;
    942   XrmQuark quark;
    943 
    944   if (name[0] != XAW_PRIV_VAR_PREFIX)
    945     return (name);
    946 
    947   variable = _XawFindActionVar(list, name);
    948   if (!variable || variable->qvalue == NULLQUARK)
    949     return (name);
    950   unescape = _XawUnescapeActionVarValue(XrmQuarkToString(variable->qvalue));
    951   if (unescape)
    952     {
    953       quark = XrmStringToQuark(unescape);
    954       XtFree(unescape);
    955     }
    956   else
    957     quark = variable->qvalue;
    958 
    959   return (XrmQuarkToString(quark));
    960 }
    961 
    962 XawActionVarList *
    963 XawGetActionVarList(Widget w)
    964 {
    965   XawActionVarList *list;
    966 
    967   list = _XawFindActionVarList(w);
    968   if (!list)
    969     list = _XawCreateActionVarList(w);
    970 
    971   return (list);
    972 }
    973 
    974 static int
    975 qcmp_action_variable_list(register _Xconst void *left,
    976 			  register _Xconst void *right)
    977 {
    978   return (int)((char *)((*(XawActionVarList **)left)->widget) -
    979 	       (char *)((*(XawActionVarList **)right)->widget));
    980 }
    981 
    982 static XawActionVarList *
    983 _XawCreateActionVarList(Widget w)
    984 {
    985   XawActionVarList *list;
    986 
    987 #ifdef DIAGNOSTIC
    988   fprintf(stderr, "(*) Creating action variable list for widget %s (%p)\n",
    989 	  XtName(w), w);
    990 #endif
    991 
    992   list = (XawActionVarList *)XtMalloc((Cardinal)sizeof(XawActionVarList));
    993   list->widget = w;
    994   list->num_variables = 0;
    995   list->variables = NULL;
    996 
    997   if (!variable_list)
    998     {
    999       num_variable_list = 1;
   1000       variable_list = (XawActionVarList **)XtMalloc((Cardinal)sizeof(XawActionVarList*));
   1001       variable_list[0] = list;
   1002     }
   1003   else
   1004     {
   1005       ++num_variable_list;
   1006       variable_list = (XawActionVarList **)
   1007 	XtRealloc((char *)variable_list,
   1008 		  (Cardinal)sizeof(XawActionVarList *) * num_variable_list);
   1009       variable_list[num_variable_list - 1] = list;
   1010       qsort(variable_list, num_variable_list, sizeof(XawActionVarList*),
   1011 	    qcmp_action_variable_list);
   1012     }
   1013 
   1014   XtAddCallback(w, XtNdestroyCallback, _XawDestroyActionVarList,
   1015 		(XtPointer)list);
   1016 
   1017   return (list);
   1018 }
   1019 
   1020 static int
   1021 bcmp_action_variable_list(register _Xconst void *widget,
   1022 			  register _Xconst void *list)
   1023 {
   1024   return (int)((char *)widget
   1025              - (char *)((*(XawActionVarList **)list)->widget));
   1026 }
   1027 
   1028 static XawActionVarList *
   1029 _XawFindActionVarList(Widget w)
   1030 {
   1031   XawActionVarList **list;
   1032 
   1033   if (!num_variable_list)
   1034     return (NULL);
   1035 
   1036   list = (XawActionVarList **)bsearch(w, variable_list, num_variable_list,
   1037 				      sizeof(XawActionVarList*),
   1038 				      bcmp_action_variable_list);
   1039 
   1040   return (list ? *list : NULL);
   1041 }
   1042 
   1043 static int
   1044 qcmp_action_variable(register _Xconst void *left,
   1045 		     register _Xconst void *right)
   1046 {
   1047   return (strcmp(XrmQuarkToString((*(XawActionVar **)left)->qname),
   1048 		 XrmQuarkToString((*(XawActionVar **)right)->qname)));
   1049 }
   1050 
   1051 static XawActionVar *
   1052 _XawCreateActionVar(XawActionVarList *list, String name)
   1053 {
   1054   XawActionVar *variable;
   1055 
   1056 #ifdef DIAGNOSTIC
   1057   fprintf(stderr, "(*) Creating action variable '%s' for widget %s (%p)\n",
   1058 	  name, XtName(list->widget), list->widget);
   1059 #endif
   1060 
   1061   variable = (XawActionVar *)XtMalloc((Cardinal)sizeof(XawActionVar));
   1062   variable->qname = XrmStringToQuark(name);
   1063   variable->qvalue = NULLQUARK;
   1064 
   1065   if (!list->variables)
   1066     {
   1067       list->num_variables = 1;
   1068       list->variables = (XawActionVar **)XtMalloc((Cardinal)sizeof(XawActionVar*));
   1069       list->variables[0] = variable;
   1070     }
   1071   else
   1072     {
   1073       ++list->num_variables;
   1074       list->variables = (XawActionVar **)XtRealloc((char *)list->variables,
   1075 						   (Cardinal) sizeof(XawActionVar *) *
   1076 						   list->num_variables);
   1077       list->variables[list->num_variables - 1] = variable;
   1078       qsort(list->variables, list->num_variables, sizeof(XawActionVar*),
   1079 	    qcmp_action_variable);
   1080     }
   1081   return (variable);
   1082 }
   1083 
   1084 static int
   1085 bcmp_action_variable(register _Xconst void *string,
   1086 		     register _Xconst void *variable)
   1087 {
   1088   return (strcmp((String)string,
   1089 		 XrmQuarkToString((*(XawActionVar **)variable)->qname)));
   1090 }
   1091 
   1092 static XawActionVar *
   1093 _XawFindActionVar(XawActionVarList *list, String name)
   1094 {
   1095   XawActionVar **var;
   1096 
   1097   if (!list->variables)
   1098     return (NULL);
   1099 
   1100   var = (XawActionVar **)bsearch(name, list->variables, list->num_variables,
   1101 				 sizeof(XawActionVar*), bcmp_action_variable);
   1102 
   1103   return (var ? *var : NULL);
   1104 }
   1105 
   1106 /*ARGSUSED*/
   1107 static void
   1108 _XawDestroyActionVarList(Widget w, XtPointer client_data, XtPointer call_data _X_UNUSED)
   1109 {
   1110   XawActionVarList *list = (XawActionVarList *)client_data;
   1111   Cardinal i;
   1112 
   1113   for (i = 0; i < num_variable_list; i++)
   1114     if (variable_list[i] == list)
   1115       break;
   1116   if (i >= num_variable_list || list->widget != w
   1117       || variable_list[i]->widget != w)
   1118     {
   1119       XtWarning("destroy-variable-list(): Bad widget argument.");
   1120       return;
   1121     }
   1122   if (--num_variable_list > 0)
   1123     {
   1124       memmove(&variable_list[i], &variable_list[i + 1],
   1125 	    (num_variable_list - i) * sizeof(XawActionVarList *));
   1126       variable_list = (XawActionVarList **)
   1127 	XtRealloc((char *)variable_list, (Cardinal) sizeof(XawActionVarList *) *
   1128 		  num_variable_list);
   1129     }
   1130   else
   1131     {
   1132       XtFree((char *)variable_list);
   1133       variable_list = NULL;
   1134     }
   1135 
   1136   XtFree((char *)list->variables);
   1137   XtFree((char *)list);
   1138 }
   1139 
   1140 #endif /* OLDXAW */
   1141