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