diff options
Diffstat (limited to 'src/3rdparty/xkbcommon/src/xkbcomp/include.c')
-rw-r--r-- | src/3rdparty/xkbcommon/src/xkbcomp/include.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/src/3rdparty/xkbcommon/src/xkbcomp/include.c b/src/3rdparty/xkbcommon/src/xkbcomp/include.c new file mode 100644 index 0000000000..b4a4014635 --- /dev/null +++ b/src/3rdparty/xkbcommon/src/xkbcomp/include.c @@ -0,0 +1,289 @@ +/************************************************************ + * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of Silicon Graphics not be + * used in advertising or publicity pertaining to distribution + * of the software without specific prior written permission. + * Silicon Graphics makes no representation about the suitability + * of this software for any purpose. It is provided "as is" + * without any express or implied warranty. + * + * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH + * THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + ********************************************************/ + +/* + * 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 <errno.h> +#include <limits.h> +#include <stdio.h> + +#include "xkbcomp-priv.h" +#include "include.h" + +/** + * Parse an include statement. Each call returns a file name, along with + * (possibly) a specific map in the file, an explicit group designator, and + * the separator from the next file, used to determine the merge mode. + * + * @param str_inout Input statement, modified in-place. Should be passed in + * repeatedly. If str_inout is NULL, the parsing has completed. + * + * @param file_rtrn Set to the name of the include file to be used. Combined + * with an enum xkb_file_type, this determines which file to look for in the + * include path. + * + * @param map_rtrn Set to the string between '(' and ')', if any. This will + * result in the compilation of a specific named map within the file (e.g. + * xkb_symbols "basic" { ... }) , as opposed to the default map of the file. + * + * @param nextop_rtrn Set to the next operation in the complete statement, + * which is '\0' if it's the last file or '+' or '|' if there are more. + * Separating the files with '+' sets the merge mode to MERGE_MODE_OVERRIDE, + * while '|' sets the merge mode to MERGE_MODE_AUGMENT. + * + * @param extra_data Set to the string after ':', if any. Currently the + * extra data is only used for setting an explicit group index for a symbols + * file. + * + * @return true if parsing was successful, false for an illegal string. + * + * Example: "evdev+aliases(qwerty):2" + * str_inout = "aliases(qwerty):2" + * file_rtrn = "evdev" + * map_rtrn = NULL + * nextop_retrn = "+" + * extra_data = NULL + * + * 2nd run with "aliases(qwerty):2" + * str_inout = NULL + * file_rtrn = "aliases" + * map_rtrn = "qwerty" + * nextop_retrn = "" + * extra_data = "2" + * + */ +bool +ParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn, + char *nextop_rtrn, char **extra_data) +{ + char *tmp, *str, *next; + + str = *str_inout; + + /* + * Find the position in the string where the next file is included, + * if there is more than one left in the statement. + */ + next = strpbrk(str, "|+"); + if (next) { + /* Got more files, this function will be called again. */ + *nextop_rtrn = *next; + /* Separate the string, for strchr etc. to work on this file only. */ + *next++ = '\0'; + } + else { + /* This is the last file in this statement, won't be called again. */ + *nextop_rtrn = '\0'; + next = NULL; + } + + /* + * Search for the explicit group designator, if any. If it's there, + * it goes after the file name and map. + */ + tmp = strchr(str, ':'); + if (tmp != NULL) { + *tmp++ = '\0'; + *extra_data = strdup(tmp); + } + else { + *extra_data = NULL; + } + + /* Look for a map, if any. */ + tmp = strchr(str, '('); + if (tmp == NULL) { + /* No map. */ + *file_rtrn = strdup(str); + *map_rtrn = NULL; + } + else if (str[0] == '(') { + /* Map without file - invalid. */ + free(*extra_data); + return false; + } + else { + /* Got a map; separate the file and the map for the strdup's. */ + *tmp++ = '\0'; + *file_rtrn = strdup(str); + str = tmp; + tmp = strchr(str, ')'); + if (tmp == NULL || tmp[1] != '\0') { + free(*file_rtrn); + free(*extra_data); + return false; + } + *tmp++ = '\0'; + *map_rtrn = strdup(str); + } + + /* Set up the next file for the next call, if any. */ + if (*nextop_rtrn == '\0') + *str_inout = NULL; + else if (*nextop_rtrn == '|' || *nextop_rtrn == '+') + *str_inout = next; + else + return false; + + return true; +} + +static const char *xkb_file_type_include_dirs[_FILE_TYPE_NUM_ENTRIES] = { + [FILE_TYPE_KEYCODES] = "keycodes", + [FILE_TYPE_TYPES] = "types", + [FILE_TYPE_COMPAT] = "compat", + [FILE_TYPE_SYMBOLS] = "symbols", + [FILE_TYPE_GEOMETRY] = "geometry", + [FILE_TYPE_KEYMAP] = "keymap", + [FILE_TYPE_RULES] = "rules", +}; + +/** + * Return the xkb directory based on the type. + */ +static const char * +DirectoryForInclude(enum xkb_file_type type) +{ + if (type >= _FILE_TYPE_NUM_ENTRIES) + return ""; + return xkb_file_type_include_dirs[type]; +} + +FILE * +FindFileInXkbPath(struct xkb_context *ctx, const char *name, + enum xkb_file_type type, char **pathRtrn) +{ + unsigned int i; + FILE *file = NULL; + char buf[PATH_MAX]; + const char *typeDir; + + typeDir = DirectoryForInclude(type); + + for (i = 0; i < xkb_context_num_include_paths(ctx); i++) { + int 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", + xkb_context_include_path_get(ctx, i), typeDir, name); + continue; + } + + file = fopen(buf, "r"); + if (file) + break; + } + + if (!file) { + log_err(ctx, "Couldn't find file \"%s/%s\" in include paths\n", + typeDir, name); + + if (xkb_context_num_include_paths(ctx) > 0) { + log_err(ctx, "%d include paths searched:\n", + xkb_context_num_include_paths(ctx)); + for (i = 0; i < xkb_context_num_include_paths(ctx); i++) + log_err(ctx, "\t%s\n", + xkb_context_include_path_get(ctx, i)); + } + else { + log_err(ctx, "There are no include paths to search\n"); + } + + if (xkb_context_num_failed_include_paths(ctx) > 0) { + log_err(ctx, "%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(ctx, "\t%s\n", + xkb_context_failed_include_path_get(ctx, i)); + } + + return NULL; + } + + if (pathRtrn) + *pathRtrn = strdup(buf); + return file; +} + +XkbFile * +ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt, + enum xkb_file_type file_type) +{ + FILE *file; + XkbFile *xkb_file; + + file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL); + if (!file) + return false; + + xkb_file = XkbParseFile(ctx, file, stmt->file, stmt->map); + fclose(file); + 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); + return NULL; + } + + 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(xkb_file->file_type), stmt->file); + FreeXkbFile(xkb_file); + return NULL; + } + + /* FIXME: we have to check recursive includes here (or somewhere) */ + + return xkb_file; +} |