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 */
64typedef 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 */
76typedef struct _XawActionRes {
77  XrmQuark qname;
78  XrmQuark qtype;
79  Cardinal size;
80} XawActionRes;
81
82struct _XawActionResList {
83  WidgetClass widget_class;
84  XawActionRes **resources;
85  Cardinal num_common_resources;
86  Cardinal num_constraint_resources;
87};
88
89/* variables */
90typedef struct _XawActionVar {
91  XrmQuark qname;
92  XrmQuark qvalue;
93} XawActionVar;
94
95struct _XawActionVarList {
96  Widget widget;
97  Cardinal num_variables;
98  XawActionVar **variables;
99};
100
101/*
102 * Private methods
103 */
104/* expressions */
105static int get_token(XawEvalInfo*);
106static Bool expr(XawEvalInfo*);
107static Bool and(XawEvalInfo*);
108static Bool prim(XawEvalInfo*);
109
110/* resources */
111static String XawConvertActionRes(XawActionResList*, Widget w, String);
112
113static char * _XawEscapeActionVarValue(String);
114static char * _XawUnescapeActionVarValue(String);
115static XawActionResList *_XawCreateActionResList(WidgetClass);
116static XawActionResList *_XawFindActionResList(WidgetClass);
117static void _XawBindActionResList(XawActionResList*);
118static XawActionRes *_XawFindActionRes(XawActionResList*, Widget, String);
119static int qcmp_action_resource_list(_Xconst void*, _Xconst void*);
120static int bcmp_action_resource_list(_Xconst void*, _Xconst void*);
121static int qcmp_action_resource(_Xconst void*, _Xconst void*);
122static int bcmp_action_resource(_Xconst void*, _Xconst void*);
123
124/* variables */
125static String XawConvertActionVar(XawActionVarList*, String);
126static void XawDeclareActionVar(XawActionVarList*, String, String);
127
128static XawActionVarList *_XawCreateActionVarList(Widget);
129static XawActionVarList *_XawFindActionVarList(Widget);
130static XawActionVar *_XawCreateActionVar(XawActionVarList*, String);
131static XawActionVar *_XawFindActionVar(XawActionVarList*, String);
132static void _XawDestroyActionVarList(Widget, XtPointer, XtPointer);
133
134/*
135 * Initialization
136 */
137/* resources */
138static XawActionResList **resource_list;
139static Cardinal num_resource_list;
140
141/* variables */
142static XawActionVarList **variable_list;
143static Cardinal num_variable_list;
144
145/*
146 * Implementation
147 */
148/*
149 * Start of Boolean Expression Evaluation Implementation Code
150 */
151Bool
152XawParseBoolean(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
189Bool
190XawBooleanExpression(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
227static int
228get_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
312static Bool
313expr(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
334static Bool
335and(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
352static Bool
353prim(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 */
399void
400XawSetValuesAction(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
503void
504XawGetValuesAction(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
531void
532XawDeclareAction(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
552void
553XawCallProcAction(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
582static String
583XawConvertActionRes(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
649void
650XawPrintActionErrorMsg(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
672XawActionResList *
673XawGetActionResList(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
685static int
686qcmp_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
693static 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
725static int
726bcmp_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
733static 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
749static int
750qcmp_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
757static 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
833static int
834bcmp_action_resource(register _Xconst void *string,
835		     register _Xconst void *resource)
836{
837  return (strcmp((String)string,
838		 XrmQuarkToString((*(XawActionRes **)resource)->qname)));
839}
840
841static 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 */
872static 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 */
886static 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
898static void
899XawDeclareActionVar(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
937static String
938XawConvertActionVar(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
962XawActionVarList *
963XawGetActionVarList(Widget w)
964{
965  XawActionVarList *list;
966
967  list = _XawFindActionVarList(w);
968  if (!list)
969    list = _XawCreateActionVarList(w);
970
971  return (list);
972}
973
974static int
975qcmp_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
982static 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
1020static int
1021bcmp_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
1028static 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
1043static int
1044qcmp_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
1051static 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
1084static int
1085bcmp_action_variable(register _Xconst void *string,
1086		     register _Xconst void *variable)
1087{
1088  return (strcmp((String)string,
1089		 XrmQuarkToString((*(XawActionVar **)variable)->qname)));
1090}
1091
1092static 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*/
1107static 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