Move ISEMPTY to utils.h
[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     kkctgs = xkb_components_from_rules(ctx, rmlvo);
40     if (!kkctgs) {
41         log_err(ctx,
42                 "couldn't look up rules '%s', model '%s', layout '%s', "
43                 "variant '%s', options '%s'\n",
44                 rmlvo->rules, rmlvo->model, rmlvo->layout, rmlvo->variant,
45                 rmlvo->options);
46         return NULL;
47     }
48
49     inc = IncludeCreate(ctx, kkctgs->keycodes, MERGE_DEFAULT);
50     keycodes = CreateXKBFile(ctx, FILE_TYPE_KEYCODES, NULL,
51                              (ParseCommon *) inc, 0);
52
53     inc = IncludeCreate(ctx, kkctgs->types, MERGE_DEFAULT);
54     types = CreateXKBFile(ctx, FILE_TYPE_TYPES, NULL,
55                           (ParseCommon *) inc, 0);
56     AppendStmt(&keycodes->common, &types->common);
57
58     inc = IncludeCreate(ctx, kkctgs->compat, MERGE_DEFAULT);
59     compat = CreateXKBFile(ctx, FILE_TYPE_COMPAT, NULL,
60                            (ParseCommon *) inc, 0);
61     AppendStmt(&keycodes->common, &compat->common);
62
63     inc = IncludeCreate(ctx, kkctgs->symbols, MERGE_DEFAULT);
64     symbols = CreateXKBFile(ctx, FILE_TYPE_SYMBOLS, NULL,
65                             (ParseCommon *) inc, 0);
66     AppendStmt(&keycodes->common, &symbols->common);
67
68     free(kkctgs->keycodes);
69     free(kkctgs->types);
70     free(kkctgs->compat);
71     free(kkctgs->symbols);
72     free(kkctgs);
73
74     return CreateXKBFile(ctx, FILE_TYPE_KEYMAP, strdup(""),
75                          &keycodes->common, 0);
76 }
77
78 static struct xkb_keymap *
79 new_keymap(struct xkb_context *ctx)
80 {
81     struct xkb_keymap *keymap;
82
83     keymap = calloc(1, sizeof(*keymap));
84     if (!keymap)
85         return NULL;
86
87     keymap->refcnt = 1;
88     keymap->ctx = xkb_context_ref(ctx);
89
90     return keymap;
91 }
92
93 /**
94  * Compile the given file and store the output in keymap.
95  * @param file A list of XkbFiles, each denoting one type (e.g.
96  * FILE_TYPE_KEYCODES, etc.)
97  */
98 static struct xkb_keymap *
99 compile_keymap(struct xkb_context *ctx, XkbFile *file)
100 {
101     bool ok;
102     unsigned have = 0;
103     const char *main_name;
104     struct xkb_keymap *keymap;
105     XkbFile *keycodes = NULL;
106     XkbFile *types = NULL;
107     XkbFile *compat = NULL;
108     XkbFile *symbols = NULL;
109
110     keymap = new_keymap(ctx);
111     if (!keymap)
112         goto err;
113
114     main_name = file->name ? file->name : "(unnamed)";
115
116     /*
117      * Other aggregate file types are converted to FILE_TYPE_KEYMAP
118      * in the parser.
119      */
120     if (file->file_type != FILE_TYPE_KEYMAP) {
121         log_err(ctx, "Cannot compile a %s file alone into a keymap\n",
122                 FileTypeText(file->file_type));
123         goto err;
124     }
125
126     /* Check for duplicate entries in the input file */
127     for (file = (XkbFile *) file->defs; file;
128          file = (XkbFile *) file->common.next) {
129         if (have & file->file_type) {
130             log_err(ctx,
131                     "More than one %s section in a keymap file; "
132                     "All sections after the first ignored\n",
133                     FileTypeText(file->file_type));
134             continue;
135         }
136
137         switch (file->file_type) {
138         case FILE_TYPE_KEYCODES:
139             keycodes = file;
140             break;
141
142         case FILE_TYPE_TYPES:
143             types = file;
144             break;
145
146         case FILE_TYPE_SYMBOLS:
147             symbols = file;
148             break;
149
150         case FILE_TYPE_COMPAT:
151             compat = file;
152             break;
153
154         default:
155             log_err(ctx, "Cannot define %s in a keymap file\n",
156                     FileTypeText(file->file_type));
157             continue;
158         }
159
160         if (!file->topName) {
161             free(file->topName);
162             file->topName = strdup(main_name);
163         }
164
165         have |= file->file_type;
166     }
167
168     if (REQUIRED_FILE_TYPES & (~have)) {
169         enum xkb_file_type bit;
170         enum xkb_file_type missing;
171
172         missing = REQUIRED_FILE_TYPES & (~have);
173
174         for (bit = 1; missing != 0; bit <<= 1) {
175             if (missing & bit) {
176                 log_err(ctx, "Required section %s missing from keymap\n",
177                         FileTypeText(bit));
178                 missing &= ~bit;
179             }
180         }
181
182         goto err;
183     }
184
185     ok = CompileKeycodes(keycodes, keymap, MERGE_OVERRIDE);
186     if (!ok) {
187         log_err(ctx, "Failed to compile keycodes\n");
188         goto err;
189     }
190     ok = CompileKeyTypes(types, keymap, MERGE_OVERRIDE);
191     if (!ok) {
192         log_err(ctx, "Failed to compile key types\n");
193         goto err;
194     }
195     ok = CompileCompatMap(compat, keymap, MERGE_OVERRIDE);
196     if (!ok) {
197         log_err(ctx, "Failed to compile compat map\n");
198         goto err;
199     }
200     ok = CompileSymbols(symbols, keymap, MERGE_OVERRIDE);
201     if (!ok) {
202         log_err(ctx, "Failed to compile symbols\n");
203         goto err;
204     }
205
206     ok = UpdateModifiersFromCompat(keymap);
207     if (!ok)
208         goto err;
209
210     return keymap;
211
212 err:
213     log_err(ctx, "Failed to compile keymap\n");
214     xkb_map_unref(keymap);
215     return NULL;
216 }
217
218 XKB_EXPORT struct xkb_keymap *
219 xkb_map_new_from_names(struct xkb_context *ctx,
220                        const struct xkb_rule_names *rmlvo_in,
221                        enum xkb_map_compile_flags flags)
222 {
223     struct xkb_keymap *keymap = NULL;
224     struct xkb_rule_names rmlvo = *rmlvo_in;
225     XkbFile *file;
226
227     if (isempty(rmlvo.rules))
228         rmlvo.rules = DEFAULT_XKB_RULES;
229     if (isempty(rmlvo.model))
230         rmlvo.model = DEFAULT_XKB_MODEL;
231     if (isempty(rmlvo.layout))
232         rmlvo.layout = DEFAULT_XKB_LAYOUT;
233
234     file = keymap_file_from_names(ctx, &rmlvo);
235     if (!file) {
236         log_err(ctx, "Failed to generate parsed XKB file from components\n");
237         return NULL;
238     }
239
240     keymap = compile_keymap(ctx, file);
241     FreeXKBFile(file);
242
243     return keymap;
244 }
245
246 XKB_EXPORT struct xkb_keymap *
247 xkb_map_new_from_string(struct xkb_context *ctx,
248                         const char *string,
249                         enum xkb_keymap_format format,
250                         enum xkb_map_compile_flags flags)
251 {
252     bool ok;
253     XkbFile *file;
254     struct xkb_keymap *keymap;
255
256     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
257         log_err(ctx, "unsupported keymap format %d\n", format);
258         return NULL;
259     }
260
261     if (!string) {
262         log_err(ctx, "No string specified to generate XKB keymap\n");
263         return NULL;
264     }
265
266     ok = XKBParseString(ctx, string, "input", &file);
267     if (!ok) {
268         log_err(ctx, "Failed to parse input xkb file\n");
269         return NULL;
270     }
271
272     keymap = compile_keymap(ctx, file);
273     FreeXKBFile(file);
274     return keymap;
275 }
276
277 XKB_EXPORT struct xkb_keymap *
278 xkb_map_new_from_file(struct xkb_context *ctx,
279                       FILE *file,
280                       enum xkb_keymap_format format,
281                       enum xkb_map_compile_flags flags)
282 {
283     bool ok;
284     XkbFile *xkb_file;
285     struct xkb_keymap *keymap;
286
287     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
288         log_err(ctx, "Unsupported keymap format %d\n", format);
289         return NULL;
290     }
291
292     if (!file) {
293         log_err(ctx, "No file specified to generate XKB keymap\n");
294         return NULL;
295     }
296
297     ok = XKBParseFile(ctx, file, "(unknown file)", &xkb_file);
298     if (!ok) {
299         log_err(ctx, "Failed to parse input xkb file\n");
300         return NULL;
301     }
302
303     keymap = compile_keymap(ctx, xkb_file);
304     FreeXKBFile(xkb_file);
305     return keymap;
306 }
307
308 XKB_EXPORT struct xkb_keymap *
309 xkb_map_ref(struct xkb_keymap *keymap)
310 {
311     keymap->refcnt++;
312     return keymap;
313 }
314
315 XKB_EXPORT void
316 xkb_map_unref(struct xkb_keymap *keymap)
317 {
318     unsigned int i;
319     struct xkb_key *key;
320
321     if (!keymap || --keymap->refcnt > 0)
322         return;
323
324     for (i = 0; i < keymap->num_types; i++) {
325         free(keymap->types[i].map);
326         free(keymap->types[i].level_names);
327     }
328     free(keymap->types);
329
330     darray_foreach(key, keymap->keys) {
331         free(key->sym_index);
332         free(key->num_syms);
333         darray_free(key->syms);
334         free(key->actions);
335     }
336     darray_free(keymap->keys);
337
338     darray_free(keymap->sym_interpret);
339
340     darray_free(keymap->key_aliases);
341
342     free(keymap->keycodes_section_name);
343     free(keymap->symbols_section_name);
344     free(keymap->types_section_name);
345     free(keymap->compat_section_name);
346
347     xkb_context_unref(keymap->ctx);
348
349     free(keymap);
350 }