Commit dd29b14e1138172d4ff961e65235d86654072099

Ran Benita 2012-10-03T12:57:53

Remove the XKB_NUM_VIRTUAL_MODIFIERS limit Turn the virtual modifiers arrays in the keymap to a single darray, which doesn't use this limit. The number of virtual modifiers is still limited by the size of xkb_mod_mask_t, so we make sure not to go over that. Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/src/keymap-dump.c b/src/keymap-dump.c
index f591847..1ed1346 100644
--- a/src/keymap-dump.c
+++ b/src/keymap-dump.c
@@ -127,17 +127,15 @@ err:
 static bool
 write_vmods(struct xkb_keymap *keymap, struct buf *buf)
 {
-    xkb_mod_index_t i, num_vmods = 0;
+    const struct xkb_vmod *vmod;
+    xkb_mod_index_t num_vmods = 0;
 
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) {
-        if (!keymap->vmod_names[i])
-            continue;
+    darray_foreach(vmod, keymap->vmods) {
         if (num_vmods == 0)
             write_buf(buf, "\t\tvirtual_modifiers ");
         else
             write_buf(buf, ",");
-        write_buf(buf, "%s",
-                  xkb_atom_text(keymap->ctx, keymap->vmod_names[i]));
+        write_buf(buf, "%s", xkb_atom_text(keymap->ctx, vmod->name));
         num_vmods++;
     }
 
@@ -527,7 +525,8 @@ write_compat(struct xkb_keymap *keymap, struct buf *buf)
         if (interp->virtual_mod != XKB_MOD_INVALID) {
             write_buf(buf, "\t\t\tvirtualModifier= %s;\n",
                       xkb_atom_text(keymap->ctx,
-                                    keymap->vmod_names[interp->virtual_mod]));
+                                    darray_item(keymap->vmods,
+                                                interp->virtual_mod).name));
         }
 
         if (interp->match & MATCH_LEVEL_ONE_ONLY)
diff --git a/src/keymap.c b/src/keymap.c
index bc2632f..0471e3a 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -107,6 +107,7 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
     darray_free(keymap->sym_interpret);
     darray_free(keymap->key_aliases);
     darray_free(keymap->group_names);
+    darray_free(keymap->vmods);
     free(keymap->keycodes_section_name);
     free(keymap->symbols_section_name);
     free(keymap->types_section_name);
@@ -121,15 +122,9 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
 XKB_EXPORT xkb_mod_index_t
 xkb_keymap_num_mods(struct xkb_keymap *keymap)
 {
-    xkb_mod_index_t i;
-
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++)
-        if (!keymap->vmod_names[i])
-            break;
-
     /* We always have all the core modifiers (for now), plus any virtual
      * modifiers we may have defined. */
-    return i + XKB_NUM_CORE_MODS;
+    return XKB_NUM_CORE_MODS + darray_size(keymap->vmods);
 }
 
 /**
@@ -139,6 +134,7 @@ XKB_EXPORT const char *
 xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
 {
     const char *name;
+    const struct xkb_vmod *vmod;
 
     if (idx >= xkb_keymap_num_mods(keymap))
         return NULL;
@@ -146,11 +142,11 @@ xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
     /* First try to find a legacy modifier name.  If that fails, try to
      * find a virtual mod name. */
     name = ModIndexToName(idx);
-    if (!name)
-        name = xkb_atom_text(keymap->ctx,
-                             keymap->vmod_names[idx - XKB_NUM_CORE_MODS]);
+    if (name)
+        return name;
 
-    return name;
+    vmod = &darray_item(keymap->vmods, idx - XKB_NUM_CORE_MODS);
+    return xkb_atom_text(keymap->ctx, vmod->name);
 }
 
 /**
@@ -161,6 +157,7 @@ xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name)
 {
     xkb_mod_index_t i;
     xkb_atom_t atom;
+    const struct xkb_vmod *vmod;
 
     i = ModNameToIndex(name);
     if (i != XKB_MOD_INVALID)
@@ -170,12 +167,9 @@ xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name)
     if (atom == XKB_ATOM_NONE)
         return XKB_MOD_INVALID;
 
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) {
-        if (keymap->vmod_names[i] == XKB_ATOM_NONE)
-            break;
-        if (keymap->vmod_names[i] == atom)
+    darray_enumerate(i, vmod, keymap->vmods)
+        if (vmod->name == atom)
             return i + XKB_NUM_CORE_MODS;
-    }
 
     return XKB_MOD_INVALID;
 }
diff --git a/src/keymap.h b/src/keymap.h
index 62a8940..f50b091 100644
--- a/src/keymap.h
+++ b/src/keymap.h
@@ -103,9 +103,12 @@
  */
 #define XKB_NUM_GROUPS 4
 
+/* Don't allow more vmods than we can hold in xkb_mod_mask_t. */
+#define XKB_MAX_VIRTUAL_MODS \
+    ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * 8 - XKB_NUM_CORE_MODS))
+
 /* These should all be dynamic. */
 #define XKB_NUM_INDICATORS 32
