Use const char * in struct xkb_rule_names
[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 <limits.h>
28 #include "xkbcomp.h"
29 #include "xkballoc.h"
30 #include "xkbrules.h"
31 #include "xkbpath.h"
32 #include "parseutils.h"
33 #include "utils.h"
34
35 /* Global debugging flags */
36 unsigned int debugFlags = 0;
37 unsigned int warningLevel = 0;
38
39 #define ISEMPTY(str) (!(str) || (strlen(str) == 0))
40
41 static XkbFile *
42 XkbKeymapFileFromComponents(const struct xkb_component_names * ktcsg)
43 {
44     XkbFile *keycodes, *types, *compat, *symbols, *geometry;
45     IncludeStmt *inc;
46
47     if (!ktcsg) {
48         ERROR("no components to generate keymap file from\n");
49         return NULL;
50     }
51
52     inc = IncludeCreate(ktcsg->keycodes, MergeDefault);
53     keycodes = CreateXKBFile(XkmKeyNamesIndex, NULL, (ParseCommon *)inc, 0);
54
55     inc = IncludeCreate(ktcsg->types, MergeDefault);
56     types = CreateXKBFile(XkmTypesIndex, NULL, (ParseCommon *)inc, 0);
57     AppendStmt(&keycodes->common, &types->common);
58
59     inc = IncludeCreate(ktcsg->compat, MergeDefault);
60     compat = CreateXKBFile(XkmCompatMapIndex, NULL, (ParseCommon *)inc, 0);
61     AppendStmt(&keycodes->common, &compat->common);
62
63     inc = IncludeCreate(ktcsg->symbols, MergeDefault);
64     symbols = CreateXKBFile(XkmSymbolsIndex, NULL, (ParseCommon *)inc, 0);
65     AppendStmt(&keycodes->common, &symbols->common);
66
67     inc = IncludeCreate(ktcsg->geometry, MergeDefault);
68     geometry = CreateXKBFile(XkmGeometryIndex, NULL, (ParseCommon *)inc, 0);
69     AppendStmt(&keycodes->common, &geometry->common);
70
71     return CreateXKBFile(XkmKeymapFile, ktcsg->keymap ? ktcsg->keymap : "",
72                          &keycodes->common, 0);
73 }
74
75 static struct xkb_component_names *
76 XkbComponentsFromRules(const char *rules, const XkbRF_VarDefsPtr defs)
77 {
78     FILE *rulesFile = NULL;
79     char *rulesPath = NULL;
80     static XkbRF_RulesPtr loaded = NULL;
81     static char *cached_name = NULL;
82     struct xkb_component_names * names = NULL;
83
84     if (!cached_name || strcmp(rules, cached_name) != 0) {
85         if (loaded)
86             XkbcRF_Free(loaded, True);
87         loaded = NULL;
88         free(cached_name);
89         cached_name = NULL;
90     }
91
92     if (!loaded) {
93         rulesFile = XkbFindFileInPath((char *)rules, XkmRulesFile, &rulesPath);
94         if (!rulesFile) {
95             ERROR("could not find \"%s\" rules in XKB path\n", rules);
96             goto out;
97         }
98
99         if (!(loaded = _XkbTypedCalloc(1, XkbRF_RulesRec))) {
100             ERROR("failed to allocate XKB rules\n");
101             goto unwind_file;
102         }
103
104         if (!XkbcRF_LoadRules(rulesFile, loaded)) {
105             ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
106             goto unwind_file;
107         }
108
109         cached_name = strdup(rules);
110     }
111
112     if (!(names = _XkbTypedCalloc(1, struct xkb_component_names))) {
113         ERROR("failed to allocate XKB components\n");
114         goto unwind_file;
115     }
116
117     if (!XkbcRF_GetComponents(loaded, defs, names)) {
118         free(names->keymap);
119         free(names->keycodes);
120         free(names->types);
121         free(names->compat);
122         free(names->symbols);
123         free(names->geometry);
124         free(names);
125         names = NULL;
126         ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
127     }
128
129 unwind_file:
130     if (rulesFile)
131         fclose(rulesFile);
132     free(rulesPath);
133 out:
134     return names;
135 }
136
137 struct xkb_desc *
138 xkb_compile_keymap_from_rules(const struct xkb_rule_names *rmlvo)
139 {
140     XkbRF_VarDefsRec defs;
141     struct xkb_component_names * names;
142     struct xkb_desc * xkb;
143
144     if (!rmlvo || ISEMPTY(rmlvo->rules) || ISEMPTY(rmlvo->layout)) {
145         ERROR("rules and layout required to generate XKB keymap\n");
146         return NULL;
147     }
148
149     defs.model = (char *) rmlvo->model;
150     defs.layout = (char *) rmlvo->layout;
151     defs.variant = (char *) rmlvo->variant;
152     defs.options = (char *) rmlvo->options;
153
154     names = XkbComponentsFromRules(rmlvo->rules, &defs);
155     if (!names) {
156         ERROR("failed to generate XKB components from rules \"%s\"\n",
157               rmlvo->rules);
158         return NULL;
159     }
160
161     xkb = xkb_compile_keymap_from_components(names);
162
163     free(names->keymap);
164     free(names->keycodes);
165     free(names->types);
166     free(names->compat);
167     free(names->symbols);
168     free(names->geometry);
169     free(names);
170
171     return xkb;
172 }
173
174 static XkbFile *
175 XkbChooseMap(XkbFile *file, const char *name)
176 {
177     XkbFile *map = file;
178
179     /* map specified? */
180     if (name) {
181         while (map) {
182             if (map->name && strcmp(map->name, name) == 0)
183                 break;
184             map = (XkbFile *) map->common.next;
185         }
186
187         if (!map)
188             ERROR("no map named \"%s\" in input file\n", name);
189     }
190     else if (file->common.next) {
191         /* look for map with XkbLC_Default flag. */
192         for (; map; map = (XkbFile *) map->common.next) {
193             if (map->flags & XkbLC_Default)
194                 break;
195         }
196
197         if (!map) {
198             map = file;
199             WARN("no map specified, but components have several\n");
200             WARN("using the first defined map, \"%s\"\n",
201                  map->name ? map->name : "");
202         }
203     }
204
205     return map;
206 }
207
208 struct xkb_desc *
209 xkb_compile_keymap_from_components(const struct xkb_component_names * ktcsg)
210 {
211     XkbFile *file, *mapToUse;
212     struct xkb_desc * xkb;
213
214     uSetErrorFile(NULL);
215
216     if (!ktcsg || ISEMPTY(ktcsg->keycodes)) {
217         ERROR("keycodes required to generate XKB keymap\n");
218         goto fail;
219     }
220
221     if (!(file = XkbKeymapFileFromComponents(ktcsg))) {
222         ERROR("failed to generate parsed XKB file from components\n");
223         goto fail;
224     }
225
226     /* Find map to use */
227     if (!(mapToUse = XkbChooseMap(file, NULL)))
228         goto unwind_file;
229
230     /* Compile the keyboard */
231     if (!(xkb = XkbcAllocKeyboard())) {
232         ERROR("could not allocate keyboard description\n");
233         goto unwind_file;
234     }
235
236     if (!CompileKeymap(mapToUse, xkb, MergeReplace)) {
237         ERROR("failed to compile keymap\n");
238         goto unwind_xkb;
239     }
240
241     return xkb;
242 unwind_xkb:
243     XkbcFreeKeyboard(xkb, XkbAllComponentsMask, True);
244 unwind_file:
245     /* XXX: here's where we would free the XkbFile */
246 fail:
247     return NULL;
248 }
249
250 struct xkb_desc *
251 xkb_compile_keymap_from_file(FILE *inputFile, const char *mapName)
252 {
253     XkbFile *file, *mapToUse;
254     struct xkb_desc * xkb;
255
256     if (!inputFile) {
257         ERROR("no file specified to generate XKB keymap\n");
258         goto fail;
259     }
260
261     setScanState("input", 1);
262     if (!XKBParseFile(inputFile, &file) || !file) {
263         ERROR("failed to parse input xkb file\n");
264         goto fail;
265     }
266
267     /* Find map to use */
268     if (!(mapToUse = XkbChooseMap(file, mapName)))
269         goto unwind_file;
270
271     switch (mapToUse->type) {
272     case XkmSemanticsFile:
273     case XkmLayoutFile:
274     case XkmKeymapFile:
275         break;
276     default:
277         ERROR("file type %d not handled\n", mapToUse->type);
278         goto unwind_file;
279     }
280
281     /* Compile the keyboard */
282     if (!(xkb = XkbcAllocKeyboard())) {
283         ERROR("could not allocate keyboard description\n");
284         goto unwind_file;
285     }
286
287     if (!CompileKeymap(mapToUse, xkb, MergeReplace)) {
288         ERROR("failed to compile keymap\n");
289         goto unwind_xkb;
290     }
291
292     return xkb;
293 unwind_xkb:
294     XkbcFreeKeyboard(xkb, XkbAllComponentsMask, True);
295 unwind_file:
296     /* XXX: here's where we would free the XkbFile */
297 fail:
298     return NULL;
299 }