diff --git a/src/xkbcomp/ast-build.c b/src/xkbcomp/ast-build.c index 7c7646140..068a7e30a 100644 --- a/src/xkbcomp/ast-build.c +++ b/src/xkbcomp/ast-build.c @@ -534,8 +534,8 @@ IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge) } XkbFile * -XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs, - enum xkb_map_flags flags) +XkbFileCreate(enum xkb_file_type type, const char *file_name, char *name, + ParseCommon *defs, enum xkb_map_flags flags) { XkbFile *file; @@ -545,6 +545,7 @@ XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs, XkbEscapeMapName(name); file->file_type = type; + file->file_name = file_name; file->name = name ? name : strdup("(unnamed)"); file->defs = defs; file->flags = flags; @@ -570,7 +571,7 @@ XkbFileFromComponents(struct xkb_context *ctx, if (!include) goto err; - file = XkbFileCreate(type, NULL, (ParseCommon *) include, 0); + file = XkbFileCreate(type, NULL, NULL, (ParseCommon *) include, 0); if (!file) { FreeInclude(include); goto err; @@ -582,7 +583,7 @@ XkbFileFromComponents(struct xkb_context *ctx, defsLast = defsLast->next = &file->common; } - file = XkbFileCreate(FILE_TYPE_KEYMAP, NULL, defs, 0); + file = XkbFileCreate(FILE_TYPE_KEYMAP, NULL, NULL, defs, 0); if (!file) goto err; diff --git a/src/xkbcomp/ast-build.h b/src/xkbcomp/ast-build.h index 3afb08038..e8359a62c 100644 --- a/src/xkbcomp/ast-build.h +++ b/src/xkbcomp/ast-build.h @@ -116,8 +116,8 @@ IncludeStmt * IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge); XkbFile * -XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs, - enum xkb_map_flags flags); +XkbFileCreate(enum xkb_file_type type, const char *file_name, char *name, + ParseCommon *defs, enum xkb_map_flags flags); void FreeStmt(ParseCommon *stmt); diff --git a/src/xkbcomp/ast.h b/src/xkbcomp/ast.h index 8b0901f94..6c5bae7a8 100644 --- a/src/xkbcomp/ast.h +++ b/src/xkbcomp/ast.h @@ -352,6 +352,7 @@ enum xkb_map_flags { typedef struct { ParseCommon common; enum xkb_file_type file_type; + const char *file_name; char *name; ParseCommon *defs; enum xkb_map_flags flags; diff --git a/src/xkbcomp/compat.c b/src/xkbcomp/compat.c index 9b6f9de58..d5b83e0ea 100644 --- a/src/xkbcomp/compat.c +++ b/src/xkbcomp/compat.c @@ -86,6 +86,8 @@ typedef struct { typedef struct { char *name; int errorCount; + /* shared list of parents includes of the current processed file */ + include_parents *include_parents; SymInterpInfo default_interp; darray(SymInterpInfo) interps; LedInfo default_led; @@ -148,10 +150,12 @@ ReportLedNotArray(CompatInfo *info, LedInfo *ledi, const char *field) static void InitCompatInfo(CompatInfo *info, struct xkb_context *ctx, + include_parents *parents, ActionsInfo *actions, const struct xkb_mod_set *mods) { memset(info, 0, sizeof(*info)); info->ctx = ctx; + info->include_parents = parents; info->actions = actions; info->mods = *mods; info->default_interp.merge = MERGE_OVERRIDE; @@ -430,7 +434,8 @@ HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *include) { CompatInfo included; - InitCompatInfo(&included, info->ctx, info->actions, &info->mods); + InitCompatInfo(&included, info->ctx, info->include_parents, + info->actions, &info->mods); included.name = include->stmt; include->stmt = NULL; @@ -438,14 +443,16 @@ HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *include) CompatInfo next_incl; XkbFile *file; - file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_COMPAT); + file = ProcessIncludeFile(info->ctx, info->include_parents, + stmt, FILE_TYPE_COMPAT); if (!file) { info->errorCount += 10; ClearCompatInfo(&included); return false; } - InitCompatInfo(&next_incl, info->ctx, info->actions, &included.mods); + InitCompatInfo(&next_incl, info->ctx, info->include_parents, + info->actions, &included.mods); next_incl.default_interp = info->default_interp; next_incl.default_interp.merge = stmt->merge; next_incl.default_led = info->default_led; @@ -760,6 +767,10 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge) free(info->name); info->name = strdup_safe(file->name); + include_parents_append(info->ctx, info->include_parents, + file->file_name, file->name, + !!(file->flags & MAP_IS_DEFAULT)); + for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) { switch (stmt->type) { case STMT_INCLUDE: @@ -800,6 +811,8 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge) break; } } + + darray_remove_last(*info->include_parents); } /* Temporary struct for CopyInterps. */ @@ -909,12 +922,14 @@ CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap, { CompatInfo info; ActionsInfo *actions; + include_parents parents = darray_new(); actions = NewActionsInfo(); if (!actions) return false; - InitCompatInfo(&info, keymap->ctx, actions, &keymap->mods); + InitCompatInfo(&info, keymap->ctx, &parents, + actions, &keymap->mods); info.default_interp.merge = merge; info.default_led.merge = merge; @@ -927,10 +942,12 @@ CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap, ClearCompatInfo(&info); FreeActionsInfo(actions); + darray_free(parents); return true; err_info: ClearCompatInfo(&info); FreeActionsInfo(actions); + darray_free(parents); return false; } diff --git a/src/xkbcomp/include.c b/src/xkbcomp/include.c index d47156eff..4ac1344c2 100644 --- a/src/xkbcomp/include.c +++ b/src/xkbcomp/include.c @@ -174,6 +174,48 @@ ParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn, return true; } +void +include_parents_append(struct xkb_context *ctx, include_parents *parents, + const char *file, char *map, bool is_map_default) +{ + struct include_atom parent = { + .file = isempty(file) ? XKB_ATOM_NONE + : xkb_atom_intern(ctx, file, strlen(file)), + .map = isempty(map) ? XKB_ATOM_NONE + : xkb_atom_intern(ctx, map, strlen(map)), + .is_map_default = is_map_default + }; + + darray_append(*parents, parent); +} + +static inline bool +include_atom_eq(struct include_atom *atom, xkb_atom_t file, xkb_atom_t map) +{ + return atom->file == file && + (atom->map == map || + /* in case map is null, it must be the default map */ + (map == XKB_ATOM_NONE && atom->is_map_default)); +} + +static struct include_atom * +include_parents_lookup(struct xkb_context *ctx, include_parents *parents, + const char *file_str, char *map_str) +{ + struct include_atom *parent; + xkb_atom_t file = isempty(file_str) + ? XKB_ATOM_NONE + : xkb_atom_intern(ctx, file_str, strlen(file_str)); + xkb_atom_t map = isempty(map_str) + ? XKB_ATOM_NONE + : xkb_atom_intern(ctx, map_str, strlen(map_str)); + darray_foreach(parent, *parents) { + if (include_atom_eq(parent, file, map)) + return parent; + } + return NULL; +} + static const char *xkb_file_type_include_dirs[_FILE_TYPE_NUM_ENTRIES] = { [FILE_TYPE_KEYCODES] = "keycodes", [FILE_TYPE_TYPES] = "types", @@ -289,18 +331,36 @@ FindFileInXkbPath(struct xkb_context *ctx, const char *name, } XkbFile * -ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt, +ProcessIncludeFile(struct xkb_context *ctx, + include_parents *parents, IncludeStmt *stmt, enum xkb_file_type file_type) { FILE *file; XkbFile *xkb_file = NULL; + struct include_atom *recursive_inc; unsigned int offset = 0; + /* Check recursive imports */ + recursive_inc = include_parents_lookup(ctx, parents, stmt->file, stmt->map); + if (recursive_inc) { + struct include_atom *current_file = &darray_item(*parents, darray_size(*parents) - 1); + log_err(ctx, XKB_LOG_MESSAGE_NO_ID, + "Recursive import of %s \"%s(%s)\" in \"%s(%s)\"\n", + xkb_file_type_to_string(file_type), + xkb_atom_text(ctx, recursive_inc->file), + xkb_atom_text(ctx, recursive_inc->map), + xkb_atom_text(ctx, current_file->file), + xkb_atom_text(ctx, current_file->map)); + return NULL; + } + file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL, &offset); - if (!file) + if (!file) { return NULL; + } while (file) { + xkb_file = XkbParseFile(ctx, file, stmt->file, stmt->map); fclose(file); @@ -336,7 +396,5 @@ ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt, stmt->file); } - /* FIXME: we have to check recursive includes here (or somewhere) */ - return xkb_file; } diff --git a/src/xkbcomp/include.h b/src/xkbcomp/include.h index 8f360e3cb..269167997 100644 --- a/src/xkbcomp/include.h +++ b/src/xkbcomp/include.h @@ -27,6 +27,21 @@ #ifndef XKBCOMP_INCLUDE_H #define XKBCOMP_INCLUDE_H +#include "context.h" +#include "atom.h" + +struct include_atom { + xkb_atom_t file; + xkb_atom_t map; + bool is_map_default; +}; + +typedef darray(struct include_atom) include_parents; + +void +include_parents_append(struct xkb_context *ctx, include_parents *parents, + const char *file, char *map, bool is_map_default); + bool ParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn, char *nextop_rtrn, char **extra_data); @@ -37,7 +52,8 @@ FindFileInXkbPath(struct xkb_context *ctx, const char *name, unsigned int *offset); XkbFile * -ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt, +ProcessIncludeFile(struct xkb_context *ctx, + include_parents *parents, IncludeStmt *stmt, enum xkb_file_type file_type); #endif diff --git a/src/xkbcomp/keycodes.c b/src/xkbcomp/keycodes.c index 91471ea7f..8e4d13269 100644 --- a/src/xkbcomp/keycodes.c +++ b/src/xkbcomp/keycodes.c @@ -47,6 +47,8 @@ typedef struct { typedef struct { char *name; int errorCount; + /* shared list of parents includes of the current processed file */ + include_parents *include_parents; xkb_keycode_t min_key_code; xkb_keycode_t max_key_code; @@ -155,10 +157,12 @@ ClearKeyNamesInfo(KeyNamesInfo *info) } static void -InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_context *ctx) +InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_context *ctx, + include_parents *parents) { memset(info, 0, sizeof(*info)); info->ctx = ctx; + info->include_parents = parents; info->min_key_code = XKB_KEYCODE_INVALID; #if XKB_KEYCODE_INVALID < XKB_KEYCODE_MAX #error "Hey, you can't be changing stuff like that." @@ -339,7 +343,7 @@ HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *include) { KeyNamesInfo included; - InitKeyNamesInfo(&included, info->ctx); + InitKeyNamesInfo(&included, info->ctx, info->include_parents); included.name = include->stmt; include->stmt = NULL; @@ -347,14 +351,15 @@ HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *include) KeyNamesInfo next_incl; XkbFile *file; - file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_KEYCODES); + file = ProcessIncludeFile(info->ctx, info->include_parents, + stmt, FILE_TYPE_KEYCODES); if (!file) { info->errorCount += 10; ClearKeyNamesInfo(&included); return false; } - InitKeyNamesInfo(&next_incl, info->ctx); + InitKeyNamesInfo(&next_incl, info->ctx, info->include_parents); HandleKeycodesFile(&next_incl, file, MERGE_OVERRIDE); @@ -494,6 +499,10 @@ HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge) free(info->name); info->name = strdup_safe(file->name); + include_parents_append(info->ctx, info->include_parents, + file->file_name, file->name, + !!(file->flags & MAP_IS_DEFAULT)); + for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) { switch (stmt->type) { case STMT_INCLUDE: @@ -529,6 +538,8 @@ HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge) break; } } + + darray_remove_last(*info->include_parents); } /***====================================================================***/ @@ -661,8 +672,9 @@ CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge) { KeyNamesInfo info; + include_parents parents = darray_new(); - InitKeyNamesInfo(&info, keymap->ctx); + InitKeyNamesInfo(&info, keymap->ctx, &parents); HandleKeycodesFile(&info, file, merge); if (info.errorCount != 0) @@ -672,9 +684,11 @@ CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap, goto err_info; ClearKeyNamesInfo(&info); + darray_free(parents); return true; err_info: ClearKeyNamesInfo(&info); + darray_free(parents); return false; } diff --git a/src/xkbcomp/parser.y b/src/xkbcomp/parser.y index 0fd663ac7..ee73c7032 100644 --- a/src/xkbcomp/parser.y +++ b/src/xkbcomp/parser.y @@ -263,7 +263,7 @@ XkbFile : XkbCompositeMap XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE XkbMapConfigList CBRACE SEMI - { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5.head, $1); } + { $$ = XkbFileCreate($2, param->scanner->file_name, $3, (ParseCommon *) $5.head, $1); } ; XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; } @@ -281,7 +281,7 @@ XkbMapConfig : OptFlags FileType OptMapName OBRACE DeclList CBRACE SEMI { - $$ = XkbFileCreate($2, $3, $5.head, $1); + $$ = XkbFileCreate($2, param->scanner->file_name, $3, $5.head, $1); } ; diff --git a/src/xkbcomp/symbols.c b/src/xkbcomp/symbols.c index 20eebeb20..a00518760 100644 --- a/src/xkbcomp/symbols.c +++ b/src/xkbcomp/symbols.c @@ -175,6 +175,8 @@ typedef struct { typedef struct { char *name; /* e.g. pc+us+inet(evdev) */ int errorCount; + /* shared list of parents includes of the current processed file */ + include_parents *include_parents; enum merge_mode merge; xkb_layout_index_t explicit_group; darray(KeyInfo) keys; @@ -191,10 +193,12 @@ typedef struct { static void InitSymbolsInfo(SymbolsInfo *info, const struct xkb_keymap *keymap, + include_parents *parents, ActionsInfo *actions, const struct xkb_mod_set *mods) { memset(info, 0, sizeof(*info)); info->ctx = keymap->ctx; + info->include_parents = parents; info->keymap = keymap; info->merge = MERGE_OVERRIDE; InitKeyInfo(keymap->ctx, &info->default_key); @@ -569,7 +573,8 @@ HandleIncludeSymbols(SymbolsInfo *info, IncludeStmt *include) { SymbolsInfo included; - InitSymbolsInfo(&included, info->keymap, info->actions, &info->mods); + InitSymbolsInfo(&included, info->keymap, info->include_parents, + info->actions, &info->mods); included.name = include->stmt; include->stmt = NULL; @@ -577,15 +582,16 @@ HandleIncludeSymbols(SymbolsInfo *info, IncludeStmt *include) SymbolsInfo next_incl; XkbFile *file; - file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_SYMBOLS); + file = ProcessIncludeFile(info->ctx, info->include_parents, + stmt, FILE_TYPE_SYMBOLS); if (!file) { info->errorCount += 10; ClearSymbolsInfo(&included); return false; } - InitSymbolsInfo(&next_incl, info->keymap, info->actions, - &included.mods); + InitSymbolsInfo(&next_incl, info->keymap, info->include_parents, + info->actions, &included.mods); if (stmt->modifier) { next_incl.explicit_group = atoi(stmt->modifier) - 1; if (next_incl.explicit_group >= XKB_MAX_GROUPS) { @@ -1245,6 +1251,10 @@ HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge) free(info->name); info->name = strdup_safe(file->name); + include_parents_append(info->ctx, info->include_parents, + file->file_name, file->name, + !!(file->flags & MAP_IS_DEFAULT)); + for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) { switch (stmt->type) { case STMT_INCLUDE: @@ -1282,6 +1292,8 @@ HandleSymbolsFile(SymbolsInfo *info, XkbFile *file, enum merge_mode merge) break; } } + + darray_remove_last(*info->include_parents); } /** @@ -1633,12 +1645,13 @@ CompileSymbols(XkbFile *file, struct xkb_keymap *keymap, { SymbolsInfo info; ActionsInfo *actions; + include_parents parents = darray_new(); actions = NewActionsInfo(); if (!actions) return false; - InitSymbolsInfo(&info, keymap, actions, &keymap->mods); + InitSymbolsInfo(&info, keymap, &parents, actions, &keymap->mods); info.default_key.merge = merge; HandleSymbolsFile(&info, file, merge); @@ -1651,10 +1664,12 @@ CompileSymbols(XkbFile *file, struct xkb_keymap *keymap, ClearSymbolsInfo(&info); FreeActionsInfo(actions); + darray_free(parents); return true; err_info: FreeActionsInfo(actions); ClearSymbolsInfo(&info); + darray_free(parents); return false; } diff --git a/src/xkbcomp/types.c b/src/xkbcomp/types.c index 34e10286c..5b9800453 100644 --- a/src/xkbcomp/types.c +++ b/src/xkbcomp/types.c @@ -53,6 +53,8 @@ typedef struct { typedef struct { char *name; int errorCount; + /* shared list of parents includes of the current processed file */ + include_parents *include_parents; darray(KeyTypeInfo) types; struct xkb_mod_set mods; @@ -100,10 +102,12 @@ ReportTypeBadType(KeyTypesInfo *info, xkb_message_code_t code, static void InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_context *ctx, + include_parents *parents, const struct xkb_mod_set *mods) { memset(info, 0, sizeof(*info)); info->ctx = ctx; + info->include_parents = parents; info->mods = *mods; } @@ -180,6 +184,11 @@ MergeIncludedKeyTypes(KeyTypesInfo *into, KeyTypesInfo *from, { if (from->errorCount > 0) { into->errorCount += from->errorCount; + // Free unused types + KeyTypeInfo *type; + darray_foreach(type, from->types) { + ClearKeyTypeInfo(type); + } return; } @@ -212,7 +221,7 @@ HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include) { KeyTypesInfo included; - InitKeyTypesInfo(&included, info->ctx, &info->mods); + InitKeyTypesInfo(&included, info->ctx, info->include_parents, &info->mods); included.name = include->stmt; include->stmt = NULL; @@ -220,14 +229,16 @@ HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include) KeyTypesInfo next_incl; XkbFile *file; - file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_TYPES); + file = ProcessIncludeFile(info->ctx, info->include_parents, + stmt, FILE_TYPE_TYPES); if (!file) { info->errorCount += 10; ClearKeyTypesInfo(&included); return false; } - InitKeyTypesInfo(&next_incl, info->ctx, &included.mods); + InitKeyTypesInfo(&next_incl, info->ctx, info->include_parents, + &included.mods); HandleKeyTypesFile(&next_incl, file, stmt->merge); @@ -651,6 +662,10 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge) free(info->name); info->name = strdup_safe(file->name); + include_parents_append(info->ctx, info->include_parents, + file->file_name, file->name, + !!(file->flags & MAP_IS_DEFAULT)); + for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) { switch (stmt->type) { case STMT_INCLUDE: @@ -688,6 +703,8 @@ HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge) break; } } + + darray_remove_last(*info->include_parents); } /***====================================================================***/ @@ -746,8 +763,9 @@ CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge) { KeyTypesInfo info; + include_parents parents = darray_new(); - InitKeyTypesInfo(&info, keymap->ctx, &keymap->mods); + InitKeyTypesInfo(&info, keymap->ctx, &parents, &keymap->mods); HandleKeyTypesFile(&info, file, merge); if (info.errorCount != 0) @@ -757,9 +775,11 @@ CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap, goto err_info; ClearKeyTypesInfo(&info); + darray_free(parents); return true; err_info: ClearKeyTypesInfo(&info); + darray_free(parents); return false; } diff --git a/test/buffercomp.c b/test/buffercomp.c index 9a7603654..721f5cbb0 100644 --- a/test/buffercomp.c +++ b/test/buffercomp.c @@ -31,6 +31,88 @@ #define DATA_PATH "keymaps/stringcomp.data" +static void +test_recursive(void) +{ + struct xkb_context *ctx = test_get_context(0); + struct xkb_keymap *keymap; + + assert(ctx); + + const char* const keymaps[] = { + /* Recursive keycodes */ + "Keycodes: recursive", + "xkb_keymap {" + " xkb_keycodes { include \"evdev+recursive\" };" + " xkb_types { include \"complete\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"pc\" };" + "};", + "Keycodes: recursive(bar)", + "xkb_keymap {" + " xkb_keycodes { include \"evdev+recursive(bar)\" };" + " xkb_types { include \"complete\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"pc\" };" + "};", + /* Recursive key types */ + "Key types: recursive", + "xkb_keymap {" + " xkb_keycodes { include \"evdev\" };" + " xkb_types { include \"recursive\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"pc\" };" + "};", + "Key types: recursive(bar)", + "xkb_keymap {" + " xkb_keycodes { include \"evdev\" };" + " xkb_types { include \"recursive(bar)\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"pc\" };" + "};", + /* Recursive compat */ + "Compat: recursive", + "xkb_keymap {" + " xkb_keycodes { include \"evdev\" };" + " xkb_types { include \"recursive\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"pc\" };" + "};", + "Compat: recursive(bar)", + "xkb_keymap {" + " xkb_keycodes { include \"evdev\" };" + " xkb_types { include \"complete\" };" + " xkb_compat { include \"recursive(bar)\" };" + " xkb_symbols { include \"pc\" };" + "};", + /* Recursive symbols */ + "Symbols: recursive", + "xkb_keymap {" + " xkb_keycodes { include \"evdev\" };" + " xkb_types { include \"complete\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"recursive\" };" + "};", + "Symbols: recursive(bar)", + "xkb_keymap {" + " xkb_keycodes { include \"evdev\" };" + " xkb_types { include \"complete\" };" + " xkb_compat { include \"complete\" };" + " xkb_symbols { include \"recursive(bar)\" };" + // "};" + }; + + int len = sizeof(keymaps) / sizeof(keymaps[0]); + + for (int k = 0; k < len; k++) { + fprintf(stderr, "*** Recursive test: %s ***\n", keymaps[k++]); + keymap = test_compile_buffer(ctx, keymaps[k], strlen(keymaps[k])); + assert(!keymap); + } + + xkb_context_unref(ctx); +} + int main(int argc, char *argv[]) { @@ -92,5 +174,7 @@ main(int argc, char *argv[]) xkb_context_unref(ctx); + test_recursive(); + return 0; } diff --git a/test/data/compat/recursive b/test/data/compat/recursive new file mode 100644 index 000000000..3273eadf7 --- /dev/null +++ b/test/data/compat/recursive @@ -0,0 +1,12 @@ +default +xkb_compatibility "foo" { + include "recursive" +}; + +xkb_compatibility "bar" { + include "recursive(baz)" +}; + +xkb_compatibility "baz" { + include "recursive(bar)" +}; diff --git a/test/data/keycodes/recursive b/test/data/keycodes/recursive new file mode 100644 index 000000000..6711a606d --- /dev/null +++ b/test/data/keycodes/recursive @@ -0,0 +1,15 @@ +default +xkb_keycodes "foo" { + include "recursive" + = 0x100000; +}; + +xkb_keycodes "bar" { + include "recursive(baz)" + = 0x100001; +}; + +xkb_keycodes "baz" { + include "recursive(bar)" + = 0x100002; +}; diff --git a/test/data/symbols/recursive b/test/data/symbols/recursive new file mode 100644 index 000000000..2a9ad63e7 --- /dev/null +++ b/test/data/symbols/recursive @@ -0,0 +1,12 @@ +default +xkb_symbols "foo" { + include "recursive" +}; + +xkb_symbols "bar" { + include "recursive(baz)" +}; + +xkb_symbols "baz" { + include "recursive(bar)" +}; diff --git a/test/data/types/recursive b/test/data/types/recursive new file mode 100644 index 000000000..4b75a34c9 --- /dev/null +++ b/test/data/types/recursive @@ -0,0 +1,27 @@ +default +xkb_types "foo" { + type "FOO" { + modifiers = None; + map[None] = Level1; + level_name[Level1]= "Any"; + }; + include "recursive" +}; + +xkb_types "bar" { + type "BAR" { + modifiers = None; + map[None] = Level1; + level_name[Level1]= "Any"; + }; + include "recursive(baz)" +}; + +xkb_types "baz" { + type "BAZ" { + modifiers = None; + map[None] = Level1; + level_name[Level1]= "Any"; + }; + include "recursive(bar)" +};