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