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