upload tizen2.0 source
[framework/uifw/xorg/util/x11-xkb-utils.git] / xkbcomp / expr.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4  Permission to use, copy, modify, and distribute this
5  software and its documentation for any purpose and without
6  fee is hereby granted, provided that the above copyright
7  notice appear in all copies and that both that copyright
8  notice and this permission notice appear in supporting
9  documentation, and that the name of Silicon Graphics not be 
10  used in advertising or publicity pertaining to distribution 
11  of the software without specific prior written permission.
12  Silicon Graphics makes no representation about the suitability 
13  of this software for any purpose. It is provided "as is"
14  without any express or implied warranty.
15  
16  SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
17  SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
18  AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
20  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
21  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
22  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25  ********************************************************/
26
27 #include "xkbcomp.h"
28 #include "tokens.h"
29 #include "expr.h"
30
31 #include <ctype.h>
32
33 /***====================================================================***/
34
35 char *
36 exprOpText(unsigned type)
37 {
38     static char buf[32];
39
40     switch (type)
41     {
42     case ExprValue:
43         strcpy(buf, "literal");
44         break;
45     case ExprIdent:
46         strcpy(buf, "identifier");
47         break;
48     case ExprActionDecl:
49         strcpy(buf, "action declaration");
50         break;
51     case ExprFieldRef:
52         strcpy(buf, "field reference");
53         break;
54     case ExprArrayRef:
55         strcpy(buf, "array reference");
56         break;
57     case ExprKeysymList:
58         strcpy(buf, "list of keysyms");
59         break;
60     case ExprActionList:
61         strcpy(buf, "list of actions");
62         break;
63     case OpAdd:
64         strcpy(buf, "addition");
65         break;
66     case OpSubtract:
67         strcpy(buf, "subtraction");
68         break;
69     case OpMultiply:
70         strcpy(buf, "multiplication");
71         break;
72     case OpDivide:
73         strcpy(buf, "division");
74         break;
75     case OpAssign:
76         strcpy(buf, "assignment");
77         break;
78     case OpNot:
79         strcpy(buf, "logical not");
80         break;
81     case OpNegate:
82         strcpy(buf, "arithmetic negation");
83         break;
84     case OpInvert:
85         strcpy(buf, "bitwise inversion");
86         break;
87     case OpUnaryPlus:
88         strcpy(buf, "plus sign");
89         break;
90     default:
91         snprintf(buf, sizeof(buf), "illegal(%d)", type);
92         break;
93     }
94     return buf;
95 }
96
97 char *
98 exprTypeText(unsigned type)
99 {
100     static char buf[20];
101
102     switch (type)
103     {
104     case TypeUnknown:
105         strcpy(buf, "unknown");
106         break;
107     case TypeBoolean:
108         strcpy(buf, "boolean");
109         break;
110     case TypeInt:
111         strcpy(buf, "int");
112         break;
113     case TypeString:
114         strcpy(buf, "string");
115         break;
116     case TypeAction:
117         strcpy(buf, "action");
118         break;
119     case TypeKeyName:
120         strcpy(buf, "keyname");
121         break;
122     default:
123         snprintf(buf, sizeof(buf), "illegal(%d)", type);
124         break;
125     }
126     return buf;
127 }
128
129 int
130 ExprResolveLhs(ExprDef * expr,
131                ExprResult * elem_rtrn,
132                ExprResult * field_rtrn, ExprDef ** index_rtrn)
133 {
134     switch (expr->op)
135     {
136     case ExprIdent:
137         elem_rtrn->str = NULL;
138         field_rtrn->str = XkbAtomGetString(NULL, expr->value.str);
139         *index_rtrn = NULL;
140         return True;
141     case ExprFieldRef:
142         elem_rtrn->str = XkbAtomGetString(NULL, expr->value.field.element);
143         field_rtrn->str = XkbAtomGetString(NULL, expr->value.field.field);
144         *index_rtrn = NULL;
145         return True;
146     case ExprArrayRef:
147         elem_rtrn->str = XkbAtomGetString(NULL, expr->value.array.element);
148         field_rtrn->str = XkbAtomGetString(NULL, expr->value.array.field);
149         *index_rtrn = expr->value.array.entry;
150         return True;
151     }
152     WSGO1("Unexpected operator %d in ResolveLhs\n", expr->op);
153     return False;
154 }
155
156 Bool
157 SimpleLookup(XPointer priv,
158              Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
159 {
160     LookupEntry *entry;
161     register char *str;
162
163     if ((priv == NULL) ||
164         (field == None) || (elem != None) ||
165         ((type != TypeInt) && (type != TypeFloat)))
166     {
167         return False;
168     }
169     str = XkbAtomGetString(NULL, field);
170     for (entry = (LookupEntry *) priv;
171          (entry != NULL) && (entry->name != NULL); entry++)
172     {
173         if (uStrCaseCmp(str, entry->name) == 0)
174         {
175             val_rtrn->uval = entry->result;
176             if (type == TypeFloat)
177                 val_rtrn->uval *= XkbGeomPtsPerMM;
178             return True;
179         }
180     }
181     return False;
182 }
183
184 Bool
185 RadioLookup(XPointer priv,
186             Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
187 {
188     register char *str;
189     int rg;
190
191     if ((field == None) || (elem != None) || (type != TypeInt))
192         return False;
193     str = XkbAtomGetString(NULL, field);
194     if (str)
195     {
196         if (uStrCasePrefix("group", str))
197             str += strlen("group");
198         else if (uStrCasePrefix("radiogroup", str))
199             str += strlen("radiogroup");
200         else if (uStrCasePrefix("rg", str))
201             str += strlen("rg");
202         else if (!isdigit(str[0]))
203             str = NULL;
204     }
205     if ((!str) || (sscanf(str, "%i", &rg) < 1) || (rg < 1)
206         || (rg > XkbMaxRadioGroups))
207         return False;
208     val_rtrn->uval = rg;
209     return True;
210 }
211
212 int
213 TableLookup(XPointer priv,
214             Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
215 {
216     LookupTable *tbl = (LookupTable *) priv;
217     register char *str;
218
219     if ((priv == NULL) || (field == None) || (type != TypeInt))
220         return False;
221     str = XkbAtomGetString(NULL, elem);
222     while (tbl)
223     {
224         if (((str == NULL) && (tbl->element == NULL)) ||
225             ((str != NULL) && (tbl->element != NULL) &&
226              (uStrCaseCmp(str, tbl->element) == 0)))
227         {
228             break;
229         }
230         tbl = tbl->nextElement;
231     }
232     if (tbl == NULL)            /* didn't find a matching element */
233         return False;
234     priv = (XPointer) tbl->entries;
235     return SimpleLookup(priv, (Atom) None, field, type, val_rtrn);
236 }
237
238 static LookupEntry modIndexNames[] = {
239     {"shift", ShiftMapIndex},
240     {"control", ControlMapIndex},
241     {"lock", LockMapIndex},
242     {"mod1", Mod1MapIndex},
243     {"mod2", Mod2MapIndex},
244     {"mod3", Mod3MapIndex},
245     {"mod4", Mod4MapIndex},
246     {"mod5", Mod5MapIndex},
247     {"none", XkbNoModifier},
248     {NULL, 0}
249 };
250
251 int
252 LookupModIndex(XPointer priv,
253                Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
254 {
255     return SimpleLookup((XPointer) modIndexNames, elem, field, type,
256                         val_rtrn);
257 }
258
259 int
260 LookupModMask(XPointer priv,
261               Atom elem, Atom field, unsigned type, ExprResult * val_rtrn)
262 {
263     char *str;
264
265     if ((elem != None) || (type != TypeInt))
266         return False;
267     str = XkbAtomGetString(NULL, field);
268     if (str == NULL)
269         return False;
270     if (uStrCaseCmp(str, "all") == 0)
271         val_rtrn->uval = 0xff;
272     else if (uStrCaseCmp(str, "none") == 0)
273         val_rtrn->uval = 0;
274     else if (LookupModIndex(priv, elem, field, type, val_rtrn))
275         val_rtrn->uval = (1 << val_rtrn->uval);
276     else if (priv != NULL)
277     {
278         LookupPriv *lpriv = (LookupPriv *) priv;
279         if ((lpriv->chain == NULL) ||
280             (!(*lpriv->chain) (lpriv->chainPriv, elem, field, type,
281                                val_rtrn)))
282             return False;
283     }
284     else
285         return False;
286     return True;
287 }
288
289 int
290 ExprResolveModIndex(ExprDef * expr,
291                     ExprResult * val_rtrn,
292                     IdentLookupFunc lookup, XPointer lookupPriv)
293 {
294     int ok = 0;
295     char *bogus = NULL;
296
297     switch (expr->op)
298     {
299     case ExprValue:
300         if (expr->type != TypeInt)
301         {
302             ERROR1
303                 ("Found constant of type %s where a modifier mask was expected\n",
304                  exprTypeText(expr->type));
305             return False;
306         }
307         else if ((expr->value.ival >= XkbNumModifiers)
308                  || (expr->value.ival < 0))
309         {
310             ERROR2("Illegal modifier index (%d, must be 0..%d)\n",
311                    expr->value.ival, XkbNumModifiers - 1);
312             return False;
313         }
314         val_rtrn->ival = expr->value.ival;
315         return True;
316     case ExprIdent:
317         if (LookupModIndex(lookupPriv, (Atom) None, expr->value.str,
318                            (unsigned) TypeInt, val_rtrn))
319         {
320             return True;
321         }
322         if (lookup)
323         {
324             ok = (*lookup) (lookupPriv,
325                             None, expr->value.str, TypeInt, val_rtrn);
326         }
327         if (!ok)
328             ERROR1("Cannot determine modifier index for \"%s\"\n",
329                    XkbAtomText(NULL, expr->value.str, XkbMessage));
330         break;
331     case ExprFieldRef:
332         bogus = "field reference";
333         break;
334     case ExprArrayRef:
335         bogus = "array reference";
336         break;
337     case ExprActionDecl:
338         bogus = "function";
339         break;
340     case OpAdd:
341     case OpSubtract:
342     case OpMultiply:
343     case OpDivide:
344     case OpInvert:
345     case OpNegate:
346     case OpNot:
347     case OpUnaryPlus:
348         bogus = "arithmetic operations";
349         break;
350     case OpAssign:
351         bogus = "assignment";
352         break;
353     default:
354         WSGO1("Unknown operator %d in ResolveModIndex\n", expr->op);
355         return False;
356     }
357     if (bogus)
358     {
359         ERROR1("Modifier index must be a name or number, %s ignored\n",
360                bogus);
361         return False;
362     }
363     return ok;
364 }
365
366 int
367 ExprResolveModMask(ExprDef * expr,
368                    ExprResult * val_rtrn,
369                    IdentLookupFunc lookup, XPointer lookupPriv)
370 {
371     LookupPriv priv;
372
373     priv.priv = NULL;
374     priv.chain = lookup;
375     priv.chainPriv = lookupPriv;
376     return ExprResolveMask(expr, val_rtrn, LookupModMask, (XPointer) & priv);
377 }
378
379 int
380 ExprResolveBoolean(ExprDef * expr,
381                    ExprResult * val_rtrn,
382                    IdentLookupFunc lookup, XPointer lookupPriv)
383 {
384     int ok = 0;
385     char *bogus = NULL;
386
387     switch (expr->op)
388     {
389     case ExprValue:
390         if (expr->type != TypeBoolean)
391         {
392             ERROR1
393                 ("Found constant of type %s where boolean was expected\n",
394                  exprTypeText(expr->type));
395             return False;
396         }
397         val_rtrn->ival = expr->value.ival;
398         return True;
399     case ExprIdent:
400         bogus = XkbAtomGetString(NULL, expr->value.str);
401         if (bogus)
402         {
403             if ((uStrCaseCmp(bogus, "true") == 0) ||
404                 (uStrCaseCmp(bogus, "yes") == 0) ||
405                 (uStrCaseCmp(bogus, "on") == 0))
406             {
407                 val_rtrn->uval = 1;
408                 return True;
409             }
410             else if ((uStrCaseCmp(bogus, "false") == 0) ||
411                      (uStrCaseCmp(bogus, "no") == 0) ||
412                      (uStrCaseCmp(bogus, "off") == 0))
413             {
414                 val_rtrn->uval = 0;
415                 return True;
416             }
417         }
418         if (lookup)
419         {
420             ok = (*lookup) (lookupPriv,
421                             None, expr->value.str, TypeBoolean, val_rtrn);
422         }
423         if (!ok)
424             ERROR1("Identifier \"%s\" of type int is unknown\n",
425                    XkbAtomText(NULL, expr->value.str, XkbMessage));
426         return ok;
427     case ExprFieldRef:
428         if (lookup)
429         {
430             ok = (*lookup) (lookupPriv,
431                             expr->value.field.element,
432                             expr->value.field.field, TypeBoolean, val_rtrn);
433         }
434         if (!ok)
435             ERROR2("Default \"%s.%s\" of type boolean is unknown\n",
436                    XkbAtomText(NULL, expr->value.field.element, XkbMessage),
437                    XkbAtomText(NULL, expr->value.field.field, XkbMessage));
438         return ok;
439     case OpInvert:
440     case OpNot:
441         ok = ExprResolveBoolean(expr, val_rtrn, lookup, lookupPriv);
442         if (ok)
443             val_rtrn->uval = !val_rtrn->uval;
444         return ok;
445     case OpAdd:
446         if (bogus == NULL)
447             bogus = "Addition";
448     case OpSubtract:
449         if (bogus == NULL)
450             bogus = "Subtraction";
451     case OpMultiply:
452         if (bogus == NULL)
453             bogus = "Multiplication";
454     case OpDivide:
455         if (bogus == NULL)
456             bogus = "Division";
457     case OpAssign:
458         if (bogus == NULL)
459             bogus = "Assignment";
460     case OpNegate:
461         if (bogus == NULL)
462             bogus = "Negation";
463         ERROR1("%s of boolean values not permitted\n", bogus);
464         break;
465     case OpUnaryPlus:
466         ERROR("Unary \"+\" operator not permitted for boolean values\n");
467         break;
468     default:
469         WSGO1("Unknown operator %d in ResolveBoolean\n", expr->op);
470         break;
471     }
472     return False;
473 }
474
475 int
476 ExprResolveFloat(ExprDef * expr,
477                  ExprResult * val_rtrn,
478                  IdentLookupFunc lookup, XPointer lookupPriv)
479 {
480     int ok = 0;
481     ExprResult leftRtrn, rightRtrn;
482     ExprDef *left, *right;
483
484     switch (expr->op)
485     {
486     case ExprValue:
487         if (expr->type == TypeString)
488         {
489             register char *str;
490             str = XkbAtomGetString(NULL, expr->value.str);
491             if ((str != NULL) && (strlen(str) == 1))
492             {
493                 val_rtrn->uval = str[0] * XkbGeomPtsPerMM;
494                 return True;
495             }
496         }
497         if ((expr->type != TypeInt) && (expr->type != TypeFloat))
498         {
499             ERROR1("Found constant of type %s, expected a number\n",
500                    exprTypeText(expr->type));
501             return False;
502         }
503         val_rtrn->ival = expr->value.ival;
504         if (expr->type == TypeInt)
505             val_rtrn->ival *= XkbGeomPtsPerMM;
506         return True;
507     case ExprIdent:
508         if (lookup)
509         {
510             ok = (*lookup) (lookupPriv,
511                             None, expr->value.str, TypeFloat, val_rtrn);
512         }
513         if (!ok)
514             ERROR1("Numeric identifier \"%s\" unknown\n",
515                    XkbAtomText(NULL, expr->value.str, XkbMessage));
516         return ok;
517     case ExprFieldRef:
518         if (lookup)
519         {
520             ok = (*lookup) (lookupPriv,
521                             expr->value.field.element,
522                             expr->value.field.field, TypeFloat, val_rtrn);
523         }
524         if (!ok)
525             ERROR2("Numeric default \"%s.%s\" unknown\n",
526                    XkbAtomText(NULL, expr->value.field.element, XkbMessage),
527                    XkbAtomText(NULL, expr->value.field.field, XkbMessage));
528         return ok;
529     case OpAdd:
530     case OpSubtract:
531     case OpMultiply:
532     case OpDivide:
533         left = expr->value.binary.left;
534         right = expr->value.binary.right;
535         if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv) &&
536             ExprResolveFloat(right, &rightRtrn, lookup, lookupPriv))
537         {
538             switch (expr->op)
539             {
540             case OpAdd:
541                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
542                 break;
543             case OpSubtract:
544                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
545                 break;
546             case OpMultiply:
547                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
548                 break;
549             case OpDivide:
550                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
551                 break;
552             }
553             return True;
554         }
555         return False;
556     case OpAssign:
557         WSGO("Assignment operator not implemented yet\n");
558         break;
559     case OpNot:
560         left = expr->value.child;
561         if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv))
562         {
563             ERROR("The ! operator cannot be applied to a number\n");
564         }
565         return False;
566     case OpInvert:
567     case OpNegate:
568         left = expr->value.child;
569         if (ExprResolveFloat(left, &leftRtrn, lookup, lookupPriv))
570         {
571             if (expr->op == OpNegate)
572                 val_rtrn->ival = -leftRtrn.ival;
573             else
574                 val_rtrn->ival = ~leftRtrn.ival;
575             return True;
576         }
577         return False;
578     case OpUnaryPlus:
579         left = expr->value.child;
580         return ExprResolveFloat(left, val_rtrn, lookup, lookupPriv);
581     default:
582         WSGO1("Unknown operator %d in ResolveFloat\n", expr->op);
583         break;
584     }
585     return False;
586 }
587
588 int
589 ExprResolveInteger(ExprDef * expr,
590                    ExprResult * val_rtrn,
591                    IdentLookupFunc lookup, XPointer lookupPriv)
592 {
593     int ok = 0;
594     ExprResult leftRtrn, rightRtrn;
595     ExprDef *left, *right;
596
597     switch (expr->op)
598     {
599     case ExprValue:
600         if (expr->type == TypeString)
601         {
602             register char *str;
603             str = XkbAtomGetString(NULL, expr->value.str);
604             if (str != NULL)
605                 switch (strlen(str))
606                 {
607                 case 0:
608                     val_rtrn->uval = 0;
609                     return True;
610                 case 1:
611                     val_rtrn->uval = str[0];
612                     return True;
613                 default:
614                     break;
615                 }
616         }
617         if ((expr->type != TypeInt) && (expr->type != TypeFloat))
618         {
619             ERROR1
620                 ("Found constant of type %s where an int was expected\n",
621                  exprTypeText(expr->type));
622             return False;
623         }
624         val_rtrn->ival = expr->value.ival;
625         if (expr->type == TypeFloat)
626             val_rtrn->ival /= XkbGeomPtsPerMM;
627         return True;
628     case ExprIdent:
629         if (lookup)
630         {
631             ok = (*lookup) (lookupPriv,
632                             None, expr->value.str, TypeInt, val_rtrn);
633         }
634         if (!ok)
635             ERROR1("Identifier \"%s\" of type int is unknown\n",
636                    XkbAtomText(NULL, expr->value.str, XkbMessage));
637         return ok;
638     case ExprFieldRef:
639         if (lookup)
640         {
641             ok = (*lookup) (lookupPriv,
642                             expr->value.field.element,
643                             expr->value.field.field, TypeInt, val_rtrn);
644         }
645         if (!ok)
646             ERROR2("Default \"%s.%s\" of type int is unknown\n",
647                    XkbAtomText(NULL, expr->value.field.element, XkbMessage),
648                    XkbAtomText(NULL, expr->value.field.field, XkbMessage));
649         return ok;
650     case OpAdd:
651     case OpSubtract:
652     case OpMultiply:
653     case OpDivide:
654         left = expr->value.binary.left;
655         right = expr->value.binary.right;
656         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv) &&
657             ExprResolveInteger(right, &rightRtrn, lookup, lookupPriv))
658         {
659             switch (expr->op)
660             {
661             case OpAdd:
662                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
663                 break;
664             case OpSubtract:
665                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
666                 break;
667             case OpMultiply:
668                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
669                 break;
670             case OpDivide:
671                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
672                 break;
673             }
674             return True;
675         }
676         return False;
677     case OpAssign:
678         WSGO("Assignment operator not implemented yet\n");
679         break;
680     case OpNot:
681         left = expr->value.child;
682         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
683         {
684             ERROR("The ! operator cannot be applied to an integer\n");
685         }
686         return False;
687     case OpInvert:
688     case OpNegate:
689         left = expr->value.child;
690         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
691         {
692             if (expr->op == OpNegate)
693                 val_rtrn->ival = -leftRtrn.ival;
694             else
695                 val_rtrn->ival = ~leftRtrn.ival;
696             return True;
697         }
698         return False;
699     case OpUnaryPlus:
700         left = expr->value.child;
701         return ExprResolveInteger(left, val_rtrn, lookup, lookupPriv);
702     default:
703         WSGO1("Unknown operator %d in ResolveInteger\n", expr->op);
704         break;
705     }
706     return False;
707 }
708
709 int
710 ExprResolveString(ExprDef * expr,
711                   ExprResult * val_rtrn,
712                   IdentLookupFunc lookup, XPointer lookupPriv)
713 {
714     int ok = 0;
715     ExprResult leftRtrn, rightRtrn;
716     ExprDef *left;
717     ExprDef *right;
718     char *bogus = NULL;
719
720     switch (expr->op)
721     {
722     case ExprValue:
723         if (expr->type != TypeString)
724         {
725             ERROR1("Found constant of type %s, expected a string\n",
726                    exprTypeText(expr->type));
727             return False;
728         }
729         val_rtrn->str = XkbAtomGetString(NULL, expr->value.str);
730         if (val_rtrn->str == NULL)
731         {
732             static char *empty = "";
733             val_rtrn->str = empty;
734         }
735         return True;
736     case ExprIdent:
737         if (lookup)
738         {
739             ok = (*lookup) (lookupPriv,
740                             None, expr->value.str, TypeString, val_rtrn);
741         }
742         if (!ok)
743             ERROR1("Identifier \"%s\" of type string not found\n",
744                    XkbAtomText(NULL, expr->value.str, XkbMessage));
745         return ok;
746     case ExprFieldRef:
747         if (lookup)
748         {
749             ok = (*lookup) (lookupPriv,
750                             expr->value.field.element,
751                             expr->value.field.field, TypeString, val_rtrn);
752         }
753         if (!ok)
754             ERROR2("Default \"%s.%s\" of type string not found\n",
755                    XkbAtomText(NULL, expr->value.field.element, XkbMessage),
756                    XkbAtomText(NULL, expr->value.field.field, XkbMessage));
757         return ok;
758     case OpAdd:
759         left = expr->value.binary.left;
760         right = expr->value.binary.right;
761         if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv) &&
762             ExprResolveString(right, &rightRtrn, lookup, lookupPriv))
763         {
764             int len;
765             char *new;
766             len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
767             new = (char *) uAlloc(len);
768             if (new)
769             {
770                 sprintf(new, "%s%s", leftRtrn.str, rightRtrn.str);
771                 val_rtrn->str = new;
772                 return True;
773             }
774         }
775         return False;
776     case OpSubtract:
777         if (bogus == NULL)
778             bogus = "Subtraction";
779     case OpMultiply:
780         if (bogus == NULL)
781             bogus = "Multiplication";
782     case OpDivide:
783         if (bogus == NULL)
784             bogus = "Division";
785     case OpAssign:
786         if (bogus == NULL)
787             bogus = "Assignment";
788     case OpNegate:
789         if (bogus == NULL)
790             bogus = "Negation";
791     case OpInvert:
792         if (bogus == NULL)
793             bogus = "Bitwise complement";
794         ERROR1("%s of string values not permitted\n", bogus);
795         return False;
796     case OpNot:
797         left = expr->value.child;
798         if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
799         {
800             ERROR("The ! operator cannot be applied to a string\n");
801         }
802         return False;
803     case OpUnaryPlus:
804         left = expr->value.child;
805         if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
806         {
807             ERROR("The + operator cannot be applied to a string\n");
808         }
809         return False;
810     default:
811         WSGO1("Unknown operator %d in ResolveString\n", expr->op);
812         break;
813     }
814     return False;
815 }
816
817 int
818 ExprResolveKeyName(ExprDef * expr,
819                    ExprResult * val_rtrn,
820                    IdentLookupFunc lookup, XPointer lookupPriv)
821 {
822     int ok = 0;
823     ExprDef *left;
824     ExprResult leftRtrn;
825     char *bogus = NULL;
826
827     switch (expr->op)
828     {
829     case ExprValue:
830         if (expr->type != TypeKeyName)
831         {
832             ERROR1("Found constant of type %s, expected a key name\n",
833                    exprTypeText(expr->type));
834             return False;
835         }
836         memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
837         return True;
838     case ExprIdent:
839         if (lookup)
840         {
841             ok = (*lookup) (lookupPriv,
842                             None, expr->value.str, TypeString, val_rtrn);
843         }
844         if (!ok)
845             ERROR1("Identifier \"%s\" of type string not found\n",
846                    XkbAtomText(NULL, expr->value.str, XkbMessage));
847         return ok;
848     case ExprFieldRef:
849         if (lookup)
850         {
851             ok = (*lookup) (lookupPriv,
852                             expr->value.field.element,
853                             expr->value.field.field, TypeString, val_rtrn);
854         }
855         if (!ok)
856             ERROR2("Default \"%s.%s\" of type key name not found\n",
857                    XkbAtomText(NULL, expr->value.field.element, XkbMessage),
858                    XkbAtomText(NULL, expr->value.field.field, XkbMessage));
859         return ok;
860     case OpAdd:
861         if (bogus == NULL)
862             bogus = "Addition";
863     case OpSubtract:
864         if (bogus == NULL)
865             bogus = "Subtraction";
866     case OpMultiply:
867         if (bogus == NULL)
868             bogus = "Multiplication";
869     case OpDivide:
870         if (bogus == NULL)
871             bogus = "Division";
872     case OpAssign:
873         if (bogus == NULL)
874             bogus = "Assignment";
875     case OpNegate:
876         if (bogus == NULL)
877             bogus = "Negation";
878     case OpInvert:
879         if (bogus == NULL)
880             bogus = "Bitwise complement";
881         ERROR1("%s of key name values not permitted\n", bogus);
882         return False;
883     case OpNot:
884         left = expr->value.binary.left;
885         if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
886         {
887             ERROR("The ! operator cannot be applied to a key name\n");
888         }
889         return False;
890     case OpUnaryPlus:
891         left = expr->value.binary.left;
892         if (ExprResolveString(left, &leftRtrn, lookup, lookupPriv))
893         {
894             ERROR("The + operator cannot be applied to a key name\n");
895         }
896         return False;
897     default:
898         WSGO1("Unknown operator %d in ResolveKeyName\n", expr->op);
899         break;
900     }
901     return False;
902 }
903
904 /***====================================================================***/
905
906 int
907 ExprResolveEnum(ExprDef * expr, ExprResult * val_rtrn, LookupEntry * values)
908 {
909     if (expr->op != ExprIdent)
910     {
911         ERROR1("Found a %s where an enumerated value was expected\n",
912                exprOpText(expr->op));
913         return False;
914     }
915     if (!SimpleLookup((XPointer) values, (Atom) None, expr->value.str,
916                       (unsigned) TypeInt, val_rtrn))
917     {
918         int nOut = 0;
919         ERROR1("Illegal identifier %s (expected one of: ",
920                XkbAtomText(NULL, expr->value.str, XkbMessage));
921         while (values && values->name)
922         {
923             if (nOut != 0)
924                 INFO1(", %s", values->name);
925             else
926                 INFO1("%s", values->name);
927             values++;
928             nOut++;
929         }
930         INFO(")\n");
931         return False;
932     }
933     return True;
934 }
935
936 int
937 ExprResolveMask(ExprDef * expr,
938                 ExprResult * val_rtrn,
939                 IdentLookupFunc lookup, XPointer lookupPriv)
940 {
941     int ok = 0;
942     ExprResult leftRtrn, rightRtrn;
943     ExprDef *left, *right;
944     char *bogus = NULL;
945
946     switch (expr->op)
947     {
948     case ExprValue:
949         if (expr->type != TypeInt)
950         {
951             ERROR1
952                 ("Found constant of type %s where a mask was expected\n",
953                  exprTypeText(expr->type));
954             return False;
955         }
956         val_rtrn->ival = expr->value.ival;
957         return True;
958     case ExprIdent:
959         if (lookup)
960         {
961             ok = (*lookup) (lookupPriv,
962                             None, expr->value.str, TypeInt, val_rtrn);
963         }
964         if (!ok)
965             ERROR1("Identifier \"%s\" of type int is unknown\n",
966                    XkbAtomText(NULL, expr->value.str, XkbMessage));
967         return ok;
968     case ExprFieldRef:
969         if (lookup)
970         {
971             ok = (*lookup) (lookupPriv,
972                             expr->value.field.element,
973                             expr->value.field.field, TypeInt, val_rtrn);
974         }
975         if (!ok)
976             ERROR2("Default \"%s.%s\" of type int is unknown\n",
977                    XkbAtomText(NULL, expr->value.field.element, XkbMessage),
978                    XkbAtomText(NULL, expr->value.field.field, XkbMessage));
979         return ok;
980     case ExprArrayRef:
981         bogus = "array reference";
982     case ExprActionDecl:
983         if (bogus == NULL)
984             bogus = "function use";
985         ERROR1("Unexpected %s in mask expression\n", bogus);
986         ACTION("Expression ignored\n");
987         return False;
988     case OpAdd:
989     case OpSubtract:
990     case OpMultiply:
991     case OpDivide:
992         left = expr->value.binary.left;
993         right = expr->value.binary.right;
994         if (ExprResolveMask(left, &leftRtrn, lookup, lookupPriv) &&
995             ExprResolveMask(right, &rightRtrn, lookup, lookupPriv))
996         {
997             switch (expr->op)
998             {
999             case OpAdd:
1000                 val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
1001                 break;
1002             case OpSubtract:
1003                 val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
1004                 break;
1005             case OpMultiply:
1006             case OpDivide:
1007                 ERROR1("Cannot %s masks\n",
1008                        expr->op == OpDivide ? "divide" : "multiply");
1009                 ACTION("Illegal operation ignored\n");
1010                 return False;
1011             }
1012             return True;
1013         }
1014         return False;
1015     case OpAssign:
1016         WSGO("Assignment operator not implemented yet\n");
1017         break;
1018     case OpInvert:
1019         left = expr->value.child;
1020         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
1021         {
1022             val_rtrn->ival = ~leftRtrn.ival;
1023             return True;
1024         }
1025         return False;
1026     case OpUnaryPlus:
1027     case OpNegate:
1028     case OpNot:
1029         left = expr->value.child;
1030         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
1031         {
1032             ERROR1("The %s operator cannot be used with a mask\n",
1033                    (expr->op == OpNegate ? "-" : "!"));
1034         }
1035         return False;
1036     default:
1037         WSGO1("Unknown operator %d in ResolveMask\n", expr->op);
1038         break;
1039     }
1040     return False;
1041 }
1042
1043 int
1044 ExprResolveKeySym(ExprDef * expr,
1045                   ExprResult * val_rtrn,
1046                   IdentLookupFunc lookup, XPointer lookupPriv)
1047 {
1048     int ok = 0;
1049     KeySym sym;
1050
1051     if (expr->op == ExprIdent)
1052     {
1053         char *str;
1054         str = XkbAtomGetString(NULL, expr->value.str);
1055         if ((str != NULL) && ((sym = XStringToKeysym(str)) != NoSymbol))
1056         {
1057             val_rtrn->uval = sym;
1058             return True;
1059         }
1060     }
1061     ok = ExprResolveInteger(expr, val_rtrn, lookup, lookupPriv);
1062     if ((ok) && (val_rtrn->uval < 10))
1063         val_rtrn->uval += '0';
1064     return ok;
1065 }