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