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