Home | History | Annotate | Download | only in xkbcomp
      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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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