1 /************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 ********************************************************/
27 #define DEBUG_VAR debugFlags
31 #include "xkbcommon/xkbcommon.h"
32 #include "XKBcommonint.h"
34 #ifndef DFLT_XKB_CONFIG_ROOT
35 #define DFLT_XKB_CONFIG_ROOT "/usr/lib/X11/xkb"
45 static Bool noDefaultPath = False;
46 /* number of entries allocated for includePath */
48 /* number of actual entries in includePath */
49 static int nPathEntries;
50 /* Holds all directories we might be including data from */
51 static char **includePath = NULL;
54 * Extract the first token from an include statement.
55 * @param str_inout Input statement, modified in-place. Can be passed in
56 * repeatedly. If str_inout is NULL, the parsing has completed.
57 * @param file_rtrn Set to the include file to be used.
58 * @param map_rtrn Set to whatever comes after ), if any.
59 * @param nextop_rtrn Set to the next operation in the complete statement.
60 * @param extra_data Set to the string between ( and ), if any.
62 * @return True if parsing was succcessful, False for an illegal string.
64 * Example: "evdev+aliases(qwerty)"
65 * str_inout = aliases(qwerty)
71 * 2nd run with "aliases(qwerty)"
80 XkbParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
81 char *nextop_rtrn, char **extra_data)
83 char *tmp, *str, *next;
86 if ((*str == '+') || (*str == '|'))
88 *file_rtrn = *map_rtrn = NULL;
94 *file_rtrn = *map_rtrn = NULL;
95 *nextop_rtrn = str[1];
100 /* search for tokens inside the string */
101 next = strpbrk(str, "|+");
104 /* set nextop_rtrn to \0, next to next character */
105 *nextop_rtrn = *next;
113 /* search for :, store result in extra_data */
114 tmp = strchr(str, ':');
118 *extra_data = _XkbDupString(tmp);
124 tmp = strchr(str, '(');
127 *file_rtrn = _XkbDupString(str);
130 else if (str[0] == '(')
138 *file_rtrn = _XkbDupString(str);
140 tmp = strchr(str, ')');
141 if ((tmp == NULL) || (tmp[1] != '\0'))
148 *map_rtrn = _XkbDupString(str);
151 if (*nextop_rtrn == '\0')
153 else if ((*nextop_rtrn == '|') || (*nextop_rtrn == '+'))
161 XkbAddDefaultDirectoriesToPath(void);
164 * Init memory for include paths.
167 XkbInitIncludePath(void)
173 includePath = (char **) calloc(szPath, sizeof(char *));
177 XkbAddDefaultDirectoriesToPath();
182 * Remove all entries from the global includePath.
185 XkbClearIncludePath(void)
191 for (i = 0; i < nPathEntries; i++)
193 if (includePath[i] != NULL)
195 free(includePath[i]);
196 includePath[i] = NULL;
201 noDefaultPath = True;
206 * Add the given path to the global includePath variable.
207 * If dir is NULL, the includePath is emptied.
210 XkbAddDirectoryToPath(const char *dir)
214 if (!XkbInitIncludePath())
217 if ((dir == NULL) || (dir[0] == '\0'))
219 XkbClearIncludePath();
223 dir = (char *) __XOS2RedirRoot(dir);
226 if (len + 2 >= PATH_MAX)
227 { /* allow for '/' and at least one character */
228 ERROR("Path entry (%s) too long (maxiumum length is %d)\n",
232 if (nPathEntries >= szPath)
234 szPath += PATH_CHUNK;
235 includePath = (char **) realloc(includePath, szPath * sizeof(char *));
236 if (includePath == NULL)
238 WSGO("Allocation failed (includePath)\n");
242 includePath[nPathEntries] = strdup(dir);
243 if (includePath[nPathEntries] == NULL)
245 WSGO("Allocation failed (includePath[%d])\n", nPathEntries);
253 XkbAddDefaultDirectoriesToPath(void)
255 if (!XkbInitIncludePath())
259 XkbAddDirectoryToPath(DFLT_XKB_CONFIG_ROOT);
262 /***====================================================================***/
265 * Return the xkb directory based on the type.
266 * Do not free the memory returned by this function.
269 XkbDirectoryForInclude(unsigned type)
275 case XkmSemanticsFile:
276 strcpy(buf, "semantics");
279 strcpy(buf, "layout");
282 strcpy(buf, "keymap");
284 case XkmKeyNamesIndex:
285 strcpy(buf, "keycodes");
288 strcpy(buf, "types");
290 case XkmSymbolsIndex:
291 strcpy(buf, "symbols");
293 case XkmCompatMapIndex:
294 strcpy(buf, "compat");
296 case XkmGeometryFile:
297 case XkmGeometryIndex:
298 strcpy(buf, "geometry");
301 strcpy(buf, "rules");
310 /***====================================================================***/
312 typedef struct _FileCacheEntry
318 struct _FileCacheEntry *next;
320 static FileCacheEntry *fileCache;
323 * Add the file with the given name to the internal cache to avoid opening and
324 * parsing the file multiple times. If a cache entry for the same name + type
325 * is already present, the entry is overwritten and the data belonging to the
326 * previous entry is returned.
328 * @parameter name The name of the file (e.g. evdev).
329 * @parameter type Type of the file (XkbTypesIdx, ... or XkbSemanticsFile, ...)
330 * @parameter path The full path to the file.
331 * @parameter data Already parsed data.
333 * @return The data from the overwritten file or NULL.
336 XkbAddFileToCache(char *name, unsigned type, char *path, void *data)
338 FileCacheEntry *entry;
340 for (entry = fileCache; entry != NULL; entry = entry->next)
342 if ((type == entry->type) && (uStringEqual(name, entry->name)))
344 void *old = entry->data;
345 WSGO("Replacing file cache entry (%s/%d)\n", name, type);
351 entry = uTypedAlloc(FileCacheEntry);
358 entry->next = fileCache;
365 * Search for the given name + type in the cache.
367 * @parameter name The name of the file (e.g. evdev).
368 * @parameter type Type of the file (XkbTypesIdx, ... or XkbSemanticsFile, ...)
369 * @parameter pathRtrn Set to the full path of the given entry.
371 * @return the data from the cache entry or NULL if no matching entry was found.
374 XkbFindFileInCache(char *name, unsigned type, char **pathRtrn)
376 FileCacheEntry *entry;
378 for (entry = fileCache; entry != NULL; entry = entry->next)
380 if ((type == entry->type) && (uStringEqual(name, entry->name)))
382 *pathRtrn = entry->path;
389 /***====================================================================***/
392 * Search for the given file name in the include directories.
394 * @param type one of XkbTypesIndex, XkbCompatMapIndex, ..., or
395 * XkbSemanticsFile, XkmKeymapFile, ...
396 * @param pathReturn is set to the full path of the file if found.
398 * @return an FD to the file or NULL. If NULL is returned, the value of
399 * pathRtrn is undefined.
402 XkbFindFileInPath(char *name, unsigned type, char **pathRtrn)
406 int nameLen, typeLen, pathLen;
407 char buf[PATH_MAX], *typeDir;
409 if (!XkbInitIncludePath())
412 typeDir = XkbDirectoryForInclude(type);
413 nameLen = strlen(name);
414 typeLen = strlen(typeDir);
415 for (i = 0; i < nPathEntries; i++)
417 pathLen = strlen(includePath[i]);
421 if ((nameLen + typeLen + pathLen + 2) >= PATH_MAX)
423 ERROR("File name (%s/%s/%s) too long\n", includePath[i],
428 snprintf(buf, sizeof(buf), "%s/%s/%s", includePath[i], typeDir, name);
429 file = fopen(buf, "r");
434 if ((file != NULL) && (pathRtrn != NULL))
436 *pathRtrn = (char *) calloc(strlen(buf) + 1, sizeof(char));
437 if (*pathRtrn != NULL)
438 strcpy(*pathRtrn, buf);