Remove useless stuff from utils
[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 "xkbmisc.h"
33 #include "parseutils.h"
34 #include "utils.h"
35
36 /* Global warning level */
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;
45     IncludeStmt *inc;
46
47     inc = IncludeCreate(ktcsg->keycodes, MergeDefault);
48     keycodes = CreateXKBFile(XkmKeyNamesIndex, NULL, (ParseCommon *)inc, 0);
49
50     inc = IncludeCreate(ktcsg->types, MergeDefault);
51     types = CreateXKBFile(XkmTypesIndex, NULL, (ParseCommon *)inc, 0);
52     AppendStmt(&keycodes->common, &types->common);
53
54     inc = IncludeCreate(ktcsg->compat, MergeDefault);
55     compat = CreateXKBFile(XkmCompatMapIndex, NULL, (ParseCommon *)inc, 0);
56     AppendStmt(&keycodes->common, &compat->common);
57
58     inc = IncludeCreate(ktcsg->symbols, MergeDefault);
59     symbols = CreateXKBFile(XkmSymbolsIndex, NULL, (ParseCommon *)inc, 0);
60     AppendStmt(&keycodes->common, &symbols->common);
61
62     return CreateXKBFile(XkmKeymapFile, ktcsg->keymap ? ktcsg->keymap : strdup(""),
63                          &keycodes->common, 0);
64 }
65
66 static struct xkb_component_names *
67 XkbComponentsFromRules(const char *rules, const XkbRF_VarDefsPtr defs)
68 {
69     FILE *rulesFile = NULL;
70     char *rulesPath = NULL;
71     XkbRF_RulesPtr loaded = NULL;
72     struct xkb_component_names * names = NULL;
73
74     rulesFile = XkbFindFileInPath(rules, XkmRulesFile, &rulesPath);
75     if (!rulesFile) {
76         ERROR("could not find \"%s\" rules in XKB path\n", rules);
77         return NULL;
78     }
79
80     if (!(loaded = _XkbTypedCalloc(1, XkbRF_RulesRec))) {
81         ERROR("failed to allocate XKB rules\n");
82         goto unwind_file;
83     }
84
85     if (!XkbcRF_LoadRules(rulesFile, loaded)) {
86         ERROR("failed to load XKB rules \"%s\"\n", rulesPath);
87         goto unwind_file;
88     }
89
90     if (!(names = _XkbTypedCalloc(1, struct xkb_component_names))) {
91         ERROR("failed to allocate XKB components\n");
92         goto unwind_file;
93     }
94
95     if (!XkbcRF_GetComponents(loaded, defs, names)) {
96         free(names->keymap);
97         free(names->keycodes);
98         free(names->types);
99         free(names->compat);
100         free(names->symbols);
101         free(names);
102         names = NULL;
103         ERROR("no components returned from XKB rules \"%s\"\n", rulesPath);
104     }
105
106 unwind_file:
107     XkbcRF_Free(loaded);
108     if (rulesFile)
109         fclose(rulesFile);
110     free(rulesPath);
111     return names;
112 }
113
114 struct xkb_desc *
115 xkb_map_new_from_names(const struct xkb_rule_names *rmlvo)
116 {
117     XkbRF_VarDefsRec defs;
118     struct xkb_component_names * names;
119     struct xkb_desc * xkb;
120
121     if (!rmlvo || ISEMPTY(rmlvo->rules) || ISEMPTY(rmlvo->layout)) {
122         ERROR("rules and layout required to generate XKB keymap\n");
123         return NULL;
124     }
125
126     defs.model = rmlvo->model;
127     defs.layout = rmlvo->layout;
128     defs.variant = rmlvo->variant;
129     defs.options = rmlvo->options;
130
131     names = XkbComponentsFromRules(rmlvo->rules, &defs);
132     if (!names) {
133         ERROR("failed to generate XKB components from rules \"%s\"\n",
134               rmlvo->rules);
135         return NULL;
136     }
137
138     xkb = xkb_map_new_from_kccgst(names);
139
140     free(names->keymap);
141     free(names->keycodes);
142     free(names->types);
143     free(names->compat);
144     free(names->symbols);
145     free(names);
146
147     return xkb;
148 }
149
150 static XkbFile *
151 XkbChooseMap(XkbFile *file, const char *name)
152 {
153     XkbFile *map = file;
154
155     /* map specified? */
156     if (name) {
157         while (map) {
158             if (map->name && strcmp(map->name, name) == 0)
159                 break;
160             map = (XkbFile *) map->common.next;
161         }
162
163         if (!map)
164             ERROR("no map named \"%s\" in input file\n", name);
165     }
166     else if (file->common.next) {
167         /* look for map with XkbLC_Default flag. */
168         for (; map; map = (XkbFile *) map->common.next) {
169             if (map->flags & XkbLC_Default)
170                 break;
171         }
172
173         if (!map) {
174             map = file;
175             WARN("no map specified, but components have several\n");
176             WARN("using the first defined map, \"%s\"\n",
177                  map->name ? map->name : "");
178         }
179     }
180
181     return map;
182 }
183
184 static struct xkb_desc *
185 compile_keymap(XkbFile *file)
186 {
187     XkbFile *mapToUse;
188     struct xkb_desc * xkb = NULL;
189
190     /* Find map to use */
191     mapToUse = XkbChooseMap(file, NULL);
192     if (!mapToUse)
193         goto err;
194
195     switch (mapToUse->type) {
196     case XkmSemanticsFile:
197     case XkmLayoutFile:
198     case XkmKeymapFile:
199         break;
200     default:
201         ERROR("file type %d not handled\n", mapToUse->type);
202         goto err;
203     }
204
205     xkb = CompileKeymap(mapToUse, MergeReplace);
206     if (!xkb)
207         goto err;
208
209 err:
210     FreeXKBFile(file);
211     free(scanFile);
212     XkbFreeIncludePath();
213     XkbcFreeAllAtoms();
214     return xkb;
215 }
216
217 struct xkb_desc *
218 xkb_map_new_from_kccgst(const struct xkb_component_names *kccgst)
219 {
220     XkbFile *file;
221
222     if (!kccgst) {
223         ERROR("no components specified\n");
224         return NULL;
225     }
226
227     if (ISEMPTY(kccgst->keycodes)) {
228         ERROR("keycodes required to generate XKB keymap\n");
229         return NULL;
230     }
231
232     if (ISEMPTY(kccgst->compat)) {
233         ERROR("compat map required to generate XKB keymap\n");
234         return NULL;
235     }
236
237     if (ISEMPTY(kccgst->types)) {
238         ERROR("types required to generate XKB keymap\n");
239         return NULL;
240     }
241
242     if (ISEMPTY(kccgst->symbols)) {
243         ERROR("symbols required to generate XKB keymap\n");
244         return NULL;
245     }
246
247     if (!(file = XkbKeymapFileFromComponents(kccgst))) {
248         ERROR("failed to generate parsed XKB file from components\n");
249         return NULL;
250     }
251
252     return compile_keymap(file);
253 }
254
255 struct xkb_desc *
256 xkb_map_new_from_string(const char *string, enum xkb_keymap_format format)
257 {
258     XkbFile *file;
259
260     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
261         ERROR("unsupported keymap format %d\n", format);
262         return NULL;
263     }
264
265     if (!string) {
266         ERROR("no string specified to generate XKB keymap\n");
267         return NULL;
268     }
269
270     setScanState("input", 1);
271     if (!XKBParseString(string, &file) || !file) {
272         ERROR("failed to parse input xkb file\n");
273         return NULL;
274     }
275
276     return compile_keymap(file);
277 }
278
279 struct xkb_desc *
280 xkb_map_new_from_fd(int fd, enum xkb_keymap_format format)
281 {
282     XkbFile *file;
283     FILE *fptr;
284
285     if (format != XKB_KEYMAP_FORMAT_TEXT_V1) {
286         ERROR("unsupported keymap format %d\n", format);
287         return NULL;
288     }
289
290     if (fd < 0) {
291         ERROR("no file specified to generate XKB keymap\n");
292         return NULL;
293     }
294
295     fptr = fdopen(fd, "r");
296     if (!fptr) {
297         ERROR("couldn't associate fd with file pointer\n");
298         return NULL;
299     }
300
301     setScanState("input", 1);
302     if (!XKBParseFile(fptr, &file) || !file) {
303         ERROR("failed to parse input xkb file\n");
304         return NULL;
305     }
306
307     return compile_keymap(file);
308 }
309
310 void
311 xkb_map_ref(struct xkb_desc *xkb)
312 {
313     xkb->refcnt++;
314 }
315
316 void
317 xkb_map_unref(struct xkb_desc *xkb)
318 {
319     if (--xkb->refcnt > 0)
320         return;
321
322     XkbcFreeKeyboard(xkb);
323 }