upload tizen2.0 source
[framework/uifw/xorg/util/x11-xkb-utils.git] / xkbcomp / xkbpath.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
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.
15  
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.
24
25  ********************************************************/
26
27 #include <X11/Xlib.h>
28 #include <X11/XKBlib.h>
29
30 #define DEBUG_VAR debugFlags
31 #include "utils.h"
32 #include <stdlib.h>
33 #include <X11/extensions/XKM.h>
34 #include "xkbpath.h"
35
36 #ifndef DFLT_XKB_CONFIG_ROOT
37 #define DFLT_XKB_CONFIG_ROOT    "/usr/lib/X11/xkb"
38 #endif
39
40 #ifndef PATH_MAX
41 #define PATH_MAX 1024
42 #endif
43
44 #define PATH_CHUNK      8       /* initial szPath */
45
46 static Bool noDefaultPath = False;
47 static int szPath;         /* number of entries allocated for includePath */
48 static int nPathEntries;   /* number of actual entries in includePath */
49 static char **includePath; /* Holds all directories we might be including data from */
50
51 /**
52  * Extract the first token from an include statement.
53  * @param str_inout Input statement, modified in-place. Can be passed in
54  * repeatedly. If str_inout is NULL, the parsing has completed.
55  * @param file_rtrn Set to the include file to be used.
56  * @param map_rtrn Set to whatever comes after ), if any.
57  * @param nextop_rtrn Set to the next operation in the complete statement.
58  * @param extra_data Set to the string between ( and ), if any.
59  *
60  * @return True if parsing was succcessful, False for an illegal string.
61  *
62  * Example: "evdev+aliases(qwerty)"
63  *      str_inout = aliases(qwerty)
64  *      nextop_retrn = +
65  *      extra_data = NULL
66  *      file_rtrn = evdev
67  *      map_rtrn = NULL
68  *
69  * 2nd run with "aliases(qwerty)"
70  *      str_inout = NULL
71  *      file_rtrn = aliases
72  *      map_rtrn = qwerty
73  *      extra_data = NULL
74  *      nextop_retrn = ""
75  *
76  */
77 Bool
78 XkbParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
79                    char *nextop_rtrn, char **extra_data)
80 {
81     char *tmp, *str, *next;
82
83     str = *str_inout;
84     if ((*str == '+') || (*str == '|'))
85     {
86         *file_rtrn = *map_rtrn = NULL;
87         *nextop_rtrn = *str;
88         next = str + 1;
89     }
90     else if (*str == '%')
91     {
92         *file_rtrn = *map_rtrn = NULL;
93         *nextop_rtrn = str[1];
94         next = str + 2;
95     }
96     else
97     {
98         /* search for tokens inside the string */
99         next = strpbrk(str, "|+");
100         if (next)
101         {
102             /* set nextop_rtrn to \0, next to next character */
103             *nextop_rtrn = *next;
104             *next++ = '\0';
105         }
106         else
107         {
108             *nextop_rtrn = '\0';
109             next = NULL;
110         }
111         /* search for :, store result in extra_data */
112         tmp = strchr(str, ':');
113         if (tmp != NULL)
114         {
115             *tmp++ = '\0';
116             *extra_data = uStringDup(tmp);
117         }
118         else
119         {
120             *extra_data = NULL;
121         }
122         tmp = strchr(str, '(');
123         if (tmp == NULL)
124         {
125             *file_rtrn = uStringDup(str);
126             *map_rtrn = NULL;
127         }
128         else if (str[0] == '(')
129         {
130             uFree(*extra_data);
131             return False;
132         }
133         else
134         {
135             *tmp++ = '\0';
136             *file_rtrn = uStringDup(str);
137             str = tmp;
138             tmp = strchr(str, ')');
139             if ((tmp == NULL) || (tmp[1] != '\0'))
140             {
141                 uFree(*file_rtrn);
142                 uFree(*extra_data);
143                 return False;
144             }
145             *tmp++ = '\0';
146             *map_rtrn = uStringDup(str);
147         }
148     }
149     if (*nextop_rtrn == '\0')
150         *str_inout = NULL;
151     else if ((*nextop_rtrn == '|') || (*nextop_rtrn == '+'))
152         *str_inout = next;
153     else
154         return False;
155     return True;
156 }
157
158 /**
159  * Init memory for include paths.
160  */
161 Bool
162 XkbInitIncludePath(void)
163 {
164     szPath = PATH_CHUNK;
165     includePath = (char **) calloc(szPath, sizeof(char *));
166     if (includePath == NULL)
167         return False;
168     return True;
169 }
170
171 void
172 XkbAddDefaultDirectoriesToPath(void)
173 {
174     if (noDefaultPath)
175         return;
176     XkbAddDirectoryToPath(DFLT_XKB_CONFIG_ROOT);
177 }
178
179 /**
180  * Remove all entries from the global includePath.
181  */
182 void
183 XkbClearIncludePath(void)
184 {
185     register int i;
186
187     if (szPath > 0)
188     {
189         for (i = 0; i < nPathEntries; i++)
190         {
191             if (includePath[i] != NULL)
192             {
193                 uFree(includePath[i]);
194                 includePath[i] = NULL;
195             }
196         }
197         nPathEntries = 0;
198     }
199     noDefaultPath = True;
200     return;
201 }
202
203 /**
204  * Add the given path to the global includePath variable.
205  * If dir is NULL, the includePath is emptied.
206  */
207 Bool
208 XkbAddDirectoryToPath(const char *dir)
209 {
210     int len;
211     if ((dir == NULL) || (dir[0] == '\0'))
212     {
213         XkbClearIncludePath();
214         return True;
215     }
216 #ifdef __UNIXOS2__
217     dir = (char *) __XOS2RedirRoot(dir);
218 #endif
219     len = strlen(dir);
220     if (len + 2 >= PATH_MAX)
221     {                           /* allow for '/' and at least one character */
222         ERROR2("Path entry (%s) too long (maxiumum length is %d)\n",
223                dir, PATH_MAX - 3);
224         return False;
225     }
226     if (nPathEntries >= szPath)
227     {
228         szPath += PATH_CHUNK;
229         includePath = (char **) realloc(includePath, szPath * sizeof(char *));
230         if (includePath == NULL)
231         {
232             WSGO("Allocation failed (includePath)\n");
233             return False;
234         }
235     }
236     includePath[nPathEntries] =
237         (char *) calloc(strlen(dir) + 1, sizeof(char));
238     if (includePath[nPathEntries] == NULL)
239     {
240         WSGO1("Allocation failed (includePath[%d])\n", nPathEntries);
241         return False;
242     }
243     strcpy(includePath[nPathEntries++], dir);
244     return True;
245 }
246
247 /***====================================================================***/
248
249 /**
250  * Return the xkb directory based on the type.
251  * Do not free the memory returned by this function.
252  */
253 char *
254 XkbDirectoryForInclude(unsigned type)
255 {
256     static char buf[32];
257
258     switch (type)
259     {
260     case XkmSemanticsFile:
261         strcpy(buf, "semantics");
262         break;
263     case XkmLayoutFile:
264         strcpy(buf, "layout");
265         break;
266     case XkmKeymapFile:
267         strcpy(buf, "keymap");
268         break;
269     case XkmKeyNamesIndex:
270         strcpy(buf, "keycodes");
271         break;
272     case XkmTypesIndex:
273         strcpy(buf, "types");
274         break;
275     case XkmSymbolsIndex:
276         strcpy(buf, "symbols");
277         break;
278     case XkmCompatMapIndex:
279         strcpy(buf, "compat");
280         break;
281     case XkmGeometryFile:
282     case XkmGeometryIndex:
283         strcpy(buf, "geometry");
284         break;
285     default:
286         strcpy(buf, "");
287         break;
288     }
289     return buf;
290 }
291
292 /***====================================================================***/
293
294 typedef struct _FileCacheEntry
295 {
296     char *name;
297     unsigned type;
298     char *path;
299     void *data;
300     struct _FileCacheEntry *next;
301 } FileCacheEntry;
302 static FileCacheEntry *fileCache;
303
304 /**
305  * Add the file with the given name to the internal cache to avoid opening and
306  * parsing the file multiple times. If a cache entry for the same name + type
307  * is already present, the entry is overwritten and the data belonging to the
308  * previous entry is returned.
309  *
310  * @parameter name The name of the file (e.g. evdev).
311  * @parameter type Type of the file (XkbTypesIdx, ... or XkbSemanticsFile, ...)
312  * @parameter path The full path to the file.
313  * @parameter data Already parsed data.
314  *
315  * @return The data from the overwritten file or NULL.
316  */
317 void *
318 XkbAddFileToCache(char *name, unsigned type, char *path, void *data)
319 {
320     FileCacheEntry *entry;
321
322     for (entry = fileCache; entry != NULL; entry = entry->next)
323     {
324         if ((type == entry->type) && (uStringEqual(name, entry->name)))
325         {
326             void *old = entry->data;
327             WSGO2("Replacing file cache entry (%s/%d)\n", name, type);
328             entry->path = path;
329             entry->data = data;
330             return old;
331         }
332     }
333     entry = uTypedAlloc(FileCacheEntry);
334     if (entry != NULL)
335     {
336         entry->name = name;
337         entry->type = type;
338         entry->path = path;
339         entry->data = data;
340         entry->next = fileCache;
341         fileCache = entry;
342     }
343     return NULL;
344 }
345
346 /**
347  * Search for the given name + type in the cache.
348  *
349  * @parameter name The name of the file (e.g. evdev).
350  * @parameter type Type of the file (XkbTypesIdx, ... or XkbSemanticsFile, ...)
351  * @parameter pathRtrn Set to the full path of the given entry.
352  *
353  * @return the data from the cache entry or NULL if no matching entry was found.
354  */
355 void *
356 XkbFindFileInCache(char *name, unsigned type, char **pathRtrn)
357 {
358     FileCacheEntry *entry;
359
360     for (entry = fileCache; entry != NULL; entry = entry->next)
361     {
362         if ((type == entry->type) && (uStringEqual(name, entry->name)))
363         {
364             *pathRtrn = entry->path;
365             return entry->data;
366         }
367     }
368     return NULL;
369 }
370
371 /***====================================================================***/
372
373 /**
374  * Search for the given file name in the include directories.
375  *
376  * @param type one of XkbTypesIndex, XkbCompatMapIndex, ..., or
377  * XkbSemanticsFile, XkmKeymapFile, ...
378  * @param pathReturn is set to the full path of the file if found.
379  *
380  * @return an FD to the file or NULL. If NULL is returned, the value of
381  * pathRtrn is undefined.
382  */
383 FILE *
384 XkbFindFileInPath(char *name, unsigned type, char **pathRtrn)
385 {
386     register int i;
387     FILE *file = NULL;
388     int nameLen, typeLen, pathLen;
389     char buf[PATH_MAX], *typeDir;
390
391     typeDir = XkbDirectoryForInclude(type);
392     nameLen = strlen(name);
393     typeLen = strlen(typeDir);
394     for (i = 0; i < nPathEntries; i++)
395     {
396         pathLen = strlen(includePath[i]);
397         if (typeLen < 1)
398             continue;
399
400         if ((nameLen + typeLen + pathLen + 2) >= PATH_MAX)
401         {
402             ERROR3("File name (%s/%s/%s) too long\n", includePath[i],
403                    typeDir, name);
404             ACTION("Ignored\n");
405             continue;
406         }
407         snprintf(buf, sizeof(buf), "%s/%s/%s", includePath[i], typeDir, name);
408         file = fopen(buf, "r");
409         if (file != NULL)
410             break;
411     }
412
413     if ((file != NULL) && (pathRtrn != NULL))
414     {
415         *pathRtrn = (char *) calloc(strlen(buf) + 1, sizeof(char));
416         if (*pathRtrn != NULL)
417             strcpy(*pathRtrn, buf);
418     }
419     return file;
420 }