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