The Pedigree Project 0.1
keymap/main.c
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <ctype.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#include "cmd.h"
30#include "parser.h"
31
32extern int yylex();
33extern int yyparse();
34extern FILE* yyin;
35extern char** environ;
36extern YYSTYPE yylval;
37
38#ifndef NOT_PEDIGREE
39extern int pedigree_load_keymap(char* buffer, size_t len);
40#endif
41
42typedef struct sparse_entry sparse_t;
43
44cmd_t* cmds[MAX_CMDS];
45int n_cmds = 0;
46
47int sparse_pos = 0;
48int sparse_buffsz = 0;
49sparse_t* sparse_buff = 0;
50
51int data_pos = 0;
52int data_buffsz = 0;
53char* data_buff = 0;
54
55// Modifiers are CTRL and SHIFT, ALT, ALTGR.
56// Combinators are 256 user-programmable combining flags (used for accents).
57
58#define SPECIAL 0x80000000
59
60typedef struct table_entry {
61 uint32_t flags; // SPECIAL | modifiers
62 uint32_t val; // If flags & SPECIAL, 4 char string for special key, else U+val.
64
65#define TABLE_IDX(combinator, modifiers, scancode) \
66 (((combinator & 0xFF) << 11) | ((modifiers & 0xF) << 7) | (scancode & 0x7F))
67#define TABLE_MAX TABLE_IDX(0xFF, 0xF, 0x7F)
68
69table_entry_t table[TABLE_MAX + 1];
70
71#define SPARSE_NULL 0
72#define SPARSE_DATA_FLAG 0x8000
73
74typedef struct sparse_entry {
75 uint16_t left;
76 uint16_t right;
77} sparse_t;
78
79int sparse_add() {
80 int ret = sparse_pos;
81 int sz = sizeof(sparse_t);
82 if (sparse_pos + sz > sparse_buffsz) {
83 if (sparse_pos + sz >= 32768) {
84 fprintf(stderr, "Too many sparse nodes.\n");
85 exit(1);
86 }
87 sparse_t* new_sparse_buff = realloc(sparse_buff, sparse_buffsz + sz + sizeof(sparse_t));
88 if (!new_sparse_buff) {
89 fprintf(stderr, "Couldn't allocate buffer for new sparse buffer: %s.\n", strerror(errno));
90 exit(1);
91 }
92 sparse_buff = new_sparse_buff;
93 sparse_buffsz += sz + sizeof(sparse_t);
94 }
95 sparse_pos += sz;
96
97 return ret;
98}
99
100int data_add(table_entry_t* start, table_entry_t* end) {
101 int ret = data_pos;
102 int sz = (unsigned long)end - (unsigned long)start;
103 if (data_pos + sz > data_buffsz) {
104 if (data_pos + sz >= 32768) {
105 fprintf(stderr, "Too much data.\n");
106 exit(1);
107 }
108 char* new_data_buff = realloc(data_buff, data_buffsz + sz + sizeof(sparse_t));
109 if (!new_data_buff) {
110 fprintf(stderr, "Couldn't allocate buffer for new data buffer: %s.\n", strerror(errno));
111 exit(1);
112 }
113 data_buff = new_data_buff;
114 data_buffsz += sz + sizeof(sparse_t);
115 }
116
117 memcpy(&data_buff[data_pos], (char*)start, sz);
118 data_pos += sz;
119
120 return ret;
121}
122
123int all_set(table_entry_t* start, table_entry_t* end) {
124 for (; start < end; start++) {
125 if (start->flags == 0 && start->val == 0)
126 return 0;
127 }
128 return 1;
129}
130
131int all_clear(table_entry_t* start, table_entry_t* end) {
132 for (; start < end; start++) {
133 if (start->flags != 0 || start->val != 0)
134 return 0;
135 }
136 return 1;
137}
138
139int yywrap() {
140 return 1;
141}
142
143int yyerror(const char* str) __attribute__((noreturn));
144int yyerror(const char* str) {
145 printf("Syntax error: %s\n", str);
146 exit(1);
147}
148
149void usage() {
150 printf(
151 "keymap: Compile or install a keyboard mapping.\n\
152Usage: keymap [compile|install] file \n");
153}
154
155void parse(char* filename) {
156 FILE* stream = fopen(filename, "r");
157 if (!stream) {
158 fprintf(stderr, "Unable to open file `%s'\n", filename);
159 exit(1);
160 }
161 yyin = stream;
162 yyparse();
163
164 memset(table, 0, sizeof(table_entry_t) * (TABLE_MAX + 1));
165
166 int i;
167 for (i = 0; i < n_cmds; i++) {
168 int comb = cmds[i]->combinators & 0xFF;
169 int modifiers = cmds[i]->modifiers & 0xF;
170
171 unsigned int idx = TABLE_IDX(comb, modifiers, cmds[i]->scancode);
172 table[idx].flags = cmds[i]->set_modifiers;
173 if (cmds[i]->unicode_point != 0) {
174 table[idx].val = cmds[i]->unicode_point;
175 } else if (cmds[i]->val != 0) {
176 table[idx].flags |= SPECIAL;
177 memcpy((char*)&(table[idx].val), cmds[i]->val, strlen(cmds[i]->val));
178 }
179 }
180}
181
182int sparse(int idx, int bisect_size) {
183 int byte_offset = sparse_add();
184 sparse_t* me = &sparse_buff[byte_offset / sizeof(*sparse_buff)];
185
186 // Check the right child - is everything zero?
187 if (all_clear(&table[idx - bisect_size], &table[idx]) > 0) {
188 // All zero, don't do anything with this child.
189 me->left = SPARSE_NULL;
190 } else if ((all_set(&table[idx - bisect_size], &table[idx]) > 0) || (bisect_size % 2)) {
191 // printf("DATA: %x -> %x (L)\n", idx-bisect_size, idx);
192 // All set, add to data section and set ptr.
193 me->left = data_add(&table[idx - bisect_size], &table[idx]) |
194 SPARSE_DATA_FLAG /* This is actual data, not another node. */;
195 } else {
196 uint16_t tmp = sparse(idx - bisect_size / 2, bisect_size / 2);
197 // Buffer location may have changed with the me->left call.
198 me = &sparse_buff[byte_offset / sizeof(*sparse_buff)];
199 me->left = tmp;
200 }
201
202 // Check the right child - is everything zero?
203 if (all_clear(&table[idx], &table[idx + bisect_size]) > 0) {
204 // All zero, don't do anything with this child.
205 me->right = SPARSE_NULL;
206 } else if ((all_set(&table[idx], &table[idx + bisect_size]) > 0) || (bisect_size % 2)) {
207 // printf("DATA: %x -> %x (R)\n", idx, idx+bisect_size);
208 // All set, add to data section and set ptr.
209 me->right = data_add(&table[idx], &table[idx + bisect_size]) |
210 SPARSE_DATA_FLAG /* This is actual data, not another node. */;
211 } else {
212 uint16_t tmp = sparse(idx + bisect_size / 2, bisect_size / 2);
213 // Buffer location may have changed with the me->left call.
214 me = &sparse_buff[byte_offset / sizeof(*sparse_buff)];
215 me->right = tmp;
216 }
217
218 return byte_offset;
219}
220
221void compile(char* filename) {
222 parse(filename);
223
224 // Table created, now create the sparse tree.
225 sparse((TABLE_MAX + 1) / 2, (TABLE_MAX + 1) / 2);
226
227 // room for .kmc + null terminator
228 char* fname = (char*)malloc(strlen(filename) + 5);
229 strcpy(fname, filename);
230 strcat(fname, ".kmc");
231
232 // Write out.
233 FILE* stream = fopen(fname, "w");
234 if (!stream) {
235 fprintf(stderr, "Unable to open output file `%s'\n", fname);
236 exit(1);
237 }
238
239 int idx = 2 * sizeof(int);
240 fwrite(&idx, sizeof(idx), 1, stream);
241 idx = sparse_buffsz + 2 * sizeof(int);
242
243 fwrite(&idx, sizeof(idx), 1, stream);
244 fwrite(sparse_buff, 1, sparse_buffsz, stream);
245 fwrite(data_buff, 1, data_buffsz, stream);
246 fclose(stream);
247
248 printf("Compiled keymap file written to `%s'.\n", fname);
249
250 // clear fname for header part
251 memset(fname, 0, strlen(filename) + 5);
252 strcpy(fname, filename);
253 strcat(fname, ".h");
254
255 // Write out.
256 stream = fopen(fname, "w");
257 if (!stream) {
258 fprintf(stderr, "Unable to open output file `%s'\n", fname);
259 exit(1);
260 }
261
262 // Change the filename to uppercase and underscored for the header guard.
263 char* header_guard = strdup(fname);
264 int i;
265 for (i = 0; i < (int)strlen(fname); i++) {
266 if (fname[i] == '.' || fname[i] == '/')
267 header_guard[i] = '_';
268 else
269 header_guard[i] = toupper(fname[i]);
270 }
271
272 fprintf(stream,
273 "/*\n\
274 * Copyright (c) 2010 James Molloy, Burtescu Eduard\n\
275 *\n\
276 * Permission to use, copy, modify, and distribute this software for any\n\
277 * purpose with or without fee is hereby granted, provided that the above\n\
278 * copyright notice and this permission notice appear in all copies.\n\
279 *\n\
280 * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n\
281 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n\
282 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n\
283 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n\
284 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n\
285 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n\
286 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\
287 */\n\
288\n\
289#ifndef %s\n\
290#define %s\n\
291\n\
292static char sparseBuff[%d] =\n\"",
293 header_guard, header_guard, sparse_buffsz + 1);
294
295 for (i = 0; i < sparse_buffsz; i++) {
296 fprintf(stream, "\\x%02x", (unsigned char)((char*)sparse_buff)[i]);
297 if ((i % 20) == 0 && i != 0)
298 fprintf(stream, "\\\n");
299 }
300 fprintf(stream, "\";\n\nstatic char dataBuff[%d] =\n\"", data_buffsz + 1);
301 for (i = 0; i < data_buffsz; i++) {
302 fprintf(stream, "\\x%02x", (unsigned char)data_buff[i]);
303 if ((i % 20) == 0 && i != 0)
304 fprintf(stream, "\\\n");
305 }
306 fprintf(stream, "\";\n\n#endif\n");
307
308 fclose(stream);
309
310 free(header_guard);
311
312 printf("Compiled keymap header file written to `%s'.\n", fname);
313}
314
315void install(char* filename) {
316#ifdef NOT_PEDIGREE
317 fprintf(stderr, "Unable to install a keymap on non-pedigree OS.\n");
318 exit(1);
319#else
320
321 // Look for a '.kmc' extension.
322 int len = strlen(filename);
323 if (len < 4 || filename[len - 3] != 'k' || filename[len - 2] != 'm' || filename[len - 1] != 'c') {
324 printf(
325 "Warning: Filename does not end in '.kmc' - are you sure this "
326 "is a compiled keymap file?\n");
327 printf(
328 "*** If you load an invalid keymap your system will be rendered "
329 "unusable without a manual reboot. ***\n");
330 printf("\nContinue? [no] ");
331
332 char input[64];
333 if ((scanf("%63s", input) != 1) || (strcmp(input, "yes") != 0)) {
334 printf("Aborted, no change took place.\n");
335 exit(0);
336 }
337 }
338
339 // Load the file in to a buffer.
340 FILE* stream = fopen(filename, "r");
341 if (!stream) {
342 fprintf(stderr, "Error opening file `%s'.\n", filename);
343 return;
344 }
345 fseek(stream, 0, SEEK_END);
346 len = ftell(stream);
347 fseek(stream, 0, SEEK_SET);
348
349 char* buffer = (char*)malloc(len);
350 fread(buffer, 1, len, stream);
351 fclose(stream);
352
353 if (pedigree_load_keymap(buffer, len))
354 fprintf(stderr, "Error loading keymap.\n");
355 else
356 printf("Keymap loaded.\n");
357 exit(0);
358#endif
359}
360
361int main(int argc, char** argv) {
362 if (argc != 3) {
363 usage();
364 exit(0);
365 }
366
367 if (!strcmp(argv[1], "compile"))
368 compile(argv[2]);
369 else if (!strcmp(argv[1], "install"))
370 install(argv[2]);
371 else
372 usage();
373
374 exit(0);
375}
Definition cmd.h:30
Definition keymap/main.c:74
Definition keymap/main.c:60