Allocate xkb_component_names on stack
[platform/upstream/libxkbcommon.git] / src / xkbcomp / xkbcomp.c
1 /*
2  * Copyright 2009  Dan Nicholson
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Except as contained in this notice, the names of the authors or their
22  * institutions shall not be used in advertising or otherwise to promote the
23  * sale, use or other dealings in this Software without prior written
24  * authorization from the authors.
25  */
26
27 #include "xkbcomp-priv.h"
28 #include "rules.h"
29 #include "parseutils.h"
30
31 static XkbFile *
32 keymap_file_from_names(struct xkb_context *ctx,
33                        const struct xkb_rule_names *rmlvo)
34 {
35     struct xkb_component_names kkctgs;
36     XkbFile *keycodes, *types, *compat, *symbols;
37     IncludeStmt *inc;
38
39     if (!xkb_components_from_rules(ctx, rmlvo, &kkctgs)) {
40         log_err(ctx,
41                 "Couldn't look up rules '%s', model '%s', layout '%s', "
42                 "variant '%s', options '%s'\n",
43                 rmlvo->rules, rmlvo->model, rmlvo->layout, rmlvo->variant,
44                 rmlvo->options);
45         return NULL;
46     }
47
48     inc = IncludeCreate(ctx, kkctgs.keycodes, MERGE_DEFAULT);
49     keycodes = CreateXKBFile(ctx, FILE_TYPE_KEYCODES, NULL,
50                              (ParseCommon *) inc, 0);
51
52     inc = IncludeCreate(ctx, kkctgs.types, MERGE_DEFAULT);
53     types = CreateXKBFile(ctx, FILE_TYPE_TYPES, NULL,
54                           (ParseCommon *) inc, 0);
55     AppendStmt(&keycodes->common, &types->common);
56
57     inc = IncludeCreate(ctx, kkctgs.compat, MERGE_DEFAULT);
58     compat = CreateXKBFile(ctx, FILE_TYPE_COMPAT, NULL,
59                            (ParseCommon *) inc, 0);
60     AppendStmt(&keycodes->common, &compat->common);
61
62     inc = IncludeCreate(ctx, kkctgs.symbols, MERGE_DEFAULT);
63     symbols = CreateXKBFile(ctx, FILE_TYPE_SYMBOLS, NULL,
64                             (ParseCommon *) inc, 0);
65     AppendStmt(&keycodes->common, &symbols->common);
66
67     free(kkctgs.keycodes);
68     free(kkctgs.types);
69     free(kkctgs.compat);
70     free(kkctgs.symbols);
71
72     return CreateXKBFile(ctx, FILE_TYPE_KEYMAP, strdup(""),
73                          &keycodes->common, 0);
74 }
75
76 static struct xkb_keymap *
77 new_keymap(struct xkb_context *ctx)
78 {
79     struct xkb_keymap *keymap;
80
81     keymap = calloc(1, sizeof(*keymap));
82     if (!keymap)
83         return NULL;
84
85     keymap->refcnt = 1;
86     keymap->ctx = xkb_context_ref(ctx);
87
88     return keymap;
89 }
90
91 /**
92  * Compile the given file and store the output in keymap.
93  * @param file A list of XkbFiles, each denoting one type (e.g.
94  * FILE_TYPE_KEYCODES, etc.)
95  */
96 static struct xkb_keymap *
97 compile_keymap(struct xkb_context *ctx, XkbFile *file)
98 {
99     bool ok;
100     unsigned have = 0;
101     const char *main_name;
102     struct xkb_keymap *keymap;
103     XkbFile *keycodes = NULL;
104     XkbFile *types = NULL;
105     XkbFile *compat = NULL;
106     XkbFile *symbols = NULL;
107
108     keymap = new_keymap(ctx);
109     if (!keymap)
110         goto err;
111
112     main_name = file->name ? file->name : "(unnamed)";
113
114     /*
115      * Other aggregate file types are converted to FILE_TYPE_KEYMAP
116      * in the parser.
117      */
118     if (file->file_type != FILE_TYPE_KEYMAP) {
119         log_err(ctx, "Cannot compile a %s file alone into a keymap\n",
120                 FileTypeText(file->file_type));
121         goto err;
122     }
123
124     /* Check for duplicate entries in the input file */
125     for (file = (XkbFile *) file->defs; file;
126          file = (XkbFile *) file->common.next) {
127         if (have & file->file_type) {
128             log_err(ctx,
129                     "More than one %s section in a keymap file; "
130                     "All sections after the first ignored\n",
131                     FileTypeText(file->file_type));
132             continue;
133         }
134
135         switch (file->file_type) {
136         case FILE_TYPE_KEYCODES:
137             keycodes = file;
138             break;
139
140         case FILE_TYPE_TYPES:
141             types = file;
142             break;
143
144         case FILE_TYPE_SYMBOLS:
145             symbols = file;
146             break;
147
148         case FILE_TYPE_COMPAT:
149             compat = file;
150             break;
151
152         default:
153             log_err(ctx, "Cannot define %s in a keymap file\n",
154                     FileTypeText(file->file_type));
155             continue;
156         }
157
158         if (!file->topName) {
159             free(file->topName);
160             file->topName = strdup(main_name);
161         }
162
163         have |= file->file_type;
164     }
165
166     if (REQUIRED_FILE_TYPES & (~have)) {
167         enum xkb_file_type bit;
168         enum xkb_file_type missing;
169
170         missing = REQUIRED_FILE_TYPES & (~have);
171
172         for (bit = 1; missing != 0; bit <<= 1) {
173             if (missing & bit) {
174                 log_err(ctx, "Required section %s missing from keymap\n",
175                         FileTypeText(bit));
176                 missing &= ~bit;
177             }
178         }
179
180         goto err;
181     }
182
183     ok = CompileKeycodes(keycodes, keymap, MERGE_OVERRIDE);
184     if (!ok) {
185         log_err(ctx, "Failed to compile keycodes\n");
186         goto err;
187     }
188     ok = CompileKeyTypes(types, keymap, MERGE_OVERRIDE);
189     if (!ok) {
190         log_err(ctx, "Failed to compile key types\n");
191         goto err;
192     }
193     ok = CompileCompatMap(compat, keymap, MERGE_OVERRIDE);
194     if (!ok) {
195         log_err(ctx, "Failed to compile compat map\n");
196         goto err;
197     }
198     ok = CompileSymbols(symbols, keymap, MERGE_OVERRIDE);
199     if (!ok) {
200         log_err(ctx, "Failed to compile symbols\n");
201         goto err;
202     }
203
204     ok = UpdateModifiersFromCompat(keymap);
205     if (!ok)
206         goto err;
207
208     return keymap;
209
210 err:
211     log_err(ctx, "Failed to compile keymap\n");
212     xkb_map_unref(keymap);
213     return NULL;
214 }
215
216 XKB_EXPORT struct xkb_keymap *
217 xkb_map_new_from_names(struct xkb_context *ctx,
218                        const struct xkb_rule_names *rmlvo_in,
219                        enum xkb_map_compile_flags flags)
220 {
221     struct xkb_rule_names rmlvo = *rmlvo_in;
222     XkbFile *file;
223     struct xkb_keymap *keymap;
224
225     if (isempty(rmlvo.rules))
226         rmlvo.rules = DEFAULT_XKB_RULES;
227     if (isempty(rmlvo.model))
228         rmlvo.model = DEFAULT_XKB_MODEL;
229     if (isempty(rmlvo.layout))
230         rmlvo.layout = DEFAULT_XKB_LAYOUT;
231
232     file = keymap_file_from_names(ctx, &rmlvo);
233     if (!file) {
234         log_err(ctx,
235                 "Failed to generate parsed XKB file from components\n");
236         return NULL;
237     }
238
239     keymap = compile_keymap(ctx, file);
240     FreeXKBFile(file);
241     return keymap;
242 }
243
244 XKB_EXPORT struct xkb_keymap *
245 xkb_map_new_from_string(struct xkb_context *ctx,
246                         const char *string,
247                         enum xkb_keymap_format format,
248                         enum xkb_map_compile_flags flags)
249 {
250     bool ok;
251     XkbFile *file;
252     struct xkb_keymap *keymap;
253
254     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
255         log_err(ctx, "Unsupported keymap format %d\n", format);
256         return NULL;
257     }
258
259     if (!string) {
260         log_err(ctx, "No string specified to generate XKB keymap\n");
261         return NULL;
262     }
263
264     ok = XKBParseString(ctx, string, "input", &file);
265     if (!ok) {
266         log_err(ctx, "Failed to parse input xkb file\n");
267         return NULL;
268     }
269
270     keymap = compile_keymap(ctx, file);
271     FreeXKBFile(file);
272     return keymap;
273 }
274
275 XKB_EXPORT struct xkb_keymap *
276 xkb_map_new_from_file(struct xkb_context *ctx,
277                       FILE *file,
278                       enum xkb_keymap_format format,
279                       enum xkb_map_compile_flags flags)
280 {
281     bool ok;
282     XkbFile *xkb_file;
283     struct xkb_keymap *keymap;
284
285     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
286         log_err(ctx, "Unsupported keymap format %d\n", format);
287         return NULL;
288     }
289
290     if (!file) {
291         log_err(ctx, "No file specified to generate XKB keymap\n");
292         return NULL;
293     }
294
295     ok = XKBParseFile(ctx, file, "(unknown file)", &xkb_file);
296     if (!ok) {
297         log_err(ctx, "Failed to parse input xkb file\n");
298         return NULL;
299     }
300
301     keymap = compile_keymap(ctx, xkb_file);
302     FreeXKBFile(xkb_file);
303     return keymap;
304 }
305
306 XKB_EXPORT struct xkb_keymap *
307 xkb_map_ref(struct xkb_keymap *keymap)
308 {
309     keymap->refcnt++;
310     return keymap;
311 }
312
313 XKB_EXPORT void
314 xkb_map_unref(struct xkb_keymap *keymap)
315 {
316     unsigned int i;
317     struct xkb_key *key;
318
319     if (!keymap || --keymap->refcnt > 0)
320         return;
321
322     for (i = 0; i < keymap->num_types; i++) {
323         free(keymap->types[i].map);
324         free(keymap->types[i].level_names);
325     }
326     free(keymap->types);
327
328     darray_foreach(key, keymap->keys) {
329         free(key->sym_index);
330         free(key->num_syms);
331         darray_free(key->syms);
332         free(key->actions);
333     }
334     darray_free(keymap->keys);
335
336     darray_free(keymap->sym_interpret);
337
338     darray_free(keymap->key_aliases);
339
340     free(keymap->keycodes_section_name);
341     free(keymap->symbols_section_name);
342     free(keymap->types_section_name);
343     free(keymap->compat_section_name);
344
345     xkb_context_unref(keymap->ctx);
346
347     free(keymap);
348 }