Fix NULL after deref issue detected by static analysis tool
[platform/upstream/libxkbcommon.git] / src / xkbcomp / types.c
index 227d390..fa12c23 100644 (file)
  *
  ********************************************************/
 
+#include "config.h"
+
 #include "xkbcomp-priv.h"
 #include "text.h"
 #include "vmod.h"
 #include "expr.h"
 #include "include.h"
 
-/*
- * The xkb_types section
- * =====================
- * This section is the second to be processesed, after xkb_keycodes.
- * However, it is completely independent and could have been the first
- * to be processed (it does not refer to specific keys as specified in
- * the xkb_keycodes section).
- *
- * This section defines key types, which, given a key and a keyboard
- * state (i.e. modifier state and group), determine the shift level to
- * be used in translating the key to keysyms. These types are assigned
- * to each group in each key, in the xkb_symbols section.
- *
- * Key types are called this way because, in a way, they really describe
- * the "type" of the key (or more correctly, a specific group of the
- * key). For example, an ordinary keymap will provide a type called
- * "KEYPAD", which consists of two levels, with the second level being
- * chosen according to the state of the Num Lock (or Shift) modifiers.
- * Another example is a type called "ONE_LEVEL", which is usually
- * assigned to keys such as Escape; these have just one level and are
- * not affected by the modifier state. Yet more common examples are
- * "TWO_LEVEL" (with Shift choosing the second level), "ALPHABETIC"
- * (where Caps Lock may also choose the second level), etc.
- *
- * Type definitions
- * ----------------
- *  Statements of the form:
- *      type "FOUR_LEVEL" { ... }
- *
- * The above would create a new type named "FOUR_LEVEL".
- * The body of the definition may include statements of the following
- * forms:
- *
- * - level_name statements (mandatory for each level in the type):
- *      level_name[Level1] = "Base";
- *
- *   Gives each level in this type a descriptive name. It isn't used
- *   for any thing.
- *   Note: A level may be specified as Level[1-8] or just a number (can
- *   be more than 8).
- *
- * - modifiers statement (mandatory, should be specified only once):
- *      modifiers = Shift+Lock+LevelThree;
- *
- *   A mask of real and virtual modifiers. These are the only modifiers
- *   being considered when matching the modifier state against the type.
- *   The other modifiers, whether active or not, are masked out in the
- *   calculation.
- *
- * - map entry statements (should have at least as many mappings as there
- *   are levels in the type):
- *      map[Shift+LevelThree] = Level4;
- *
- *   If the active modifiers, masked with the type's modifiers (as stated
- *   above), match (i.e. equal) the modifiers inside the map[] statement,
- *   then the level in the right hand side is chosen. For example, in the
- *   above, if in the current keyboard state the Shift and LevelThree
- *   modifiers are active, while the Lock modifier is not, then the
- *   keysym(s) in the 4th level of the group will be returned to the
- *   user.
- *
- * - preserve statements:
- *      map[Shift+Lock+LevelThree] = Level5;
- *      preserve[Shift+Lock+LevelThree] = Lock;
- *
- *   When a map entry matches the active modifiers and the level it
- *   specified is chosen, then these modifiers are said to be "consumed";
- *   for example, in a simple US keymap where the "g" key is assigned an
- *   ordinary ALPHABETIC key type, if the Lock (Caps Lock) modifier is
- *   active and the key is pressed, then a "G" keysym is produced (as
- *   opposed to lower-case "g"). This is because the type definition has
- *   a map entry like the following:
- *      map[Lock] = Level2;
- *   And as such the Lock modifier is consumed. This information is
- *   relevant for applications which further process the modifiers,
- *   since by then the consumed modifiers have already "done their part"
- *   and should be masked out.
- *
- *   However, sometimes even if a modifier is actually used to choose
- *   the shift level (as Lock above), it should *not* be reported as
- *   consumed, for various reasons. In this case, a preserve[] statement
- *   can be used to augment the map entry. The modifiers inside the square
- *   brackets should match one of the map[] statements in the type. The
- *   right hand side should consists of modifiers from the left hand
- *   side; these modifiers are then "preserved" and not reported as
- *   consumed.
- *
- * Virtual modifier statements
- * ---------------------------
- * Statements of the form:
- *     virtual_modifiers LControl;
- *
- * Can appear in the xkb_types, xkb_compat, xkb_symbols sections.
- * TODO
- *
- * Effect on keymap
- * ----------------
- * After all of the xkb_types sections have been compiled, the following
- * members of struct xkb_keymap are finalized:
- *      struct xkb_key_type *types;
- *      unsigned int num_types;
- *      char *types_section_name;
- * TODO: virtual modifiers.
- */
-
 enum type_field {
-    TYPE_FIELD_MASK       = (1 << 0),
-    TYPE_FIELD_MAP        = (1 << 1),
-    TYPE_FIELD_PRESERVE   = (1 << 2),
+    TYPE_FIELD_MASK = (1 << 0),
+    TYPE_FIELD_MAP = (1 << 1),
+    TYPE_FIELD_PRESERVE = (1 << 2),
     TYPE_FIELD_LEVEL_NAME = (1 << 3),
 };
 
 typedef struct {
     enum type_field defined;
-    unsigned file_id;
     enum merge_mode merge;
 
     xkb_atom_t name;
     xkb_mod_mask_t mods;
     xkb_level_index_t num_levels;
-    darray(struct xkb_kt_map_entry) entries;
+    darray(struct xkb_key_type_entry) entries;
     darray(xkb_atom_t) level_names;
 } KeyTypeInfo;
 
 typedef struct {
     char *name;
     int errorCount;
-    unsigned file_id;
 
     darray(KeyTypeInfo) types;
-    struct xkb_keymap *keymap;
+    struct xkb_mod_set mods;
+
+    struct xkb_context *ctx;
 } KeyTypesInfo;
 
 /***====================================================================***/
 
 static inline const char *
