blob: 23573f807707a30129dda39c048df8c3974226a3 [file]
/* loadkeys.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-2012 Alexey Gladkov <gladkov.alexey@gmail.com>
*
* This file is covered by the GNU General Public License,
* which should be included with kbd as the file COPYING.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#include <sysexits.h>
#include <sys/ioctl.h>
#include <keymap.h>
#include "libcommon.h"
#ifdef USE_XKB
#include "xkbsupport.h"
#endif
static const char *const dirpath1[] = {
DATADIR "/" KEYMAPDIR "/**",
KERNDIR "/",
NULL
};
static const char *const suffixes[] = {
"",
".kmap",
".map",
NULL
};
static void KBD_ATTR_NORETURN
usage(int rc, const struct kbd_help *options)
{
fprintf(stderr, _("Usage: %s [option...] [mapfile...]\n"),
program_invocation_short_name);
print_options(options);
fprintf(stderr, "\n");
fprintf(stderr, _("Default keymap: %s\n"), DEFMAP);
fprintf(stderr, _("Available shapes:\n"
" 2 - default output;\n"
" 4 - one line for each keycode;\n"
" 8 - one line for each (modifier,keycode) pair;\n"
" 16 - one line for each keycode until 1st hole.\n"
));
print_report_bugs();
exit(rc);
}
int main(int argc, char *argv[])
{
int options = 0;
lk_table_shape table_shape = LK_SHAPE_DEFAULT;
const char *const *dirpath;
const char *dirpath2[] = { NULL, NULL };
struct lk_ctx *ctx;
lk_flags flags = 0;
int c, i, rc = -1;
int fd = -1;
int kbd_mode;
int kd_mode;
char *console = NULL;
char *ev;
struct kbdfile_ctx *fctx;
struct kbdfile *fp = NULL;
#ifdef USE_XKB
struct xkeymap_params xkeymap_params = {
.model = "pc104",
.layout = NULL,
.variant = NULL,
.options = NULL,
.locale = NULL,
};
int use_xkb = 0;
#endif
setuplocale();
const char *const short_opts = "abcC:dhmpst::uqvV";
const struct option long_opts[] = {
{ "console", required_argument, NULL, 'C' },
{ "ascii", no_argument, NULL, 'a' },
{ "bkeymap", no_argument, NULL, 'b' },
{ "clearcompose", no_argument, NULL, 'c' },
{ "default", no_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "mktable", no_argument, NULL, 'm' },
{ "parse", no_argument, NULL, 'p' },
{ "clearstrings", no_argument, NULL, 's' },
{ "tkeymap", optional_argument, NULL, 't' },
{ "unicode", no_argument, NULL, 'u' },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
#ifdef USE_XKB
//{ "xkb-rules", required_argument, NULL, 1 },
{ "xkb-model", required_argument, NULL, 2 },
{ "xkb-layout", required_argument, NULL, 3 },
{ "xkb-variant", required_argument, NULL, 4 },
{ "xkb-options", required_argument, NULL, 5 },
{ "xkb-locale", required_argument, NULL, 6 },
#endif
{ NULL, 0, NULL, 0 }
};
const struct kbd_help opthelp[] = {
#ifdef USE_XKB
{ "--xkb-model=STR", _("Specifies model used to choose component names.") },
{ "--xkb-layout=STR", _("Specifies layout used to choose component names.") },
{ "--xkb-variant=STR", _("Specifies layout variant used to choose component names.") },
{ "--xkb-options=STR", _("Adds an option used to choose component names.") },
{ "--xkb-locale=LOCALE", _("Use LOCALE to search an appropriate compose file.") },
#endif
{ "-C, --console=DEV", _("the console device to be used.") },
{ "-a, --ascii", _("force conversion to ASCII.") },
{ "-b, --bkeymap", _("output a binary keymap to stdout.") },
{ "-c, --clearcompose", _("clear kernel compose table.") },
{ "-d, --default", _("load default.") },
{ "-m, --mktable", _("output a 'defkeymap.c' to stdout.") },
{ "-p, --parse", _("search and parse keymap without action.") },
{ "-s, --clearstrings", _("clear kernel string table.") },
{ "-u, --unicode", _("force conversion to Unicode.") },
{ "-q, --quiet", _("suppress all normal output.") },
{ "-t, --tkeymap[=SHAPE]", _("output a text keymap to stdout.") },
{ "-v, --verbose", _("be more verbose.") },
{ "-V, --version", _("print version number.") },
{ "-h, --help", _("print this usage message.") },
{ NULL, NULL }
};
enum options {
OPT_A = (1 << 1),
OPT_B = (1 << 2),
OPT_D = (1 << 3),
OPT_M = (1 << 4),
OPT_U = (1 << 5),
OPT_P = (1 << 6),
OPT_T = (1 << 7)
};
ctx = lk_init();
if (!ctx) {
exit(EXIT_FAILURE);
}
if (!(fctx = kbdfile_context_new()))
kbd_error(EXIT_FAILURE, errno, _("Unable to create kbdfile context"));
while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (c) {
#ifdef USE_XKB
case 2:
xkeymap_params.model = optarg;
use_xkb = 1;
break;
case 3:
xkeymap_params.layout = optarg;
use_xkb = 1;
break;
case 4:
xkeymap_params.variant = optarg;
use_xkb = 1;
break;
case 5:
xkeymap_params.options = optarg;
use_xkb = 1;
break;
case 6:
xkeymap_params.locale = optarg;
use_xkb = 1;
break;
#endif
case 'a':
options |= OPT_A;
break;
case 'b':
options |= OPT_B;
break;
case 'c':
flags |= LK_FLAG_CLEAR_COMPOSE;
break;
case 'C':
console = optarg;
break;
case 'd':
options |= OPT_D;
break;
case 'm':
options |= OPT_M;
break;
case 'p':
options |= OPT_P;
break;
case 's':
flags |= LK_FLAG_CLEAR_STRINGS;
break;
case 'u':
options |= OPT_U;
flags |= LK_FLAG_UNICODE_MODE;
flags |= LK_FLAG_PREFER_UNICODE;
break;
case 'q':
lk_set_log_priority(ctx, LOG_ERR);
break;
case 't':
options |= OPT_T;
if (optarg) {
table_shape = atoi(optarg);
}
break;
case 'v':
lk_set_log_priority(ctx, LOG_INFO);
break;
case 'V':
print_version_and_exit();
break;
case 'h':
usage(EXIT_SUCCESS, opthelp);
break;
case '?':
usage(EX_USAGE, opthelp);
break;
}
}
if ((options & OPT_U) && (options & OPT_A))
kbd_error(EXIT_FAILURE, 0, _("Options %s and %s are mutually exclusive."),
"--unicode", "--ascii");
if (!(options & OPT_M) && !(options & OPT_B) && !(options & OPT_T)) {
/* get console */
if ((fd = getfd(console)) < 0)
kbd_error(EXIT_FAILURE, 0, _("Couldn't get a file descriptor referring to the console."));
/* check whether the keyboard is in Unicode mode */
if (ioctl(fd, KDGKBMODE, &kbd_mode))
kbd_error(EXIT_FAILURE, errno, _("Unable to read keyboard mode"));
if (ioctl(fd, KDGETMODE, &kd_mode))
kbd_error(EXIT_FAILURE, errno, _("Unable to read console mode"));
if (kbd_mode == K_UNICODE) {
if (options & OPT_A) {
kbd_warning(0,
_("Warning: loading non-Unicode keymap on Unicode console\n"
" (perhaps you want to do `kbd_mode -a'?)"));
} else {
flags |= LK_FLAG_PREFER_UNICODE;
}
/* reset -u option if keyboard is in K_UNICODE anyway */
flags ^= LK_FLAG_UNICODE_MODE;
} else if (options & OPT_U && kd_mode != KD_GRAPHICS) {
kbd_warning(0,
_("Warning: loading Unicode keymap on non-Unicode console\n"
" (perhaps you want to do `kbd_mode -u'?)"));
}
}
lk_set_parser_flags(ctx, flags);
dirpath = dirpath1;
if ((ev = getenv("LOADKEYS_KEYMAP_PATH")) != NULL) {
dirpath2[0] = ev;
dirpath = dirpath2;
}
if (options & OPT_D) {
if (!(fp = kbdfile_new(fctx)))
kbd_error(EXIT_FAILURE, 0, _("Unable to create kbdfile instance: %m"));
/* first read default map - search starts in . */
if (kbdfile_find(DEFMAP, dirpath, suffixes, fp))
kbd_error(EXIT_FAILURE, 0, _("Unable to find file: %s"), DEFMAP);
rc = lk_parse_keymap(ctx, fp);
kbdfile_free(fp);
if (rc == -1)
goto fail;
#ifdef USE_XKB
} else if (use_xkb) {
if (!xkeymap_params.locale || !*xkeymap_params.locale)
xkeymap_params.locale = getenv("LC_ALL");
if (!xkeymap_params.locale || !*xkeymap_params.locale)
xkeymap_params.locale = getenv("LC_CTYPE");
if (!xkeymap_params.locale || !*xkeymap_params.locale)
xkeymap_params.locale = getenv("LANG");
if (!xkeymap_params.locale || !*xkeymap_params.locale)
xkeymap_params.locale = "C";
rc = convert_xkb_keymap(ctx, &xkeymap_params);
if (rc == -1)
goto fail;
#endif
} else if (optind == argc) {
if (!(fp = kbdfile_new(fctx)))
kbd_error(EXIT_FAILURE, 0, _("Unable to create kbdfile instance: %m"));
kbdfile_set_file(fp, stdin);
kbdfile_set_pathname(fp, "<stdin>");
rc = lk_parse_keymap(ctx, fp);
kbdfile_free(fp);
if (rc == -1)
goto fail;
}
for (i = optind; argv[i]; i++) {
if (!(fp = kbdfile_new(fctx))) {
kbd_error(EXIT_FAILURE, 0, _("Unable to create kbdfile instance: %m"));
}
if (!strcmp(argv[i], "-")) {
kbdfile_set_file(fp, stdin);
kbdfile_set_pathname(fp, "<stdin>");
} else if (kbdfile_find(argv[i], dirpath, suffixes, fp)) {
kbd_warning(0, _("Unable to open file: %s: %m"), argv[i]);
goto fail;
}
rc = lk_parse_keymap(ctx, fp);
kbdfile_free(fp);
if (rc == -1)
goto fail;
}
if (!(options & OPT_P)) {
if (options & OPT_B) {
rc = lk_dump_bkeymap(ctx, stdout);
} else if (options & OPT_M) {
rc = lk_dump_ctable(ctx, stdout);
} else if (options & OPT_T) {
rc = lk_dump_keymap2(ctx, stdout, table_shape, 0);
if (rc < 0)
goto fail;
#ifdef KDGKBDIACR
lk_dump_diacs(ctx, stdout);
#endif
rc = 0;
} else {
rc = lk_load_keymap(ctx, fd, kbd_mode);
}
}
else if (getenv("LK_DUMPKEYS")) {
lk_dump_keymap(ctx, stdout, LK_SHAPE_SEPARATE_LINES, 0);
lk_dump_diacs(ctx, stdout);
}
fail:
lk_free(ctx);
kbdfile_context_free(fctx);
if (fd >= 0)
close(fd);
if (rc < 0)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}