2 * Copyright © 2018 Red Hat, Inc.
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:
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
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.
34 #include "xkbcommon/xkbcommon.h"
35 #if ENABLE_PRIVATE_APIS
36 #include "xkbcomp/xkbcomp-priv.h"
37 #include "xkbcomp/rules.h"
39 #include "tools-common.h"
41 #define DEFAULT_INCLUDE_PATH_PLACEHOLDER "__defaults__"
43 static bool verbose = false;
44 static enum output_format {
48 FORMAT_KEYMAP_FROM_XKB,
49 } output_format = FORMAT_KEYMAP;
50 static const char *includes[64];
51 static size_t num_includes = 0;
56 printf("Usage: %s [OPTIONS]\n"
58 "Compile the given RMLVO to a keymap and print it\n"
62 " Print this help and exit\n"
64 " Enable verbose debugging output\n"
65 #if ENABLE_PRIVATE_APIS
67 " Print a keymap which only includes the KcCGST component names instead of the full keymap\n"
70 " Print the full RMLVO with the defaults filled in for missing elements\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"
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"
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"
87 "XKB-specific options:\n"
89 " The XKB ruleset (default: '%s')\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"
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>");
106 parse_options(int argc, char **argv, struct xkb_rule_names *names)
114 OPT_INCLUDE_DEFAULTS,
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},
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},
141 int option_index = 0;
142 c = getopt_long(argc, argv, "h", opts, &option_index);
154 output_format = FORMAT_KCCGST;
157 output_format = FORMAT_RMLVO;
160 output_format = FORMAT_KEYMAP_FROM_XKB;
163 if (num_includes >= ARRAY_SIZE(includes)) {
164 fprintf(stderr, "error: too many includes\n");
165 exit(EXIT_INVALID_USAGE);
167 includes[num_includes++] = optarg;
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);
174 includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
177 names->rules = optarg;
180 names->model = optarg;
183 names->layout = optarg;
186 names->variant = optarg;
189 names->options = optarg;
193 exit(EXIT_INVALID_USAGE);
202 print_rmlvo(struct xkb_context *ctx, const struct xkb_rule_names *rmlvo)
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 : "");
212 print_kccgst(struct xkb_context *ctx, const struct xkb_rule_names *rmlvo)
214 #if ENABLE_PRIVATE_APIS
215 struct xkb_component_names kccgst;
217 if (!xkb_components_from_rules(ctx, rmlvo, &kccgst))
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"
226 kccgst.keycodes, kccgst.types, kccgst.compat, kccgst.symbols);
227 free(kccgst.keycodes);
230 free(kccgst.symbols);
239 print_keymap(struct xkb_context *ctx, const struct xkb_rule_names *rmlvo)
241 struct xkb_keymap *keymap;
243 keymap = xkb_keymap_new_from_names(ctx, rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
247 printf("%s\n", xkb_keymap_get_as_string(keymap,
248 XKB_KEYMAP_FORMAT_TEXT_V1));
249 xkb_keymap_unref(keymap);
254 print_keymap_from_file(struct xkb_context *ctx)
256 struct xkb_keymap *keymap = NULL;
257 char *keymap_string = NULL;
259 bool success = false;
263 fprintf(stderr, "Failed to create tmpfile\n");
271 len = fread(buf, 1, sizeof(buf), stdin);
273 fprintf(stderr, "Failed to read from stdin\n");
277 size_t wlen = fwrite(buf, 1, len, file);
279 fprintf(stderr, "Failed to write to tmpfile\n");
286 fseek(file, 0, SEEK_SET);
287 keymap = xkb_keymap_new_from_file(ctx, file,
288 XKB_KEYMAP_FORMAT_TEXT_V1, 0);
290 fprintf(stderr, "Couldn't create xkb keymap\n");
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");
300 fputs(keymap_string, stdout);
306 xkb_keymap_unref(keymap);
313 main(int argc, char **argv)
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 */
323 .options = DEFAULT_XKB_OPTIONS,
329 return EXIT_INVALID_USAGE;
332 if (!parse_options(argc, argv, &names))
333 return EXIT_INVALID_USAGE;
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;
341 names.layout = DEFAULT_XKB_LAYOUT;
342 names.variant = DEFAULT_XKB_VARIANT;
345 ctx = xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES);
349 xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_DEBUG);
350 xkb_context_set_log_verbosity(ctx, 10);
353 if (num_includes == 0)
354 includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
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);
361 xkb_context_include_path_append(ctx, include);
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);
374 xkb_context_unref(ctx);