/* dump.c * * This file is part of kbd project. * Copyright (C) 1993 Risto Kankkunen. * Copyright (C) 1993 Eugene G. Crosser. * Copyright (C) 1994-2007 Andries E. Brouwer. * Copyright (C) 2007-2013 Alexey Gladkov * * This file is covered by the GNU General Public License, * which should be included with kbd as the file COPYING. */ #include "config.h" #include #include #include #include #include "keymap.h" #include "contextP.h" #include "ksyms.h" #include "modifiers.h" #include "libcommon.h" #define U(x) ((x) ^ 0xf000) static void outchar(FILE *fd, unsigned int c, int comma) { fprintf(fd, "'"); fprintf(fd, (c == '\'' || c == '\\') ? "\\%c" : isgraph(c) ? "%c" : "\\%03o", c); fprintf(fd, comma ? "', " : "'"); } // FIXME: Merge outchar ? static void dumpchar(FILE *fd, unsigned int c, int comma) { fprintf(fd, "'"); fprintf(fd, (c == '\'' || c == '\\') ? "\\%c" : (isgraph(c) || c == ' ' || c >= 0200) ? "%c" : "\\%03o", c); fprintf(fd, comma ? "', " : "'"); } int lk_dump_bkeymap(struct lk_ctx *ctx, FILE *fd) { int i, j; char magic[] = "bkeymap"; if (lk_add_constants(ctx) < 0) return -1; if (fwrite(magic, 7, 1, fd) != 1) goto fail; for (i = 0; i < MAX_NR_KEYMAPS; i++) { char flag = lk_map_exists(ctx, i) ? 1 : 0; if (fwrite(&flag, sizeof(flag), 1, fd) != 1) goto fail; } for (i = 0; i < MAX_NR_KEYMAPS; i++) { if (!lk_map_exists(ctx, i)) continue; for (j = 0; j < NR_KEYS / 2; j++) { int v = lk_get_key(ctx, i, j); if (fwrite(&v, sizeof(v), 1, fd) != 1) goto fail; } } return 0; fail: ERR(ctx, _("Error writing map to file")); return -1; } static char * mk_mapname(char modifier) { static const char *mods[8] = { "shift", "altgr", "ctrl", "alt", "shl", "shr", "ctl", "ctr" }; static char buf[60]; int i; if (!modifier) { strcat(buf, "plain"); return buf; } buf[0] = 0; for (i = 0; i < 8; i++) if (modifier & (1 << i)) { if (buf[0]) strcat(buf, "_"); strcat(buf, mods[i]); } return buf; } int lk_dump_ctable(struct lk_ctx *ctx, FILE *fd) { int j; int i, imax; int maxfunc; long func_table_offs[MAX_NR_FUNC]; long func_buf_offset = 0; struct lk_kbdiacr *kddiac; if (lk_add_constants(ctx) < 0) return -1; fprintf(fd, /* not to be translated... */ "/* Do not edit this file! It was automatically generated by */\n"); fprintf(fd, "/* loadkeys --mktable defkeymap.map > defkeymap.c */\n\n"); fprintf(fd, "#include \n"); fprintf(fd, "#include \n\n"); for (i = 0; i < MAX_NR_KEYMAPS; i++) if (lk_map_exists(ctx, i)) { if (i) fprintf(fd, "static "); fprintf(fd, "unsigned short %s_map[NR_KEYS] = {", mk_mapname((char) i)); for (j = 0; j < NR_KEYS; j++) { if (!(j % 8)) fprintf(fd, "\n"); fprintf(fd, "\t0x%04x,", U(lk_get_key(ctx, i, j))); } fprintf(fd, "\n};\n\n"); } for (imax = MAX_NR_KEYMAPS - 1; imax > 0; imax--) if (lk_map_exists(ctx, imax)) break; fprintf(fd, "ushort *key_maps[MAX_NR_KEYMAPS] = {"); for (i = 0; i <= imax; i++) { fprintf(fd, (i % 4) ? " " : "\n\t"); if (lk_map_exists(ctx, i)) fprintf(fd, "%s_map,", mk_mapname((char) i)); else fprintf(fd, "0,"); } if (imax < MAX_NR_KEYMAPS - 1) fprintf(fd, "\t0"); fprintf(fd, "\n};\n\nunsigned int keymap_count = %u;\n\n", (unsigned int)ctx->keymap->count); /* uglified just for xgettext - it complains about nonterminated strings */ fprintf(fd, "/*\n" " * Philosophy: most people do not define more strings, but they who do\n" " * often want quite a lot of string space. So, we statically allocate\n" " * the default and allocate dynamically in chunks of 512 bytes.\n" " */\n" "\n"); for (maxfunc = MAX_NR_FUNC; maxfunc; maxfunc--) if (lk_array_get_ptr(ctx->func_table, maxfunc - 1)) break; fprintf(fd, "char func_buf[] = {\n"); for (i = 0; i < maxfunc; i++) { unsigned char *ptr, *func; func = ptr = lk_array_get_ptr(ctx->func_table, i); if (!ptr) continue; func_table_offs[i] = func_buf_offset; fprintf(fd, "\t"); for (; *ptr; ptr++) outchar(fd, *ptr, 1); fprintf(fd, "0, \n"); func_buf_offset += (ptr - func + 1); } if (!maxfunc) fprintf(fd, "\t0\n"); fprintf(fd, "};\n\n"); fprintf(fd, "char *funcbufptr = func_buf;\n" "int funcbufsize = sizeof(func_buf);\n" "int funcbufleft = 0; /* space left */\n" "\n"); fprintf(fd, "char *func_table[MAX_NR_FUNC] = {\n"); for (i = 0; i < maxfunc; i++) { if (lk_array_get_ptr(ctx->func_table, i)) fprintf(fd, "\tfunc_buf + %ld,\n", func_table_offs[i]); else fprintf(fd, "\t0,\n"); } if (maxfunc < MAX_NR_FUNC) fprintf(fd, "\t0,\n"); fprintf(fd, "};\n"); if (ctx->flags & LK_FLAG_PREFER_UNICODE) { fprintf(fd, "\nstruct kbdiacruc accent_table[MAX_DIACR] = {\n"); for (i = 0; i < ctx->accent_table->count; i++) { kddiac = lk_array_get_ptr(ctx->accent_table, i); fprintf(fd, "\t{"); outchar(fd, kddiac->diacr, 1); outchar(fd, kddiac->base, 1); fprintf(fd, "0x%04x},", kddiac->result); if (i % 2) fprintf(fd, "\n"); } if (i % 2) fprintf(fd, "\n"); fprintf(fd, "};\n\n"); } else { fprintf(fd, "\nstruct kbdiacr accent_table[MAX_DIACR] = {\n"); for (i = 0; i < ctx->accent_table->count; i++) { kddiac = lk_array_get_ptr(ctx->accent_table, i); fprintf(fd, "\t{"); outchar(fd, kddiac->diacr, 1); outchar(fd, kddiac->base, 1); outchar(fd, kddiac->result, 0); fprintf(fd, "},"); if (i % 2) fprintf(fd, "\n"); } if (i % 2) fprintf(fd, "\n"); fprintf(fd, "};\n\n"); } fprintf(fd, "unsigned int accent_table_size = %u;\n", (unsigned int)ctx->accent_table->count); return 0; } /* void dump_funcs(void) */ void lk_dump_funcs(struct lk_ctx *ctx, FILE *fd) { int i; for (i = 0; i < ctx->func_table->total; i++) { char *ptr = lk_array_get_ptr(ctx->func_table, i); if (!ptr) continue; fprintf(fd, "string %s = \"", get_sym(ctx, KT_FN, i)); for (; *ptr; ptr++) { if (*ptr == '"' || *ptr == '\\') { fputc('\\', fd); fputc(*ptr, fd); } else if (isgraph(*ptr) || *ptr == ' ') { fputc(*ptr, fd); } else { fprintf(fd, "\\%03hho", *ptr); } } fputc('"', fd); fputc('\n', fd); } } /* void dump_diacs(void) */ void lk_dump_diacs(struct lk_ctx *ctx, FILE *fd) { unsigned int i; struct lk_kbdiacr *ptr; const char *ksym; for (i = 0; i < ctx->accent_table->count; i++) { ptr = lk_array_get_ptr(ctx->accent_table, i); if (!ptr) continue; fprintf(fd, "compose "); dumpchar(fd, ptr->diacr, 0); fprintf(fd, " "); dumpchar(fd, ptr->base, 0); #ifdef KDGKBDIACRUC if (ctx->flags & LK_FLAG_PREFER_UNICODE) { ksym = codetoksym(ctx, (int) ptr->result ^ 0xf000); if (ksym) { fprintf(fd, " to %s\n", ksym); } else { fprintf(fd, " to U+%04x\n", ptr->result); } } else #endif if (ptr->result > 0xff) { // impossible case? fprintf(fd, " to 0x%x\n", ptr->result); } else { ksym = codetoksym(ctx, (int) ptr->result); if (ksym) { fprintf(fd, " to %s\n", ksym); } else { fprintf(fd, " to "); dumpchar(fd, ptr->result, 0); fprintf(fd, "\n"); } } } } void lk_dump_keymaps(struct lk_ctx *ctx, FILE *fd) { int i, n, m, s; i = n = m = s = 0; fprintf(fd, "keymaps"); for (i = 0; i < ctx->keymap->total; i++) { if (ctx->keywords & LK_KEYWORD_ALTISMETA && i == (i | M_ALT)) continue; if (!lk_map_exists(ctx, i)) { if (!m) continue; n--, m--; (n == m) ? fprintf(fd, "%c%d", (s ? ',' : ' '), n) : fprintf(fd, "%c%d-%d", (s ? ',' : ' '), n, m); n = m = 0; s = 1; } else { if (!n) n = i + 1; m = i + 1; } } if (m) { n--, m--; (n == m) ? fprintf(fd, "%c%d", (s ? ',' : ' '), n) : fprintf(fd, "%c%d-%d", (s ? ',' : ' '), n, m); } fprintf(fd, "\n"); } static void print_mod(FILE *fd, int x) { if (x) { modifier_t *mod = (modifier_t *)modifiers; while (mod->name) { if (x & (1 << mod->bit)) fprintf(fd, "%s\t", mod->name); mod++; } } else { fprintf(fd, "plain\t"); } } static void print_keysym(struct lk_ctx *ctx, FILE *fd, int code, char numeric) { int t, v; const char *p; int plus; fprintf(fd, " "); t = KTYP(code); v = KVAL(code); if (t >= syms_size) { if (!numeric && (p = codetoksym(ctx, code)) != NULL) fprintf(fd, "%-16s", p); else fprintf(fd, "U+%04x ", code ^ 0xf000); return; } plus = 0; if (t == KT_LETTER) { t = KT_LATIN; fprintf(fd, "+"); plus++; } if (!numeric && t == KT_LATIN && (p = codetoksym(ctx, code))) fprintf(fd, "%-*s", 16 - plus, p); else if (!numeric && t < syms_size && v < get_sym_size(ctx, t) && (p = get_sym(ctx, t, v))[0]) fprintf(fd, "%-*s", 16 - plus, p); else if (!numeric && t == KT_META && v < 128 && v < get_sym_size(ctx, KT_LATIN) && (p = get_sym(ctx, KT_LATIN, v))[0]) fprintf(fd, "Meta_%-11s", p); else fprintf(fd, "0x%04x %s", code, plus ? "" : " "); } static void print_bind(struct lk_ctx *ctx, FILE *fd, int bufj, int i, int j, char numeric) { if (j) fprintf(fd, "\t"); print_mod(fd, j); fprintf(fd, "keycode %3d =", i); print_keysym(ctx, fd, bufj, numeric); fprintf(fd, "\n"); } void lk_dump_keys(struct lk_ctx *ctx, FILE *fd, lk_table_shape table, char numeric) { int i, j; int buf[MAX_NR_KEYMAPS]; int isletter, islatin, isasexpected; int typ, val; int alt_is_meta = 0; int all_holes; int zapped[MAX_NR_KEYMAPS]; ssize_t keymapnr = ctx->keymap->total; if (!keymapnr) return; if (table == LK_SHAPE_FULL_TABLE || table == LK_SHAPE_SEPARATE_LINES) goto no_shorthands; /* first pass: determine whether to set alt_is_meta */ for (j = 0; j < ctx->keymap->total; j++) { int ja = (j | M_ALT); if (!(j != ja && lk_map_exists(ctx, j) && lk_map_exists(ctx, ja))) continue; for (i = 1; i < NR_KEYS; i++) { int buf0, buf1, type; buf0 = lk_get_key(ctx, j, i); if (buf0 == -1) break; type = KTYP(buf0); if ((type == KT_LATIN || type == KT_LETTER) && KVAL(buf0) < 128) { buf1 = lk_map_exists(ctx, ja) ? lk_get_key(ctx, ja, i) : -1; if (buf1 != K(KT_META, KVAL(buf0))) goto not_alt_is_meta; } } } alt_is_meta = 1; fprintf(fd, "alt_is_meta\n"); not_alt_is_meta: no_shorthands: for (i = 1; i < NR_KEYS; i++) { all_holes = 1; for (j = 0; j < keymapnr; j++) { buf[j] = K_HOLE; if (lk_map_exists(ctx, j)) buf[j] = lk_get_key(ctx, j, i); if (buf[j] != K_HOLE) all_holes = 0; } if (all_holes && table != LK_SHAPE_FULL_TABLE) continue; if (table == LK_SHAPE_FULL_TABLE) { fprintf(fd, "keycode %3d =", i); for (j = 0; j < keymapnr; j++) { if (lk_map_exists(ctx, j)) print_keysym(ctx, fd, buf[j], numeric); } fprintf(fd, "\n"); continue; } if (table == LK_SHAPE_SEPARATE_LINES) { for (j = 0; j < keymapnr; j++) { //if (buf[j] != K_HOLE) print_bind(ctx, fd, buf[j], i, j, numeric); } fprintf(fd, "\n"); continue; } typ = KTYP(buf[0]); val = KVAL(buf[0]); islatin = (typ == KT_LATIN || typ == KT_LETTER); isletter = (islatin && ((val >= 'A' && val <= 'Z') || (val >= 'a' && val <= 'z'))); isasexpected = 0; if (isletter) { int defs[16]; defs[0] = K(KT_LETTER, val); defs[1] = K(KT_LETTER, val ^ 32); defs[2] = defs[0]; defs[3] = defs[1]; for (j = 4; j < 8; j++) defs[j] = K(KT_LATIN, val & ~96); for (j = 8; j < 16; j++) defs[j] = K(KT_META, KVAL(defs[j - 8])); for (j = 0; j < keymapnr; j++) { if (lk_map_exists(ctx, j)) { if ((j >= 16 && buf[j] != K_HOLE) || (j < 16 && buf[j] != defs[j])) goto unexpected; } } isasexpected = 1; } unexpected: /* wipe out predictable meta bindings */ for (j = 0; j < keymapnr; j++) zapped[j] = 0; if (alt_is_meta) { for (j = 0; j < keymapnr; j++) { int ja, ktyp; ja = (j | M_ALT); if (j != ja && lk_map_exists(ctx, ja) && ((ktyp = KTYP(buf[j])) == KT_LATIN || ktyp == KT_LETTER) && KVAL(buf[j]) < 128) { if (buf[ja] != K(KT_META, KVAL(buf[j]))) fprintf(stderr, _("impossible: not meta?\n")); buf[ja] = K_HOLE; zapped[ja] = 1; } } } fprintf(fd, "keycode %3d =", i); if (isasexpected) { /* print only a single entry */ /* suppress the + for ordinary a-zA-Z */ print_keysym(ctx, fd, K(KT_LATIN, val), numeric); fprintf(fd, "\n"); } else { /* choose between single entry line followed by exceptions, and long line followed by exceptions; avoid VoidSymbol */ int bad, count; bad = count = 0; for (j = 1; j < keymapnr; j++) { if (zapped[j]) continue; if (buf[j] != buf[0]) bad++; if (buf[j] != K_HOLE) count++; } if (bad <= count && bad < keymapnr - 1) { if (buf[0] != K_HOLE) { print_keysym(ctx, fd, buf[0], numeric); } fprintf(fd, "\n"); for (j = 1; j < keymapnr; j++) { if (lk_map_exists(ctx, j)) { if (buf[j] != buf[0] && !zapped[j]) { print_bind(ctx, fd, buf[j], i, j, numeric); } } } } else { for (j = 0; j < keymapnr && buf[j] != K_HOLE && (table != LK_SHAPE_UNTIL_HOLE || lk_map_exists(ctx, j)); j++) { //print_bind(ctx, fd, buf[j], i, j, numeric); print_keysym(ctx, fd, buf[j], numeric); } fprintf(fd, "\n"); for (; j < keymapnr; j++) { if (buf[j] != K_HOLE) { print_bind(ctx, fd, buf[j], i, j, numeric); } } } } } } void lk_dump_keymap(struct lk_ctx *ctx, FILE *fd, lk_table_shape table, char numeric) { lk_dump_keymaps(ctx, fd); lk_dump_keys(ctx, fd, table, numeric); lk_dump_funcs(ctx, fd); }