-MapEntryTxt(KeyTypesInfo *info, struct xkb_kt_map_entry *entry)
+MapEntryTxt(KeyTypesInfo *info, struct xkb_key_type_entry *entry)
 {
-    return ModMaskText(info->keymap, entry->mods.mods);
+    return ModMaskText(info->ctx, &info->mods, entry->mods.mods);
 }
 
 static inline const char *
 TypeTxt(KeyTypesInfo *info, KeyTypeInfo *type)
 {
-    return xkb_atom_text(info->keymap->ctx, type->name);
+    return xkb_atom_text(info->ctx, type->name);
 }
 
 static inline const char *
 TypeMaskTxt(KeyTypesInfo *info, KeyTypeInfo *type)
 {
-    return ModMaskText(info->keymap, type->mods);
+    return ModMaskText(info->ctx, &info->mods, type->mods);
 }
 
 static inline bool
 ReportTypeShouldBeArray(KeyTypesInfo *info, KeyTypeInfo *type,
                         const char *field)
 {
-    return ReportShouldBeArray(info->keymap->ctx, "key type", field,
+    return ReportShouldBeArray(info->ctx, "key type", field,
                                TypeTxt(info, type));
 }
 
 static inline bool
-ReportTypeBadType(KeyTypesInfo *info, KeyTypeInfo *type,
-                  const char *field, const char *wanted)
+ReportTypeBadType(KeyTypesInfo *info, xkb_message_code_t code,
+                  KeyTypeInfo *type, const char *field, const char *wanted)
 {
-    return ReportBadType(info->keymap->ctx, "key type", field,
+    return ReportBadType(info->ctx, code, "key type", field,
                          TypeTxt(info, type), wanted);
 }
 
-static inline bool
-ReportTypeBadWidth(KeyTypesInfo *info, const char *type, int has, int needs)
-{
-    log_err(info->keymap->ctx,
-            "Key type \"%s\" has %d levels, must have %d; "
-            "Illegal type definition ignored\n",
-            type, has, needs);
-    return false;
-}
-
 /***====================================================================***/
 
 static void
-InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_keymap *keymap,
-                 unsigned file_id)
+InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_context *ctx,
+                 const struct xkb_mod_set *mods)
 {
     memset(info, 0, sizeof(*info));
-    info->keymap = keymap;
-    info->file_id = file_id;
+    info->ctx = ctx;
+    info->mods = *mods;
 }
 
 static void
