compile-keymap.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. /*
  2. * Copyright © 2018 Red Hat, Inc.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <getopt.h>
  9. #include <locale.h>
  10. #include <stdio.h>
  11. #include <stdbool.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include "xkbcommon/xkbcommon-errors.h"
  15. #include "xkbcommon/xkbcommon.h"
  16. #include "tools-common.h"
  17. #include "src/utils.h"
  18. #include "src/keymap-formats.h"
  19. #define DEFAULT_INCLUDE_PATH_PLACEHOLDER "__defaults__"
  20. enum input_format {
  21. INPUT_FORMAT_AUTO = 0,
  22. INPUT_FORMAT_RMLVO,
  23. INPUT_FORMAT_KEYMAP
  24. };
  25. enum output_format {
  26. OUTPUT_FORMAT_KEYMAP = 0,
  27. OUTPUT_FORMAT_RMLVO,
  28. OUTPUT_FORMAT_KCCGST,
  29. OUTPUT_FORMAT_KCCGST_YAML,
  30. OUTPUT_FORMAT_MODMAPS,
  31. };
  32. static bool verbose = false;
  33. static const char *includes[64] = { 0 };
  34. static size_t num_includes = 0;
  35. static bool test = false;
  36. static void
  37. usage(FILE *file, const char *progname)
  38. {
  39. fprintf(file,
  40. "Usage: %s [OPTIONS]\n"
  41. "\n"
  42. "Compile the given input to a keymap and print it\n"
  43. "\n"
  44. "General options:\n"
  45. " --help\n"
  46. " Print this help and exit\n"
  47. " --version\n"
  48. " Print version information and exit\n"
  49. " --verbose\n"
  50. " Enable verbose debugging output\n"
  51. " --test\n"
  52. " Test compilation but do not print the keymap.\n"
  53. "\n"
  54. "Input options:\n"
  55. " --include\n"
  56. " Add the given path to the include path list. This option is\n"
  57. " order-dependent, include paths given first are searched first.\n"
  58. " If an include path is given, the default include path list is\n"
  59. " not used. Use --include-defaults to add the default include\n"
  60. " paths\n"
  61. " --include-defaults\n"
  62. " Add the default set of include directories.\n"
  63. " This option is order-dependent, include paths given first\n"
  64. " are searched first.\n"
  65. " --input-format <format>\n"
  66. " The keymap format to use for parsing (default: '%s')\n"
  67. " --format <format>\n"
  68. " The keymap format to use for both parsing and serializing\n"
  69. " --input-strict\n"
  70. " Parse using the strict mode.\n"
  71. " --strict\n"
  72. " Parse and serialize using the strict mode.\n"
  73. " --keymap <file>\n"
  74. " --from-xkb <file>\n"
  75. " Load the corresponding XKB file, ignore RMLVO options. If <file>\n"
  76. " is \"-\" or missing, then load from stdin."
  77. " This option must not be used with --kccgst.\n"
  78. " --rules <rules>\n"
  79. " The XKB ruleset (default: '%s')\n"
  80. " --model <model>\n"
  81. " The XKB model (default: '%s')\n"
  82. " --layout <layout>\n"
  83. " The XKB layout (default: '%s')\n"
  84. " --variant <variant>\n"
  85. " The XKB layout variant (default: '%s')\n"
  86. " --options <options>\n"
  87. " The XKB options (default: '%s')\n"
  88. " --enable-environment-names\n"
  89. " Allow to set the default RMLVO values via the following environment variables:\n"
  90. " - XKB_DEFAULT_RULES\n"
  91. " - XKB_DEFAULT_MODEL\n"
  92. " - XKB_DEFAULT_LAYOUT\n"
  93. " - XKB_DEFAULT_VARIANT\n"
  94. " - XKB_DEFAULT_OPTIONS\n"
  95. " Note that this option may affect the default values of the previous options.\n"
  96. " This option must not be used with --keymap.\n"
  97. "\n"
  98. "Output options:\n"
  99. " --output-format <format>\n"
  100. " The keymap format to use for serializing (default: same as input)\n"
  101. " --output-strict\n"
  102. " Serialize using the strict mode\n"
  103. " --no-pretty\n"
  104. " Do not pretty-print when serializing a keymap\n"
  105. " --drop-unused\n"
  106. " Disable unused bits serialization\n"
  107. " --explicit-defaults\n"
  108. " Force serializing default values\n"
  109. " --explicit-vmods\n"
  110. " Force serializing virtual modifiers encodings\n"
  111. " --explicit-keys\n"
  112. " Force serializing key values\n"
  113. " --explicit-values\n"
  114. " Force serializing all values\n"
  115. " --layouts-mask\n"
  116. " Hexadecimal mask of the layouts indices to select for serializing\n"
  117. " --kccgst\n"
  118. " Print a keymap which only includes the KcCGST component names instead of the full keymap\n"
  119. " --kccgst-yaml\n"
  120. " Print the KcCGST component names in YAML format\n"
  121. " --rmlvo\n"
  122. " Print the full RMLVO with the defaults filled in for missing elements, in YAML format\n"
  123. " --modmaps\n"
  124. " Print real and virtual key modmaps and modifiers encodings in YAML format\n"
  125. "\n",
  126. progname,
  127. xkb_keymap_get_format_label(DEFAULT_INPUT_KEYMAP_FORMAT),
  128. DEFAULT_XKB_RULES, DEFAULT_XKB_MODEL, DEFAULT_XKB_LAYOUT,
  129. DEFAULT_XKB_VARIANT ? DEFAULT_XKB_VARIANT : "<none>",
  130. DEFAULT_XKB_OPTIONS ? DEFAULT_XKB_OPTIONS : "<none>");
  131. }
  132. static inline bool
  133. is_incompatible_with_keymap_input(enum output_format format)
  134. {
  135. switch (format) {
  136. case OUTPUT_FORMAT_KCCGST:
  137. case OUTPUT_FORMAT_KCCGST_YAML:
  138. case OUTPUT_FORMAT_RMLVO:
  139. return true;
  140. default:
  141. return false;
  142. }
  143. }
  144. static bool
  145. parse_options(int argc, char **argv,
  146. enum input_format *input_format_out,
  147. enum output_format *output_format_out,
  148. enum xkb_keymap_format *keymap_input_format,
  149. enum xkb_keymap_format *keymap_output_format,
  150. enum xkb_keymap_compile_flags *compile_flags,
  151. enum xkb_keymap_serialize_flags *serialize_flags,
  152. xkb_layout_mask_t *layout_mask,
  153. bool *use_env_names,
  154. char **path, struct xkb_rule_names *names)
  155. {
  156. enum input_format input_format = INPUT_FORMAT_AUTO;
  157. enum output_format output_format = OUTPUT_FORMAT_KEYMAP;
  158. enum options {
  159. /* General */
  160. OPT_VERBOSE,
  161. OPT_TEST,
  162. /* Input */
  163. OPT_INCLUDE,
  164. OPT_INCLUDE_DEFAULTS,
  165. OPT_KEYMAP,
  166. OPT_ENABLE_ENV_NAMES,
  167. OPT_KEYMAP_INPUT_FORMAT,
  168. OPT_KEYMAP_FORMAT,
  169. OPT_KEYMAP_INPUT_STRICT,
  170. OPT_KEYMAP_STRICT,
  171. OPT_RULES,
  172. OPT_MODEL,
  173. OPT_LAYOUT,
  174. OPT_VARIANT,
  175. OPT_OPTION,
  176. /* Output */
  177. OPT_KEYMAP_OUTPUT_FORMAT,
  178. OPT_KEYMAP_OUTPUT_STRICT,
  179. OPT_KEYMAP_NO_PRETTY,
  180. OPT_KEYMAP_DROP_UNUSED,
  181. OPT_KEYMAP_EXPLICIT_DEFAULTS,
  182. OPT_KEYMAP_EXPLICIT_VMODS,
  183. OPT_KEYMAP_EXPLICIT_KEYS,
  184. OPT_KEYMAP_EXPLICIT,
  185. OPT_KEYMAP_LAYOUTS,
  186. OPT_KCCGST,
  187. OPT_KCCGST_YAML,
  188. OPT_RMLVO,
  189. OPT_MODMAPS,
  190. };
  191. static struct option opts[] = {
  192. /*
  193. * General
  194. */
  195. {"help", no_argument, 0, 'h'},
  196. {"version", no_argument, 0, 'V'},
  197. {"verbose", no_argument, 0, OPT_VERBOSE},
  198. {"test", no_argument, 0, OPT_TEST},
  199. /*
  200. * Input
  201. */
  202. {"include", required_argument, 0, OPT_INCLUDE},
  203. {"include-defaults", no_argument, 0, OPT_INCLUDE_DEFAULTS},
  204. {"keymap", optional_argument, 0, OPT_KEYMAP},
  205. /* Alias maintained for backward compatibility */
  206. {"from-xkb", optional_argument, 0, OPT_KEYMAP},
  207. {"input-strict", no_argument, 0, OPT_KEYMAP_INPUT_STRICT},
  208. {"strict", no_argument, 0, OPT_KEYMAP_STRICT},
  209. {"enable-environment-names", no_argument, 0, OPT_ENABLE_ENV_NAMES},
  210. {"input-format", required_argument, 0, OPT_KEYMAP_INPUT_FORMAT},
  211. {"format", required_argument, 0, OPT_KEYMAP_FORMAT},
  212. {"rules", required_argument, 0, OPT_RULES},
  213. {"model", required_argument, 0, OPT_MODEL},
  214. {"layout", required_argument, 0, OPT_LAYOUT},
  215. {"variant", required_argument, 0, OPT_VARIANT},
  216. {"options", required_argument, 0, OPT_OPTION},
  217. /*
  218. * Output
  219. */
  220. {"output-format", required_argument, 0, OPT_KEYMAP_OUTPUT_FORMAT},
  221. {"output-strict", no_argument, 0, OPT_KEYMAP_OUTPUT_STRICT},
  222. {"no-pretty", no_argument, 0, OPT_KEYMAP_NO_PRETTY},
  223. {"drop-unused", no_argument, 0, OPT_KEYMAP_DROP_UNUSED},
  224. {"explicit-defaults",no_argument, 0, OPT_KEYMAP_EXPLICIT_DEFAULTS},
  225. {"explicit-vmods", no_argument, 0, OPT_KEYMAP_EXPLICIT_VMODS},
  226. {"explicit-keys", no_argument, 0, OPT_KEYMAP_EXPLICIT_KEYS},
  227. {"explicit-values", no_argument, 0, OPT_KEYMAP_EXPLICIT},
  228. {"layouts-mask", required_argument, 0, OPT_KEYMAP_LAYOUTS},
  229. {"kccgst", no_argument, 0, OPT_KCCGST},
  230. {"kccgst-yaml", no_argument, 0, OPT_KCCGST_YAML},
  231. {"rmlvo", no_argument, 0, OPT_RMLVO},
  232. {"modmaps", no_argument, 0, OPT_MODMAPS},
  233. {0, 0, 0, 0},
  234. };
  235. *use_env_names = false;
  236. int option_index = 0;
  237. while (1) {
  238. option_index = 0;
  239. int c = getopt_long(argc, argv, "hV", opts, &option_index);
  240. if (c == -1)
  241. break;
  242. switch (c) {
  243. /* General */
  244. case 'h':
  245. usage(stdout, argv[0]);
  246. exit(EXIT_SUCCESS);
  247. case 'V':
  248. printf("%s\n", LIBXKBCOMMON_VERSION);
  249. exit(EXIT_SUCCESS);
  250. case OPT_VERBOSE:
  251. verbose = true;
  252. break;
  253. case OPT_TEST:
  254. test = true;
  255. break;
  256. /* Input */
  257. case OPT_INCLUDE:
  258. if (num_includes >= ARRAY_SIZE(includes))
  259. goto too_many_includes;
  260. includes[num_includes++] = optarg;
  261. break;
  262. case OPT_INCLUDE_DEFAULTS:
  263. if (num_includes >= ARRAY_SIZE(includes))
  264. goto too_many_includes;
  265. includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
  266. break;
  267. case OPT_KEYMAP:
  268. if (*use_env_names)
  269. goto keymap_env_error;
  270. if (input_format == INPUT_FORMAT_RMLVO)
  271. goto input_format_error;
  272. if (is_incompatible_with_keymap_input(output_format))
  273. goto output_incompatible_with_keymap_input_error;
  274. input_format = INPUT_FORMAT_KEYMAP;
  275. /* Optional arguments require `=`, but we want to make this
  276. * requirement optional too, so that both `--keymap=xxx` and
  277. * `--keymap xxx` work. */
  278. if (!optarg && argv[optind] &&
  279. (argv[optind][0] != '-' || strcmp(argv[optind], "-") == 0 )) {
  280. *path = argv[optind++];
  281. } else {
  282. *path = optarg;
  283. }
  284. break;
  285. case OPT_ENABLE_ENV_NAMES:
  286. if (input_format == INPUT_FORMAT_KEYMAP)
  287. goto keymap_env_error;
  288. *use_env_names = true;
  289. input_format = INPUT_FORMAT_RMLVO;
  290. break;
  291. case OPT_KEYMAP_INPUT_FORMAT:
  292. *keymap_input_format = xkb_keymap_parse_format(optarg);
  293. if (!(*keymap_input_format)) {
  294. fprintf(stderr, "ERROR: invalid --input-format: \"%s\"\n", optarg);
  295. usage(stderr, argv[0]);
  296. exit(EXIT_INVALID_USAGE);
  297. }
  298. break;
  299. case OPT_KEYMAP_OUTPUT_FORMAT:
  300. *keymap_output_format = xkb_keymap_parse_format(optarg);
  301. if (!(*keymap_output_format)) {
  302. fprintf(stderr, "ERROR: invalid --output-format: \"%s\"\n", optarg);
  303. usage(stderr, argv[0]);
  304. exit(EXIT_INVALID_USAGE);
  305. }
  306. break;
  307. case OPT_KEYMAP_FORMAT:
  308. *keymap_input_format = xkb_keymap_parse_format(optarg);
  309. if (!(*keymap_input_format)) {
  310. fprintf(stderr, "ERROR: invalid --format: \"%s\"\n", optarg);
  311. usage(stderr, argv[0]);
  312. exit(EXIT_INVALID_USAGE);
  313. }
  314. *keymap_output_format = *keymap_input_format;
  315. break;
  316. case OPT_KEYMAP_INPUT_STRICT:
  317. *compile_flags |= XKB_KEYMAP_COMPILE_STRICT_MODE;
  318. break;
  319. case OPT_KEYMAP_OUTPUT_STRICT:
  320. *compile_flags |= XKB_KEYMAP_SERIALIZE_STRICT_MODE;
  321. break;
  322. case OPT_KEYMAP_STRICT:
  323. *compile_flags |= XKB_KEYMAP_COMPILE_STRICT_MODE;
  324. *serialize_flags |= XKB_KEYMAP_SERIALIZE_STRICT_MODE;
  325. break;
  326. case OPT_KEYMAP_NO_PRETTY:
  327. *serialize_flags &= ~XKB_KEYMAP_SERIALIZE_PRETTY;
  328. break;
  329. case OPT_KEYMAP_DROP_UNUSED:
  330. *serialize_flags &= ~XKB_KEYMAP_SERIALIZE_KEEP_UNUSED;
  331. break;
  332. case OPT_KEYMAP_EXPLICIT_DEFAULTS:
  333. *serialize_flags |= XKB_KEYMAP_SERIALIZE_EXPLICIT_DEFAULT_VALUES;
  334. break;
  335. case OPT_KEYMAP_EXPLICIT_VMODS:
  336. *serialize_flags |= XKB_KEYMAP_SERIALIZE_EXPLICIT_VMODS;
  337. break;
  338. case OPT_KEYMAP_EXPLICIT_KEYS:
  339. *serialize_flags |= XKB_KEYMAP_SERIALIZE_EXPLICIT_KEY_VALUES;
  340. break;
  341. case OPT_KEYMAP_EXPLICIT:
  342. *serialize_flags |= XKB_KEYMAP_SERIALIZE_EXPLICIT_DEFAULT_VALUES
  343. | XKB_KEYMAP_SERIALIZE_EXPLICIT_VMODS
  344. | XKB_KEYMAP_SERIALIZE_EXPLICIT_KEY_VALUES;
  345. break;
  346. case OPT_KEYMAP_LAYOUTS: {
  347. uint32_t mask = 0;
  348. if (!tools_parse_mask(optarg, TOOLS_ARG_REQUIRED, &mask))
  349. goto invalid_usage;
  350. *layout_mask = mask;
  351. break;
  352. }
  353. case OPT_RULES:
  354. if (input_format == INPUT_FORMAT_KEYMAP)
  355. goto input_format_error;
  356. names->rules = optarg;
  357. input_format = INPUT_FORMAT_RMLVO;
  358. break;
  359. case OPT_MODEL:
  360. if (input_format == INPUT_FORMAT_KEYMAP)
  361. goto input_format_error;
  362. names->model = optarg;
  363. input_format = INPUT_FORMAT_RMLVO;
  364. break;
  365. case OPT_LAYOUT:
  366. if (input_format == INPUT_FORMAT_KEYMAP)
  367. goto input_format_error;
  368. names->layout = optarg;
  369. input_format = INPUT_FORMAT_RMLVO;
  370. break;
  371. case OPT_VARIANT:
  372. if (input_format == INPUT_FORMAT_KEYMAP)
  373. goto input_format_error;
  374. names->variant = optarg;
  375. input_format = INPUT_FORMAT_RMLVO;
  376. break;
  377. case OPT_OPTION:
  378. if (input_format == INPUT_FORMAT_KEYMAP)
  379. goto input_format_error;
  380. names->options = optarg;
  381. input_format = INPUT_FORMAT_RMLVO;
  382. break;
  383. /* Output */
  384. case OPT_KCCGST:
  385. assert(is_incompatible_with_keymap_input(OUTPUT_FORMAT_KCCGST));
  386. if (input_format == INPUT_FORMAT_KEYMAP)
  387. goto output_incompatible_with_keymap_input_error;
  388. if (output_format != OUTPUT_FORMAT_KEYMAP &&
  389. output_format != OUTPUT_FORMAT_KCCGST)
  390. goto output_format_error;
  391. output_format = OUTPUT_FORMAT_KCCGST;
  392. break;
  393. case OPT_KCCGST_YAML:
  394. assert(is_incompatible_with_keymap_input(OUTPUT_FORMAT_KCCGST_YAML));
  395. if (input_format == INPUT_FORMAT_KEYMAP)
  396. goto output_incompatible_with_keymap_input_error;
  397. if (output_format != OUTPUT_FORMAT_KEYMAP &&
  398. output_format != OUTPUT_FORMAT_KCCGST_YAML)
  399. goto output_format_error;
  400. output_format = OUTPUT_FORMAT_KCCGST_YAML;
  401. break;
  402. case OPT_RMLVO:
  403. assert(is_incompatible_with_keymap_input(OUTPUT_FORMAT_RMLVO));
  404. if (input_format == INPUT_FORMAT_KEYMAP)
  405. goto output_incompatible_with_keymap_input_error;
  406. if (output_format != OUTPUT_FORMAT_KEYMAP &&
  407. output_format != OUTPUT_FORMAT_RMLVO)
  408. goto output_format_error;
  409. output_format = OUTPUT_FORMAT_RMLVO;
  410. break;
  411. case OPT_MODMAPS:
  412. assert(!is_incompatible_with_keymap_input(OUTPUT_FORMAT_MODMAPS));
  413. if (output_format != OUTPUT_FORMAT_KEYMAP &&
  414. output_format != OUTPUT_FORMAT_MODMAPS)
  415. goto output_format_error;
  416. output_format = OUTPUT_FORMAT_MODMAPS;
  417. break;
  418. default:
  419. goto invalid_usage;
  420. }
  421. }
  422. if (optind < argc && !isempty(argv[optind])) {
  423. /* Some positional arguments left: use as a keymap input */
  424. if (input_format != INPUT_FORMAT_AUTO ||
  425. is_incompatible_with_keymap_input(output_format)) {
  426. goto too_much_arguments;
  427. }
  428. input_format = INPUT_FORMAT_KEYMAP;
  429. *path = argv[optind++];
  430. if (optind < argc) {
  431. /* Further positional arguments is an error */
  432. too_much_arguments:
  433. fprintf(stderr, "ERROR: Too many positional arguments\n");
  434. goto invalid_usage;
  435. }
  436. } else if (is_pipe_or_regular_file(STDIN_FILENO) &&
  437. input_format != INPUT_FORMAT_RMLVO &&
  438. !is_incompatible_with_keymap_input(output_format)) {
  439. /* No positional argument: detect piping */
  440. input_format = INPUT_FORMAT_KEYMAP;
  441. }
  442. if (isempty(*path) || strcmp(*path, "-") == 0)
  443. *path = NULL;
  444. *input_format_out = input_format;
  445. *output_format_out = output_format;
  446. return true;
  447. input_format_error:
  448. fprintf(stderr, "ERROR: Cannot use RMLVO options with keymap input\n");
  449. goto invalid_usage;
  450. keymap_env_error:
  451. fprintf(stderr, "ERROR: --keymap is not compatible with "
  452. "--enable-environment-names\n");
  453. goto invalid_usage;
  454. output_format_error:
  455. fprintf(stderr, "ERROR: Cannot mix output formats\n");
  456. goto invalid_usage;
  457. output_incompatible_with_keymap_input_error:
  458. fprintf(stderr, "ERROR: Output format incompatible with keymap input\n");
  459. goto invalid_usage;
  460. too_many_includes:
  461. fprintf(stderr, "ERROR: too many includes (max: %zu)\n",
  462. ARRAY_SIZE(includes));
  463. invalid_usage:
  464. usage(stderr, argv[0]);
  465. exit(EXIT_INVALID_USAGE);
  466. }
  467. static const char success_text[] = "Success!";
  468. static int
  469. print_rmlvo(struct xkb_context *ctx, struct xkb_rule_names *rmlvo)
  470. {
  471. /* Resolve default RMLVO values */
  472. struct xkb_rule_names resolved = { NULL };
  473. if (!xkb_components_names_from_rules(ctx, rmlvo, &resolved, NULL)) {
  474. fprintf(stderr, "ERROR: failed to get RMLVO names from rules\n");
  475. return EXIT_FAILURE;
  476. } else if (test) {
  477. fprintf(stderr, "%s\n", success_text);
  478. return EXIT_SUCCESS;
  479. }
  480. printf("rules: \"%s\"\nmodel: \"%s\"\nlayout: \"%s\"\nvariant: \"%s\"\n"
  481. "options: \"%s\"\n",
  482. resolved.rules, resolved.model, resolved.layout,
  483. resolved.variant ? resolved.variant : "",
  484. resolved.options ? resolved.options : "");
  485. return EXIT_SUCCESS;
  486. }
  487. static int
  488. print_kccgst(struct xkb_context *ctx, struct xkb_rule_names *rmlvo, bool yaml)
  489. {
  490. struct xkb_component_names kccgst = { 0 };
  491. int rc = EXIT_SUCCESS;
  492. /* Resolve missing RMLVO values, then resolve the RMLVO names to
  493. * KcCGST components */
  494. if (!xkb_components_names_from_rules(ctx, rmlvo, NULL, &kccgst)) {
  495. fprintf(stderr, "ERROR: failed to get KcCGST components from rules\n");
  496. rc = EXIT_FAILURE;
  497. goto out;
  498. } else if (test) {
  499. fprintf(stderr, "%s\n", success_text);
  500. goto out;
  501. }
  502. if (yaml) {
  503. printf("keycodes: \"%s\"\n"
  504. "types: \"%s\"\n"
  505. "compat: \"%s\"\n"
  506. "symbols: \"%s\"\n",
  507. kccgst.keycodes, kccgst.types, kccgst.compatibility,
  508. kccgst.symbols);
  509. /* Contrary to the previous components, geometry can be empty */
  510. if (!isempty(kccgst.geometry)) {
  511. printf("geometry: \"%s\"\n", kccgst.geometry);
  512. }
  513. } else {
  514. printf("xkb_keymap {\n"
  515. " xkb_keycodes { include \"%s\" };\n"
  516. " xkb_types { include \"%s\" };\n"
  517. " xkb_compat { include \"%s\" };\n"
  518. " xkb_symbols { include \"%s\" };\n",
  519. kccgst.keycodes, kccgst.types, kccgst.compatibility,
  520. kccgst.symbols);
  521. /* Contrary to the previous components, geometry can be empty */
  522. if (!isempty(kccgst.geometry)) {
  523. printf(" xkb_geometry { include \"%s\" };\n", kccgst.geometry);
  524. }
  525. printf("};\n");
  526. }
  527. out:
  528. free(kccgst.keycodes);
  529. free(kccgst.types);
  530. free(kccgst.compatibility);
  531. free(kccgst.symbols);
  532. free(kccgst.geometry);
  533. return rc;
  534. }
  535. static struct xkb_keymap*
  536. load_keymap(struct xkb_context *ctx, enum xkb_keymap_format keymap_input_format,
  537. enum xkb_keymap_compile_flags compile_flags, enum input_format format,
  538. const struct xkb_rule_names *rmlvo,
  539. const char *path)
  540. {
  541. if (format == INPUT_FORMAT_KEYMAP) {
  542. FILE *file = NULL;
  543. if (path) {
  544. /* Read from regular file */
  545. file = fopen(path, "rb");
  546. } else {
  547. /* Read from stdin */
  548. file = tools_read_stdin();
  549. }
  550. if (!file) {
  551. fprintf(stderr, "ERROR: Failed to open keymap file \"%s\": %s\n",
  552. path ? path : "stdin", strerror(errno));
  553. return NULL;
  554. }
  555. return xkb_keymap_new_from_file(ctx, file,
  556. keymap_input_format,
  557. compile_flags);
  558. } else {
  559. return xkb_keymap_new_from_names2(ctx, rmlvo, keymap_input_format,
  560. compile_flags);
  561. }
  562. }
  563. static int
  564. print_keymap(struct xkb_context *ctx,
  565. enum xkb_keymap_format keymap_input_format,
  566. enum xkb_keymap_compile_flags compile_flags,
  567. enum input_format format,
  568. const struct xkb_rule_names *rmlvo, const char *path,
  569. const struct xkb_keymap_serialize_config *config)
  570. {
  571. int ret = EXIT_SUCCESS;
  572. struct xkb_keymap *keymap = load_keymap(ctx, keymap_input_format,
  573. compile_flags, format, rmlvo, path);
  574. if (!keymap) {
  575. fprintf(stderr, "ERROR: Couldn't create xkb keymap\n");
  576. ret = EXIT_FAILURE;
  577. } else if (test) {
  578. fprintf(stderr, "%s\n", success_text);
  579. } else {
  580. struct xkb_keymap_serialize_result result = { .size = sizeof(result) };
  581. const enum xkb_error_code error =
  582. xkb_keymap_serialize(keymap, config, &result);
  583. if (error != XKB_SUCCESS) {
  584. fprintf(stderr, "ERROR %d: Couldn't get the keymap string\n", error);
  585. ret = EXIT_FAILURE;
  586. } else {
  587. fputs(result.serialized, stdout);
  588. free(result.serialized);
  589. }
  590. }
  591. xkb_keymap_unref(keymap);
  592. return ret;
  593. }
  594. static int
  595. print_modmaps(struct xkb_context *ctx,
  596. enum xkb_keymap_format keymap_input_format,
  597. enum xkb_keymap_compile_flags compile_flags,
  598. enum input_format format, const struct xkb_rule_names *rmlvo,
  599. const char *path)
  600. {
  601. int ret = EXIT_SUCCESS;
  602. struct xkb_keymap *keymap = load_keymap(ctx, keymap_input_format,
  603. compile_flags, format, rmlvo, path);
  604. if (!keymap) {
  605. fprintf(stderr, "ERROR: Couldn't create xkb keymap\n");
  606. ret = EXIT_FAILURE;
  607. } else if (test) {
  608. fprintf(stderr, "%s\n", success_text);
  609. } else {
  610. print_modifiers_encodings(keymap);
  611. printf("\n");
  612. print_keys_modmaps(keymap);
  613. }
  614. xkb_keymap_unref(keymap);
  615. return ret;
  616. }
  617. int
  618. main(int argc, char **argv)
  619. {
  620. struct xkb_context *ctx;
  621. char *keymap_path = NULL;
  622. struct xkb_rule_names names = { 0 };
  623. bool use_env_names = false;
  624. enum xkb_keymap_format keymap_input_format = DEFAULT_INPUT_KEYMAP_FORMAT;
  625. static_assert(DEFAULT_OUTPUT_KEYMAP_FORMAT == XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  626. "Out of sync usage()");
  627. enum xkb_keymap_format keymap_output_format = DEFAULT_OUTPUT_KEYMAP_FORMAT;
  628. enum xkb_keymap_compile_flags compile_flags =
  629. (enum xkb_keymap_compile_flags) DEFAULT_KEYMAP_COMPILE_FLAGS;
  630. enum xkb_keymap_serialize_flags serialize_flags =
  631. (enum xkb_keymap_serialize_flags) DEFAULT_KEYMAP_SERIALIZE_FLAGS;
  632. xkb_layout_mask_t layout_mask = 0; /* all layouts by default */
  633. setlocale(LC_ALL, "");
  634. if (argc < 1) {
  635. usage(stderr, argv[0]);
  636. return EXIT_INVALID_USAGE;
  637. }
  638. enum input_format input_format = INPUT_FORMAT_AUTO;
  639. enum output_format output_format = OUTPUT_FORMAT_KEYMAP;
  640. if (!parse_options(argc, argv, &input_format, &output_format,
  641. &keymap_input_format, &keymap_output_format,
  642. &compile_flags, &serialize_flags, &layout_mask,
  643. &use_env_names, &keymap_path, &names))
  644. return EXIT_INVALID_USAGE;
  645. enum xkb_context_flags ctx_flags = XKB_CONTEXT_NO_DEFAULT_INCLUDES;
  646. if (!use_env_names)
  647. ctx_flags |= XKB_CONTEXT_NO_ENVIRONMENT_NAMES;
  648. ctx = xkb_context_new(ctx_flags);
  649. if (!ctx) {
  650. fprintf(stderr, "ERROR: cannot create xkb context\n");
  651. return EXIT_FAILURE;
  652. }
  653. if (verbose)
  654. tools_enable_verbose_logging(ctx);
  655. if (num_includes == 0)
  656. includes[num_includes++] = DEFAULT_INCLUDE_PATH_PLACEHOLDER;
  657. for (size_t i = 0; i < num_includes; i++) {
  658. const char *include = includes[i];
  659. if (strcmp(include, DEFAULT_INCLUDE_PATH_PLACEHOLDER) == 0)
  660. xkb_context_include_path_append_default(ctx);
  661. else
  662. xkb_context_include_path_append(ctx, include);
  663. }
  664. int rc = EXIT_FAILURE;
  665. switch (output_format) {
  666. case OUTPUT_FORMAT_RMLVO:
  667. assert(input_format != INPUT_FORMAT_KEYMAP);
  668. rc = print_rmlvo(ctx, &names);
  669. break;
  670. case OUTPUT_FORMAT_KCCGST:
  671. assert(input_format != INPUT_FORMAT_KEYMAP);
  672. rc = print_kccgst(ctx, &names, false);
  673. break;
  674. case OUTPUT_FORMAT_KCCGST_YAML:
  675. assert(input_format != INPUT_FORMAT_KEYMAP);
  676. rc = print_kccgst(ctx, &names, true);
  677. break;
  678. case OUTPUT_FORMAT_MODMAPS:
  679. rc = print_modmaps(ctx, keymap_input_format,
  680. compile_flags, input_format, &names, keymap_path);
  681. break;
  682. default: {
  683. struct xkb_keymap_serialize_config config = {
  684. .size = sizeof(config),
  685. .flags = serialize_flags,
  686. .format = keymap_output_format,
  687. .layouts = layout_mask,
  688. };
  689. rc = print_keymap(ctx, keymap_input_format, compile_flags, input_format,
  690. &names, keymap_path, &config);
  691. }
  692. }
  693. xkb_context_unref(ctx);
  694. return rc;
  695. }