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