summaryrefslogtreecommitdiff
path: root/src/bindings_file.c
blob: 4eab11fc96a805548725e2d329371c60de16767c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "bindings_file.h"
#include "binding.h"

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>


struct binding *bindings = NULL;
size_t nbindings = 0;

void skip_space(char **c)
{
	for (; **c && isspace(**c); (*c)++);
}

int read_int(char **c, int out[static 1])
{
	if (!isdigit(**c))
	{
		return -1;
	}
	errno = 0;
	char *end = NULL;
	*out = strtol(*c, &end, 10);
	if (errno)
	{
		return -1;
	}
	*c = end;
	return 0;
}

void parse_bindings_file(const char path[static 1])
{
	size_t cap = 512;
	bindings = malloc(sizeof (struct binding) * cap);
	FILE *f = fopen(path, "r");
	if (f == NULL)
	{
		fprintf(stderr, "failed to open bindings file: %s: %s\n", path,
		        strerror(errno));
		exit(EXIT_FAILURE);
	}

	size_t line_nb = 0;
	char *line = NULL;
	size_t n;
	while (getline(&line, &n, f) != -1)
	{
		line_nb++;
		struct binding binding = {0};
		char *end = strchr(line, '#');
		if (end == NULL)
		{
			end = line + strlen(line);
		}
		*end = '\0';
		char *c = line;

		skip_space(&c);
		if (c == end) continue;

		/* code */
		int code;
		for (;;)
		{
			if (read_int(&c, &code) < 0 || c >= end)
			{
				goto fail;
			}
			set_key(binding.keys, code);
			if (*c++ != '+')
			{
				c--;
				break;
			}
		}

		/* press | release */
		skip_space(&c);
		if (strncmp(c, "press", strlen("press")) == 0)
		{
			c += strlen("press");
			binding.value = PRESSED;
		}
		else if (strncmp(c, "release", strlen("release")) == 0)
		{
			c += strlen("release");
			binding.value = RELEASED;
		}
		else
		{
			goto fail;
		}

		/* cmd */
		skip_space(&c);
		if (c >= end)
		{
			goto fail;
		}
		binding.cmd = malloc(end - c + 1);
		memcpy(binding.cmd, c, end - c + 1);

		if (nbindings >= cap)
		{
			cap *= 2;
			bindings = realloc(bindings, cap * sizeof (struct binding));
		}
		bindings[nbindings++] = binding;
	}
	if (!feof(f))
	{
		fprintf(stderr, "failed to read bindings file: %s: %s\n", path,
		        strerror(errno));
	}
	free(line);
	fclose(f);
	return;

fail:
	fprintf(stderr, "syntax error at line %ld\n", line_nb);
	exit(EXIT_FAILURE);
}