*
********************************************************/
+/*
+ * Copyright © 2012 Ran Benita <ran234@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
#include <errno.h>
#include <limits.h>
#include <stdio.h>
return true;
}
-/***====================================================================***/
-
static const char *xkb_file_type_include_dirs[_FILE_TYPE_NUM_ENTRIES] = {
[FILE_TYPE_KEYCODES] = "keycodes",
[FILE_TYPE_TYPES] = "types",
return xkb_file_type_include_dirs[type];
}
-/***====================================================================***/
+static void
+LogIncludePaths(struct xkb_context *ctx)
+{
+ unsigned int i;
+
+ if (xkb_context_num_include_paths(ctx) > 0) {
+ log_err_with_code(ctx,
+ XKB_ERROR_INCLUDED_FILE_NOT_FOUND,
+ "%d include paths searched:\n",
+ xkb_context_num_include_paths(ctx));
+ for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
+ log_err_with_code(ctx,
+ XKB_ERROR_INCLUDED_FILE_NOT_FOUND,
+ "\t%s\n",
+ xkb_context_include_path_get(ctx, i));
+ }
+ else {
+ log_err_with_code(ctx,
+ XKB_ERROR_INCLUDED_FILE_NOT_FOUND,
+ "There are no include paths to search\n");
+ }
+
+ if (xkb_context_num_failed_include_paths(ctx) > 0) {
+ log_err_with_code(ctx,
+ XKB_ERROR_INCLUDED_FILE_NOT_FOUND,
+ "%d include paths could not be added:\n",
+ xkb_context_num_failed_include_paths(ctx));
+ for (i = 0; i < xkb_context_num_failed_include_paths(ctx); i++)
+ log_err_with_code(ctx,
+ XKB_ERROR_INCLUDED_FILE_NOT_FOUND,
+ "\t%s\n",
+ xkb_context_failed_include_path_get(ctx, i));
+ }
+}
/**
- * Search for the given file name in the include directories.
+ * Return an open file handle to the first file (counting from offset) with the
+ * given name in the include paths, starting at the offset.
*
- * @param ctx the XKB ctx containing the include paths
- * @param type one of FILE_TYPE_TYPES, FILE_TYPE_COMPAT, ..., or
- * FILE_TYPE_KEYMAP or FILE_TYPE_RULES
- * @param pathRtrn is set to the full path of the file if found.
+ * offset must be zero the first time this is called and is set to the index the
+ * file was found. Call again with offset+1 to keep searching through the
+ * include paths.
*
- * @return an FD to the file or NULL. If NULL is returned, the value of
- * pathRtrn is undefined.
+ * If this function returns NULL, no more files are available.
*/
FILE *
FindFileInXkbPath(struct xkb_context *ctx, const char *name,
- enum xkb_file_type type, char **pathRtrn)
+ enum xkb_file_type type, char **pathRtrn,
+ unsigned int *offset)
{
- size_t i;
- int ret;
+ unsigned int i;
FILE *file = NULL;
- char buf[PATH_MAX];
+ char *buf = NULL;
const char *typeDir;
typeDir = DirectoryForInclude(type);
- for (i = 0; i < xkb_context_num_include_paths(ctx); i++) {
- ret = snprintf(buf, sizeof(buf), "%s/%s/%s",
- xkb_context_include_path_get(ctx, i), typeDir, name);
- if (ret >= (ssize_t) sizeof(buf)) {
- log_err(ctx, "File name (%s/%s/%s) too long\n",
+
+ for (i = *offset; i < xkb_context_num_include_paths(ctx); i++) {
+ buf = asprintf_safe("%s/%s/%s", xkb_context_include_path_get(ctx, i),
+ typeDir, name);
+ if (!buf) {
+ log_err_with_code(ctx,
+ XKB_ERROR_ALLOCATION_ERROR,
+ "Failed to alloc buffer for (%s/%s/%s)\n",
xkb_context_include_path_get(ctx, i), typeDir, name);
continue;
}
- file = fopen(buf, "r");
- if (file == NULL) {
- log_err(ctx, "Couldn't open file (%s/%s/%s): %s\n",
- xkb_context_include_path_get(ctx, i), typeDir, name,
- strerror(errno));
- continue;
+
+ file = fopen(buf, "rb");
+ if (file) {
+ if (pathRtrn) {
+ *pathRtrn = buf;
+ buf = NULL;
+ }
+ *offset = i;
+ goto out;
}
- break;
}
- if ((file != NULL) && (pathRtrn != NULL))
- *pathRtrn = strdup(buf);
+ /* We only print warnings if we can't find the file on the first lookup */
+ if (*offset == 0) {
+ log_err_with_code(ctx,
+ XKB_ERROR_INCLUDED_FILE_NOT_FOUND,
+ "Couldn't find file \"%s/%s\" in include paths\n",
+ typeDir, name);
+ LogIncludePaths(ctx);
+ }
+
+out:
+ free(buf);
return file;
}
-/**
- * Open the file given in the include statement and parse it's content.
- * If the statement defines a specific map to use, this map is returned in
- * file_rtrn. Otherwise, the default map is returned.
- *
- * @param ctx The ctx containing include paths
- * @param stmt The include statement, specifying the file name to look for.
- * @param file_type Type of file (FILE_TYPE_KEYCODES, etc.)
- * @param file_rtrn Returns the key map to be used.
- * @param merge_rtrn Always returns stmt->merge.
- *
- * @return true on success or false otherwise.
- */
-bool
-ProcessIncludeFile(struct xkb_context *ctx,
- IncludeStmt * stmt,
- enum xkb_file_type file_type,
- XkbFile ** file_rtrn, enum merge_mode *merge_rtrn)
+XkbFile *
+ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt,
+ enum xkb_file_type file_type)
{
FILE *file;
- XkbFile *rtrn, *mapToUse, *next;
+ XkbFile *xkb_file = NULL;
+ unsigned int offset = 0;
- file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL);
- if (file == NULL) {
- log_err(ctx, "Can't find file \"%s\" for %s include\n", stmt->file,
- DirectoryForInclude(file_type));
- return false;
- }
+ file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL, &offset);
+ if (!file)
+ return NULL;
- if (!XkbParseFile(ctx, file, stmt->file, &rtrn)) {
- log_err(ctx, "Error interpreting include file \"%s\"\n", stmt->file);
+ while (file) {
+ xkb_file = XkbParseFile(ctx, file, stmt->file, stmt->map);
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);
+ if (xkb_file) {
+ if (xkb_file->file_type != file_type) {
+ log_err_with_code(ctx,
+ XKB_ERROR_INVALID_INCLUDED_FILE,
+ "Include file of wrong type (expected %s, got %s); "
+ "Include file \"%s\" ignored\n",
+ xkb_file_type_to_string(file_type),
+ xkb_file_type_to_string(xkb_file->file_type), stmt->file);
+ FreeXkbFile(xkb_file);
+ xkb_file = NULL;
+ } else {
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);
- }
+ offset++;
+ file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL, &offset);
}
- if (mapToUse->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);
- return false;
+ if (!xkb_file) {
+ if (stmt->map)
+ log_err_with_code(ctx,
+ XKB_ERROR_INVALID_INCLUDED_FILE,
+ "Couldn't process include statement for '%s(%s)'\n",
+ stmt->file, stmt->map);
+ else
+ log_err_with_code(ctx,
+ XKB_ERROR_INVALID_INCLUDED_FILE,
+ "Couldn't process include statement for '%s'\n",
+ stmt->file);
}
/* FIXME: we have to check recursive includes here (or somewhere) */
- *file_rtrn = mapToUse;
- *merge_rtrn = stmt->merge;
- return true;
+ return xkb_file;
}