xref: /aosp_15_r20/external/libxkbcommon/src/xkbcomp/include.c (revision 2b949d0487e80d67f1fda82db69e101e761f8064)
1*2b949d04SAndroid Build Coastguard Worker /************************************************************
2*2b949d04SAndroid Build Coastguard Worker  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3*2b949d04SAndroid Build Coastguard Worker  *
4*2b949d04SAndroid Build Coastguard Worker  * Permission to use, copy, modify, and distribute this
5*2b949d04SAndroid Build Coastguard Worker  * software and its documentation for any purpose and without
6*2b949d04SAndroid Build Coastguard Worker  * fee is hereby granted, provided that the above copyright
7*2b949d04SAndroid Build Coastguard Worker  * notice appear in all copies and that both that copyright
8*2b949d04SAndroid Build Coastguard Worker  * notice and this permission notice appear in supporting
9*2b949d04SAndroid Build Coastguard Worker  * documentation, and that the name of Silicon Graphics not be
10*2b949d04SAndroid Build Coastguard Worker  * used in advertising or publicity pertaining to distribution
11*2b949d04SAndroid Build Coastguard Worker  * of the software without specific prior written permission.
12*2b949d04SAndroid Build Coastguard Worker  * Silicon Graphics makes no representation about the suitability
13*2b949d04SAndroid Build Coastguard Worker  * of this software for any purpose. It is provided "as is"
14*2b949d04SAndroid Build Coastguard Worker  * without any express or implied warranty.
15*2b949d04SAndroid Build Coastguard Worker  *
16*2b949d04SAndroid Build Coastguard Worker  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17*2b949d04SAndroid Build Coastguard Worker  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18*2b949d04SAndroid Build Coastguard Worker  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19*2b949d04SAndroid Build Coastguard Worker  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20*2b949d04SAndroid Build Coastguard Worker  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21*2b949d04SAndroid Build Coastguard Worker  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22*2b949d04SAndroid Build Coastguard Worker  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23*2b949d04SAndroid Build Coastguard Worker  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24*2b949d04SAndroid Build Coastguard Worker  *
25*2b949d04SAndroid Build Coastguard Worker  ********************************************************/
26*2b949d04SAndroid Build Coastguard Worker 
27*2b949d04SAndroid Build Coastguard Worker /*
28*2b949d04SAndroid Build Coastguard Worker  * Copyright © 2012 Ran Benita <[email protected]>
29*2b949d04SAndroid Build Coastguard Worker  *
30*2b949d04SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
31*2b949d04SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
32*2b949d04SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
33*2b949d04SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34*2b949d04SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
35*2b949d04SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
36*2b949d04SAndroid Build Coastguard Worker  *
37*2b949d04SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
38*2b949d04SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
39*2b949d04SAndroid Build Coastguard Worker  * Software.
40*2b949d04SAndroid Build Coastguard Worker  *
41*2b949d04SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42*2b949d04SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43*2b949d04SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44*2b949d04SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45*2b949d04SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46*2b949d04SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47*2b949d04SAndroid Build Coastguard Worker  * DEALINGS IN THE SOFTWARE.
48*2b949d04SAndroid Build Coastguard Worker  */
49*2b949d04SAndroid Build Coastguard Worker 
50*2b949d04SAndroid Build Coastguard Worker #include "config.h"
51*2b949d04SAndroid Build Coastguard Worker 
52*2b949d04SAndroid Build Coastguard Worker #include <errno.h>
53*2b949d04SAndroid Build Coastguard Worker #include <limits.h>
54*2b949d04SAndroid Build Coastguard Worker #include <stdio.h>
55*2b949d04SAndroid Build Coastguard Worker 
56*2b949d04SAndroid Build Coastguard Worker #include "xkbcomp-priv.h"
57*2b949d04SAndroid Build Coastguard Worker #include "include.h"
58*2b949d04SAndroid Build Coastguard Worker 
59*2b949d04SAndroid Build Coastguard Worker /**
60*2b949d04SAndroid Build Coastguard Worker  * Parse an include statement. Each call returns a file name, along with
61*2b949d04SAndroid Build Coastguard Worker  * (possibly) a specific map in the file, an explicit group designator, and
62*2b949d04SAndroid Build Coastguard Worker  * the separator from the next file, used to determine the merge mode.
63*2b949d04SAndroid Build Coastguard Worker  *
64*2b949d04SAndroid Build Coastguard Worker  * @param str_inout Input statement, modified in-place. Should be passed in
65*2b949d04SAndroid Build Coastguard Worker  * repeatedly. If str_inout is NULL, the parsing has completed.
66*2b949d04SAndroid Build Coastguard Worker  *
67*2b949d04SAndroid Build Coastguard Worker  * @param file_rtrn Set to the name of the include file to be used. Combined
68*2b949d04SAndroid Build Coastguard Worker  * with an enum xkb_file_type, this determines which file to look for in the
69*2b949d04SAndroid Build Coastguard Worker  * include path.
70*2b949d04SAndroid Build Coastguard Worker  *
71*2b949d04SAndroid Build Coastguard Worker  * @param map_rtrn Set to the string between '(' and ')', if any. This will
72*2b949d04SAndroid Build Coastguard Worker  * result in the compilation of a specific named map within the file (e.g.
73*2b949d04SAndroid Build Coastguard Worker  * xkb_symbols "basic" { ... }) , as opposed to the default map of the file.
74*2b949d04SAndroid Build Coastguard Worker  *
75*2b949d04SAndroid Build Coastguard Worker  * @param nextop_rtrn Set to the next operation in the complete statement,
76*2b949d04SAndroid Build Coastguard Worker  * which is '\0' if it's the last file or '+' or '|' if there are more.
77*2b949d04SAndroid Build Coastguard Worker  * Separating the files with '+' sets the merge mode to MERGE_MODE_OVERRIDE,
78*2b949d04SAndroid Build Coastguard Worker  * while '|' sets the merge mode to MERGE_MODE_AUGMENT.
79*2b949d04SAndroid Build Coastguard Worker  *
80*2b949d04SAndroid Build Coastguard Worker  * @param extra_data Set to the string after ':', if any. Currently the
81*2b949d04SAndroid Build Coastguard Worker  * extra data is only used for setting an explicit group index for a symbols
82*2b949d04SAndroid Build Coastguard Worker  * file.
83*2b949d04SAndroid Build Coastguard Worker  *
84*2b949d04SAndroid Build Coastguard Worker  * @return true if parsing was successful, false for an illegal string.
85*2b949d04SAndroid Build Coastguard Worker  *
86*2b949d04SAndroid Build Coastguard Worker  * Example: "evdev+aliases(qwerty):2"
87*2b949d04SAndroid Build Coastguard Worker  *      str_inout = "aliases(qwerty):2"
88*2b949d04SAndroid Build Coastguard Worker  *      file_rtrn = "evdev"
89*2b949d04SAndroid Build Coastguard Worker  *      map_rtrn = NULL
90*2b949d04SAndroid Build Coastguard Worker  *      nextop_retrn = "+"
91*2b949d04SAndroid Build Coastguard Worker  *      extra_data = NULL
92*2b949d04SAndroid Build Coastguard Worker  *
93*2b949d04SAndroid Build Coastguard Worker  * 2nd run with "aliases(qwerty):2"
94*2b949d04SAndroid Build Coastguard Worker  *      str_inout = NULL
95*2b949d04SAndroid Build Coastguard Worker  *      file_rtrn = "aliases"
96*2b949d04SAndroid Build Coastguard Worker  *      map_rtrn = "qwerty"
97*2b949d04SAndroid Build Coastguard Worker  *      nextop_retrn = ""
98*2b949d04SAndroid Build Coastguard Worker  *      extra_data = "2"
99*2b949d04SAndroid Build Coastguard Worker  *
100*2b949d04SAndroid Build Coastguard Worker  */
101*2b949d04SAndroid Build Coastguard Worker bool
ParseIncludeMap(char ** str_inout,char ** file_rtrn,char ** map_rtrn,char * nextop_rtrn,char ** extra_data)102*2b949d04SAndroid Build Coastguard Worker ParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
103*2b949d04SAndroid Build Coastguard Worker                 char *nextop_rtrn, char **extra_data)
104*2b949d04SAndroid Build Coastguard Worker {
105*2b949d04SAndroid Build Coastguard Worker     char *tmp, *str, *next;
106*2b949d04SAndroid Build Coastguard Worker 
107*2b949d04SAndroid Build Coastguard Worker     str = *str_inout;
108*2b949d04SAndroid Build Coastguard Worker 
109*2b949d04SAndroid Build Coastguard Worker     /*
110*2b949d04SAndroid Build Coastguard Worker      * Find the position in the string where the next file is included,
111*2b949d04SAndroid Build Coastguard Worker      * if there is more than one left in the statement.
112*2b949d04SAndroid Build Coastguard Worker      */
113*2b949d04SAndroid Build Coastguard Worker     next = strpbrk(str, "|+");
114*2b949d04SAndroid Build Coastguard Worker     if (next) {
115*2b949d04SAndroid Build Coastguard Worker         /* Got more files, this function will be called again. */
116*2b949d04SAndroid Build Coastguard Worker         *nextop_rtrn = *next;
117*2b949d04SAndroid Build Coastguard Worker         /* Separate the string, for strchr etc. to work on this file only. */
118*2b949d04SAndroid Build Coastguard Worker         *next++ = '\0';
119*2b949d04SAndroid Build Coastguard Worker     }
120*2b949d04SAndroid Build Coastguard Worker     else {
121*2b949d04SAndroid Build Coastguard Worker         /* This is the last file in this statement, won't be called again. */
122*2b949d04SAndroid Build Coastguard Worker         *nextop_rtrn = '\0';
123*2b949d04SAndroid Build Coastguard Worker         next = NULL;
124*2b949d04SAndroid Build Coastguard Worker     }
125*2b949d04SAndroid Build Coastguard Worker 
126*2b949d04SAndroid Build Coastguard Worker     /*
127*2b949d04SAndroid Build Coastguard Worker      * Search for the explicit group designator, if any. If it's there,
128*2b949d04SAndroid Build Coastguard Worker      * it goes after the file name and map.
129*2b949d04SAndroid Build Coastguard Worker      */
130*2b949d04SAndroid Build Coastguard Worker     tmp = strchr(str, ':');
131*2b949d04SAndroid Build Coastguard Worker     if (tmp != NULL) {
132*2b949d04SAndroid Build Coastguard Worker         *tmp++ = '\0';
133*2b949d04SAndroid Build Coastguard Worker         *extra_data = strdup(tmp);
134*2b949d04SAndroid Build Coastguard Worker     }
135*2b949d04SAndroid Build Coastguard Worker     else {
136*2b949d04SAndroid Build Coastguard Worker         *extra_data = NULL;
137*2b949d04SAndroid Build Coastguard Worker     }
138*2b949d04SAndroid Build Coastguard Worker 
139*2b949d04SAndroid Build Coastguard Worker     /* Look for a map, if any. */
140*2b949d04SAndroid Build Coastguard Worker     tmp = strchr(str, '(');
141*2b949d04SAndroid Build Coastguard Worker     if (tmp == NULL) {
142*2b949d04SAndroid Build Coastguard Worker         /* No map. */
143*2b949d04SAndroid Build Coastguard Worker         *file_rtrn = strdup(str);
144*2b949d04SAndroid Build Coastguard Worker         *map_rtrn = NULL;
145*2b949d04SAndroid Build Coastguard Worker     }
146*2b949d04SAndroid Build Coastguard Worker     else if (str[0] == '(') {
147*2b949d04SAndroid Build Coastguard Worker         /* Map without file - invalid. */
148*2b949d04SAndroid Build Coastguard Worker         free(*extra_data);
149*2b949d04SAndroid Build Coastguard Worker         return false;
150*2b949d04SAndroid Build Coastguard Worker     }
151*2b949d04SAndroid Build Coastguard Worker     else {
152*2b949d04SAndroid Build Coastguard Worker         /* Got a map; separate the file and the map for the strdup's. */
153*2b949d04SAndroid Build Coastguard Worker         *tmp++ = '\0';
154*2b949d04SAndroid Build Coastguard Worker         *file_rtrn = strdup(str);
155*2b949d04SAndroid Build Coastguard Worker         str = tmp;
156*2b949d04SAndroid Build Coastguard Worker         tmp = strchr(str, ')');
157*2b949d04SAndroid Build Coastguard Worker         if (tmp == NULL || tmp[1] != '\0') {
158*2b949d04SAndroid Build Coastguard Worker             free(*file_rtrn);
159*2b949d04SAndroid Build Coastguard Worker             free(*extra_data);
160*2b949d04SAndroid Build Coastguard Worker             return false;
161*2b949d04SAndroid Build Coastguard Worker         }
162*2b949d04SAndroid Build Coastguard Worker         *tmp++ = '\0';
163*2b949d04SAndroid Build Coastguard Worker         *map_rtrn = strdup(str);
164*2b949d04SAndroid Build Coastguard Worker     }
165*2b949d04SAndroid Build Coastguard Worker 
166*2b949d04SAndroid Build Coastguard Worker     /* Set up the next file for the next call, if any. */
167*2b949d04SAndroid Build Coastguard Worker     if (*nextop_rtrn == '\0')
168*2b949d04SAndroid Build Coastguard Worker         *str_inout = NULL;
169*2b949d04SAndroid Build Coastguard Worker     else if (*nextop_rtrn == '|' || *nextop_rtrn == '+')
170*2b949d04SAndroid Build Coastguard Worker         *str_inout = next;
171*2b949d04SAndroid Build Coastguard Worker     else
172*2b949d04SAndroid Build Coastguard Worker         return false;
173*2b949d04SAndroid Build Coastguard Worker 
174*2b949d04SAndroid Build Coastguard Worker     return true;
175*2b949d04SAndroid Build Coastguard Worker }
176*2b949d04SAndroid Build Coastguard Worker 
177*2b949d04SAndroid Build Coastguard Worker static const char *xkb_file_type_include_dirs[_FILE_TYPE_NUM_ENTRIES] = {
178*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_KEYCODES] = "keycodes",
179*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_TYPES] = "types",
180*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_COMPAT] = "compat",
181*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_SYMBOLS] = "symbols",
182*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_GEOMETRY] = "geometry",
183*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_KEYMAP] = "keymap",
184*2b949d04SAndroid Build Coastguard Worker     [FILE_TYPE_RULES] = "rules",
185*2b949d04SAndroid Build Coastguard Worker };
186*2b949d04SAndroid Build Coastguard Worker 
187*2b949d04SAndroid Build Coastguard Worker /**
188*2b949d04SAndroid Build Coastguard Worker  * Return the xkb directory based on the type.
189*2b949d04SAndroid Build Coastguard Worker  */
190*2b949d04SAndroid Build Coastguard Worker static const char *
DirectoryForInclude(enum xkb_file_type type)191*2b949d04SAndroid Build Coastguard Worker DirectoryForInclude(enum xkb_file_type type)
192*2b949d04SAndroid Build Coastguard Worker {
193*2b949d04SAndroid Build Coastguard Worker     if (type >= _FILE_TYPE_NUM_ENTRIES)
194*2b949d04SAndroid Build Coastguard Worker         return "";
195*2b949d04SAndroid Build Coastguard Worker     return xkb_file_type_include_dirs[type];
196*2b949d04SAndroid Build Coastguard Worker }
197*2b949d04SAndroid Build Coastguard Worker 
198*2b949d04SAndroid Build Coastguard Worker static void
LogIncludePaths(struct xkb_context * ctx)199*2b949d04SAndroid Build Coastguard Worker LogIncludePaths(struct xkb_context *ctx)
200*2b949d04SAndroid Build Coastguard Worker {
201*2b949d04SAndroid Build Coastguard Worker     unsigned int i;
202*2b949d04SAndroid Build Coastguard Worker 
203*2b949d04SAndroid Build Coastguard Worker     if (xkb_context_num_include_paths(ctx) > 0) {
204*2b949d04SAndroid Build Coastguard Worker         log_err(ctx, "%d include paths searched:\n",
205*2b949d04SAndroid Build Coastguard Worker                 xkb_context_num_include_paths(ctx));
206*2b949d04SAndroid Build Coastguard Worker         for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
207*2b949d04SAndroid Build Coastguard Worker             log_err(ctx, "\t%s\n",
208*2b949d04SAndroid Build Coastguard Worker                     xkb_context_include_path_get(ctx, i));
209*2b949d04SAndroid Build Coastguard Worker     }
210*2b949d04SAndroid Build Coastguard Worker     else {
211*2b949d04SAndroid Build Coastguard Worker         log_err(ctx, "There are no include paths to search\n");
212*2b949d04SAndroid Build Coastguard Worker     }
213*2b949d04SAndroid Build Coastguard Worker 
214*2b949d04SAndroid Build Coastguard Worker     if (xkb_context_num_failed_include_paths(ctx) > 0) {
215*2b949d04SAndroid Build Coastguard Worker         log_err(ctx, "%d include paths could not be added:\n",
216*2b949d04SAndroid Build Coastguard Worker                 xkb_context_num_failed_include_paths(ctx));
217*2b949d04SAndroid Build Coastguard Worker         for (i = 0; i < xkb_context_num_failed_include_paths(ctx); i++)
218*2b949d04SAndroid Build Coastguard Worker             log_err(ctx, "\t%s\n",
219*2b949d04SAndroid Build Coastguard Worker                     xkb_context_failed_include_path_get(ctx, i));
220*2b949d04SAndroid Build Coastguard Worker     }
221*2b949d04SAndroid Build Coastguard Worker }
222*2b949d04SAndroid Build Coastguard Worker 
223*2b949d04SAndroid Build Coastguard Worker /**
224*2b949d04SAndroid Build Coastguard Worker  * Return an open file handle to the first file (counting from offset) with the
225*2b949d04SAndroid Build Coastguard Worker  * given name in the include paths, starting at the offset.
226*2b949d04SAndroid Build Coastguard Worker  *
227*2b949d04SAndroid Build Coastguard Worker  * offset must be zero the first time this is called and is set to the index the
228*2b949d04SAndroid Build Coastguard Worker  * file was found. Call again with offset+1 to keep searching through the
229*2b949d04SAndroid Build Coastguard Worker  * include paths.
230*2b949d04SAndroid Build Coastguard Worker  *
231*2b949d04SAndroid Build Coastguard Worker  * If this function returns NULL, no more files are available.
232*2b949d04SAndroid Build Coastguard Worker  */
233*2b949d04SAndroid Build Coastguard Worker FILE *
FindFileInXkbPath(struct xkb_context * ctx,const char * name,enum xkb_file_type type,char ** pathRtrn,unsigned int * offset)234*2b949d04SAndroid Build Coastguard Worker FindFileInXkbPath(struct xkb_context *ctx, const char *name,
235*2b949d04SAndroid Build Coastguard Worker                   enum xkb_file_type type, char **pathRtrn,
236*2b949d04SAndroid Build Coastguard Worker                   unsigned int *offset)
237*2b949d04SAndroid Build Coastguard Worker {
238*2b949d04SAndroid Build Coastguard Worker     unsigned int i;
239*2b949d04SAndroid Build Coastguard Worker     FILE *file = NULL;
240*2b949d04SAndroid Build Coastguard Worker     char *buf = NULL;
241*2b949d04SAndroid Build Coastguard Worker     const char *typeDir;
242*2b949d04SAndroid Build Coastguard Worker 
243*2b949d04SAndroid Build Coastguard Worker     typeDir = DirectoryForInclude(type);
244*2b949d04SAndroid Build Coastguard Worker 
245*2b949d04SAndroid Build Coastguard Worker     for (i = *offset; i < xkb_context_num_include_paths(ctx); i++) {
246*2b949d04SAndroid Build Coastguard Worker         buf = asprintf_safe("%s/%s/%s", xkb_context_include_path_get(ctx, i),
247*2b949d04SAndroid Build Coastguard Worker                             typeDir, name);
248*2b949d04SAndroid Build Coastguard Worker         if (!buf) {
249*2b949d04SAndroid Build Coastguard Worker             log_err(ctx, "Failed to alloc buffer for (%s/%s/%s)\n",
250*2b949d04SAndroid Build Coastguard Worker                     xkb_context_include_path_get(ctx, i), typeDir, name);
251*2b949d04SAndroid Build Coastguard Worker             continue;
252*2b949d04SAndroid Build Coastguard Worker         }
253*2b949d04SAndroid Build Coastguard Worker 
254*2b949d04SAndroid Build Coastguard Worker         file = fopen(buf, "rb");
255*2b949d04SAndroid Build Coastguard Worker         if (file) {
256*2b949d04SAndroid Build Coastguard Worker             if (pathRtrn) {
257*2b949d04SAndroid Build Coastguard Worker                 *pathRtrn = buf;
258*2b949d04SAndroid Build Coastguard Worker                 buf = NULL;
259*2b949d04SAndroid Build Coastguard Worker             }
260*2b949d04SAndroid Build Coastguard Worker             *offset = i;
261*2b949d04SAndroid Build Coastguard Worker             goto out;
262*2b949d04SAndroid Build Coastguard Worker         }
263*2b949d04SAndroid Build Coastguard Worker     }
264*2b949d04SAndroid Build Coastguard Worker 
265*2b949d04SAndroid Build Coastguard Worker     /* We only print warnings if we can't find the file on the first lookup */
266*2b949d04SAndroid Build Coastguard Worker     if (*offset == 0) {
267*2b949d04SAndroid Build Coastguard Worker         log_err(ctx, "Couldn't find file \"%s/%s\" in include paths\n",
268*2b949d04SAndroid Build Coastguard Worker                 typeDir, name);
269*2b949d04SAndroid Build Coastguard Worker         LogIncludePaths(ctx);
270*2b949d04SAndroid Build Coastguard Worker     }
271*2b949d04SAndroid Build Coastguard Worker 
272*2b949d04SAndroid Build Coastguard Worker out:
273*2b949d04SAndroid Build Coastguard Worker     free(buf);
274*2b949d04SAndroid Build Coastguard Worker     return file;
275*2b949d04SAndroid Build Coastguard Worker }
276*2b949d04SAndroid Build Coastguard Worker 
277*2b949d04SAndroid Build Coastguard Worker XkbFile *
ProcessIncludeFile(struct xkb_context * ctx,IncludeStmt * stmt,enum xkb_file_type file_type)278*2b949d04SAndroid Build Coastguard Worker ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt,
279*2b949d04SAndroid Build Coastguard Worker                    enum xkb_file_type file_type)
280*2b949d04SAndroid Build Coastguard Worker {
281*2b949d04SAndroid Build Coastguard Worker     FILE *file;
282*2b949d04SAndroid Build Coastguard Worker     XkbFile *xkb_file = NULL;
283*2b949d04SAndroid Build Coastguard Worker     unsigned int offset = 0;
284*2b949d04SAndroid Build Coastguard Worker 
285*2b949d04SAndroid Build Coastguard Worker     file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL, &offset);
286*2b949d04SAndroid Build Coastguard Worker     if (!file)
287*2b949d04SAndroid Build Coastguard Worker         return NULL;
288*2b949d04SAndroid Build Coastguard Worker 
289*2b949d04SAndroid Build Coastguard Worker     while (file) {
290*2b949d04SAndroid Build Coastguard Worker         xkb_file = XkbParseFile(ctx, file, stmt->file, stmt->map);
291*2b949d04SAndroid Build Coastguard Worker         fclose(file);
292*2b949d04SAndroid Build Coastguard Worker 
293*2b949d04SAndroid Build Coastguard Worker         if (xkb_file) {
294*2b949d04SAndroid Build Coastguard Worker             if (xkb_file->file_type != file_type) {
295*2b949d04SAndroid Build Coastguard Worker                 log_err(ctx,
296*2b949d04SAndroid Build Coastguard Worker                         "Include file of wrong type (expected %s, got %s); "
297*2b949d04SAndroid Build Coastguard Worker                         "Include file \"%s\" ignored\n",
298*2b949d04SAndroid Build Coastguard Worker                         xkb_file_type_to_string(file_type),
299*2b949d04SAndroid Build Coastguard Worker                         xkb_file_type_to_string(xkb_file->file_type), stmt->file);
300*2b949d04SAndroid Build Coastguard Worker                 FreeXkbFile(xkb_file);
301*2b949d04SAndroid Build Coastguard Worker                 xkb_file = NULL;
302*2b949d04SAndroid Build Coastguard Worker             } else {
303*2b949d04SAndroid Build Coastguard Worker                 break;
304*2b949d04SAndroid Build Coastguard Worker             }
305*2b949d04SAndroid Build Coastguard Worker         }
306*2b949d04SAndroid Build Coastguard Worker 
307*2b949d04SAndroid Build Coastguard Worker         offset++;
308*2b949d04SAndroid Build Coastguard Worker         file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL, &offset);
309*2b949d04SAndroid Build Coastguard Worker     }
310*2b949d04SAndroid Build Coastguard Worker 
311*2b949d04SAndroid Build Coastguard Worker     if (!xkb_file) {
312*2b949d04SAndroid Build Coastguard Worker         if (stmt->map)
313*2b949d04SAndroid Build Coastguard Worker             log_err(ctx, "Couldn't process include statement for '%s(%s)'\n",
314*2b949d04SAndroid Build Coastguard Worker                     stmt->file, stmt->map);
315*2b949d04SAndroid Build Coastguard Worker         else
316*2b949d04SAndroid Build Coastguard Worker             log_err(ctx, "Couldn't process include statement for '%s'\n",
317*2b949d04SAndroid Build Coastguard Worker                     stmt->file);
318*2b949d04SAndroid Build Coastguard Worker     }
319*2b949d04SAndroid Build Coastguard Worker 
320*2b949d04SAndroid Build Coastguard Worker     /* FIXME: we have to check recursive includes here (or somewhere) */
321*2b949d04SAndroid Build Coastguard Worker 
322*2b949d04SAndroid Build Coastguard Worker     return xkb_file;
323*2b949d04SAndroid Build Coastguard Worker }
324