Utils use _GNU_SOURCE
[platform/upstream/kbd.git] / src / libkeymap / dump.c
1 /* dump.c
2  *
3  * This file is part of kbd project.
4  * Copyright (C) 1993  Risto Kankkunen.
5  * Copyright (C) 1993  Eugene G. Crosser.
6  * Copyright (C) 1994-2007  Andries E. Brouwer.
7  * Copyright (C) 2007-2013  Alexey Gladkov <gladkov.alexey@gmail.com>
8  *
9  * This file is covered by the GNU General Public License,
10  * which should be included with kbd as the file COPYING.
11  */
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <unistd.h>
16
17 #include "ksyms.h"
18 #include "modifiers.h"
19 #include "nls.h"
20
21 #include "keymap.h"
22
23 #define U(x) ((x) ^ 0xf000)
24
25 static void
26 outchar(FILE *fd, unsigned char c, int comma)
27 {
28         fprintf(fd, "'");
29         fprintf(fd, (c == '\'' || c == '\\') ? "\\%c"
30                : isgraph(c) ? "%c"
31                : "\\%03o", c);
32         fprintf(fd, comma ? "', " : "'");
33 }
34
35 // FIXME: Merge outchar ?
36 static void
37 dumpchar(FILE *fd, unsigned char c, int comma)
38 {
39         fprintf(fd, "'");
40         fprintf(fd, (c == '\'' || c == '\\') ? "\\%c"
41                : (isgraph(c) || c == ' ' || c >= 0200) ? "%c"
42                : "\\%03o", c);
43         fprintf(fd, comma ? "', " : "'");
44 }
45
46 int
47 lk_dump_bkeymap(struct keymap *kmap)
48 {
49         int i, j;
50
51         //u_char *p;
52         char flag, magic[] = "bkeymap";
53         unsigned short v;
54
55         if (lk_add_constants(kmap) < 0)
56                 return -1;
57
58         if (write(1, magic, 7) == -1)
59                 goto fail;
60         for (i = 0; i < MAX_NR_KEYMAPS; i++) {
61                 flag = kmap->key_map[i] ? 1 : 0;
62                 if (write(1, &flag, 1) == -1)
63                         goto fail;
64         }
65         for (i = 0; i < MAX_NR_KEYMAPS; i++) {
66                 if (kmap->key_map[i]) {
67                         for (j = 0; j < NR_KEYS / 2; j++) {
68                                 v = lk_get_key(kmap, i, j);
69                                 if (write(1, &v, 2) == -1)
70                                         goto fail;
71                         }
72                 }
73         }
74         return 0;
75
76  fail:  ERR(kmap, _("Error writing map to file"));
77         return -1;
78 }
79
80 static char *
81 mk_mapname(char modifier)
82 {
83         static char *mods[8] = {
84                 "shift", "altgr", "ctrl", "alt", "shl", "shr", "ctl", "ctr"
85         };
86         static char buf[60];
87         int i;
88
89         if (!modifier)
90                 return "plain";
91         buf[0] = 0;
92         for (i = 0; i < 8; i++)
93                 if (modifier & (1 << i)) {
94                         if (buf[0])
95                                 strcat(buf, "_");
96                         strcat(buf, mods[i]);
97                 }
98         return buf;
99 }
100
101 int
102 lk_dump_ctable(struct keymap *kmap, FILE *fd)
103 {
104         int j;
105         unsigned int i, imax;
106
107         char *ptr;
108         unsigned int maxfunc;
109         unsigned int keymap_count = 0;
110         unsigned int func_table_offs[MAX_NR_FUNC];
111         unsigned int func_buf_offset = 0;
112
113         if (lk_add_constants(kmap) < 0)
114                 return -1;
115
116         fprintf(fd,
117 /* not to be translated... */
118                     "/* Do not edit this file! It was automatically generated by   */\n");
119         fprintf(fd, "/*    loadkeys --mktable defkeymap.map > defkeymap.c          */\n\n");
120         fprintf(fd, "#include <linux/types.h>\n");
121         fprintf(fd, "#include <linux/keyboard.h>\n");
122         fprintf(fd, "#include <linux/kd.h>\n\n");
123
124         for (i = 0; i < MAX_NR_KEYMAPS; i++)
125                 if (kmap->key_map[i]) {
126                         keymap_count++;
127                         if (i)
128                                 fprintf(fd, "static ");
129                         fprintf(fd, "u_short %s_map[NR_KEYS] = {", mk_mapname(i));
130                         for (j = 0; j < NR_KEYS; j++) {
131                                 if (!(j % 8))
132                                         fprintf(fd, "\n");
133                                 fprintf(fd, "\t0x%04x,", U(lk_get_key(kmap, i, j)));
134                         }
135                         fprintf(fd, "\n};\n\n");
136                 }
137
138         for (imax = MAX_NR_KEYMAPS - 1; imax > 0; imax--)
139                 if (kmap->key_map[imax])
140                         break;
141         fprintf(fd, "ushort *key_maps[MAX_NR_KEYMAPS] = {");
142         for (i = 0; i <= imax; i++) {
143                 fprintf(fd, (i % 4) ? " " : "\n\t");
144                 if (kmap->key_map[i])
145                         fprintf(fd, "%s_map,", mk_mapname(i));
146                 else
147                         fprintf(fd, "0,");
148         }
149         if (imax < MAX_NR_KEYMAPS - 1)
150                 fprintf(fd, "\t0");
151         fprintf(fd, "\n};\n\nunsigned int keymap_count = %d;\n\n", keymap_count);
152
153 /* uglified just for xgettext - it complains about nonterminated strings */
154         fprintf(fd,
155                "/*\n"
156                " * Philosophy: most people do not define more strings, but they who do\n"
157                " * often want quite a lot of string space. So, we statically allocate\n"
158                " * the default and allocate dynamically in chunks of 512 bytes.\n"
159                " */\n" "\n");
160         for (maxfunc = MAX_NR_FUNC; maxfunc; maxfunc--)
161                 if (kmap->func_table[maxfunc - 1])
162                         break;
163
164         fprintf(fd, "char func_buf[] = {\n");
165         for (i = 0; i < maxfunc; i++) {
166                 ptr = kmap->func_table[i];
167                 if (ptr) {
168                         func_table_offs[i] = func_buf_offset;
169                         fprintf(fd, "\t");
170                         for (; *ptr; ptr++)
171                                 outchar(fd, *ptr, 1);
172                         fprintf(fd, "0, \n");
173                         func_buf_offset += (ptr - kmap->func_table[i] + 1);
174                 }
175         }
176         if (!maxfunc)
177                 fprintf(fd, "\t0\n");
178         fprintf(fd, "};\n\n");
179
180         fprintf(fd,
181                "char *funcbufptr = func_buf;\n"
182                "int funcbufsize = sizeof(func_buf);\n"
183                "int funcbufleft = 0;          /* space left */\n" "\n");
184
185         fprintf(fd, "char *func_table[MAX_NR_FUNC] = {\n");
186         for (i = 0; i < maxfunc; i++) {
187                 if (kmap->func_table[i])
188                         fprintf(fd, "\tfunc_buf + %u,\n", func_table_offs[i]);
189                 else
190                         fprintf(fd, "\t0,\n");
191         }
192         if (maxfunc < MAX_NR_FUNC)
193                 fprintf(fd, "\t0,\n");
194         fprintf(fd, "};\n");
195
196 #ifdef KDSKBDIACRUC
197         if (kmap->prefer_unicode) {
198                 fprintf(fd, "\nstruct kbdiacruc accent_table[MAX_DIACR] = {\n");
199                 for (i = 0; i < kmap->accent_table_size; i++) {
200                         fprintf(fd, "\t{");
201                         outchar(fd, kmap->accent_table[i].diacr, 1);
202                         outchar(fd, kmap->accent_table[i].base, 1);
203                         fprintf(fd, "0x%04x},", kmap->accent_table[i].result);
204                         if (i % 2)
205                                 fprintf(fd, "\n");
206                 }
207                 if (i % 2)
208                         fprintf(fd, "\n");
209                 fprintf(fd, "};\n\n");
210         } else
211 #endif
212         {
213                 fprintf(fd, "\nstruct kbdiacr accent_table[MAX_DIACR] = {\n");
214                 for (i = 0; i < kmap->accent_table_size; i++) {
215                         fprintf(fd, "\t{");
216                         outchar(fd, kmap->accent_table[i].diacr, 1);
217                         outchar(fd, kmap->accent_table[i].base, 1);
218                         outchar(fd, kmap->accent_table[i].result, 0);
219                         fprintf(fd, "},");
220                         if (i % 2)
221                                 fprintf(fd, "\n");
222                 }
223                 if (i % 2)
224                         fprintf(fd, "\n");
225                 fprintf(fd, "};\n\n");
226         }
227         fprintf(fd, "unsigned int accent_table_size = %d;\n", kmap->accent_table_size);
228         return 0;
229 }
230
231 /* void dump_funcs(void) */
232 void
233 lk_dump_funcs(struct keymap *kmap, FILE *fd)
234 {
235         unsigned int i;
236         char *ptr;
237         unsigned int maxfunc;
238
239         for (maxfunc = MAX_NR_FUNC; maxfunc; maxfunc--) {
240                 if (kmap->func_table[maxfunc - 1])
241                         break;
242         }
243
244         for (i = 0; i < maxfunc; i++) {
245                 ptr = kmap->func_table[i];
246                 if (!ptr)
247                         continue;
248
249                 fprintf(fd, "string %s = \"", syms[KT_FN].table[i]);
250
251                 for (; *ptr; ptr++) {
252                         if (*ptr == '"' || *ptr == '\\') {
253                                 fputc('\\', fd);
254                                 fputc(*ptr, fd);
255                         } else if (isgraph(*ptr) || *ptr == ' ') {
256                                 fputc(*ptr, fd);
257                         } else {
258                                 fprintf(fd, "\\%03o", *ptr);
259                         }
260                 }
261                 fputc('"', fd);
262                 fputc('\n', fd);
263         }
264 }
265
266 /* void dump_diacs(void) */
267 void
268 lk_dump_diacs(struct keymap *kmap, FILE *fd)
269 {
270         unsigned int i;
271 #ifdef KDSKBDIACRUC
272         if (kmap->prefer_unicode) {
273                 for (i = 0; i < kmap->accent_table_size; i++) {
274                         fprintf(fd, "compose ");
275                         dumpchar(fd, kmap->accent_table[i].diacr & 0xff, 0);
276                         fprintf(fd, " ");
277                         dumpchar(fd, kmap->accent_table[i].base & 0xff, 0);
278                         fprintf(fd, " to U+%04x\n", kmap->accent_table[i].result);
279                 }
280         } else
281 #endif
282         {
283                 for (i = 0; i < kmap->accent_table_size; i++) {
284                         fprintf(fd, "compose ");
285                         dumpchar(fd, kmap->accent_table[i].diacr, 0);
286                         fprintf(fd, " ");
287                         dumpchar(fd, kmap->accent_table[i].base, 0);
288                         fprintf(fd, " to ");
289                         dumpchar(fd, kmap->accent_table[i].result, 0);
290                         fprintf(fd, "\n");
291                 }
292         }
293 }
294
295 void
296 lk_dump_keymaps(struct keymap *kmap, FILE *fd)
297 {
298         int i, m0, m;
299         char c = ' ';
300
301         fprintf(fd, "keymaps");
302         for (i = 0; i < kmap->max_keymap; i++) {
303                 if (i)
304                         c = ',';
305                 m0 = m = kmap->defining[i];
306                 while (i+1 < kmap->max_keymap && kmap->defining[i+1] == m+1)
307                         i++, m++;
308                 if (!m0)
309                         continue;
310                 (m0 == m)
311                         ? fprintf(fd, "%c%d"   , c, m0-1)
312                         : fprintf(fd, "%c%d-%d", c, m0-1, m-1);
313         }
314         fprintf(fd, "\n");
315 }
316
317 static void
318 print_mod(FILE *fd, int x)
319 {
320         if (x) {
321                 modifier_t *mod = (modifier_t *) modifiers;
322                 while (mod->name) {
323                         if (x & (1 << mod->bit))
324                                 fprintf(fd, "%s\t", mod->name);
325                         mod++;
326                 }
327         } else {
328                 fprintf(fd, "plain\t");
329         }
330 }
331
332 static void
333 print_keysym(struct keymap *kmap, FILE *fd, int code, char numeric)
334 {
335         unsigned int t;
336         int v;
337         const char *p;
338         int plus;
339
340         fprintf(fd, " ");
341         t = KTYP(code);
342         v = KVAL(code);
343         if (t >= syms_size) {
344                 if (!numeric && (p = codetoksym(kmap, code)) != NULL)
345                         fprintf(fd, "%-16s", p);
346                 else
347                         fprintf(fd, "U+%04x          ", code ^ 0xf000);
348                 return;
349         }
350         plus = 0;
351         if (t == KT_LETTER) {
352                 t = KT_LATIN;
353                 fprintf(fd, "+");
354                 plus++;
355         }
356         if (!numeric && t < syms_size && v < syms[t].size &&
357             (p = syms[t].table[v])[0])
358                 fprintf(fd, "%-*s", 16 - plus, p);
359         else if (!numeric && t == KT_META && v < 128 && v < syms[0].size &&
360                  (p = syms[0].table[v])[0])
361                 fprintf(fd, "Meta_%-11s", p);
362         else
363                 fprintf(fd, "0x%04x         %s", code, plus ? "" : " ");
364 }
365
366 static void
367 print_bind(struct keymap *kmap, FILE *fd, int bufj, int i, int j, char numeric)
368 {
369         if(j)
370                 fprintf(fd, "\t");
371         print_mod(fd, j);
372         fprintf(fd, "keycode %3d =", i);
373         print_keysym(kmap, fd, bufj, numeric);
374         fprintf(fd, "\n");
375 }
376
377 void
378 lk_dump_keys(struct keymap *kmap, FILE *fd, char table_shape, char numeric)
379 {
380         int i, j, k;
381         int buf[MAX_NR_KEYMAPS];
382         int isletter, islatin, isasexpected;
383         int typ, val;
384         int alt_is_meta = 0;
385         int all_holes;
386         int zapped[MAX_NR_KEYMAPS];
387         int keymapnr = kmap->max_keymap;
388
389         if (!keymapnr)
390                 return;
391
392         if (table_shape == FULL_TABLE || table_shape == SEPARATE_LINES)
393                 goto no_shorthands;
394
395         /* first pass: determine whether to set alt_is_meta */
396         for (j = 0; j < MAX_NR_KEYMAPS; j++) {
397                 int ja = (j | M_ALT);
398
399                 if (!(j != ja && kmap->defining[j] && kmap->defining[ja]))
400                         continue;
401
402                 for (i = 1; i < NR_KEYS; i++) {
403                         int buf0, buf1, type;
404
405                         buf0 = lk_get_key(kmap, j, i);
406
407                         if (buf0 == -1)
408                                 break;
409
410                         type = KTYP(buf0);
411
412                         if ((type == KT_LATIN || type == KT_LETTER) && KVAL(buf0) < 128) {
413                                 buf1 = (kmap->defining[ja])
414                                         ? lk_get_key(kmap, ja, i)
415                                         : -1;
416
417                                 if (buf1 != K(KT_META, KVAL(buf0)))
418                                         goto not_alt_is_meta;
419                         }
420                 }
421         }
422         alt_is_meta = 1;
423         fprintf(fd, "alt_is_meta\n");
424
425 not_alt_is_meta:
426 no_shorthands:
427
428         for (i = 1; i < NR_KEYS; i++) {
429                 all_holes = 1;
430
431                 for (j = 0; j < keymapnr; j++) {
432                         buf[j] = (kmap->defining[j])
433                                 ? lk_get_key(kmap, kmap->defining[j]-1, i)
434                                 : K_HOLE;
435
436                         if (buf[j] != K_HOLE)
437                                 all_holes = 0;
438                 }
439
440                 if (all_holes)
441                         continue;
442
443                 if (table_shape == FULL_TABLE) {
444                         fprintf(fd, "keycode %3d =", i);
445
446                         for (j = 0; j < keymapnr; j++)
447                                 print_keysym(kmap, fd, buf[j], numeric);
448
449                         fprintf(fd, "\n");
450                         continue;
451                 }
452
453                 if (table_shape == SEPARATE_LINES) {
454                         for (j = 0; j < keymapnr; j++) {
455                                 //if (buf[j] != K_HOLE)
456                                 print_bind(kmap, fd, buf[j], i, kmap->defining[j]-1, numeric);
457                         }
458
459                         fprintf(fd, "\n");
460                         continue;
461                 }
462
463                 fprintf(fd, "\n");
464
465                 typ = KTYP(buf[0]);
466                 val = KVAL(buf[0]);
467                 islatin = (typ == KT_LATIN || typ == KT_LETTER);
468                 isletter = (islatin &&
469                         ((val >= 'A' && val <= 'Z') ||
470                          (val >= 'a' && val <= 'z')));
471
472                 isasexpected = 0;
473                 if (isletter) {
474                         u_short defs[16];
475                         defs[0] = K(KT_LETTER, val);
476                         defs[1] = K(KT_LETTER, val ^ 32);
477                         defs[2] = defs[0];
478                         defs[3] = defs[1];
479
480                         for (j = 4; j < 8; j++)
481                                 defs[j] = K(KT_LATIN, val & ~96);
482
483                         for (j = 8; j < 16; j++)
484                                 defs[j] = K(KT_META, KVAL(defs[j-8]));
485
486                         for (j = 0; j < keymapnr; j++) {
487                                 k = kmap->defining[j] - 1;
488
489                                 if ((k >= 16 && buf[j] != K_HOLE) || (k < 16 && buf[j] != defs[k]))
490                                         goto unexpected;
491                         }
492
493                         isasexpected = 1;
494                 }
495 unexpected:
496
497                 /* wipe out predictable meta bindings */
498                 for (j = 0; j < keymapnr; j++)
499                         zapped[j] = 0;
500
501                 if (alt_is_meta) {
502                         for(j = 0; j < keymapnr; j++) {
503                                 int ka, ja, ktyp;
504
505                                 k = kmap->defining[j] - 1;
506                                 ka = (k | M_ALT);
507                                 ja = kmap->defining[ka] - 1;
508
509                                 if (k != ka && ja >= 0
510                                     && ((ktyp=KTYP(buf[j])) == KT_LATIN || ktyp == KT_LETTER)
511                                     && KVAL(buf[j]) < 128) {
512                                         if (buf[ja] != K(KT_META, KVAL(buf[j])))
513                                                 fprintf(stderr, _("impossible: not meta?\n"));
514                                         buf[ja] = K_HOLE;
515                                         zapped[ja] = 1;
516                                 }
517                         }
518                 }
519
520                 fprintf(fd, "keycode %3d =", i);
521
522                 if (isasexpected) {
523                         /* print only a single entry */
524                         /* suppress the + for ordinary a-zA-Z */
525                         print_keysym(kmap, fd, K(KT_LATIN, val), numeric);
526                         fprintf(fd, "\n");
527                 } else {
528                         /* choose between single entry line followed by exceptions,
529                            and long line followed by exceptions; avoid VoidSymbol */
530                         int bad = 0;
531                         int count = 0;
532
533                         for (j = 1; j < keymapnr; j++) {
534                                 if (zapped[j])
535                                         continue;
536
537                                 if (buf[j] != buf[0])
538                                         bad++;
539
540                                 if (buf[j] != K_HOLE)
541                                         count++;
542                         }
543
544                         if (bad <= count && bad < keymapnr-1) {
545                                 if (buf[0] != K_HOLE) {
546                                         print_keysym(kmap, fd, buf[0], numeric);
547                                 }
548                                 fprintf(fd, "\n");
549
550                                 for (j = 1; j < keymapnr; j++) {
551                                         if (buf[j] != buf[0] && !zapped[j]) {
552                                                 print_bind(kmap, fd, buf[j], i, kmap->defining[j]-1, numeric);
553                                         }
554                                 }
555                         } else {
556                                 for (j = 0;
557                                      j < keymapnr && buf[j] != K_HOLE &&
558                                         (j == 0 || table_shape != UNTIL_HOLE ||
559                                         kmap->defining[j]-1 == kmap->defining[j-1]-1+1);
560                                      j++) {
561                                         //print_bind(kmap, fd, buf[j], i, kmap->defining[j]-1, numeric);
562                                         print_keysym(kmap, fd, buf[j], numeric);
563                                 }
564
565                                 fprintf(fd, "\n");
566
567                                 for (; j < keymapnr; j++) {
568                                         if (buf[j] != K_HOLE) {
569                                                 print_bind(kmap, fd, buf[j], i, kmap->defining[j]-1, numeric);
570                                         }
571                                 }
572                         }
573                 }
574         }
575 }
576
577 void
578 lk_dump_keymap(struct keymap *kmap, FILE *fd, char table_shape, char numeric)
579 {
580         lk_dump_keymaps(kmap, fd);
581         lk_dump_keys(kmap, fd, table_shape, numeric);
582         lk_dump_funcs(kmap, fd);
583 }