compile-compose.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Copyright © 2021 Ran Benita <ran@unusedvar.com>
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include <getopt.h>
  7. #include <locale.h>
  8. #include <stdbool.h>
  9. #include "xkbcommon/xkbcommon.h"
  10. #include "xkbcommon/xkbcommon-keysyms.h"
  11. #include "xkbcommon/xkbcommon-compose.h"
  12. #include "src/compose/dump.h"
  13. #include "src/keysym.h"
  14. #include "tools/tools-common.h"
  15. static void
  16. usage(FILE *fp, char *progname)
  17. {
  18. fprintf(fp,
  19. "Usage: %s [--help] [--version] [--verbose] [--locale LOCALE] [--test] [FILE]\n",
  20. progname);
  21. fprintf(fp,
  22. "\n"
  23. "Compile a Compose file and print it\n"
  24. "\n"
  25. "Options:\n"
  26. " --help\n"
  27. " Print this help and exit\n"
  28. " --version\n"
  29. " Print version information and exit\n"
  30. " --verbose\n"
  31. " Enable verbose debugging output\n"
  32. " --file FILE\n"
  33. " Specify a Compose file to load.\n"
  34. " DEPRECATED: use the positional argument instead.\n"
  35. " --locale LOCALE\n"
  36. " Specify the locale directly, instead of relying on the environment variables\n"
  37. " LC_ALL, LC_TYPE and LANG.\n"
  38. " --test\n"
  39. " Test compilation but do not print the Compose file.\n");
  40. }
  41. int
  42. main(int argc, char *argv[])
  43. {
  44. const char *locale = NULL;
  45. const char *path = NULL;
  46. enum xkb_compose_format format = XKB_COMPOSE_FORMAT_TEXT_V1;
  47. bool verbose = false;
  48. bool test = false;
  49. enum options {
  50. OPT_VERBOSE,
  51. OPT_FILE,
  52. OPT_LOCALE,
  53. OPT_TEST,
  54. };
  55. static struct option opts[] = {
  56. {"help", no_argument, 0, 'h'},
  57. {"version", no_argument, 0, 'V'},
  58. {"verbose", no_argument, 0, OPT_VERBOSE},
  59. {"file", required_argument, 0, OPT_FILE},
  60. {"locale", required_argument, 0, OPT_LOCALE},
  61. {"test", no_argument, 0, OPT_TEST},
  62. {0, 0, 0, 0},
  63. };
  64. setlocale(LC_ALL, "");
  65. /* Initialize the locale to use */
  66. locale = setlocale(LC_CTYPE, NULL);
  67. if (!locale)
  68. locale = "C";
  69. while (1) {
  70. int opt;
  71. int option_index = 0;
  72. opt = getopt_long(argc, argv, "hV", opts, &option_index);
  73. if (opt == -1)
  74. break;
  75. switch (opt) {
  76. case OPT_VERBOSE:
  77. verbose = true;
  78. break;
  79. case OPT_FILE:
  80. path = optarg;
  81. fprintf(stderr, "WARNING: the flag --file is deprecated\n");
  82. break;
  83. case OPT_LOCALE:
  84. locale = optarg;
  85. break;
  86. case OPT_TEST:
  87. test = true;
  88. break;
  89. case 'h':
  90. usage(stdout, argv[0]);
  91. return EXIT_SUCCESS;
  92. case 'V':
  93. printf("%s\n", LIBXKBCOMMON_VERSION);
  94. exit(EXIT_SUCCESS);
  95. default:
  96. usage(stderr, argv[0]);
  97. return EXIT_INVALID_USAGE;
  98. }
  99. }
  100. if (locale == NULL) {
  101. fprintf(stderr, "ERROR: Cannot determine the locale.\n");
  102. usage(stderr, argv[0]);
  103. return EXIT_INVALID_USAGE;
  104. }
  105. if (optind < argc && !isempty(argv[optind])) {
  106. /* Some positional arguments left: use a file */
  107. if (path) {
  108. fprintf(stderr,
  109. "ERROR: Path already provided via the flag: --file\n");
  110. usage(stderr, argv[0]);
  111. exit(EXIT_INVALID_USAGE);
  112. }
  113. path = argv[optind++];
  114. if (optind < argc) {
  115. fprintf(stderr, "ERROR: Too many positional arguments\n");
  116. usage(stderr, argv[0]);
  117. exit(EXIT_INVALID_USAGE);
  118. }
  119. } else if (is_pipe_or_regular_file(STDIN_FILENO)) {
  120. /* No positional argument: detect piping */
  121. path = "-";
  122. }
  123. struct xkb_context *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  124. if (!ctx) {
  125. fprintf(stderr, "ERROR: Couldn't create xkb context\n");
  126. return EXIT_FAILURE;
  127. }
  128. if (verbose)
  129. tools_enable_verbose_logging(ctx);
  130. int ret = EXIT_FAILURE;
  131. struct xkb_compose_table *compose_table = NULL;
  132. if (path != NULL) {
  133. FILE *file;
  134. if (isempty(path) || strcmp(path, "-") == 0) {
  135. /* Read from stdin */
  136. file = tools_read_stdin();
  137. } else {
  138. /* Read from regular file */
  139. file = fopen(path, "rb");
  140. }
  141. if (file == NULL) {
  142. perror(path);
  143. goto file_error;
  144. }
  145. compose_table =
  146. xkb_compose_table_new_from_file(ctx, file, locale, format,
  147. XKB_COMPOSE_COMPILE_NO_FLAGS);
  148. fclose(file);
  149. if (!compose_table) {
  150. fprintf(stderr,
  151. "ERROR: Couldn't create compose from file: %s\n", path);
  152. goto out;
  153. }
  154. } else {
  155. compose_table =
  156. xkb_compose_table_new_from_locale(ctx, locale,
  157. XKB_COMPOSE_COMPILE_NO_FLAGS);
  158. if (!compose_table) {
  159. fprintf(stderr,
  160. "ERROR: Couldn't create compose from locale \"%s\"\n",
  161. locale);
  162. goto out;
  163. }
  164. }
  165. if (test) {
  166. ret = EXIT_SUCCESS;
  167. goto out;
  168. }
  169. ret = xkb_compose_table_dump(stdout, compose_table)
  170. ? EXIT_SUCCESS
  171. : EXIT_FAILURE;
  172. out:
  173. xkb_compose_table_unref(compose_table);
  174. file_error:
  175. xkb_context_unref(ctx);
  176. return ret;
  177. }