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