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 "config.h"
28 
29 #include "xkbcomp-priv.h"
30 #include "text.h"
31 #include "expr.h"
32 
33 typedef bool (*IdentLookupFunc)(struct xkb_context *ctx, const void *priv,
34                                 xkb_atom_t field, enum expr_value_type type,
35                                 unsigned int *val_rtrn);
36 
37 bool
ExprResolveLhs(struct xkb_context * ctx,const ExprDef * expr,const char ** elem_rtrn,const char ** field_rtrn,ExprDef ** index_rtrn)38 ExprResolveLhs(struct xkb_context *ctx, const ExprDef *expr,
39                const char **elem_rtrn, const char **field_rtrn,
40                ExprDef **index_rtrn)
41 {
42     switch (expr->expr.op) {
43     case EXPR_IDENT:
44         *elem_rtrn = NULL;
45         *field_rtrn = xkb_atom_text(ctx, expr->ident.ident);
46         *index_rtrn = NULL;
47         return (*field_rtrn != NULL);
48     case EXPR_FIELD_REF:
49         *elem_rtrn = xkb_atom_text(ctx, expr->field_ref.element);
50         *field_rtrn = xkb_atom_text(ctx, expr->field_ref.field);
51         *index_rtrn = NULL;
52         return (*elem_rtrn != NULL && *field_rtrn != NULL);
53     case EXPR_ARRAY_REF:
54         *elem_rtrn = xkb_atom_text(ctx, expr->array_ref.element);
55         *field_rtrn = xkb_atom_text(ctx, expr->array_ref.field);
56         *index_rtrn = expr->array_ref.entry;
57         if (expr->array_ref.element != XKB_ATOM_NONE && *elem_rtrn == NULL)
58             return false;
59         if (*field_rtrn == NULL)
60             return false;
61         return true;
62     default:
63         break;
64     }
65     log_wsgo(ctx, "Unexpected operator %d in ResolveLhs\n", expr->expr.op);
66     return false;
67 }
68 
69 static bool
SimpleLookup(struct xkb_context * ctx,const void * priv,xkb_atom_t field,enum expr_value_type type,unsigned int * val_rtrn)70 SimpleLookup(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
71              enum expr_value_type type, unsigned int *val_rtrn)
72 {
73     const LookupEntry *entry;
74     const char *str;
75 
76     if (!priv || field == XKB_ATOM_NONE || type != EXPR_TYPE_INT)
77         return false;
78 
79     str = xkb_atom_text(ctx, field);
80     for (entry = priv; entry && entry->name; entry++) {
81         if (istreq(str, entry->name)) {
82             *val_rtrn = entry->value;
83             return true;
84         }
85     }
86 
87     return false;
88 }
89 
90 /* Data passed in the *priv argument for LookupModMask. */
91 typedef struct {
92     const struct xkb_mod_set *mods;
93     enum mod_type mod_type;
94 } LookupModMaskPriv;
95 
96 static bool
LookupModMask(struct xkb_context * ctx,const void * priv,xkb_atom_t field,enum expr_value_type type,xkb_mod_mask_t * val_rtrn)97 LookupModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
98               enum expr_value_type type, xkb_mod_mask_t *val_rtrn)
99 {
100     const char *str;
101     xkb_mod_index_t ndx;
102     const LookupModMaskPriv *arg = priv;
103     const struct xkb_mod_set *mods = arg->mods;
104     enum mod_type mod_type = arg->mod_type;
105 
106     if (type != EXPR_TYPE_INT)
107         return false;
108 
109     str = xkb_atom_text(ctx, field);
110     if (!str)
111         return false;
112 
113     if (istreq(str, "all")) {
114         *val_rtrn  = MOD_REAL_MASK_ALL;
115         return true;
116     }
117 
118     if (istreq(str, "none")) {
119         *val_rtrn = 0;
120         return true;
121     }
122 
123     ndx = XkbModNameToIndex(mods, field, mod_type);
124     if (ndx == XKB_MOD_INVALID)
125         return false;
126 
127     *val_rtrn = (1u << ndx);
128     return true;
129 }
130 
131 bool
ExprResolveBoolean(struct xkb_context * ctx,const ExprDef * expr,bool * set_rtrn)132 ExprResolveBoolean(struct xkb_context *ctx, const ExprDef *expr,
133                    bool *set_rtrn)
134 {
135     bool ok = false;
136     const char *ident;
137 
138     switch (expr->expr.op) {
139     case EXPR_VALUE:
140         if (expr->expr.value_type != EXPR_TYPE_BOOLEAN) {
141             log_err(ctx,
142                     "Found constant of type %s where boolean was expected\n",
143                     expr_value_type_to_string(expr->expr.value_type));
144             return false;
145         }
146         *set_rtrn = expr->boolean.set;
147         return true;
148 
149     case EXPR_IDENT:
150         ident = xkb_atom_text(ctx, expr->ident.ident);
151         if (ident) {
152             if (istreq(ident, "true") ||
153                 istreq(ident, "yes") ||
154                 istreq(ident, "on")) {
155                 *set_rtrn = true;
156                 return true;
157             }
158             else if (istreq(ident, "false") ||
159                      istreq(ident, "no") ||
160                      istreq(ident, "off")) {
161                 *set_rtrn = false;
162                 return true;
163             }
164         }
165         log_err(ctx, "Identifier \"%s\" of type boolean is unknown\n", ident);
166         return false;
167 
168     case EXPR_FIELD_REF:
169         log_err(ctx, "Default \"%s.%s\" of type boolean is unknown\n",
170                 xkb_atom_text(ctx, expr->field_ref.element),
171                 xkb_atom_text(ctx, expr->field_ref.field));
172         return false;
173 
174     case EXPR_INVERT:
175     case EXPR_NOT:
176         ok = ExprResolveBoolean(ctx, expr->unary.child, set_rtrn);
177         if (ok)
178             *set_rtrn = !*set_rtrn;
179         return ok;
180     case EXPR_ADD:
181     case EXPR_SUBTRACT:
182     case EXPR_MULTIPLY:
183     case EXPR_DIVIDE:
184     case EXPR_ASSIGN:
185     case EXPR_NEGATE:
186     case EXPR_UNARY_PLUS:
187     case EXPR_ACTION_DECL:
188     case EXPR_ACTION_LIST:
189     case EXPR_KEYSYM_LIST:
190         log_err(ctx, "%s of boolean values not permitted\n",
191                 expr_op_type_to_string(expr->expr.op));
192         break;
193 
194     default:
195         log_wsgo(ctx, "Unknown operator %d in ResolveBoolean\n",
196                  expr->expr.op);
197         break;
198     }
199 
200     return false;
201 }
202 
203 bool
ExprResolveKeyCode(struct xkb_context * ctx,const ExprDef * expr,xkb_keycode_t * kc)204 ExprResolveKeyCode(struct xkb_context *ctx, const ExprDef *expr,
205                    xkb_keycode_t *kc)
206 {
207     xkb_keycode_t leftRtrn, rightRtrn;
208 
209     switch (expr->expr.op) {
210     case EXPR_VALUE:
211         if (expr->expr.value_type != EXPR_TYPE_INT) {
212             log_err(ctx,
213                     "Found constant of type %s where an int was expected\n",
214                     expr_value_type_to_string(expr->expr.value_type));
215             return false;
216         }
217 
218         *kc = (xkb_keycode_t) expr->integer.ival;
219         return true;
220 
221     case EXPR_ADD:
222     case EXPR_SUBTRACT:
223     case EXPR_MULTIPLY:
224     case EXPR_DIVIDE:
225         if (!ExprResolveKeyCode(ctx, expr->binary.left, &leftRtrn) ||
226             !ExprResolveKeyCode(ctx, expr->binary.right, &rightRtrn))
227             return false;
228 
229         switch (expr->expr.op) {
230         case EXPR_ADD:
231             *kc = leftRtrn + rightRtrn;
232             break;
233         case EXPR_SUBTRACT:
234             *kc = leftRtrn - rightRtrn;
235             break;
236         case EXPR_MULTIPLY:
237             *kc = leftRtrn * rightRtrn;
238             break;
239         case EXPR_DIVIDE:
240             if (rightRtrn == 0) {
241                 log_err(ctx, "Cannot divide by zero: %d / %d\n",
242                         leftRtrn, rightRtrn);
243                 return false;
244             }
245 
246             *kc = leftRtrn / rightRtrn;
247             break;
248         default:
249             break;
250         }
251 
252         return true;
253 
254     case EXPR_NEGATE:
255         if (!ExprResolveKeyCode(ctx, expr->unary.child, &leftRtrn))
256             return false;
257 
258         *kc = ~leftRtrn;
259         return true;
260 
261     case EXPR_UNARY_PLUS:
262         return ExprResolveKeyCode(ctx, expr->unary.child, kc);
263 
264     default:
265         log_wsgo(ctx, "Unknown operator %d in ResolveKeyCode\n",
266                  expr->expr.op);
267         break;
268     }
269 
270     return false;
271 }
272 
273 /**
274  * This function returns ... something.  It's a bit of a guess, really.
275  *
276  * If an integer is given in value ctx, it will be returned in ival.
277  * If an ident or field reference is given, the lookup function (if given)
278  * will be called.  At the moment, only SimpleLookup use this, and they both
279  * return the results in uval.  And don't support field references.
280  *
281  * Cool.
282  */
283 static bool
ExprResolveIntegerLookup(struct xkb_context * ctx,const ExprDef * expr,int * val_rtrn,IdentLookupFunc lookup,const void * lookupPriv)284 ExprResolveIntegerLookup(struct xkb_context *ctx, const ExprDef *expr,
285                          int *val_rtrn, IdentLookupFunc lookup,
286                          const void *lookupPriv)
287 {
288     bool ok = false;
289     int l, r;
290     unsigned u;
291     ExprDef *left, *right;
292 
293     switch (expr->expr.op) {
294     case EXPR_VALUE:
295         if (expr->expr.value_type != EXPR_TYPE_INT) {
296             log_err(ctx,
297                     "Found constant of type %s where an int was expected\n",
298                     expr_value_type_to_string(expr->expr.value_type));
299             return false;
300         }
301 
302         *val_rtrn = expr->integer.ival;
303         return true;
304 
305     case EXPR_IDENT:
306         if (lookup)
307             ok = lookup(ctx, lookupPriv, expr->ident.ident, EXPR_TYPE_INT, &u);
308 
309         if (!ok)
310             log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
311                     xkb_atom_text(ctx, expr->ident.ident));
312         else
313             *val_rtrn = (int) u;
314 
315         return ok;
316 
317     case EXPR_FIELD_REF:
318         log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
319                 xkb_atom_text(ctx, expr->field_ref.element),
320                 xkb_atom_text(ctx, expr->field_ref.field));
321         return false;
322 
323     case EXPR_ADD:
324     case EXPR_SUBTRACT:
325     case EXPR_MULTIPLY:
326     case EXPR_DIVIDE:
327         left = expr->binary.left;
328         right = expr->binary.right;
329         if (!ExprResolveIntegerLookup(ctx, left, &l, lookup, lookupPriv) ||
330             !ExprResolveIntegerLookup(ctx, right, &r, lookup, lookupPriv))
331             return false;
332 
333         switch (expr->expr.op) {
334         case EXPR_ADD:
335             *val_rtrn = l + r;
336             break;
337         case EXPR_SUBTRACT:
338             *val_rtrn = l - r;
339             break;
340         case EXPR_MULTIPLY:
341             *val_rtrn = l * r;
342             break;
343         case EXPR_DIVIDE:
344             if (r == 0) {
345                 log_err(ctx, "Cannot divide by zero: %d / %d\n", l, r);
346                 return false;
347             }
348             *val_rtrn = l / r;
349             break;
350         default:
351             log_err(ctx, "%s of integers not permitted\n",
352                     expr_op_type_to_string(expr->expr.op));
353             return false;
354         }
355 
356         return true;
357 
358     case EXPR_ASSIGN:
359         log_wsgo(ctx, "Assignment operator not implemented yet\n");
360         break;
361 
362     case EXPR_NOT:
363         log_err(ctx, "The ! operator cannot be applied to an integer\n");
364         return false;
365 
366     case EXPR_INVERT:
367     case EXPR_NEGATE:
368         left = expr->unary.child;
369         if (!ExprResolveIntegerLookup(ctx, left, &l, lookup, lookupPriv))
370             return false;
371 
372         *val_rtrn = (expr->expr.op == EXPR_NEGATE ? -l : ~l);
373         return true;
374 
375     case EXPR_UNARY_PLUS:
376         left = expr->unary.child;
377         return ExprResolveIntegerLookup(ctx, left, val_rtrn, lookup,
378                                         lookupPriv);
379 
380     default:
381         log_wsgo(ctx, "Unknown operator %d in ResolveInteger\n",
382                  expr->expr.op);
383         break;
384     }
385 
386     return false;
387 }
388 
389 bool
ExprResolveInteger(struct xkb_context * ctx,const ExprDef * expr,int * val_rtrn)390 ExprResolveInteger(struct xkb_context *ctx, const ExprDef *expr,
391                    int *val_rtrn)
392 {
393     return ExprResolveIntegerLookup(ctx, expr, val_rtrn, NULL, NULL);
394 }
395 
396 bool
ExprResolveGroup(struct xkb_context * ctx,const ExprDef * expr,xkb_layout_index_t * group_rtrn)397 ExprResolveGroup(struct xkb_context *ctx, const ExprDef *expr,
398                  xkb_layout_index_t *group_rtrn)
399 {
400     bool ok;
401     int result;
402 
403     ok = ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup,
404                                   groupNames);
405     if (!ok)
406         return false;
407 
408     if (result <= 0 || result > XKB_MAX_GROUPS) {
409         log_err(ctx, "Group index %u is out of range (1..%d)\n",
410                 result, XKB_MAX_GROUPS);
411         return false;
412     }
413 
414     *group_rtrn = (xkb_layout_index_t) result;
415     return true;
416 }
417 
418 bool
ExprResolveLevel(struct xkb_context * ctx,const ExprDef * expr,xkb_level_index_t * level_rtrn)419 ExprResolveLevel(struct xkb_context *ctx, const ExprDef *expr,
420                  xkb_level_index_t *level_rtrn)
421 {
422     bool ok;
423     int result;
424 
425     ok = ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup,
426                                   levelNames);
427     if (!ok)
428         return false;
429 
430     if (result < 1) {
431         log_err(ctx, "Shift level %d is out of range\n", result);
432         return false;
433     }
434 
435     /* Level is zero-indexed from now on. */
436     *level_rtrn = (unsigned int) (result - 1);
437     return true;
438 }
439 
440 bool
ExprResolveButton(struct xkb_context * ctx,const ExprDef * expr,int * btn_rtrn)441 ExprResolveButton(struct xkb_context *ctx, const ExprDef *expr, int *btn_rtrn)
442 {
443     return ExprResolveIntegerLookup(ctx, expr, btn_rtrn, SimpleLookup,
444                                     buttonNames);
445 }
446 
447 bool
ExprResolveString(struct xkb_context * ctx,const ExprDef * expr,xkb_atom_t * val_rtrn)448 ExprResolveString(struct xkb_context *ctx, const ExprDef *expr,
449                   xkb_atom_t *val_rtrn)
450 {
451     switch (expr->expr.op) {
452     case EXPR_VALUE:
453         if (expr->expr.value_type != EXPR_TYPE_STRING) {
454             log_err(ctx, "Found constant of type %s, expected a string\n",
455                     expr_value_type_to_string(expr->expr.value_type));
456             return false;
457         }
458 
459         *val_rtrn = expr->string.str;
460         return true;
461 
462     case EXPR_IDENT:
463         log_err(ctx, "Identifier \"%s\" of type string not found\n",
464                 xkb_atom_text(ctx, expr->ident.ident));
465         return false;
466 
467     case EXPR_FIELD_REF:
468         log_err(ctx, "Default \"%s.%s\" of type string not found\n",
469                 xkb_atom_text(ctx, expr->field_ref.element),
470                 xkb_atom_text(ctx, expr->field_ref.field));
471         return false;
472 
473     case EXPR_ADD:
474     case EXPR_SUBTRACT:
475     case EXPR_MULTIPLY:
476     case EXPR_DIVIDE:
477     case EXPR_ASSIGN:
478     case EXPR_NEGATE:
479     case EXPR_INVERT:
480     case EXPR_NOT:
481     case EXPR_UNARY_PLUS:
482     case EXPR_ACTION_DECL:
483     case EXPR_ACTION_LIST:
484     case EXPR_KEYSYM_LIST:
485         log_err(ctx, "%s of strings not permitted\n",
486                 expr_op_type_to_string(expr->expr.op));
487         return false;
488 
489     default:
490         log_wsgo(ctx, "Unknown operator %d in ResolveString\n",
491                  expr->expr.op);
492         break;
493     }
494     return false;
495 }
496 
497 bool
ExprResolveEnum(struct xkb_context * ctx,const ExprDef * expr,unsigned int * val_rtrn,const LookupEntry * values)498 ExprResolveEnum(struct xkb_context *ctx, const ExprDef *expr,
499                 unsigned int *val_rtrn, const LookupEntry *values)
500 {
501     if (expr->expr.op != EXPR_IDENT) {
502         log_err(ctx, "Found a %s where an enumerated value was expected\n",
503                 expr_op_type_to_string(expr->expr.op));
504         return false;
505     }
506 
507     if (!SimpleLookup(ctx, values, expr->ident.ident, EXPR_TYPE_INT,
508                       val_rtrn)) {
509         log_err(ctx, "Illegal identifier %s; expected one of:\n",
510                 xkb_atom_text(ctx, expr->ident.ident));
511         while (values && values->name)
512         {
513             log_err(ctx, "\t%s\n", values->name);
514             values++;
515         }
516         return false;
517     }
518 
519     return true;
520 }
521 
522 static bool
ExprResolveMaskLookup(struct xkb_context * ctx,const ExprDef * expr,unsigned int * val_rtrn,IdentLookupFunc lookup,const void * lookupPriv)523 ExprResolveMaskLookup(struct xkb_context *ctx, const ExprDef *expr,
524                       unsigned int *val_rtrn, IdentLookupFunc lookup,
525                       const void *lookupPriv)
526 {
527     bool ok = false;
528     unsigned int l = 0, r = 0;
529     int v;
530     ExprDef *left, *right;
531     const char *bogus = NULL;
532 
533     switch (expr->expr.op) {
534     case EXPR_VALUE:
535         if (expr->expr.value_type != EXPR_TYPE_INT) {
536             log_err(ctx,
537                     "Found constant of type %s where a mask was expected\n",
538                     expr_value_type_to_string(expr->expr.value_type));
539             return false;
540         }
541         *val_rtrn = (unsigned int) expr->integer.ival;
542         return true;
543 
544     case EXPR_IDENT:
545         ok = lookup(ctx, lookupPriv, expr->ident.ident, EXPR_TYPE_INT,
546                     val_rtrn);
547         if (!ok)
548             log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
549                     xkb_atom_text(ctx, expr->ident.ident));
550         return ok;
551 
552     case EXPR_FIELD_REF:
553         log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
554                 xkb_atom_text(ctx, expr->field_ref.element),
555                 xkb_atom_text(ctx, expr->field_ref.field));
556         return false;
557 
558     case EXPR_ARRAY_REF:
559         bogus = "array reference";
560         /* fallthrough */
561     case EXPR_ACTION_DECL:
562         if (bogus == NULL)
563             bogus = "function use";
564         log_err(ctx,
565                 "Unexpected %s in mask expression; Expression Ignored\n",
566                 bogus);
567         return false;
568 
569     case EXPR_ADD:
570     case EXPR_SUBTRACT:
571     case EXPR_MULTIPLY:
572     case EXPR_DIVIDE:
573         left = expr->binary.left;
574         right = expr->binary.right;
575         if (!ExprResolveMaskLookup(ctx, left, &l, lookup, lookupPriv) ||
576             !ExprResolveMaskLookup(ctx, right, &r, lookup, lookupPriv))
577             return false;
578 
579         switch (expr->expr.op) {
580         case EXPR_ADD:
581             *val_rtrn = l | r;
582             break;
583         case EXPR_SUBTRACT:
584             *val_rtrn = l & (~r);
585             break;
586         case EXPR_MULTIPLY:
587         case EXPR_DIVIDE:
588             log_err(ctx, "Cannot %s masks; Illegal operation ignored\n",
589                     (expr->expr.op == EXPR_DIVIDE ? "divide" : "multiply"));
590             return false;
591         default:
592             break;
593         }
594 
595         return true;
596 
597     case EXPR_ASSIGN:
598         log_wsgo(ctx, "Assignment operator not implemented yet\n");
599         break;
600 
601     case EXPR_INVERT:
602         left = expr->unary.child;
603         if (!ExprResolveIntegerLookup(ctx, left, &v, lookup, lookupPriv))
604             return false;
605 
606         *val_rtrn = ~v;
607         return true;
608 
609     case EXPR_UNARY_PLUS:
610     case EXPR_NEGATE:
611     case EXPR_NOT:
612         left = expr->unary.child;
613         if (!ExprResolveIntegerLookup(ctx, left, &v, lookup, lookupPriv))
614             log_err(ctx, "The %s operator cannot be used with a mask\n",
615                     (expr->expr.op == EXPR_NEGATE ? "-" : "!"));
616         return false;
617 
618     default:
619         log_wsgo(ctx, "Unknown operator %d in ResolveMask\n",
620                  expr->expr.op);
621         break;
622     }
623 
624     return false;
625 }
626 
627 bool
ExprResolveMask(struct xkb_context * ctx,const ExprDef * expr,unsigned int * mask_rtrn,const LookupEntry * values)628 ExprResolveMask(struct xkb_context *ctx, const ExprDef *expr,
629                 unsigned int *mask_rtrn, const LookupEntry *values)
630 {
631     return ExprResolveMaskLookup(ctx, expr, mask_rtrn, SimpleLookup, values);
632 }
633 
634 bool
ExprResolveModMask(struct xkb_context * ctx,const ExprDef * expr,enum mod_type mod_type,const struct xkb_mod_set * mods,xkb_mod_mask_t * mask_rtrn)635 ExprResolveModMask(struct xkb_context *ctx, const ExprDef *expr,
636                    enum mod_type mod_type, const struct xkb_mod_set *mods,
637                    xkb_mod_mask_t *mask_rtrn)
638 {
639     LookupModMaskPriv priv = { .mods = mods, .mod_type = mod_type };
640     return ExprResolveMaskLookup(ctx, expr, mask_rtrn, LookupModMask, &priv);
641 }
642 
643 bool
ExprResolveKeySym(struct xkb_context * ctx,const ExprDef * expr,xkb_keysym_t * sym_rtrn)644 ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr,
645                   xkb_keysym_t *sym_rtrn)
646 {
647     int val;
648 
649     if (expr->expr.op == EXPR_IDENT) {
650         const char *str = xkb_atom_text(ctx, expr->ident.ident);
651         *sym_rtrn = xkb_keysym_from_name(str, 0);
652         if (*sym_rtrn != XKB_KEY_NoSymbol)
653             return true;
654     }
655 
656     if (!ExprResolveInteger(ctx, expr, &val))
657         return false;
658 
659     if (val < 0 || val >= 10)
660         return false;
661 
662     *sym_rtrn = XKB_KEY_0 + (xkb_keysym_t) val;
663     return true;
664 }
665 
666 bool
ExprResolveMod(struct xkb_context * ctx,const ExprDef * def,enum mod_type mod_type,const struct xkb_mod_set * mods,xkb_mod_index_t * ndx_rtrn)667 ExprResolveMod(struct xkb_context *ctx, const ExprDef *def,
668                enum mod_type mod_type, const struct xkb_mod_set *mods,
669                xkb_mod_index_t *ndx_rtrn)
670 {
671     xkb_mod_index_t ndx;
672     xkb_atom_t name;
673 
674     if (def->expr.op != EXPR_IDENT) {
675         log_err(ctx,
676                 "Cannot resolve virtual modifier: "
677                 "found %s where a virtual modifier name was expected\n",
678                 expr_op_type_to_string(def->expr.op));
679         return false;
680     }
681 
682     name = def->ident.ident;
683     ndx = XkbModNameToIndex(mods, name, mod_type);
684     if (ndx == XKB_MOD_INVALID) {
685         log_err(ctx,
686                 "Cannot resolve virtual modifier: "
687                 "\"%s\" was not previously declared\n",
688                 xkb_atom_text(ctx, name));
689         return false;
690     }
691 
692     *ndx_rtrn = ndx;
693     return true;
694 }
695