1 /*
2 * Copyright © 2020 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 <stdio.h>
28 #include <getopt.h>
29
30 #include "xkbcommon/xkbregistry.h"
31
32 static void
usage(const char * progname,FILE * fp)33 usage(const char *progname, FILE *fp)
34 {
35 fprintf(fp,
36 "Usage: %s [OPTIONS] [/path/to/xkb_base_directory [/path2]...]\n"
37 "\n"
38 "Options:\n"
39 " --verbose, -v .......... Increase verbosity, use multiple times for debugging output\n"
40 " --ruleset=foo .......... Load the 'foo' ruleset\n"
41 " --skip-default-paths ... Do not load the default XKB paths\n"
42 " --load-exotic .......... Load the exotic (extra) rulesets\n"
43 "\n"
44 "Trailing arguments are treated as XKB base directory installations.\n",
45 progname);
46 }
47
48 int
main(int argc,char ** argv)49 main(int argc, char **argv)
50 {
51 int rc = 1;
52 struct rxkb_context *ctx = NULL;
53 struct rxkb_model *m;
54 struct rxkb_layout *l;
55 struct rxkb_option_group *g;
56 enum rxkb_context_flags flags = RXKB_CONTEXT_NO_FLAGS;
57 bool load_defaults = true;
58 int verbosity = 0;
59 const char *ruleset = DEFAULT_XKB_RULES;
60
61 static const struct option opts[] = {
62 {"help", no_argument, 0, 'h'},
63 {"verbose", no_argument, 0, 'v'},
64 {"load-exotic", no_argument, 0, 'e'},
65 {"skip-default-paths", no_argument, 0, 'd'},
66 {"ruleset", required_argument, 0, 'r'},
67 {0, 0, 0, 0},
68 };
69
70 while (1) {
71 int c;
72 int option_index = 0;
73
74 c = getopt_long(argc, argv, "hev", opts, &option_index);
75 if (c == -1)
76 break;
77
78 switch (c) {
79 case 'h':
80 usage(argv[0], stdout);
81 return 0;
82 case '?':
83 usage(argv[0], stderr);
84 return EXIT_INVALID_USAGE;
85 case 'd':
86 load_defaults = false;
87 break;
88 case 'e':
89 flags |= RXKB_CONTEXT_LOAD_EXOTIC_RULES;
90 break;
91 case 'r':
92 ruleset = optarg;
93 break;
94 case 'v':
95 verbosity++;
96 break;
97 }
98 }
99
100 if (optind < argc)
101 flags |= RXKB_CONTEXT_NO_DEFAULT_INCLUDES;
102
103 ctx = rxkb_context_new(flags);
104 assert(ctx);
105
106 switch (verbosity) {
107 case 0:
108 rxkb_context_set_log_level(ctx, RXKB_LOG_LEVEL_ERROR);
109 break;
110 case 1:
111 rxkb_context_set_log_level(ctx, RXKB_LOG_LEVEL_INFO);
112 break;
113 default:
114 rxkb_context_set_log_level(ctx, RXKB_LOG_LEVEL_DEBUG);
115 break;
116 }
117
118 if (optind < argc) {
119 for (int i = optind; i < argc; i++) {
120 if (!rxkb_context_include_path_append(ctx, argv[i])) {
121 fprintf(stderr, "Failed to append include path '%s'\n",
122 argv[i]);
123 goto err;
124 }
125 }
126
127 if (load_defaults) {
128 if (!rxkb_context_include_path_append_default(ctx)) {
129 fprintf(stderr, "Failed to include default paths.\n");
130 goto err;
131 }
132 }
133 }
134 if (!rxkb_context_parse(ctx, ruleset)) {
135 fprintf(stderr, "Failed to parse XKB descriptions.\n");
136 goto err;
137 }
138
139 printf("models:\n");
140 m = rxkb_model_first(ctx);
141 assert(m); /* Empty model list is usually a bug or a bad xml file */
142 while (m) {
143 const char *vendor = rxkb_model_get_vendor(m);
144 printf("- name: %s\n"
145 " vendor: %s\n"
146 " description: %s\n",
147 rxkb_model_get_name(m),
148 vendor ? vendor : "''",
149 rxkb_model_get_description(m));
150 m = rxkb_model_next(m);
151 }
152
153 printf("\n");
154 printf("layouts:\n");
155 l = rxkb_layout_first(ctx);
156 assert(l); /* Empty layout list is usually a bug or a bad xml file */
157 while (l) {
158 struct rxkb_iso639_code *iso639;
159 struct rxkb_iso3166_code *iso3166;
160 const char *variant = rxkb_layout_get_variant(l);
161 const char *brief = rxkb_layout_get_brief(l);
162
163 printf("- layout: '%s'\n"
164 " variant: '%s'\n"
165 " brief: '%s'\n"
166 " description: %s\n",
167 rxkb_layout_get_name(l),
168 variant ? variant : "",
169 brief ? brief : "''",
170 rxkb_layout_get_description(l));
171
172 printf(" iso639: [");
173 iso639 = rxkb_layout_get_iso639_first(l);
174 if (iso639) {
175 const char *sep = "";
176 while (iso639) {
177 printf("%s'%s'", sep, rxkb_iso639_code_get_code(iso639));
178 iso639 = rxkb_iso639_code_next(iso639);
179 sep = ", ";
180 }
181 }
182 printf("]\n");
183 printf(" iso3166: [");
184 iso3166 = rxkb_layout_get_iso3166_first(l);
185 if (iso3166) {
186 const char *sep = "";
187 while (iso3166) {
188 printf("%s'%s'", sep, rxkb_iso3166_code_get_code(iso3166));
189 iso3166 = rxkb_iso3166_code_next(iso3166);
190 sep = ", ";
191 }
192 }
193 printf("]\n");
194 l = rxkb_layout_next(l);
195 }
196 printf("\n");
197 printf("option_groups:\n");
198 g = rxkb_option_group_first(ctx);
199 assert(g); /* Empty option goups list is usually a bug or a bad xml file */
200 while (g) {
201 struct rxkb_option *o;
202
203 printf("- name: '%s'\n"
204 " description: %s\n"
205 " allows_multiple: %s\n"
206 " options:\n",
207 rxkb_option_group_get_name(g),
208 rxkb_option_group_get_description(g),
209 rxkb_option_group_allows_multiple(g) ? "true" : "false");
210
211 o = rxkb_option_first(g);
212 assert(o); /* Empty option list is usually a bug or a bad xml file */
213 while (o) {
214 const char *brief = rxkb_option_get_brief(o);
215
216 printf(" - name: '%s'\n"
217 " brief: '%s'\n"
218 " description: '%s'\n",
219 rxkb_option_get_name(o),
220 brief ? brief : "",
221 rxkb_option_get_description(o));
222 o = rxkb_option_next(o);
223 }
224
225 g = rxkb_option_group_next(g);
226 }
227
228 rc = 0;
229
230 err:
231 if (ctx)
232 rxkb_context_unref(ctx);
233
234 return rc;
235 }
236