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