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