• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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