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