Rename xkb_desc to xkb_keymap
[platform/upstream/libxkbcommon.git] / src / 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 <X11/X.h>
28
29 #include "xkbcomp.h"
30 #include "xkbmisc.h"
31 #include "expr.h"
32 #include "vmod.h"
33
34 #include <ctype.h>
35
36 /***====================================================================***/
37
38 typedef Bool(*IdentLookupFunc) (const void * /* priv */ ,
39                                 xkb_atom_t /* field */ ,
40                                 unsigned /* type */ ,
41                                 ExprResult *    /* val_rtrn */
42     );
43
44 /***====================================================================***/
45
46 const char *
47 exprOpText(unsigned type)
48 {
49     static char buf[32];
50
51     switch (type)
52     {
53     case ExprValue:
54         strcpy(buf, "literal");
55         break;
56     case ExprIdent:
57         strcpy(buf, "identifier");
58         break;
59     case ExprActionDecl:
60         strcpy(buf, "action declaration");
61         break;
62     case ExprFieldRef:
63         strcpy(buf, "field reference");
64         break;
65     case ExprArrayRef:
66         strcpy(buf, "array reference");
67         break;
68     case ExprKeysymList:
69         strcpy(buf, "list of keysyms");
70         break;
71     case ExprActionList:
72         strcpy(buf, "list of actions");
73         break;
74     case OpAdd:
75         strcpy(buf, "addition");
76         break;
77     case OpSubtract:
78         strcpy(buf, "subtraction");
79         break;
80     case OpMultiply:
81         strcpy(buf, "multiplication");
82         break;
83     case OpDivide:
84         strcpy(buf, "division");
85         break;
86     case OpAssign:
87         strcpy(buf, "assignment");
88         break;
89     case OpNot:
90         strcpy(buf, "logical not");
91         break;
92     case OpNegate:
93         strcpy(buf, "arithmetic negation");
94         break;
95     case OpInvert:
96         strcpy(buf, "bitwise inversion");
97         break;
98     case OpUnaryPlus:
99         strcpy(buf, "plus sign");
100         break;
101     default:
102         snprintf(buf, sizeof(buf), "illegal(%d)", type);
103         break;
104     }
105     return buf;
106 }
107
108 static const char *
109 exprTypeText(unsigned type)
110 {
111     static char buf[20];
112
113     switch (type)
114     {
115     case TypeUnknown:
116         strcpy(buf, "unknown");
117         break;
118     case TypeBoolean:
119         strcpy(buf, "boolean");
120         break;
121     case TypeInt:
122         strcpy(buf, "int");
123         break;
124     case TypeString:
125         strcpy(buf, "string");
126         break;
127     case TypeAction:
128         strcpy(buf, "action");
129         break;
130     case TypeKeyName:
131         strcpy(buf, "keyname");
132         break;
133     default:
134         snprintf(buf, sizeof(buf), "illegal(%d)", type);
135         break;
136     }
137     return buf;
138 }
139
140 int
141 ExprResolveLhs(ExprDef * expr,
142                ExprResult * elem_rtrn,
143                ExprResult * field_rtrn, ExprDef ** index_rtrn)
144 {
145     switch (expr->op)
146     {
147     case ExprIdent:
148         elem_rtrn->str = NULL;
149         field_rtrn->str = XkbcAtomGetString(expr->value.str);
150         *index_rtrn = NULL;
151         return True;
152     case ExprFieldRef:
153         elem_rtrn->str = XkbcAtomGetString(expr->value.field.element);
154         field_rtrn->str = XkbcAtomGetString(expr->value.field.field);
155         *index_rtrn = NULL;
156         return True;
157     case ExprArrayRef:
158         elem_rtrn->str = XkbcAtomGetString(expr->value.array.element);
159         field_rtrn->str = XkbcAtomGetString(expr->value.array.field);
160         *index_rtrn = expr->value.array.entry;
161         return True;
162     }
163     WSGO("Unexpected operator %d in ResolveLhs\n", expr->op);
164     return False;
165 }
166
167 static Bool
168 SimpleLookup(const void * priv, xkb_atom_t field, unsigned type,
169              ExprResult * val_rtrn)
170 {
171     const LookupEntry *entry;
172     const char *str;
173
174     if ((priv == NULL) || (field == XKB_ATOM_NONE) || (type != TypeInt))
175     {
176         return False;
177     }
178     str = XkbcAtomText(field);
179     for (entry = priv; (entry != NULL) && (entry->name != NULL); entry++)
180     {
181         if (strcasecmp(str, entry->name) == 0)
182         {
183             val_rtrn->uval = entry->result;
184             return True;
185         }
186     }
187     return False;
188 }
189
190 static const LookupEntry modIndexNames[] = {
191     {"shift", ShiftMapIndex},
192     {"control", ControlMapIndex},
193     {"lock", LockMapIndex},
194     {"mod1", Mod1MapIndex},
195     {"mod2", Mod2MapIndex},
196     {"mod3", Mod3MapIndex},
197     {"mod4", Mod4MapIndex},
198     {"mod5", Mod5MapIndex},
199     {"none", XkbNoModifier},
200     {NULL, 0}
201 };
202
203 int
204 LookupModIndex(const void * priv, xkb_atom_t field, unsigned type,
205                ExprResult * val_rtrn)
206 {
207     return SimpleLookup(modIndexNames, field, type, val_rtrn);
208 }
209
210 int
211 LookupModMask(const void * priv, xkb_atom_t field, unsigned type,
212               ExprResult * val_rtrn)
213 {
214     const char *str;
215     Bool ret = True;
216
217     if (type != TypeInt)
218         return False;
219     str = XkbcAtomText(field);
220     if (str == NULL)
221         return False;
222     if (strcasecmp(str, "all") == 0)
223         val_rtrn->uval = 0xff;
224     else if (strcasecmp(str, "none") == 0)
225         val_rtrn->uval = 0;
226     else if (LookupModIndex(priv, field, type, val_rtrn))
227         val_rtrn->uval = (1 << val_rtrn->uval);
228     else
229         ret = False;
230     return ret;
231 }
232
233 int
234 ExprResolveBoolean(ExprDef * expr,
235                    ExprResult * val_rtrn)
236 {
237     int ok = 0;
238     const char *bogus = NULL;
239
240     switch (expr->op)
241     {
242     case ExprValue:
243         if (expr->type != TypeBoolean)
244         {
245             ERROR
246                 ("Found constant of type %s where boolean was expected\n",
247                  exprTypeText(expr->type));
248             return False;
249         }
250         val_rtrn->ival = expr->value.ival;
251         return True;
252     case ExprIdent:
253         bogus = XkbcAtomText(expr->value.str);
254         if (bogus)
255         {
256             if ((strcasecmp(bogus, "true") == 0) ||
257                 (strcasecmp(bogus, "yes") == 0) ||
258                 (strcasecmp(bogus, "on") == 0))
259             {
260                 val_rtrn->uval = 1;
261                 return True;
262             }
263             else if ((strcasecmp(bogus, "false") == 0) ||
264                      (strcasecmp(bogus, "no") == 0) ||
265                      (strcasecmp(bogus, "off") == 0))
266             {
267                 val_rtrn->uval = 0;
268                 return True;
269             }
270         }
271         ERROR("Identifier \"%s\" of type int is unknown\n",
272               XkbcAtomText(expr->value.str));
273         return False;
274     case ExprFieldRef:
275         ERROR("Default \"%s.%s\" of type boolean is unknown\n",
276               XkbcAtomText(expr->value.field.element),
277               XkbcAtomText(expr->value.field.field));
278         return False;
279     case OpInvert:
280     case OpNot:
281         ok = ExprResolveBoolean(expr, val_rtrn);
282         if (ok)
283             val_rtrn->uval = !val_rtrn->uval;
284         return ok;
285     case OpAdd:
286         if (bogus == NULL)
287             bogus = "Addition";
288     case OpSubtract:
289         if (bogus == NULL)
290             bogus = "Subtraction";
291     case OpMultiply:
292         if (bogus == NULL)
293             bogus = "Multiplication";
294     case OpDivide:
295         if (bogus == NULL)
296             bogus = "Division";
297     case OpAssign:
298         if (bogus == NULL)
299             bogus = "Assignment";
300     case OpNegate:
301         if (bogus == NULL)
302             bogus = "Negation";
303         ERROR("%s of boolean values not permitted\n", bogus);
304         break;
305     case OpUnaryPlus:
306         ERROR("Unary \"+\" operator not permitted for boolean values\n");
307         break;
308     default:
309         WSGO("Unknown operator %d in ResolveBoolean\n", expr->op);
310         break;
311     }
312     return False;
313 }
314
315 int
316 ExprResolveFloat(ExprDef * expr,
317                  ExprResult * val_rtrn)
318 {
319     int ok = 0;
320     ExprResult leftRtrn, rightRtrn;
321     ExprDef *left, *right;
322
323     switch (expr->op)
324     {
325     case ExprValue:
326         if (expr->type == TypeString)
327         {
328             const char *str;
329             str = XkbcAtomText(expr->value.str);
330             if ((str != NULL) && (strlen(str) == 1))
331             {
332                 val_rtrn->uval = str[0] * XkbGeomPtsPerMM;
333                 return True;
334             }
335         }
336         if (expr->type != TypeInt)
337         {
338             ERROR("Found constant of type %s, expected a number\n",
339                    exprTypeText(expr->type));
340             return False;
341         }
342         val_rtrn->ival = expr->value.ival;
343         if (expr->type == TypeInt)
344             val_rtrn->ival *= XkbGeomPtsPerMM;
345         return True;
346     case ExprIdent:
347         ERROR("Numeric identifier \"%s\" unknown\n",
348               XkbcAtomText(expr->value.str));
349         return ok;
350     case ExprFieldRef:
351         ERROR("Numeric default \"%s.%s\" unknown\n",
352               XkbcAtomText(expr->value.field.element),
353               XkbcAtomText(expr->value.field.field));
354         return False;
355     case OpAdd:
356     case OpSubtract:
357     case OpMultiply:
358     case OpDivide:
359         left = expr->value.binary.left;
360         right = expr->value.binary.right;
361         if (ExprResolveFloat(left, &leftRtrn) &&
362             ExprResolveFloat(right, &rightRtrn))
363         {
364             switch (expr->op)
365             {
366             case OpAdd:
367                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
368                 break;
369             case OpSubtract:
370                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
371                 break;
372             case OpMultiply:
373                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
374                 break;
375             case OpDivide:
376                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
377                 break;
378             }
379             return True;
380         }
381         return False;
382     case OpAssign:
383         WSGO("Assignment operator not implemented yet\n");
384         break;
385     case OpNot:
386         ERROR("The ! operator cannot be applied to a number\n");
387         return False;
388     case OpInvert:
389     case OpNegate:
390         left = expr->value.child;
391         if (ExprResolveFloat(left, &leftRtrn))
392         {
393             if (expr->op == OpNegate)
394                 val_rtrn->ival = -leftRtrn.ival;
395             else
396                 val_rtrn->ival = ~leftRtrn.ival;
397             return True;
398         }
399         return False;
400     case OpUnaryPlus:
401         left = expr->value.child;
402         return ExprResolveFloat(left, val_rtrn);
403     default:
404         WSGO("Unknown operator %d in ResolveFloat\n", expr->op);
405         break;
406     }
407     return False;
408 }
409
410 int
411 ExprResolveKeyCode(ExprDef * expr,
412                    ExprResult * val_rtrn)
413 {
414     ExprResult leftRtrn, rightRtrn;
415     ExprDef *left, *right;
416
417     switch (expr->op)
418     {
419     case ExprValue:
420         if (expr->type != TypeInt)
421         {
422             ERROR
423                 ("Found constant of type %s where an int was expected\n",
424                  exprTypeText(expr->type));
425             return False;
426         }
427         val_rtrn->uval = expr->value.uval;
428         return True;
429     case OpAdd:
430     case OpSubtract:
431     case OpMultiply:
432     case OpDivide:
433         left = expr->value.binary.left;
434         right = expr->value.binary.right;
435         if (ExprResolveKeyCode(left, &leftRtrn) &&
436             ExprResolveKeyCode(right, &rightRtrn))
437         {
438             switch (expr->op)
439             {
440             case OpAdd:
441                 val_rtrn->uval = leftRtrn.uval + rightRtrn.uval;
442                 break;
443             case OpSubtract:
444                 val_rtrn->uval = leftRtrn.uval - rightRtrn.uval;
445                 break;
446             case OpMultiply:
447                 val_rtrn->uval = leftRtrn.uval * rightRtrn.uval;
448                 break;
449             case OpDivide:
450                 val_rtrn->uval = leftRtrn.uval / rightRtrn.uval;
451                 break;
452             }
453             return True;
454         }
455         return False;
456     case OpNegate:
457         left = expr->value.child;
458         if (ExprResolveKeyCode(left, &leftRtrn))
459         {
460             val_rtrn->uval = ~leftRtrn.uval;
461             return True;
462         }
463         return False;
464     case OpUnaryPlus:
465         left = expr->value.child;
466         return ExprResolveKeyCode(left, val_rtrn);
467     default:
468         WSGO("Unknown operator %d in ResolveKeyCode\n", expr->op);
469         break;
470     }
471     return False;
472 }
473
474 /**
475  * This function returns ... something.  It's a bit of a guess, really.
476  *
477  * If a string is given in value context, its first character will be
478  * returned in uval.  If an integer is given in value context, it will be
479  * returned in ival.  If a float is given in value context, it will be
480  * returned as millimetres (rather than points) in ival.
481  *
482  * If an ident or field reference is given, the lookup function (if given)
483  * will be called.  At the moment, only SimpleLookup use this, and they both
484  * return the results in uval.  And don't support field references.
485  *
486  * Cool.
487  */
488 static int
489 ExprResolveIntegerLookup(ExprDef * expr,
490                          ExprResult * val_rtrn,
491                          IdentLookupFunc lookup, const void * lookupPriv)
492 {
493     int ok = 0;
494     ExprResult leftRtrn, rightRtrn;
495     ExprDef *left, *right;
496
497     switch (expr->op)
498     {
499     case ExprValue:
500         if (expr->type == TypeString)
501         {
502             const char *str;
503             str = XkbcAtomText(expr->value.str);
504             if (str != NULL)
505                 switch (strlen(str))
506                 {
507                 case 0:
508                     val_rtrn->uval = 0;
509                     return True;
510                 case 1:
511                     val_rtrn->uval = str[0];
512                     return True;
513                 default:
514                     break;
515                 }
516         }
517         if (expr->type != TypeInt)
518         {
519             ERROR
520                 ("Found constant of type %s where an int was expected\n",
521                  exprTypeText(expr->type));
522             return False;
523         }
524         val_rtrn->ival = expr->value.ival;
525         return True;
526     case ExprIdent:
527         if (lookup)
528         {
529             ok = (*lookup) (lookupPriv, expr->value.str, TypeInt, val_rtrn);
530         }
531         if (!ok)
532             ERROR("Identifier \"%s\" of type int is unknown\n",
533                    XkbcAtomText(expr->value.str));
534         return ok;
535     case ExprFieldRef:
536         ERROR("Default \"%s.%s\" of type int is unknown\n",
537               XkbcAtomText(expr->value.field.element),
538               XkbcAtomText(expr->value.field.field));
539         return False;
540     case OpAdd:
541     case OpSubtract:
542     case OpMultiply:
543     case OpDivide:
544         left = expr->value.binary.left;
545         right = expr->value.binary.right;
546         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv) &&
547             ExprResolveIntegerLookup(right, &rightRtrn, lookup, lookupPriv))
548         {
549             switch (expr->op)
550             {
551             case OpAdd:
552                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
553                 break;
554             case OpSubtract:
555                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
556                 break;
557             case OpMultiply:
558                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
559                 break;
560             case OpDivide:
561                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
562                 break;
563             }
564             return True;
565         }
566         return False;
567     case OpAssign:
568         WSGO("Assignment operator not implemented yet\n");
569         break;
570     case OpNot:
571         ERROR("The ! operator cannot be applied to an integer\n");
572         return False;
573     case OpInvert:
574     case OpNegate:
575         left = expr->value.child;
576         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
577         {
578             if (expr->op == OpNegate)
579                 val_rtrn->ival = -leftRtrn.ival;
580             else
581                 val_rtrn->ival = ~leftRtrn.ival;
582             return True;
583         }
584         return False;
585     case OpUnaryPlus:
586         left = expr->value.child;
587         return ExprResolveIntegerLookup(left, val_rtrn, lookup, lookupPriv);
588     default:
589         WSGO("Unknown operator %d in ResolveInteger\n", expr->op);
590         break;
591     }
592     return False;
593 }
594
595 int
596 ExprResolveInteger(ExprDef * expr,
597                    ExprResult * val_rtrn)
598 {
599     return ExprResolveIntegerLookup(expr, val_rtrn, NULL, NULL);
600 }
601
602 int
603 ExprResolveGroup(ExprDef * expr,
604                  ExprResult * val_rtrn)
605 {
606     int ret;
607     static const LookupEntry group_names[] = {
608         { "group1", 1 },
609         { "group2", 2 },
610         { "group3", 3 },
611         { "group4", 4 },
612         { "group5", 5 },
613         { "group6", 6 },
614         { "group7", 7 },
615         { "group8", 8 },
616         { NULL, 0 }
617     };
618
619     ret = ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup, group_names);
620     if (ret == False)
621         return ret;
622
623     if (val_rtrn->uval == 0 || val_rtrn->uval > XkbNumKbdGroups) {
624         ERROR("Group index %d is out of range (1..%d)\n",
625               val_rtrn->uval, XkbNumKbdGroups);
626         return False;
627     }
628
629     return True;
630 }
631
632 int
633 ExprResolveLevel(ExprDef * expr,
634                  ExprResult * val_rtrn)
635 {
636     int ret;
637     static const LookupEntry level_names[] = {
638         { "level1", 1 },
639         { "level2", 2 },
640         { "level3", 3 },
641         { "level4", 4 },
642         { "level5", 5 },
643         { "level6", 6 },
644         { "level7", 7 },
645         { "level8", 8 },
646         { NULL, 0 }
647     };
648
649     ret = ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup, level_names);
650     if (ret == False)
651         return ret;
652
653     if (val_rtrn->ival < 1 || val_rtrn->ival > XkbMaxShiftLevel) {
654         ERROR("Shift level %d is out of range (1..%d)\n", val_rtrn->ival,
655               XkbMaxShiftLevel);
656         return False;
657     }
658
659     return True;
660 }
661
662 int
663 ExprResolveButton(ExprDef * expr,
664                   ExprResult * val_rtrn)
665 {
666     static const LookupEntry button_names[] = {
667         { "button1", 1 },
668         { "button2", 2 },
669         { "button3", 3 },
670         { "button4", 4 },
671         { "button5", 5 },
672         { "default", 0 },
673         { NULL, 0 }
674     };
675
676     return ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup,
677                                     button_names);
678 }
679
680 int
681 ExprResolveString(ExprDef * expr,
682                   ExprResult * val_rtrn)
683 {
684     ExprResult leftRtrn, rightRtrn;
685     ExprDef *left;
686     ExprDef *right;
687     const char *bogus = NULL;
688
689     switch (expr->op)
690     {
691     case ExprValue:
692         if (expr->type != TypeString)
693         {
694             ERROR("Found constant of type %s, expected a string\n",
695                    exprTypeText(expr->type));
696             return False;
697         }
698         val_rtrn->str = XkbcAtomGetString(expr->value.str);
699         if (val_rtrn->str == NULL)
700             val_rtrn->str = strdup("");
701         return True;
702     case ExprIdent:
703         ERROR("Identifier \"%s\" of type string not found\n",
704               XkbcAtomText(expr->value.str));
705         return False;
706     case ExprFieldRef:
707         ERROR("Default \"%s.%s\" of type string not found\n",
708               XkbcAtomText(expr->value.field.element),
709               XkbcAtomText(expr->value.field.field));
710         return False;
711     case OpAdd:
712         left = expr->value.binary.left;
713         right = expr->value.binary.right;
714         if (ExprResolveString(left, &leftRtrn) &&
715             ExprResolveString(right, &rightRtrn))
716         {
717             int len;
718             char *new;
719             len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
720             new = malloc(len);
721             if (new)
722             { sprintf(new, "%s%s", leftRtrn.str, rightRtrn.str);
723                 free(leftRtrn.str);
724                 free(rightRtrn.str);
725                 val_rtrn->str = new;
726                 return True;
727             }
728             free(leftRtrn.str);
729             free(rightRtrn.str);
730         }
731         return False;
732     case OpSubtract:
733         if (bogus == NULL)
734             bogus = "Subtraction";
735     case OpMultiply:
736         if (bogus == NULL)
737             bogus = "Multiplication";
738     case OpDivide:
739         if (bogus == NULL)
740             bogus = "Division";
741     case OpAssign:
742         if (bogus == NULL)
743             bogus = "Assignment";
744     case OpNegate:
745         if (bogus == NULL)
746             bogus = "Negation";
747     case OpInvert:
748         if (bogus == NULL)
749             bogus = "Bitwise complement";
750         ERROR("%s of string values not permitted\n", bogus);
751         return False;
752     case OpNot:
753         ERROR("The ! operator cannot be applied to a string\n");
754         return False;
755     case OpUnaryPlus:
756         ERROR("The + operator cannot be applied to a string\n");
757         return False;
758     default:
759         WSGO("Unknown operator %d in ResolveString\n", expr->op);
760         break;
761     }
762     return False;
763 }
764
765 int
766 ExprResolveKeyName(ExprDef * expr,
767                    ExprResult * val_rtrn)
768 {
769     const char *bogus = NULL;
770
771     switch (expr->op)
772     {
773     case ExprValue:
774         if (expr->type != TypeKeyName)
775         {
776             ERROR("Found constant of type %s, expected a key name\n",
777                    exprTypeText(expr->type));
778             return False;
779         }
780         memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
781         return True;
782     case ExprIdent:
783         ERROR("Identifier \"%s\" of type string not found\n",
784               XkbcAtomText(expr->value.str));
785         return False;
786     case ExprFieldRef:
787         ERROR("Default \"%s.%s\" of type key name not found\n",
788               XkbcAtomText(expr->value.field.element),
789               XkbcAtomText(expr->value.field.field));
790         return False;
791     case OpAdd:
792         if (bogus == NULL)
793             bogus = "Addition";
794     case OpSubtract:
795         if (bogus == NULL)
796             bogus = "Subtraction";
797     case OpMultiply:
798         if (bogus == NULL)
799             bogus = "Multiplication";
800     case OpDivide:
801         if (bogus == NULL)
802             bogus = "Division";
803     case OpAssign:
804         if (bogus == NULL)
805             bogus = "Assignment";
806     case OpNegate:
807         if (bogus == NULL)
808             bogus = "Negation";
809     case OpInvert:
810         if (bogus == NULL)
811             bogus = "Bitwise complement";
812         ERROR("%s of key name values not permitted\n", bogus);
813         return False;
814     case OpNot:
815         ERROR("The ! operator cannot be applied to a key name\n");
816         return False;
817     case OpUnaryPlus:
818         ERROR("The + operator cannot be applied to a key name\n");
819         return False;
820     default:
821         WSGO("Unknown operator %d in ResolveKeyName\n", expr->op);
822         break;
823     }
824     return False;
825 }
826
827 /***====================================================================***/
828
829 int
830 ExprResolveEnum(ExprDef * expr, ExprResult * val_rtrn, const LookupEntry * values)
831 {
832     if (expr->op != ExprIdent)
833     {
834         ERROR("Found a %s where an enumerated value was expected\n",
835                exprOpText(expr->op));
836         return False;
837     }
838     if (!SimpleLookup(values, expr->value.str, TypeInt, val_rtrn))
839     {
840         int nOut = 0;
841         ERROR("Illegal identifier %s (expected one of: ",
842                XkbcAtomText(expr->value.str));
843         while (values && values->name)
844         {
845             if (nOut != 0)
846                 INFO(", %s", values->name);
847             else
848                 INFO("%s", values->name);
849             values++;
850             nOut++;
851         }
852         INFO(")\n");
853         return False;
854     }
855     return True;
856 }
857
858 static int
859 ExprResolveMaskLookup(ExprDef * expr,
860                       ExprResult * val_rtrn,
861                       IdentLookupFunc lookup,
862                       const void * lookupPriv)
863 {
864     int ok = 0;
865     ExprResult leftRtrn, rightRtrn;
866     ExprDef *left, *right;
867     const char *bogus = NULL;
868
869     switch (expr->op)
870     {
871     case ExprValue:
872         if (expr->type != TypeInt)
873         {
874             ERROR
875                 ("Found constant of type %s where a mask was expected\n",
876                  exprTypeText(expr->type));
877             return False;
878         }
879         val_rtrn->ival = expr->value.ival;
880         return True;
881     case ExprIdent:
882         ok = (*lookup) (lookupPriv, expr->value.str, TypeInt, val_rtrn);
883         if (!ok)
884             ERROR("Identifier \"%s\" of type int is unknown\n",
885                    XkbcAtomText(expr->value.str));
886         return ok;
887     case ExprFieldRef:
888         ERROR("Default \"%s.%s\" of type int is unknown\n",
889               XkbcAtomText(expr->value.field.element),
890               XkbcAtomText(expr->value.field.field));
891         return False;
892     case ExprArrayRef:
893         bogus = "array reference";
894     case ExprActionDecl:
895         if (bogus == NULL)
896             bogus = "function use";
897         ERROR("Unexpected %s in mask expression\n", bogus);
898         ACTION("Expression ignored\n");
899         return False;
900     case OpAdd:
901     case OpSubtract:
902     case OpMultiply:
903     case OpDivide:
904         left = expr->value.binary.left;
905         right = expr->value.binary.right;
906         if (ExprResolveMaskLookup(left, &leftRtrn, lookup, lookupPriv) &&
907             ExprResolveMaskLookup(right, &rightRtrn, lookup, lookupPriv))
908         {
909             switch (expr->op)
910             {
911             case OpAdd:
912                 val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
913                 break;
914             case OpSubtract:
915                 val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
916                 break;
917             case OpMultiply:
918             case OpDivide:
919                 ERROR("Cannot %s masks\n",
920                        expr->op == OpDivide ? "divide" : "multiply");
921                 ACTION("Illegal operation ignored\n");
922                 return False;
923             }
924             return True;
925         }
926         return False;
927     case OpAssign:
928         WSGO("Assignment operator not implemented yet\n");
929         break;
930     case OpInvert:
931         left = expr->value.child;
932         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
933         {
934             val_rtrn->ival = ~leftRtrn.ival;
935             return True;
936         }
937         return False;
938     case OpUnaryPlus:
939     case OpNegate:
940     case OpNot:
941         left = expr->value.child;
942         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
943         {
944             ERROR("The %s operator cannot be used with a mask\n",
945                    (expr->op == OpNegate ? "-" : "!"));
946         }
947         return False;
948     default:
949         WSGO("Unknown operator %d in ResolveMask\n", expr->op);
950         break;
951     }
952     return False;
953 }
954
955 int
956 ExprResolveMask(ExprDef * expr,
957                 ExprResult * val_rtrn,
958                 const LookupEntry * values)
959 {
960     return ExprResolveMaskLookup(expr, val_rtrn, SimpleLookup, values);
961 }
962
963 int
964 ExprResolveModMask(ExprDef * expr,
965                    ExprResult * val_rtrn)
966 {
967     return ExprResolveMaskLookup(expr, val_rtrn, LookupModMask, NULL);
968 }
969
970 int
971 ExprResolveVModMask(ExprDef * expr,
972                     ExprResult * val_rtrn,
973                     struct xkb_keymap *xkb)
974 {
975     return ExprResolveMaskLookup(expr, val_rtrn, LookupVModMask, xkb);
976 }
977
978 int
979 ExprResolveKeySym(ExprDef * expr,
980                   ExprResult * val_rtrn)
981 {
982     int ok = 0;
983     xkb_keysym_t sym;
984
985     if (expr->op == ExprIdent)
986     {
987         const char *str;
988         str = XkbcAtomText(expr->value.str);
989         if (str) {
990             sym = xkb_string_to_keysym(str);
991             if (sym != XKB_KEYSYM_NO_SYMBOL) {
992                 val_rtrn->uval = sym;
993                 return True;
994             }
995         }
996     }
997     ok = ExprResolveInteger(expr, val_rtrn);
998     if ((ok) && (val_rtrn->uval < 10))
999         val_rtrn->uval += '0';
1000     return ok;
1001 }