@@ -247,20 +134,20 @@ FindMatchingKeyType(KeyTypesInfo *info, xkb_atom_t name)
 }
 
 static bool
-AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new)
+AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new, bool same_file)
 {
     KeyTypeInfo *old;
-    int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
+    const int verbosity = xkb_context_get_log_verbosity(info->ctx);
 
     old = FindMatchingKeyType(info, new->name);
     if (old) {
         if (new->merge == MERGE_REPLACE || new->merge == MERGE_OVERRIDE) {
-            if ((old->file_id == new->file_id && verbosity > 0) ||
-                verbosity > 9) {
-                log_warn(info->keymap->ctx,
+            if ((same_file && verbosity > 0) || verbosity > 9) {
+                log_warn(info->ctx,
+                         XKB_WARNING_CONFLICTING_KEY_TYPE_DEFINITIONS,
                          "Multiple definitions of the %s key type; "
                          "Earlier definition ignored\n",
-                         xkb_atom_text(info->keymap->ctx, new->name));
+                         xkb_atom_text(info->ctx, new->name));
             }
 
             ClearKeyTypeInfo(old);
@@ -270,17 +157,17 @@ AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new)
             return true;
         }
 
-        if (old->file_id == new->file_id)
-            log_vrb(info->keymap->ctx, 4,
+        if (same_file)
+            log_vrb(info->ctx, 4,
+                    XKB_WARNING_CONFLICTING_KEY_TYPE_DEFINITIONS,
                     "Multiple definitions of the %s key type; "
                     "Later definition ignored\n",
-                    xkb_atom_text(info->keymap->ctx, new->name));
+                    xkb_atom_text(info->ctx, new->name));
 
         ClearKeyTypeInfo(new);
         return true;
     }
 
-    new->file_id = info->file_id;
     darray_append(info->types, *new);
     return true;
 }
@@ -291,22 +178,29 @@ static void
 MergeIncludedKeyTypes(KeyTypesInfo *into, KeyTypesInfo *from,
                       enum merge_mode merge)
 {
-    KeyTypeInfo *type;
-
     if (from->errorCount > 0) {
         into->errorCount += from->errorCount;
         return;
     }
 
+    into->mods = from->mods;
+
     if (into->name == NULL) {
         into->name = from->name;
         from->name = NULL;
     }
 
-    darray_foreach(type, from->types) {
-        type->merge = (merge == MERGE_DEFAULT ? type->merge : merge);
-        if (!AddKeyType(into, type))
-            into->errorCount++;
+    if (darray_empty(into->types)) {
+        into->types = from->types;
+        darray_init(from->types);
+    }
+    else {
+        KeyTypeInfo *type;
+        darray_foreach(type, from->types) {
+            type->merge = (merge == MERGE_DEFAULT ? type->merge : merge);
+            if (!AddKeyType(into, type, false))
+                into->errorCount++;
+        }
     }
 }
 
@@ -314,38 +208,39 @@ static void
 HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge);
 
 static bool
-HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *stmt)
+HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include)
 {
-    enum merge_mode merge = MERGE_DEFAULT;
-    XkbFile *rtrn;
-    KeyTypesInfo included, next_incl;
-
-    InitKeyTypesInfo(&included, info->keymap, info->file_id);
-    if (stmt->stmt) {
-        free(included.name);
-        included.name = stmt->stmt;
-        stmt->stmt = NULL;
-    }
+    KeyTypesInfo included;
 
-    for (; stmt; stmt = stmt->next_incl) {
-        if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_TYPES,
-                                &rtrn, &merge)) {
+    if (!include)
+        return false;
+
+    InitKeyTypesInfo(&included, info->ctx, &info->mods);
+    included.name = include->stmt;
+    include->stmt = NULL;
+
+    for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
+        KeyTypesInfo next_incl;
+        XkbFile *file;
+
+        file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_TYPES);
+        if (!file) {
             info->errorCount += 10;
             ClearKeyTypesInfo(&included);
             return false;
         }
 
