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