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