Tools: Add bash completions for xkbcli
[platform/upstream/libxkbcommon.git] / tools / compile-keymap.c
1 /*
2  * Copyright © 2018 Red Hat, Inc.
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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 #include "config.h"
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <getopt.h>
29 #include <stdio.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "xkbcommon/xkbcommon.h"
35 #if ENABLE_PRIVATE_APIS
36 #include "xkbcomp/xkbcomp-priv.h"
37 #include "xkbcomp/rules.h"
38 #endif
39 #include "tools-common.h"
40
41 #define DEFAULT_INCLUDE_PATH_PLACEHOLDER "__defaults__"
42
43 static bool verbose = false;
44 static enum output_format {
45     FORMAT_RMLVO,
46     FORMAT_KEYMAP,
47     FORMAT_KCCGST,
48     FORMAT_KEYMAP_FROM_XKB,
49 } output_format = FORMAT_KEYMAP;
50 static const char *includes[64];
51 static size_t num_includes = 0;
52
53 static void
54 usage(char **argv)
55 {
56     printf("Usage: %s [OPTIONS]\n"
57            "\n"
58            "Compile the given RMLVO to a keymap and print it\n"
59            "\n"
60            "Options:\n"
61            " --help\n"
62            "    Print this help and exit\n"
63            " --verbose\n"
64            "    Enable verbose debugging output\n"
65 #if ENABLE_PRIVATE_APIS
66            " --kccgst\n"
67            "    Print a keymap which only includes the KcCGST component names instead of the full keymap\n"
68 #endif
69            " --rmlvo\n"
70            "    Print the full RMLVO with the defaults filled in for missing elements\n"
71            " --from-xkb\n"
72            "    Load the XKB file from stdin, ignore RMLVO options.\n"
73 #if ENABLE_PRIVATE_APIS
74            "    This option must not be used with --kccgst.\n"
75 #endif
76            " --include\n"
77            "    Add the given path to the include path list. This option is\n"
78            "    order-dependent, include paths given first are searched first.\n"
79            "    If an include path is given, the default include path list is\n"
80            "    not used. Use --include-defaults to add the default include\n"
81            "    paths\n"
82            " --include-defaults\n"
83            "    Add the default set of include directories.\n"
84            "    This option is order-dependent, include paths given first\n"
85            "    are searched first.\n"
86            "\n"
87            "XKB-specific options:\n"
88            " --rules <rules>\n"
89            "    The XKB ruleset (default: '%s')\n"
90            " --model <model>\n"
91            "    The XKB model (default: '%s')\n"
92            " --layout <layout>\n"
93            "    The XKB layout (default: '%s')\n"
94            " --variant <variant>\n"
95            "    The XKB layout variant (default: '%s')\n"
96            " --options <options>\n"
97            "    The XKB options (default: '%s')\n"
98            "\n",
99            argv[0], DEFAULT_XKB_RULES,
100            DEFAULT_XKB_MODEL, DEFAULT_XKB_LAYOUT,
101            DEFAULT_XKB_VARIANT ? DEFAULT_XKB_VARIANT : "<none>",
102            DEFAULT_XKB_OPTIONS ? DEFAULT_XKB_OPTIONS : "<none>");
103 }
104
105 static bool
106 parse_options(int argc, char **argv, struct xkb_rule_names *names)
107 {
108     enum options {
109         OPT_VERBOSE,
110         OPT_KCCGST,
111         OPT_RMLVO,
112         OPT_FROM_XKB,
113         OPT_INCLUDE,
114         OPT_INCLUDE_DEFAULTS,
115         OPT_RULES,
116         OPT_MODEL,
117         OPT_LAYOUT,
118         OPT_VARIANT,
119         OPT_OPTION,
120     };
121     static struct option opts[] = {
122         {"help",             no_argument,            0, 'h'},
123         {"verbose",          no_argument,            0, OPT_VERBOSE},
124 #if ENABLE_PRIVATE_APIS
125         {"kccgst",           no_argument,            0, OPT_KCCGST},
126 #endif
127         {"rmlvo",            no_argument,            0, OPT_RMLVO},
128         {"from-xkb",         no_argument,            0, OPT_FROM_XKB},
129         {"include",          required_argument,      0, OPT_INCLUDE},
130         {"include-defaults", no_argument,            0, OPT_INCLUDE_DEFAULTS},
131         {"rules",            required_argument,      0, OPT_RULES},
132         {"model",            required_argument,      0, OPT_MODEL},
133         {"layout",           required_argument,      0, OPT_LAYOUT},
134         {"variant",          required_argument,      0, OPT_VARIANT},
135         {"options",          required_argument,      0, OPT_OPTION},
136         {0, 0, 0, 0},
137     };
138
139     while (1) {
140         int c;
141         int option_index = 0;
142         c = getopt_long(argc, argv, "h", opts, &option_index);
143         if (c == -1)
144             break;
145
146         switch (c) {
147         case 'h':
148             usage(argv);
149             exit(0);
150         case OPT_VERBOSE:
151             verbose = true;
152             break;
153         case OPT_KCCGST:
154             output_format = FORMAT_KCCGST;
155             break;
156         case OPT_RMLVO:
157             output_format = FORMAT_RMLVO;
158             break;
159         case OPT_FROM_XKB:
160             output_format = FORMAT_KEYMAP_FROM_XKB;
161             break;
162         case OPT_INCLUDE:
163             if (num_includes >= ARRAY_SIZE(includes)) {
164                 fprintf(stderr, "error: too many includes\n");
165                 exit(EXIT_INVALID_USAGE);
166             }
167             includes[num_includes++] = optarg;
168             break;
169         case OPT_INCLUDE_DEFAULTS:
170             if (num_includes >= ARRAY_SIZE(includes)) {
171                 fprintf(stderr, "error: too many includes\n");
172                 exit(EXIT_INVALID_USAGE);
173             }
174             includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
175             break;
176         case OPT_RULES:
177             names->rules = optarg;
178             break;
179         case OPT_MODEL:
180             names->model = optarg;
181             break;
182         case OPT_LAYOUT:
183             names->layout = optarg;
184             break;
185         case OPT_VARIANT:
186             names->variant = optarg;
187             break;
188         case OPT_OPTION:
189             names->options = optarg;
190             break;
191         default:
192             usage(argv);
193             exit(EXIT_INVALID_USAGE);
194         }
195
196     }
197
198     return true;
199 }
200
201 static bool
202 print_rmlvo(struct xkb_context *ctx, const struct xkb_rule_names *rmlvo)
203 {
204     printf("rules: \"%s\"\nmodel: \"%s\"\nlayout: \"%s\"\nvariant: \"%s\"\noptions: \"%s\"\n",
205            rmlvo->rules, rmlvo->model, rmlvo->layout,
206            rmlvo->variant ? rmlvo->variant : "",
207            rmlvo->options ? rmlvo->options : "");
208     return true;
209 }
210
211 static bool
212 print_kccgst(struct xkb_context *ctx, const struct xkb_rule_names *rmlvo)
213 {
214 #if ENABLE_PRIVATE_APIS
215         struct xkb_component_names kccgst;
216
217         if (!xkb_components_from_rules(ctx, rmlvo, &kccgst))
218             return false;
219
220         printf("xkb_keymap {\n"
221                "  xkb_keycodes { include \"%s\" };\n"
222                "  xkb_types { include \"%s\" };\n"
223                "  xkb_compat { include \"%s\" };\n"
224                "  xkb_symbols { include \"%s\" };\n"
225                "};\n",
226                kccgst.keycodes, kccgst.types, kccgst.compat, kccgst.symbols);
227         free(kccgst.keycodes);
228         free(kccgst.types);
229         free(kccgst.compat);
230         free(kccgst.symbols);
231
232         return true;
233 #else
234         return false;
235 #endif
236 }
237
238 static bool
239 print_keymap(struct xkb_context *ctx, const struct xkb_rule_names *rmlvo)
240 {
241     struct xkb_keymap *keymap;
242
243     keymap = xkb_keymap_new_from_names(ctx, rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
244     if (keymap == NULL)
245         return false;
246
247     printf("%s\n", xkb_keymap_get_as_string(keymap,
248                                             XKB_KEYMAP_FORMAT_TEXT_V1));
249     xkb_keymap_unref(keymap);
250     return true;
251 }
252
253 static bool
254 print_keymap_from_file(struct xkb_context *ctx)
255 {
256     struct xkb_keymap *keymap = NULL;
257     char *keymap_string = NULL;
258     FILE *file = NULL;
259     bool success = false;
260
261     file = tmpfile();
262     if (!file) {
263         fprintf(stderr, "Failed to create tmpfile\n");
264         goto out;
265     }
266
267     while (true) {
268         char buf[4096];
269         size_t len;
270
271         len = fread(buf, 1, sizeof(buf), stdin);
272         if (ferror(stdin)) {
273             fprintf(stderr, "Failed to read from stdin\n");
274             goto out;
275         }
276         if (len > 0) {
277             size_t wlen = fwrite(buf, 1, len, file);
278             if (wlen != len) {
279                 fprintf(stderr, "Failed to write to tmpfile\n");
280                 goto out;
281             }
282         }
283         if (feof(stdin))
284             break;
285     }
286     fseek(file, 0, SEEK_SET);
287     keymap = xkb_keymap_new_from_file(ctx, file,
288                                       XKB_KEYMAP_FORMAT_TEXT_V1, 0);
289     if (!keymap) {
290         fprintf(stderr, "Couldn't create xkb keymap\n");
291         goto out;
292     }
293
294     keymap_string = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
295     if (!keymap_string) {
296         fprintf(stderr, "Couldn't get the keymap string\n");
297         goto out;
298     }
299
300     fputs(keymap_string, stdout);
301     success = true;
302
303 out:
304     if (file)
305         fclose(file);
306     xkb_keymap_unref(keymap);
307     free(keymap_string);
308
309     return success;
310 }
311
312 int
313 main(int argc, char **argv)
314 {
315     struct xkb_context *ctx;
316     struct xkb_rule_names names = {
317         .rules = DEFAULT_XKB_RULES,
318         .model = DEFAULT_XKB_MODEL,
319         /* layout and variant are tied together, so we either get user-supplied for
320          * both or default for both, see below */
321         .layout = NULL,
322         .variant = NULL,
323         .options = DEFAULT_XKB_OPTIONS,
324     };
325     int rc = 1;
326
327     if (argc < 1) {
328         usage(argv);
329         return EXIT_INVALID_USAGE;
330     }
331
332     if (!parse_options(argc, argv, &names))
333         return EXIT_INVALID_USAGE;
334
335     /* Now fill in the layout */
336     if (!names.layout || !*names.layout) {
337         if (names.variant && *names.variant) {
338             fprintf(stderr, "Error: a variant requires a layout\n");
339             return EXIT_INVALID_USAGE;
340         }
341         names.layout = DEFAULT_XKB_LAYOUT;
342         names.variant = DEFAULT_XKB_VARIANT;
343     }
344
345     ctx = xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES);
346     assert(ctx);
347
348     if (verbose) {
349         xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_DEBUG);
350         xkb_context_set_log_verbosity(ctx, 10);
351     }
352
353     if (num_includes == 0)
354         includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
355
356     for (size_t i = 0; i < num_includes; i++) {
357         const char *include = includes[i];
358         if (strcmp(include, DEFAULT_INCLUDE_PATH_PLACEHOLDER) == 0)
359             xkb_context_include_path_append_default(ctx);
360         else
361             xkb_context_include_path_append(ctx, include);
362     }
363
364     if (output_format == FORMAT_RMLVO) {
365         rc = print_rmlvo(ctx, &names) ? EXIT_SUCCESS : EXIT_FAILURE;
366     } else if (output_format == FORMAT_KEYMAP) {
367         rc = print_keymap(ctx, &names) ? EXIT_SUCCESS : EXIT_FAILURE;
368     } else if (output_format == FORMAT_KCCGST) {
369         rc = print_kccgst(ctx, &names) ? EXIT_SUCCESS : EXIT_FAILURE;
370     } else if (output_format == FORMAT_KEYMAP_FROM_XKB) {
371         rc = print_keymap_from_file(ctx);
372     }
373
374     xkb_context_unref(ctx);
375
376     return rc;
377 }