1 /* SPDX-License-Identifier: GPL-2.0 */
2
3 // Read a toml keymap or plain text keymap (ir-keytable 1.14 or earlier
4 // format).
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <limits.h>
11 #include <stdbool.h>
12 #include <sys/types.h>
13 #include <argp.h>
14
15 #include "keymap.h"
16 #include "toml.h"
17
18 #ifdef ENABLE_NLS
19 # define _(string) gettext(string)
20 # include "gettext.h"
21 # include <locale.h>
22 # include <langinfo.h>
23 # include <iconv.h>
24 #else
25 # define _(string) string
26 #endif
27
free_keymap(struct keymap * map)28 void free_keymap(struct keymap *map)
29 {
30 struct scancode_entry *se;
31 struct raw_entry *re;
32 struct protocol_param *param;
33 struct keymap *next;
34
35 while (map) {
36 re = map->raw;
37
38 while (re) {
39 struct raw_entry *next = re->next;
40 free(re->keycode);
41 free(re);
42 re = next;
43 }
44
45 se = map->scancode;
46
47 while (se) {
48 struct scancode_entry *next = se->next;
49 free(se->keycode);
50 free(se);
51 se = next;
52 }
53
54 param = map->param;
55
56 while (param) {
57 struct protocol_param *next = param->next;
58 free(param->name);
59 free(param);
60 param = next;
61 }
62
63 next = map->next;
64
65 free(map->name);
66 free(map->protocol);
67 free(map->variant);
68 free(map);
69
70 map = next;
71 }
72 }
73
parse_plain_keymap(char * fname,struct keymap ** keymap,bool verbose)74 static error_t parse_plain_keymap(char *fname, struct keymap **keymap, bool verbose)
75 {
76 FILE *fin;
77 int line_no = 0;
78 char *scancode, *keycode, *line = NULL;
79 size_t line_size;
80 struct scancode_entry *se;
81 struct keymap *map;
82
83 map = calloc(1, sizeof(*map));
84 if (!map) {
85 perror("parse_keymap");
86 return ENOMEM;
87 }
88
89 if (verbose)
90 fprintf(stderr, _("Parsing %s keycode file as plain text\n"), fname);
91
92 fin = fopen(fname, "r");
93 if (!fin) {
94 fprintf(stderr, _("%s: error: cannot open: %m\n"), fname);
95 return EINVAL;
96 }
97
98 while (getline(&line, &line_size, fin) >= 0) {
99 char *p = line;
100
101 line_no++;
102 while (*p == ' ' || *p == '\t')
103 p++;
104 if (line_no==1 && p[0] == '#') {
105 p++;
106 p = strtok(p, "\n\t =:");
107 do {
108 if (!p)
109 goto err_einval;
110 if (!strcmp(p, "table")) {
111 p = strtok(NULL,"\n, ");
112 if (!p)
113 goto err_einval;
114 map->name = strdup(p);
115 } else if (!strcmp(p, "type")) {
116 p = strtok(NULL, " ,\n");
117 if (!p)
118 goto err_einval;
119
120 while (p) {
121 if (!map->protocol) {
122 map->protocol = strdup(p);
123 } else {
124 struct keymap *k;
125
126 k = calloc(1, sizeof(*k));
127 k->protocol = strdup(p);
128 k->next = map->next;
129 map->next = k;
130 }
131
132 p = strtok(NULL, " ,\n");
133 }
134 } else {
135 goto err_einval;
136 }
137 p = strtok(NULL, "\n\t =:");
138 } while (p);
139 continue;
140 }
141
142 if (*p == '\n' || *p == '#')
143 continue;
144
145 scancode = strtok(p, "\n\t =:");
146 if (!scancode)
147 goto err_einval;
148 if (!strcasecmp(scancode, "scancode")) {
149 scancode = strtok(NULL, "\n\t =:");
150 if (!scancode)
151 goto err_einval;
152 }
153
154 keycode = strtok(NULL, "\n\t =:(");
155 if (!keycode)
156 goto err_einval;
157
158 se = calloc(1, sizeof(*se));
159 if (!se) {
160 free_keymap(map);
161 perror("parse_keymap");
162 fclose(fin);
163 return ENOMEM;
164 }
165
166 se->scancode = strtoull(scancode, NULL, 0);
167 se->keycode = strdup(keycode);
168 se->next = map->scancode;
169 map->scancode = se;
170 }
171 fclose(fin);
172 free(line);
173
174 if (!map->protocol) {
175 fprintf(stderr, _("Missing protocol in %s\n"), fname);
176 return EINVAL;
177 }
178
179 *keymap = map;
180
181 return 0;
182
183 err_einval:
184 free_keymap(map);
185 fprintf(stderr, _("Invalid parameter on line %d of %s\n"),
186 line_no, fname);
187 return EINVAL;
188 }
189
parse_rawir_string(const char * fname,char * str,struct raw_entry ** entry)190 static error_t parse_rawir_string(const char *fname, char *str, struct raw_entry **entry)
191 {
192 struct raw_entry *re;
193 const char sep[] = "\n\r\t\v ,";
194 const char *p;
195 char *copy;
196 int i, size = 0;
197
198 // First do one scan so that we know the length
199 copy = strdup(str);
200 p = strtok(copy, sep);
201 while (p) {
202 size++;
203 p = strtok(NULL, sep);
204 }
205
206 re = calloc(1, sizeof(*re) + sizeof(re->raw[0]) * size);
207 if (!re) {
208 fprintf(stderr, _("Failed to allocate memory"));
209 free(copy);
210 return EINVAL;
211 }
212
213 // Second scan to extract values and validate
214 strcpy(copy, str);
215 p = strtok(copy, sep);
216 i = 0;
217 while (p) {
218 long int value;
219 char *q;
220
221 value = strtoll(p, &q, 10);
222 if (*q || value == 0 || errno) {
223 fprintf(stderr, _("%s: incorrect raw value `%s'"),
224 fname, p);
225 free(copy);
226 free(re);
227 return EINVAL;
228 }
229
230 if (value < 0) {
231 if (i % 2)
232 value = -value;
233 else {
234 fprintf(stderr, _("%s: negative raw value `%ld` at position %d only allowed for gaps/spaces"),
235 fname, value, i);
236 free(copy);
237 free(re);
238 return EINVAL;
239 }
240 }
241
242 if (value <= 0 || value > USHRT_MAX) {
243 fprintf(stderr, _("%s: raw value %ld out of range"),
244 fname, value);
245 free(copy);
246 free(re);
247 return EINVAL;
248 }
249
250 re->raw[i++] = value;
251
252 p = strtok(NULL, sep);
253 }
254
255 free(copy);
256 re->raw_length = size;
257
258 *entry = re;
259
260 return 0;
261 }
262
parse_toml_raw_part(const char * fname,struct toml_array_t * raw,struct keymap * map,bool verbose)263 static error_t parse_toml_raw_part(const char *fname, struct toml_array_t *raw, struct keymap *map, bool verbose)
264 {
265 char *keycode, *raw_str;
266 struct toml_table_t *t;
267 struct raw_entry *re;
268 const char *traw;
269 int ind = 0;
270
271 while ((t = toml_table_at(raw, ind++)) != NULL) {
272 traw = toml_raw_in(t, "keycode");
273 if (!traw) {
274 fprintf(stderr, _("%s: invalid keycode for raw entry %d\n"),
275 fname, ind);
276 return EINVAL;
277 }
278
279 if (toml_rtos(traw, &keycode)) {
280 fprintf(stderr, _("%s: bad value `%s' for keycode\n"),
281 fname, traw);
282 return EINVAL;
283 }
284
285 traw = toml_raw_in(t, "raw");
286 if (!traw) {
287 fprintf(stderr, _("%s: missing raw value for entry %d\n"),
288 fname, ind);
289 free(keycode);
290 return EINVAL;
291 }
292
293 if (toml_rtos(traw, &raw_str)) {
294 fprintf(stderr, _("%s: bad value `%s' for keycode\n"),
295 fname, traw);
296 free(keycode);
297 return EINVAL;
298 }
299
300 if (parse_rawir_string(fname, raw_str, &re)) {
301 free(keycode);
302 free(raw_str);
303 return EINVAL;
304 }
305
306 free(raw_str);
307 re->keycode = keycode;
308 re->next = map->raw;
309 map->raw = re;
310 }
311
312 return 0;
313 }
314
parse_toml_protocol(const char * fname,struct toml_table_t * proot,struct keymap ** keymap,bool verbose)315 static error_t parse_toml_protocol(const char *fname, struct toml_table_t *proot, struct keymap **keymap, bool verbose)
316 {
317 struct toml_table_t *scancodes;
318 struct toml_array_t *rawarray;
319 const char *raw, *key;
320 bool have_raw_protocol = false;
321 struct keymap *map;
322 char *p;
323 int i = 0;
324
325 map = calloc(1, sizeof(*map));
326 if (!map) {
327 perror("parse_toml_protocol");
328 return ENOMEM;
329 }
330 *keymap = map;
331
332 raw = toml_raw_in(proot, "protocol");
333 if (!raw) {
334 fprintf(stderr, _("%s: protocol missing\n"), fname);
335 free_keymap(map);
336 return EINVAL;
337 }
338
339 if (toml_rtos(raw, &p)) {
340 fprintf(stderr, _("%s: bad value `%s' for protocol\n"), fname, raw);
341 free_keymap(map);
342 return EINVAL;
343 }
344
345 map->protocol = p;
346 if (!strcmp(p, "raw"))
347 have_raw_protocol = true;
348
349 raw = toml_raw_in(proot, "variant");
350 if (raw) {
351 if (toml_rtos(raw, &p)) {
352 fprintf(stderr, _("%s: bad value `%s' for variant\n"), fname, raw);
353 free_keymap(map);
354 return EINVAL;
355 }
356
357 map->variant = p;
358 }
359
360 raw = toml_raw_in(proot, "name");
361 if (raw) {
362 if (toml_rtos(raw, &p)) {
363 fprintf(stderr, _("%s: bad value `%s' for name\n"), fname, raw);
364 free_keymap(map);
365 return EINVAL;
366 }
367
368 map->name = p;
369 }
370
371 rawarray = toml_array_in(proot, "raw");
372 if (rawarray) {
373 if (toml_raw_in(proot, "scancodes")) {
374 fprintf(stderr, _("Cannot have both [raw] and [scancode] sections"));
375 free_keymap(map);
376 return EINVAL;
377 }
378 if (!have_raw_protocol) {
379 fprintf(stderr, _("Keymap with raw entries must have raw protocol"));
380 free_keymap(map);
381 return EINVAL;
382 }
383 error_t err = parse_toml_raw_part(fname, rawarray, map, verbose);
384 if (err != 0) {
385 free_keymap(map);
386 return err;
387 }
388 } else if (have_raw_protocol) {
389 fprintf(stderr, _("Keymap with raw protocol must have raw entries"));
390 free_keymap(map);
391 return EINVAL;
392 }
393
394 for (i = 0; (key = toml_key_in(proot, i)) != NULL; i++) {
395 int64_t value;
396
397 raw = toml_raw_in(proot, key);
398 if (!toml_rtoi(raw, &value)) {
399 struct protocol_param *param;
400
401 param = malloc(sizeof(*param));
402 param->name = strdup(key);
403 param->value = value;
404 param->next = map->param;
405 map->param = param;
406 if (verbose)
407 fprintf(stderr, _("%s: protocol parameter %s=%ld\n"), fname, param->name, param->value);
408 }
409 }
410
411 scancodes = toml_table_in(proot, "scancodes");
412 if (!scancodes) {
413 if (verbose)
414 fprintf(stderr, _("%s: no [protocols.scancodes] section\n"), fname);
415 return 0;
416 }
417
418 struct scancode_entry **next = &map->scancode;
419 i = 0;
420
421 for (;;) {
422 struct scancode_entry *se;
423 const char *scancode;
424 char *keycode;
425
426 scancode = toml_key_in(scancodes, i++);
427 if (!scancode)
428 break;
429
430 raw = toml_raw_in(scancodes, scancode);
431 if (!raw) {
432 fprintf(stderr, _("%s: invalid value `%s'\n"), fname, scancode);
433 free_keymap(map);
434 return EINVAL;
435 }
436
437 if (toml_rtos(raw, &keycode)) {
438 fprintf(stderr, _("%s: bad value `%s' for keycode\n"),
439 fname, keycode);
440 free_keymap(map);
441 return EINVAL;
442 }
443
444 se = calloc(1, sizeof(*se));
445 if (!se) {
446 perror("parse_keymap");
447 free(keycode);
448 free_keymap(map);
449 return ENOMEM;
450 }
451
452 se->scancode = strtoull(scancode, NULL, 0);
453 se->keycode = keycode;
454 *next = se;
455 next = &se->next;
456 }
457
458 return 0;
459 }
460
parse_toml_keymap(char * fname,struct keymap ** keymap,bool verbose)461 static error_t parse_toml_keymap(char *fname, struct keymap **keymap, bool verbose)
462 {
463 struct toml_table_t *root, *proot;
464 struct toml_array_t *arr;
465 int ret, i = 0;
466 char buf[200];
467 FILE *fin;
468
469 if (verbose)
470 fprintf(stderr, _("Parsing %s keycode file as toml\n"), fname);
471
472 fin = fopen(fname, "r");
473 if (!fin) {
474 fprintf(stderr, _("%s: error: cannot open: %m\n"), fname);
475 return EINVAL;
476 }
477
478 root = toml_parse_file(fin, buf, sizeof(buf));
479 fclose(fin);
480 if (!root) {
481 fprintf(stderr, _("%s: error: %s\n"), fname, buf);
482 return EINVAL;
483 }
484
485 arr = toml_array_in(root, "protocols");
486 if (!arr) {
487 fprintf(stderr, _("%s: missing [protocols] section\n"), fname);
488 goto out;
489 }
490
491 struct keymap *map = NULL;
492
493 for (;;) {
494 struct keymap *cur_map;
495
496 proot = toml_table_at(arr, i);
497 if (!proot)
498 break;
499
500 ret = parse_toml_protocol(fname, proot, &cur_map, verbose);
501 if (ret)
502 goto out;
503
504 if (!map) {
505 map = cur_map;
506 } else {
507 cur_map->next = map->next;
508 map->next = cur_map;
509 }
510 i++;
511 }
512
513 if (i == 0) {
514 fprintf(stderr, _("%s: no protocols found\n"), fname);
515 goto out;
516 }
517
518 toml_free(root);
519 *keymap = map;
520 return 0;
521 out:
522 toml_free(root);
523 return EINVAL;
524 }
525
parse_keymap(char * fname,struct keymap ** keymap,bool verbose)526 error_t parse_keymap(char *fname, struct keymap **keymap, bool verbose)
527 {
528 size_t len = strlen(fname);
529
530 if (len >= 5 && strcasecmp(fname + len - 5, ".toml") == 0)
531 return parse_toml_keymap(fname, keymap, verbose);
532
533 return parse_plain_keymap(fname, keymap, verbose);
534 }
535
keymap_param(struct keymap * map,const char * name,int fallback)536 int keymap_param(struct keymap *map, const char *name, int fallback)
537 {
538 struct protocol_param *param;
539
540 for (param = map->param; param; param = param->next) {
541 if (!strcmp(param->name, name))
542 return param->value;
543 }
544
545 return fallback;
546 }
547