4faa5b7082aa262b7968d4bec62eb3e742bf92c0
[platform/upstream/libxkbcommon.git] / src / 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 #define DEBUG_VAR debugFlags
28 #include "utils.h"
29 #include <errno.h>
30 #include <stdlib.h>
31 #include "xkbpath.h"
32 #include "xkbcommon/xkbcommon.h"
33 #include "XKBcommonint.h"
34
35 #ifndef DFLT_XKB_CONFIG_ROOT
36 #define DFLT_XKB_CONFIG_ROOT    "/usr/lib/X11/xkb"
37 #endif
38
39 #ifndef PATH_MAX
40 #define PATH_MAX 1024
41 #endif
42
43 /* initial szPath */
44 #define PATH_CHUNK      8
45
46 static Bool noDefaultPath = False;
47 /* number of entries allocated for includePath */
48 static int szPath;
49 /* number of actual entries in includePath */
50 static int nPathEntries;
51 /* Holds all directories we might be including data from */
52 static char **includePath = NULL;
53
54 /**
55  * Extract the first token from an include statement.
56  * @param str_inout Input statement, modified in-place. Can be passed in
57  * repeatedly. If str_inout is NULL, the parsing has completed.
58  * @param file_rtrn Set to the include file to be used.
59  * @param map_rtrn Set to whatever comes after ), if any.
60  * @param nextop_rtrn Set to the next operation in the complete statement.
61  * @param extra_data Set to the string between ( and ), if any.
62  *
63  * @return True if parsing was succcessful, False for an illegal string.
64  *
65  * Example: "evdev+aliases(qwerty)"
66  *      str_inout = aliases(qwerty)
67  *      nextop_retrn = +
68  *      extra_data = NULL
69  *      file_rtrn = evdev
70  *      map_rtrn = NULL
71  *
72  * 2nd run with "aliases(qwerty)"
73  *      str_inout = NULL
74  *      file_rtrn = aliases
75  *      map_rtrn = qwerty
76  *      extra_data = NULL
77  *      nextop_retrn = ""
78  *
79  */
80 Bool
81 XkbParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
82                    char *nextop_rtrn, char **extra_data)
83 {
84     char *tmp, *str, *next;
85
86     str = *str_inout;
87     if ((*str == '+') || (*str == '|'))
88     {
89         *file_rtrn = *map_rtrn = NULL;
90         *nextop_rtrn = *str;
91         next = str + 1;
92     }
93     else if (*str == '%')
94     {
95         *file_rtrn = *map_rtrn = NULL;
96         *nextop_rtrn = str[1];
97         next = str + 2;
98     }
99     else
100     {
101         /* search for tokens inside the string */
102         next = strpbrk(str, "|+");
103         if (next)
104         {
105             /* set nextop_rtrn to \0, next to next character */
106             *nextop_rtrn = *next;
107             *next++ = '\0';
108         }
109         else
110         {
111             *nextop_rtrn = '\0';
112             next = NULL;
113         }
114         /* search for :, store result in extra_data */
115         tmp = strchr(str, ':');
116         if (tmp != NULL)
117         {
118             *tmp++ = '\0';
119             *extra_data = _XkbDupString(tmp);
120         }
121         else
122         {
123             *extra_data = NULL;
124         }
125         tmp = strchr(str, '(');
126         if (tmp == NULL)
127         {
128             *file_rtrn = _XkbDupString(str);
129             *map_rtrn = NULL;
130         }
131         else if (str[0] == '(')
132         {
133             free(*extra_data);
134             return False;
135         }
136         else
137         {
138             *tmp++ = '\0';
139             *file_rtrn = _XkbDupString(str);
140             str = tmp;
141             tmp = strchr(str, ')');
142             if ((tmp == NULL) || (tmp[1] != '\0'))
143             {
144                 free(*file_rtrn);
145                 free(*extra_data);
146                 return False;
147             }
148             *tmp++ = '\0';
149             *map_rtrn = _XkbDupString(str);
150         }
151     }
152     if (*nextop_rtrn == '\0')
153         *str_inout = NULL;
154     else if ((*nextop_rtrn == '|') || (*nextop_rtrn == '+'))
155         *str_inout = next;
156     else
157         return False;
158     return True;
159 }
160
161 static void
162 XkbAddDefaultDirectoriesToPath(void);
163
164 /**
165  * Init memory for include paths.
166  */
167 static Bool
168 XkbInitIncludePath(void)
169 {
170     if (includePath)
171         return True;
172
173     szPath = PATH_CHUNK;
174     includePath = calloc(szPath, sizeof(char *));
175     if (!includePath)
176         return False;
177
178     XkbAddDefaultDirectoriesToPath();
179     return True;
180 }
181
182 /**
183  * Remove all entries from the global includePath.
184  */
185 static void
186 XkbClearIncludePath(void)
187 {
188     int i;
189
190     if (szPath > 0)
191     {
192         for (i = 0; i < nPathEntries; i++)
193         {
194             if (includePath[i] != NULL)
195             {
196                 free(includePath[i]);
197                 includePath[i] = NULL;
198             }
199         }
200         nPathEntries = 0;
201     }
202     noDefaultPath = True;
203 }
204
205 void
206 XkbFreeIncludePath(void)
207 {
208     XkbClearIncludePath();
209     free(includePath);
210     includePath = NULL;
211 }
212
213 /**
214  * Add the given path to the global includePath variable.
215  * If dir is NULL, the includePath is emptied.
216  */
217 static Bool
218 XkbAddDirectoryToPath(const char *dir)
219 {
220     int len;
221
222     if (!XkbInitIncludePath())
223         return False;
224
225     if ((dir == NULL) || (dir[0] == '\0'))
226     {
227         XkbClearIncludePath();
228         return True;
229     }
230 #ifdef __UNIXOS2__
231     dir = (char *) __XOS2RedirRoot(dir);
232 #endif
233     len = strlen(dir);
234     if (len + 2 >= PATH_MAX)
235     {                           /* allow for '/' and at least one character */
236         ERROR("Path entry (%s) too long (maxiumum length is %d)\n",
237                dir, PATH_MAX - 3);
238         return False;
239     }
240     if (nPathEntries >= szPath)
241     {
242         szPath += PATH_CHUNK;
243         includePath = realloc(includePath, szPath * sizeof(char *));
244         if (includePath == NULL)
245         {
246             WSGO("Allocation failed (includePath)\n");
247             return False;
248         }
249     }
250     includePath[nPathEntries] = strdup(dir);
251     if (includePath[nPathEntries] == NULL)
252     {
253         WSGO("Allocation failed (includePath[%d])\n", nPathEntries);
254         return False;
255     }
256     nPathEntries++;
257     return True;
258 }
259
260 static void
261 XkbAddDefaultDirectoriesToPath(void)
262 {
263     if (!XkbInitIncludePath())
264         return;
265     if (noDefaultPath)
266         return;
267     XkbAddDirectoryToPath(DFLT_XKB_CONFIG_ROOT);
268 }
269
270 /***====================================================================***/
271
272 /**
273  * Return the xkb directory based on the type.
274  */
275 const char *
276 XkbDirectoryForInclude(unsigned type)
277 {
278     switch (type)
279     {
280     case XkmSemanticsFile:
281         return "semantics";
282     case XkmLayoutFile:
283         return "layout";
284     case XkmKeymapFile:
285         return "keymap";
286     case XkmKeyNamesIndex:
287         return "keycodes";
288     case XkmTypesIndex:
289         return "types";
290     case XkmSymbolsIndex:
291         return "symbols";
292     case XkmCompatMapIndex:
293         return "compat";
294     case XkmGeometryFile:
295     case XkmGeometryIndex:
296         return "geometry";
297     case XkmRulesFile:
298         return "rules";
299     default:
300         return "";
301     }
302 }
303
304 /***====================================================================***/
305
306 /**
307  * Search for the given file name in the include directories.
308  *
309  * @param type one of XkbTypesIndex, XkbCompatMapIndex, ..., or
310  * XkbSemanticsFile, XkmKeymapFile, ...
311  * @param pathReturn is set to the full path of the file if found.
312  *
313  * @return an FD to the file or NULL. If NULL is returned, the value of
314  * pathRtrn is undefined.
315  */
316 FILE *
317 XkbFindFileInPath(const char *name, unsigned type, char **pathRtrn)
318 {
319     int i, ret;
320     FILE *file = NULL;
321     char buf[PATH_MAX];
322     const char *typeDir;
323
324     if (!XkbInitIncludePath())
325         return NULL;
326
327     typeDir = XkbDirectoryForInclude(type);
328     for (i = 0; i < nPathEntries; i++)
329     {
330         if (includePath[i] == NULL || *includePath[i] == '\0')
331             continue;
332
333         ret = snprintf(buf, sizeof(buf), "%s/%s/%s",
334                        includePath[i], typeDir, name);
335         if (ret >= sizeof(buf))
336         {
337             ERROR("File name (%s/%s/%s) too long\n", includePath[i],
338                    typeDir, name);
339             ACTION("Ignored\n");
340             continue;
341         }
342         file = fopen(buf, "r");
343         if (file == NULL) {
344             ERROR("Couldn't open file (%s/%s/%s): %s\n", includePath[i],
345                    typeDir, name, strerror(-errno));
346             ACTION("Ignored\n");
347             continue;
348         }
349         break;
350     }
351
352     if ((file != NULL) && (pathRtrn != NULL))
353         *pathRtrn = strdup(buf);
354     return file;
355 }