-#define XKB_NUM_VIRTUAL_MODS 16
 #define XKB_NUM_CORE_MODS 8
 
 enum xkb_action_type {
@@ -355,6 +358,11 @@ struct xkb_key {
 
 typedef darray(xkb_atom_t) darray_xkb_atom_t;
 
+struct xkb_vmod {
+    xkb_atom_t name;
+    xkb_mod_mask_t mapping; /* vmod -> real mod mapping */
+};
+
 /* Common keyboard description structure */
 struct xkb_keymap {
     struct xkb_context *ctx;
@@ -378,9 +386,7 @@ struct xkb_keymap {
 
     darray(struct xkb_sym_interpret) sym_interpret;
 
-    /* vmod -> mod mapping */
-    xkb_mod_mask_t vmods[XKB_NUM_VIRTUAL_MODS];
-    xkb_atom_t vmod_names[XKB_NUM_VIRTUAL_MODS];
+    darray(struct xkb_vmod) vmods;
 
     /* Number of groups in the key with the most groups. */
     xkb_layout_index_t num_groups;
diff --git a/src/text.c b/src/text.c
index ad0a4d6..118820b 100644
--- a/src/text.c
+++ b/src/text.c
@@ -231,36 +231,14 @@ GetBuffer(size_t size)
     return rtrn;
 }
 
-/*
- * Get a vmod name's text, where the vmod index is zero based
- * (0..XKB_NUM_VIRTUAL_MODS-1).
- */
+/* Get a vmod name's text, where the vmod index is zero based. */
 static const char *
 VModIndexText(struct xkb_keymap *keymap, xkb_mod_index_t ndx)
 {
-    int len;
-    char *rtrn;
-    const char *tmp = NULL;
-    char buf[20];
-
-    if (ndx >= XKB_NUM_VIRTUAL_MODS)
-         tmp = "illegal";
-    else
-         tmp = xkb_atom_text(keymap->ctx, keymap->vmod_names[ndx]);
-
-    if (!tmp) {
-        snprintf(buf, sizeof(buf) - 1, "%d", ndx);
-        tmp = buf;
-    }
-
-    len = strlen(tmp) + 1;
-    if (len >= BUFFER_SIZE)
-        len = BUFFER_SIZE - 1;
-
-    rtrn = GetBuffer(len);
-    strncpy(rtrn, tmp, len);
-
-    return rtrn;
+    if (ndx >= darray_size(keymap->vmods))
+        return "illegal";
+    return xkb_atom_text(keymap->ctx,
+                         darray_item(keymap->vmods, ndx).name);
 }
 
 /* Get a mod mask's text, where the mask is in rmods+vmods format. */
@@ -268,7 +246,6 @@ const char *
 VModMaskText(struct xkb_keymap *keymap, xkb_mod_mask_t cmask)
 {
     xkb_mod_index_t i;
-    xkb_mod_mask_t bit;
     xkb_mod_mask_t rmask, vmask;
     int len, rem;
     const char *mm = NULL;
@@ -289,9 +266,8 @@ VModMaskText(struct xkb_keymap *keymap, xkb_mod_mask_t cmask)
     rem = BUFFER_SIZE;
 
     if (vmask != 0) {
-        for (i = 0, bit = 1; i < XKB_NUM_VIRTUAL_MODS && rem > 1; i++, bit <<=
-                 1) {
-            if (!(vmask & bit))
+        for (i = 0; i < darray_size(keymap->vmods) && rem > 1; i++) {
+            if (!(vmask & (1 << i)))
                 continue;
 
             len = snprintf(str, rem, "%s%s",
diff --git a/src/xkbcomp/keymap.c b/src/xkbcomp/keymap.c
index 8c3cf26..b9cfc17 100644
--- a/src/xkbcomp/keymap.c
+++ b/src/xkbcomp/keymap.c
@@ -32,17 +32,16 @@
 static void
 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
 {
+    const struct xkb_vmod *vmod;
     xkb_mod_index_t i;
     xkb_mod_mask_t vmask = mods->mods >> XKB_NUM_CORE_MODS;
 
     /* The effective mask is only real mods for now. */
     mods->mask = mods->mods & 0xff;
 
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) {
-        if (!(vmask & (1 << i)))
-            continue;
-        mods->mask |= keymap->vmods[i];
-    }
+    darray_enumerate(i, vmod, keymap->vmods)
+        if (vmask & (1 << i))
+            mods->mask |= vmod->mapping;
 }
 
 static void
@@ -186,7 +185,7 @@ ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
 static bool
 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
 {
-    xkb_mod_index_t vmod;
+    struct xkb_vmod *vmod;
     xkb_led_index_t led;
     unsigned int i, j;
     struct xkb_key *key;
@@ -198,19 +197,10 @@ UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
             return false;
 
     /* Update keymap->vmods, the virtual -> real mod mapping. */
-    for (vmod = 0; vmod < XKB_NUM_VIRTUAL_MODS; vmod++)
-        keymap->vmods[vmod] = 0;
-
-    xkb_foreach_key(key, keymap) {
-        if (!key->vmodmap)
-            continue;
-
-        for (vmod = 0; vmod < XKB_NUM_VIRTUAL_MODS; vmod++) {
-            if (!(key->vmodmap & (1 << vmod)))
-                continue;
-            keymap->vmods[vmod] |= key->modmap;
-        }
-    }
+    xkb_foreach_key(key, keymap)
+        darray_enumerate(i, vmod, keymap->vmods)
+            if (key->vmodmap & (1 << i))
+                vmod->mapping |= key->modmap;
 
     /* Now update the level masks for all the types to reflect the vmods. */
     for (i = 0; i < keymap->num_types; i++) {
diff --git a/src/xkbcomp/vmod.c b/src/xkbcomp/vmod.c
index 3a517ff..a1d6bf0 100644
--- a/src/xkbcomp/vmod.c
+++ b/src/xkbcomp/vmod.c
@@ -35,9 +35,8 @@ InitVModInfo(VModInfo *info, struct xkb_keymap *keymap)
     xkb_mod_index_t i;
 
     memset(info, 0, sizeof(*info));
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++)
-        if (keymap->vmod_names[i])
-            info->defined |= (1 << i);
+    for (i = 0; i < darray_size(keymap->vmods); i++)
+        info->defined |= (1 << i);
 }
 
 bool
@@ -45,44 +44,32 @@ HandleVModDef(VModDef *stmt, struct xkb_keymap *keymap,
               enum merge_mode mergeMode, VModInfo *info)
 {
     xkb_mod_index_t i;
-    int nextFree;
-    xkb_mod_mask_t bit;
+    const struct xkb_vmod *vmod;
+    struct xkb_vmod new;
 
     if (stmt->value)
         log_err(keymap->ctx,
                 "Support for setting a value in a virtual_modifiers statement has been removed; "
                 "Value ignored\n");
 
-    nextFree = -1;
-    for (i = 0, bit = 1; i < XKB_NUM_VIRTUAL_MODS; i++, bit <<= 1) {
-        if (!(info->defined & bit)) {
-            if (nextFree < 0)
-                nextFree = i;
-            continue;
+    darray_enumerate(i, vmod, keymap->vmods) {
+        if (vmod->name == stmt->name) {
+            info->available |= 1 << i;
+            return true;
         }
-
-        /* Already defined. */
-        if (!keymap->vmod_names[i])
-            continue;
-
-        if (keymap->vmod_names[i] != stmt->name)
-            continue;
-
-        info->available |= bit;
-        return true;
     }
 
-    if (nextFree < 0) {
+    if (darray_size(keymap->vmods) >= XKB_MAX_VIRTUAL_MODS) {
         log_err(keymap->ctx,
                 "Too many virtual modifiers defined (maximum %d)\n",
-                XKB_NUM_VIRTUAL_MODS);
+                XKB_MAX_VIRTUAL_MODS);
         return false;
     }
 
-    info->defined |= (1 << nextFree);
-    info->available |= (1 << nextFree);
-
-    keymap->vmod_names[nextFree] = stmt->name;
+    new.name = stmt->name;
+    new.mapping = 0;
+    darray_append(keymap->vmods, new);
+    info->available |= (1 << (darray_size(keymap->vmods) - 1));
     return true;
 }
 
@@ -90,13 +77,14 @@ static bool
 LookupVModIndex(const struct xkb_keymap *keymap, xkb_atom_t field,
                 enum expr_value_type type, xkb_mod_index_t *val_rtrn)
 {
+    const struct xkb_vmod *vmod;
     xkb_mod_index_t i;
 
     if (type != EXPR_TYPE_INT)
         return false;
 
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) {
-        if (keymap->vmod_names[i] == field) {
+    darray_enumerate(i, vmod, keymap->vmods) {
+        if (vmod->name == field) {
             *val_rtrn = i;
             return true;
         }
@@ -126,6 +114,7 @@ bool
 ResolveVirtualModifier(ExprDef *def, struct xkb_keymap *keymap,
                        xkb_mod_index_t *ndx_rtrn, VModInfo *info)
 {
+    const struct xkb_vmod *vmod;
     xkb_mod_index_t i;
     xkb_atom_t name = def->value.str;
 
@@ -137,8 +126,8 @@ ResolveVirtualModifier(ExprDef *def, struct xkb_keymap *keymap,
         return false;
     }
 
-    for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) {
-        if ((info->available & (1 << i)) && keymap->vmod_names[i] == name) {
+    darray_enumerate(i, vmod, keymap->vmods) {
+        if ((info->available & (1 << i)) && vmod->name == name) {
             *ndx_rtrn = i;
             return true;
         }