Move CompileKeymap into xkbcomp.c
[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     unsigned have = 0;
75     bool ok;
76     enum xkb_file_type main_type;
77     const char *main_name;
78     struct xkb_keymap *keymap = XkbcAllocKeyboard(ctx);
79     struct {
80         XkbFile *keycodes;
81         XkbFile *types;
82         XkbFile *compat;
83         XkbFile *symbols;
84     } sections = { NULL };
85
86     if (!keymap)
87         return NULL;
88
89     main_type = file->type;
90     main_name = file->name ? file->name : "(unnamed)";
91
92     /*
93      * Other aggregate file types are converted to FILE_TYPE_KEYMAP
94      * in the parser.
95      */
96     if (main_type != FILE_TYPE_KEYMAP) {
97         ERROR("Cannot compile a %s file alone into a keymap\n",
98               XkbcFileTypeText(main_type));
99         goto err;
100     }
101
102     /* Check for duplicate entries in the input file */
103     for (file = (XkbFile *)file->defs; file;
104          file = (XkbFile *)file->common.next) {
105         if (have & file->type) {
106             ERROR("More than one %s section in a %s file\n",
107                    XkbcFileTypeText(file->type), XkbcFileTypeText(main_type));
108             ACTION("All sections after the first ignored\n");
109             continue;
110         }
111         else if (!(file->type & LEGAL_FILE_TYPES)) {
112             ERROR("Cannot define %s in a %s file\n",
113                    XkbcFileTypeText(file->type), XkbcFileTypeText(main_type));
114             continue;
115         }
116
117         switch (file->type) {
118         case FILE_TYPE_KEYCODES:
119             sections.keycodes = file;
120             break;
121         case FILE_TYPE_TYPES:
122             sections.types = file;
123             break;
124         case FILE_TYPE_SYMBOLS:
125             sections.symbols = file;
126             break;
127         case FILE_TYPE_COMPAT:
128             sections.compat = file;
129             break;
130         default:
131             continue;
132         }
133
134         if (!file->topName || strcmp(file->topName, main_name) != 0) {
135             free(file->topName);
136             file->topName = strdup(main_name);
137         }
138
139         have |= file->type;
140     }
141
142     if (REQUIRED_FILE_TYPES & (~have)) {
143         enum xkb_file_type bit;
144         enum xkb_file_type missing;
145
146         missing = REQUIRED_FILE_TYPES & (~have);
147
148         for (bit = 1; missing != 0; bit <<= 1) {
149             if (missing & bit) {
150                 ERROR("Required section %s missing from keymap\n",
151                       XkbcFileTypeText(bit));
152                 missing &= ~bit;
153             }
154         }
155
156         goto err;
157     }
158
159     /* compile the sections we have in the file one-by-one, or fail. */
160     if (sections.keycodes == NULL ||
161         !CompileKeycodes(sections.keycodes, keymap, MERGE_OVERRIDE))
162     {
163         ERROR("Failed to compile keycodes\n");
164         goto err;
165     }
166     if (sections.types == NULL ||
167         !CompileKeyTypes(sections.types, keymap, MERGE_OVERRIDE))
168     {
169         ERROR("Failed to compile key types\n");
170         goto err;
171     }
172     if (sections.compat == NULL ||
173         !CompileCompatMap(sections.compat, keymap, MERGE_OVERRIDE))
174     {
175         ERROR("Failed to compile compat map\n");
176         goto err;
177     }
178     if (sections.symbols == NULL ||
179         !CompileSymbols(sections.symbols, keymap, MERGE_OVERRIDE))
180     {
181         ERROR("Failed to compile symbols\n");
182         goto err;
183     }
184
185     ok = UpdateModifiersFromCompat(keymap);
186     if (!ok)
187         goto err;
188
189     FreeXKBFile(file);
190     return keymap;
191
192 err:
193     ACTION("Failed to compile keymap\n");
194     xkb_map_unref(keymap);
195     FreeXKBFile(file);
196     return NULL;
197 }
198
199 struct xkb_keymap *
200 xkb_map_new_from_kccgst(struct xkb_context *ctx,
201                         const struct xkb_component_names *kccgst,
202                         enum xkb_map_compile_flags flags)
203 {
204     XkbFile *file;
205
206     if (!kccgst) {
207         ERROR("no components specified\n");
208         return NULL;
209     }
210
211     if (ISEMPTY(kccgst->keycodes)) {
212         ERROR("keycodes required to generate XKB keymap\n");
213         return NULL;
214     }
215
216     if (ISEMPTY(kccgst->compat)) {
217         ERROR("compat map required to generate XKB keymap\n");
218         return NULL;
219     }
220
221     if (ISEMPTY(kccgst->types)) {
222         ERROR("types required to generate XKB keymap\n");
223         return NULL;
224     }
225
226     if (ISEMPTY(kccgst->symbols)) {
227         ERROR("symbols required to generate XKB keymap\n");
228         return NULL;
229     }
230
231     file = keymap_file_from_components(ctx, kccgst);
232     if (!file) {
233         ERROR("failed to generate parsed XKB file from components\n");
234         return NULL;
235     }
236
237     return compile_keymap(ctx, file);
238 }
239
240 _X_EXPORT struct xkb_keymap *
241 xkb_map_new_from_names(struct xkb_context *ctx,
242                        const struct xkb_rule_names *rmlvo,
243                        enum xkb_map_compile_flags flags)
244 {
245     struct xkb_component_names *kkctgs;
246     struct xkb_keymap *keymap;
247
248     if (!rmlvo || ISEMPTY(rmlvo->rules) || ISEMPTY(rmlvo->layout)) {
249         ERROR("rules and layout required to generate XKB keymap\n");
250         return NULL;
251     }
252
253     kkctgs = xkb_components_from_rules(ctx, rmlvo);
254     if (!kkctgs) {
255         ERROR("failed to generate XKB components from rules \"%s\"\n",
256               rmlvo->rules);
257         return NULL;
258     }
259
260     keymap = xkb_map_new_from_kccgst(ctx, kkctgs, 0);
261
262     free(kkctgs->keycodes);
263     free(kkctgs->types);
264     free(kkctgs->compat);
265     free(kkctgs->symbols);
266     free(kkctgs);
267
268     return keymap;
269 }
270
271 _X_EXPORT struct xkb_keymap *
272 xkb_map_new_from_string(struct xkb_context *ctx,
273                         const char *string,
274                         enum xkb_keymap_format format,
275                         enum xkb_map_compile_flags flags)
276 {
277     XkbFile *file;
278
279     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
280         ERROR("unsupported keymap format %d\n", format);
281         return NULL;
282     }
283
284     if (!string) {
285         ERROR("no string specified to generate XKB keymap\n");
286         return NULL;
287     }
288
289     if (!XKBParseString(ctx, string, "input", &file)) {
290         ERROR("failed to parse input xkb file\n");
291         return NULL;
292     }
293
294     return compile_keymap(ctx, file);
295 }
296
297 _X_EXPORT struct xkb_keymap *
298 xkb_map_new_from_file(struct xkb_context *ctx,
299                       FILE *file,
300                       enum xkb_keymap_format format,
301                       enum xkb_map_compile_flags flags)
302 {
303     XkbFile *xkb_file;
304
305     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
306         ERROR("unsupported keymap format %d\n", format);
307         return NULL;
308     }
309
310     if (!file) {
311         ERROR("no file specified to generate XKB keymap\n");
312         return NULL;
313     }
314
315     if (!XKBParseFile(ctx, file, "(unknown file)", &xkb_file)) {
316         ERROR("failed to parse input xkb file\n");
317         return NULL;
318     }
319
320     return compile_keymap(ctx, xkb_file);
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->refcnt > 0)
334         return;
335
336     XkbcFreeKeyboard(keymap);
337 }