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