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