XkbFile ** file_rtrn, enum merge_mode *merge_rtrn)
{
FILE *file;
- XkbFile *rtrn, *mapToUse, *next;
+ XkbFile *xkb_file;
file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL);
if (!file)
return false;
- rtrn = XkbParseFile(ctx, file, stmt->file);
- if (!rtrn) {
- log_err(ctx, "Error interpreting include file \"%s\"\n", stmt->file);
+ xkb_file = XkbParseFile(ctx, file, stmt->file, stmt->map);
+ if (!xkb_file) {
+ if (stmt->map)
+ log_err(ctx, "Couldn't process include statement for '%s(%s)'\n",
+ stmt->file, stmt->map);
+ else
+ log_err(ctx, "Couldn't process include statement for '%s'\n",
+ stmt->file);
fclose(file);
return false;
}
fclose(file);
- mapToUse = rtrn;
- if (stmt->map != NULL) {
- while (mapToUse)
- {
- next = (XkbFile *) mapToUse->common.next;
- mapToUse->common.next = NULL;
- if (streq(mapToUse->name, stmt->map) &&
- mapToUse->file_type == file_type) {
- FreeXkbFile(next);
- break;
- }
- else {
- FreeXkbFile(mapToUse);
- }
- mapToUse = next;
- }
- if (!mapToUse) {
- log_err(ctx, "No %s named \"%s\" in the include file \"%s\"\n",
- xkb_file_type_to_string(file_type), stmt->map,
- stmt->file);
- return false;
- }
- }
- else if (rtrn->common.next) {
- for (; mapToUse; mapToUse = (XkbFile *) mapToUse->common.next)
- if (mapToUse->flags & MAP_IS_DEFAULT)
- break;
-
- if (!mapToUse) {
- mapToUse = rtrn;
- log_vrb(ctx, 5,
- "No map in include statement, but \"%s\" contains several; "
- "Using first defined map, \"%s\"\n",
- stmt->file, rtrn->name);
- }
- }
-
- if (mapToUse->file_type != file_type) {
+ if (xkb_file->file_type != file_type) {
log_err(ctx,
"Include file wrong type (expected %s, got %s); "
"Include file \"%s\" ignored\n",
xkb_file_type_to_string(file_type),
- xkb_file_type_to_string(mapToUse->file_type), stmt->file);
+ xkb_file_type_to_string(xkb_file->file_type), stmt->file);
return false;
}
/* FIXME: we have to check recursive includes here (or somewhere) */
- *file_rtrn = mapToUse;
+ *file_rtrn = xkb_file;
*merge_rtrn = stmt->merge;
return true;
}
#ifndef XKBCOMP_PARSER_PRIV_H
#define XKBCOMP_PARSER_PRIV_H
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-
struct scanner_extra;
-
-struct parser_param {
- struct xkb_context *ctx;
- void *scanner;
- XkbFile *rtrn;
-};
+struct parser_param;
#include "parser.h"
int
_xkbcommon_lex(YYSTYPE *val, YYLTYPE *loc, void *scanner);
-int
-_xkbcommon_parse(struct parser_param *param);
+XkbFile *
+parse(struct xkb_context *ctx, void *scanner, const char *map);
#endif
#include "ast-build.h"
#include "parser-priv.h"
+struct parser_param {
+ struct xkb_context *ctx;
+ void *scanner;
+ XkbFile *rtrn;
+ bool more_maps;
+};
+
static void
_xkbcommon_error(struct YYLTYPE *loc, struct parser_param *param, const char *msg)
{
%%
+/*
+ * An actual file may contain more than one map. However, if we do things
+ * in the normal yacc way, i.e. aggregate all of the maps into a list and
+ * let the caller find the map it wants, we end up scanning and parsing a
+ * lot of unneeded maps (in the end we always just need one).
+ * Instead of doing that, we make yyparse return one map at a time, and
+ * then call it repeatedly until we find the map we need. Once we find it,
+ * we don't need to parse everything that follows in the file.
+ * This does mean that if we e.g. always use the first map, the file may
+ * contain complete garbage after that. But it's worth it.
+ */
+
XkbFile : XkbCompositeMap
- { $$ = param->rtrn = $1; }
- | XkbMapConfigList
- { $$ = param->rtrn = $1; }
+ { $$ = param->rtrn = $1; param->more_maps = true; }
+ | XkbMapConfig
+ { $$ = param->rtrn = $1; param->more_maps = true; YYACCEPT; }
+ | END_OF_FILE
+ { $$ = param->rtrn = NULL; param->more_maps = false; }
;
XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
%%
#undef scanner
+
+XkbFile *
+parse(struct xkb_context *ctx, void *scanner, const char *map)
+{
+ struct parser_param param;
+ int ret;
+ XkbFile *first = NULL;
+
+ param.scanner = scanner;
+ param.ctx = ctx;
+
+ /*
+ * If we got a specific map, we look for it exclusively and return
+ * immediately upon finding it. Otherwise, we need to get the
+ * default map. If we find a map marked as default, we return it
+ * immediately. If there are no maps marked as default, we return
+ * the first map in the file.
+ */
+
+ while ((ret = yyparse(¶m)) == 0 && param.more_maps) {
+ if (map) {
+ if (streq_not_null(map, param.rtrn->name))
+ return param.rtrn;
+ else
+ FreeXkbFile(param.rtrn);
+ }
+ else {
+ if (param.rtrn->flags & MAP_IS_DEFAULT) {
+ FreeXkbFile(first);
+ return param.rtrn;
+ }
+ else if (!first) {
+ first = param.rtrn;
+ }
+ else {
+ FreeXkbFile(param.rtrn);
+ }
+ }
+ }
+
+ if (ret != 0) {
+ FreeXkbFile(first);
+ return NULL;
+ }
+
+ return first;
+}
#include "parser-priv.h"
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#pragma GCC diagnostic push
struct scanner_extra {
struct xkb_context *ctx;
%%
+#pragma GCC diagnostic pop
+
static void
scanner_error_extra(struct YYLTYPE *loc, struct scanner_extra *extra,
const char *msg)
scanner_error_extra(loc, extra, msg);
}
-static void
-CheckDefaultMap(struct xkb_context *ctx, XkbFile *maps, const char *fileName)
-{
- XkbFile *dflt = NULL, *tmp;
-
- for (tmp = maps; tmp; tmp = (XkbFile *) tmp->common.next) {
- if (!(tmp->flags & MAP_IS_DEFAULT))
- continue;
-
- if (!dflt) {
- dflt = tmp;
- continue;
- }
-
- log_vrb(ctx, 3,
- "Multiple default components in %s; "
- "Using %s, ignoring %s\n",
- (fileName ? fileName : "(unknown)"),
- (dflt->name ? dflt->name : "(first)"),
- (tmp->name ? tmp->name : "(subsequent)"));
-
- tmp->flags &= (~MAP_IS_DEFAULT);
- }
-}
-
-static XkbFile *
-parse(struct xkb_context *ctx, yyscan_t scanner)
-{
- struct parser_param param;
-
- param.scanner = scanner;
- param.ctx = ctx;
-
- if (_xkbcommon_parse(¶m) != 0)
- return NULL;
-
- CheckDefaultMap(param.ctx, param.rtrn, yyget_extra(scanner)->scanFile);
- return param.rtrn;
-}
-
static bool
init_scanner(yyscan_t *scanner, struct scanner_extra *extra,
struct xkb_context *ctx, const char *file_name)
state = yy_scan_string(string, scanner);
- xkb_file = parse(ctx, scanner);
+ xkb_file = parse(ctx, scanner, NULL);
yy_delete_buffer(state, scanner);
clear_scanner(scanner);
}
XkbFile *
-XkbParseFile(struct xkb_context *ctx, FILE *file, const char *file_name)
+XkbParseFile(struct xkb_context *ctx, FILE *file,
+ const char *file_name, const char *map)
{
yyscan_t scanner;
struct scanner_extra extra;
state = yy_create_buffer(file, YY_BUF_SIZE, scanner);
yy_switch_to_buffer(state, scanner);
- xkb_file = parse(ctx, scanner);
+ xkb_file = parse(ctx, scanner, map);
yy_delete_buffer(state, scanner);
clear_scanner(scanner);
};
XkbFile *
-XkbParseFile(struct xkb_context *ctx, FILE *file, const char *file_name);
+XkbParseFile(struct xkb_context *ctx, FILE *file,
+ const char *file_name, const char *map);
XkbFile *
XkbParseString(struct xkb_context *ctx, const char *string,
return NULL;
}
- xkb_file = XkbParseFile(ctx, file, "(unknown file)");
+ xkb_file = XkbParseFile(ctx, file, "(unknown file)", NULL);
if (!xkb_file) {
log_err(ctx, "Failed to parse input xkb file\n");
return NULL;