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