-        InitKeyTypesInfo(&next_incl, info->keymap, rtrn->id);
+        InitKeyTypesInfo(&next_incl, info->ctx, &included.mods);
 
-        HandleKeyTypesFile(&next_incl, rtrn, merge);
+        HandleKeyTypesFile(&next_incl, file, stmt->merge);
 
-        MergeIncludedKeyTypes(&included, &next_incl, merge);
+        MergeIncludedKeyTypes(&included, &next_incl, stmt->merge);
 
         ClearKeyTypesInfo(&next_incl);
-        FreeXkbFile(rtrn);
+        FreeXkbFile(file);
     }
 
-    MergeIncludedKeyTypes(info, &included, merge);
+    MergeIncludedKeyTypes(info, &included, include->merge);
     ClearKeyTypesInfo(&included);
 
     return (info->errorCount == 0);
@@ -360,24 +255,25 @@ SetModifiers(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
     xkb_mod_mask_t mods;
 
     if (arrayNdx)
-        log_warn(info->keymap->ctx,
+        log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID,
                  "The modifiers field of a key type is not an array; "
                  "Illegal array subscript ignored\n");
 
-    if (!ExprResolveModMask(info->keymap, value, MOD_BOTH, &mods)) {
-        log_err(info->keymap->ctx,
+    if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, &info->mods, &mods)) {
+        log_err(info->ctx,
+                XKB_ERROR_UNSUPPORTED_MODIFIER_MASK,
                 "Key type mask field must be a modifier mask; "
                 "Key type definition ignored\n");
         return false;
     }
 
     if (type->defined & TYPE_FIELD_MASK) {
-        log_warn(info->keymap->ctx,
+        log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID,
                  "Multiple modifier mask definitions for key type %s; "
                  "Using %s, ignoring %s\n",
-                 xkb_atom_text(info->keymap->ctx, type->name),
+                 xkb_atom_text(info->ctx, type->name),
                  TypeMaskTxt(info, type),
-                 ModMaskText(info->keymap, mods));
+                 ModMaskText(info->ctx, &info->mods, mods));
         return false;
     }
 
@@ -387,10 +283,10 @@ SetModifiers(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
 
 /***====================================================================***/
 
-static struct xkb_kt_map_entry *
+static struct xkb_key_type_entry *
 FindMatchingMapEntry(KeyTypeInfo *type, xkb_mod_mask_t mods)
 {
-    struct xkb_kt_map_entry *entry;
+    struct xkb_key_type_entry *entry;
 
     darray_foreach(entry, type->entries)
         if (entry->mods.mods == mods)
@@ -401,14 +297,15 @@ FindMatchingMapEntry(KeyTypeInfo *type, xkb_mod_mask_t mods)
 
 static bool
 AddMapEntry(KeyTypesInfo *info, KeyTypeInfo *type,
-            struct xkb_kt_map_entry *new, bool clobber, bool report)
+            struct xkb_key_type_entry *new, bool clobber, bool report)
 {
-    struct xkb_kt_map_entry * old;
+    struct xkb_key_type_entry *old;
 
     old = FindMatchingMapEntry(type, new->mods.mods);
     if (old) {
         if (report && old->level != new->level) {
-            log_warn(info->keymap->ctx,
+            log_warn(info->ctx,
+                     XKB_WARNING_CONFLICTING_KEY_TYPE_MAP_ENTRY,
                      "Multiple map entries for %s in %s; "
                      "Using %d, ignoring %d\n",
                      MapEntryTxt(info, new), TypeTxt(info, type),
@@ -416,8 +313,9 @@ AddMapEntry(KeyTypesInfo *info, KeyTypeInfo *type,
                      (clobber ? old->level : new->level) + 1);
         }
         else {
-            log_vrb(info->keymap->ctx, 10,
-                    "Multiple occurences of map[%s]= %d in %s; Ignored\n",
+            log_vrb(info->ctx, 10,
+                    XKB_WARNING_CONFLICTING_KEY_TYPE_MAP_ENTRY,
+                    "Multiple occurrences of map[%s]= %d in %s; Ignored\n",
                     MapEntryTxt(info, new), new->level + 1,
                     TypeTxt(info, type));
             return true;
@@ -443,28 +341,32 @@ static bool
 SetMapEntry(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
             ExprDef *value)
 {
-    struct xkb_kt_map_entry entry;
+    struct xkb_key_type_entry entry;
 
     if (arrayNdx == NULL)
         return ReportTypeShouldBeArray(info, type, "map entry");
 
-    if (!ExprResolveModMask(info->keymap, arrayNdx, MOD_BOTH, &entry.mods.mods))
-        return ReportTypeBadType(info, type, "map entry", "modifier mask");
+    if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods,
+                            &entry.mods.mods))
+        return ReportTypeBadType(info, XKB_ERROR_UNSUPPORTED_MODIFIER_MASK,
+                                 type, "map entry", "modifier mask");
 
     if (entry.mods.mods & (~type->mods)) {
-        log_vrb(info->keymap->ctx, 1,
-                "Map entry for unused modifiers in %s; "
+        log_vrb(info->ctx, 1,
+                XKB_WARNING_UNDECLARED_MODIFIERS_IN_KEY_TYPE,
+                "Map entry for modifiers not used by type %s; "
                 "Using %s instead of %s\n",
                 TypeTxt(info, type),
-                ModMaskText(info->keymap, entry.mods.mods & type->mods),
+                ModMaskText(info->ctx, &info->mods,
+                            entry.mods.mods & type->mods),
                 MapEntryTxt(info, &entry));
         entry.mods.mods &= type->mods;
     }
 
-    if (!ExprResolveLevel(info->keymap->ctx, value, &entry.level)) {
-        log_err(info->keymap->ctx,
-                "Level specifications in a key type must be integer; "
-                "Ignoring malformed level specification\n");
+    if (!ExprResolveLevel(info->ctx, value, &entry.level)) {
+        log_err(info->ctx, XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL,
+                          "Level specifications in a key type must be integer; "
+                          "Ignoring malformed level specification\n");
         return false;
     }
 
@@ -479,8 +381,8 @@ static bool
 AddPreserve(KeyTypesInfo *info, KeyTypeInfo *type,
             xkb_mod_mask_t mods, xkb_mod_mask_t preserve_mods)
 {
-    struct xkb_kt_map_entry *entry;
-    struct xkb_kt_map_entry new;
+    struct xkb_key_type_entry *entry;
+    struct xkb_key_type_entry new;
 
     darray_foreach(entry, type->entries) {
         if (entry->mods.mods != mods)
@@ -494,22 +396,24 @@ AddPreserve(KeyTypesInfo *info, KeyTypeInfo *type,
 
         /* Map exists with same preserve; do nothing. */
         if (entry->preserve.mods == preserve_mods) {
-            log_vrb(info->keymap->ctx, 10,
+            log_vrb(info->ctx, 10,
+                    XKB_WARNING_DUPLICATE_ENTRY,
                     "Identical definitions for preserve[%s] in %s; "
                     "Ignored\n",
-                    ModMaskText(info->keymap, mods),
+                    ModMaskText(info->ctx, &info->mods, mods),
                     TypeTxt(info, type));
             return true;
         }
 
         /* Map exists with different preserve; latter wins. */
-        log_vrb(info->keymap->ctx, 1,
+        log_vrb(info->ctx, 1,
+                XKB_WARNING_CONFLICTING_KEY_TYPE_PRESERVE_ENTRIES,
                 "Multiple definitions for preserve[%s] in %s; "
                 "Using %s, ignoring %s\n",
-                ModMaskText(info->keymap, mods),
+                ModMaskText(info->ctx, &info->mods, mods),
                 TypeTxt(info, type),
-                ModMaskText(info->keymap, preserve_mods),
-                ModMaskText(info->keymap, entry->preserve.mods));
+                ModMaskText(info->ctx, &info->mods, preserve_mods),
+                ModMaskText(info->ctx, &info->mods, entry->preserve.mods));
 
         entry->preserve.mods = preserve_mods;
         return true;
@@ -518,7 +422,7 @@ AddPreserve(KeyTypesInfo *info, KeyTypeInfo *type,
     /*
      * Map does not exist, i.e. preserve[] came before map[].
      * Create a map with the specified mask mapping to Level1. The level
-     * may be overriden later with an explicit map[] statement.
+     * may be overridden later with an explicit map[] statement.
      */
     new.level = 0;
     new.mods.mods = mods;
@@ -536,28 +440,31 @@ SetPreserve(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
     if (arrayNdx == NULL)
         return ReportTypeShouldBeArray(info, type, "preserve entry");
 
-    if (!ExprResolveModMask(info->keymap, arrayNdx, MOD_BOTH, &mods))
-        return ReportTypeBadType(info, type, "preserve entry",
-                                 "modifier mask");
+    if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods, &mods))
+        return ReportTypeBadType(info, XKB_ERROR_UNSUPPORTED_MODIFIER_MASK,
+                                 type, "preserve entry", "modifier mask");
 
     if (mods & ~type->mods) {
         const char *before, *after;
 
-        before = ModMaskText(info->keymap, mods);
+        before = ModMaskText(info->ctx, &info->mods, mods);
         mods &= type->mods;
-        after = ModMaskText(info->keymap, mods);
+        after = ModMaskText(info->ctx, &info->mods, mods);
 
-        log_vrb(info->keymap->ctx, 1,
-                "Preserve for modifiers not used by the %s type; "
+        log_vrb(info->ctx, 1,
+                XKB_WARNING_UNDECLARED_MODIFIERS_IN_KEY_TYPE,
+                "Preserve entry for modifiers not used by the %s type; "
                 "Index %s converted to %s\n",
                 TypeTxt(info, type), before, after);
     }
 
-    if (!ExprResolveModMask(info->keymap, value, MOD_BOTH, &preserve_mods)) {
-        log_err(info->keymap->ctx,
+    if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, &info->mods,
+                            &preserve_mods)) {
+        log_err(info->ctx,
+                XKB_ERROR_UNSUPPORTED_MODIFIER_MASK,
                 "Preserve value in a key type is not a modifier mask; "
                 "Ignoring preserve[%s] in type %s\n",
-                ModMaskText(info->keymap, mods),
+                ModMaskText(info->ctx, &info->mods, mods),
                 TypeTxt(info, type));
         return false;
     }
@@ -565,14 +472,15 @@ SetPreserve(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
     if (preserve_mods & ~mods) {
         const char *before, *after;
 
-        before = ModMaskText(info->keymap, preserve_mods);
+        before = ModMaskText(info->ctx, &info->mods, preserve_mods);
         preserve_mods &= mods;
-        after = ModMaskText(info->keymap, preserve_mods);
+        after = ModMaskText(info->ctx, &info->mods, preserve_mods);
 
-        log_vrb(info->keymap->ctx, 1,
+        log_vrb(info->ctx, 1,
+                XKB_WARNING_ILLEGAL_KEY_TYPE_PRESERVE_RESULT,
                 "Illegal value for preserve[%s] in type %s; "
                 "Converted %s to %s\n",
-                ModMaskText(info->keymap, mods),
+                ModMaskText(info->ctx, &info->mods, mods),
                 TypeTxt(info, type), before, after);
     }
 
@@ -593,7 +501,8 @@ AddLevelName(KeyTypesInfo *info, KeyTypeInfo *type,
 
     /* Same level, same name. */
     if (darray_item(type->level_names, level) == name) {
-        log_vrb(info->keymap->ctx, 10,
+        log_vrb(info->ctx, 10,
+                XKB_WARNING_DUPLICATE_ENTRY,
                 "Duplicate names for level %d of key type %s; Ignored\n",
                 level + 1, TypeTxt(info, type));
         return true;
@@ -602,10 +511,11 @@ AddLevelName(KeyTypesInfo *info, KeyTypeInfo *type,
     /* Same level, different name. */
     if (darray_item(type->level_names, level) != XKB_ATOM_NONE) {
         const char *old, *new;
-        old = xkb_atom_text(info->keymap->ctx,
+        old = xkb_atom_text(info->ctx,
                             darray_item(type->level_names, level));
-        new = xkb_atom_text(info->keymap->ctx, name);
-        log_vrb(info->keymap->ctx, 1,
+        new = xkb_atom_text(info->ctx, name);
+        log_vrb(info->ctx, 1,
+                XKB_WARNING_CONFLICTING_KEY_TYPE_LEVEL_NAMES,
                 "Multiple names for level %d of key type %s; "
                 "Using %s, ignoring %s\n",
                 level + 1, TypeTxt(info, type),
@@ -628,19 +538,20 @@ SetLevelName(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
 {
     xkb_level_index_t level;
     xkb_atom_t level_name;
-    struct xkb_context *ctx = info->keymap->ctx;
 
     if (arrayNdx == NULL)
         return ReportTypeShouldBeArray(info, type, "level name");
 
-    if (!ExprResolveLevel(ctx, arrayNdx, &level))
-        return ReportTypeBadType(info, type, "level name", "integer");
+    if (!ExprResolveLevel(info->ctx, arrayNdx, &level))
+        return ReportTypeBadType(info, XKB_ERROR_UNSUPPORTED_SHIFT_LEVEL,
+                                 type, "level name", "integer");
 
-    if (!ExprResolveString(ctx, value, &level_name)) {
-        log_err(info->keymap->ctx,
+    if (!ExprResolveString(info->ctx, value, &level_name)) {
+        log_err(info->ctx,
+                XKB_ERROR_WRONG_FIELD_TYPE,
                 "Non-string name for level %d in key type %s; "
                 "Ignoring illegal level name definition\n",
-                level + 1, xkb_atom_text(ctx, type->name));
+                level + 1, xkb_atom_text(info->ctx, type->name));
         return false;
     }
 
@@ -672,7 +583,8 @@ SetKeyTypeField(KeyTypesInfo *info, KeyTypeInfo *type,
         type_field = TYPE_FIELD_LEVEL_NAME;
         ok = SetLevelName(info, type, arrayNdx, value);
     } else {
-        log_err(info->keymap->ctx,
+        log_err(info->ctx,
+                XKB_ERROR_UNKNOWN_FIELD,
                 "Unknown field %s in key type %s; Definition ignored\n",
                 field, TypeTxt(info, type));
     }
@@ -689,13 +601,14 @@ HandleKeyTypeBody(KeyTypesInfo *info, VarDef *def, KeyTypeInfo *type)
     ExprDef *arrayNdx;
 
     for (; def; def = (VarDef *) def->common.next) {
-        ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
+        ok = ExprResolveLhs(info->ctx, def->name, &elem, &field,
                             &arrayNdx);
         if (!ok)
             continue;
 
         if (elem && istreq(elem, "type")) {
-            log_err(info->keymap->ctx,
+            log_err(info->ctx,
+                    XKB_ERROR_INVALID_SET_DEFAULT_STATEMENT,
                     "Support for changing the default type has been removed; "
                     "Statement ignored\n");
             continue;
@@ -712,7 +625,6 @@ HandleKeyTypeDef(KeyTypesInfo *info, KeyTypeDef *def, enum merge_mode merge)
 {
     KeyTypeInfo type = {
         .defined = 0,
-        .file_id = info->file_id,
         .merge = (def->merge == MERGE_DEFAULT ? merge : def->merge),
         .name = def->name,
         .mods = 0,
@@ -726,7 +638,7 @@ HandleKeyTypeDef(KeyTypesInfo *info, KeyTypeDef *def, enum merge_mode merge)
         return false;
     }
 
-    if (!AddKeyType(info, &type)) {
+    if (!AddKeyType(info, &type, true)) {
         info->errorCount++;
         return false;
     }
@@ -751,16 +663,18 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
             ok = HandleKeyTypeDef(info, (KeyTypeDef *) stmt, merge);
             break;
         case STMT_VAR:
-            log_err(info->keymap->ctx,
+            log_err(info->ctx,
+                    XKB_ERROR_WRONG_STATEMENT_TYPE,
                     "Support for changing the default type has been removed; "
                     "Statement ignored\n");
             ok = true;
             break;
         case STMT_VMOD:
-            ok = HandleVModDef(info->keymap, (VModDef *) stmt);
+            ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
             break;
         default:
-            log_err(info->keymap->ctx,
+            log_err(info->ctx,
+                    XKB_ERROR_WRONG_STATEMENT_TYPE,
                     "Key type files may not include other declarations; "
                     "Ignoring %s\n", stmt_type_to_string(stmt->type));
             ok = false;
@@ -771,70 +685,72 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
             info->errorCount++;
 
         if (info->errorCount > 10) {
-            log_err(info->keymap->ctx,
-                    "Abandoning keytypes file \"%s\"\n", file->topName);
+            log_err(info->ctx,
+                    XKB_ERROR_INVALID_SYNTAX,
+                    "Abandoning keytypes file \"%s\"\n", file->name);
             break;
         }
     }
 }
 
-static void
-CopyDefToKeyType(KeyTypeInfo *def, struct xkb_key_type *type)
-{
-    type->mods.mods = def->mods;
-    type->num_levels = def->num_levels;
-    type->map = darray_mem(def->entries, 0);
-    type->num_entries = darray_size(def->entries);
-    darray_init(def->entries);
-    type->name = def->name;
-    type->level_names = darray_mem(def->level_names, 0);
-    darray_init(def->level_names);
-}
+/***====================================================================***/
 
 static bool
 CopyKeyTypesToKeymap(struct xkb_keymap *keymap, KeyTypesInfo *info)
 {
-    unsigned int i;
-    unsigned int num_types;
+    unsigned num_types;
+    struct xkb_key_type *types;
 
-    num_types = darray_size(info->types) ? darray_size(info->types) : 1;
-    keymap->types = calloc(num_types, sizeof(*keymap->types));
-    if (!keymap->types)
+    num_types = darray_empty(info->types) ? 1 : darray_size(info->types);
+    types = calloc(num_types, sizeof(*types));
+    if (!types)
         return false;
 
-    keymap->num_types = num_types;
-
     /*
      * If no types were specified, a default unnamed one-level type is
      * used for all keys.
      */
     if (darray_empty(info->types)) {
-        KeyTypeInfo dflt = {
-            .name = xkb_atom_intern(keymap->ctx, "default"),
-            .mods = 0,
-            .num_levels = 1,
-            .entries = darray_new(),
-            .level_names = darray_new(),
-        };
-
-        CopyDefToKeyType(&dflt, &keymap->types[0]);
-    } else {
-        for (i = 0; i < num_types; i++)
-            CopyDefToKeyType(&darray_item(info->types, i), &keymap->types[i]);
+        struct xkb_key_type *type = &types[0];
+
+        type->mods.mods = 0;
+        type->num_levels = 1;
+        type->entries = NULL;
+        type->num_entries = 0;
+        type->name = xkb_atom_intern_literal(keymap->ctx, "default");
+        type->level_names = NULL;
+        type->num_level_names = 0;
+    }
+    else {
+        for (unsigned i = 0; i < num_types; i++) {
+            KeyTypeInfo *def = &darray_item(info->types, i);
+            struct xkb_key_type *type = &types[i];
+
+            type->name = def->name;
+            type->mods.mods = def->mods;
+            type->num_levels = def->num_levels;
+            darray_steal(def->level_names, &type->level_names, &type->num_level_names);
+            darray_steal(def->entries, &type->entries, &type->num_entries);
+        }
     }
 
     keymap->types_section_name = strdup_safe(info->name);
-
+    XkbEscapeMapName(keymap->types_section_name);
+    keymap->num_types = num_types;
+    keymap->types = types;
+    keymap->mods = info->mods;
     return true;
 }
 
+/***====================================================================***/
+
 bool
 CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
                 enum merge_mode merge)
 {
     KeyTypesInfo info;
 
-    InitKeyTypesInfo(&info, keymap, file->id);
+    InitKeyTypesInfo(&info, keymap->ctx, &keymap->mods);
 
     HandleKeyTypesFile(&info, file, merge);
     if (info.errorCount != 0)