| /* 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 <sys/ioctl.h> |
| |
| #include "nls.h" |
| #include "kbd.h" |
| #include "paths.h" |
| #include "getfd.h" |
| #include "kbd_error.h" |
| |
| #include "keymap.h" |
| |
| static const char *progname = NULL; |
| static const char *const dirpath1[] = { "", DATADIR "/" KEYMAPDIR "/**", KERNDIR "/", 0 }; |
| static const char *const suffixes[] = { "", ".kmap", ".map", 0 }; |
| |
| static void __attribute__((noreturn)) |
| usage(void) |
| { |
| fprintf(stderr, _("loadkeys version %s\n" |
| "\n" |
| "Usage: %s [option...] [mapfile...]\n" |
| "\n" |
| "Valid options are:\n" |
| "\n" |
| " -a --ascii force conversion to ASCII\n" |
| " -b --bkeymap output a binary keymap to stdout\n" |
| " -c --clearcompose clear kernel compose table\n" |
| " -C --console=file\n" |
| " the console device to be used\n" |
| " -d --default load \"%s\"\n" |
| " -h --help display this help text\n" |
| " -m --mktable output a \"defkeymap.c\" to stdout\n" |
| " -p --parse search and parse keymap without action\n" |
| " -q --quiet suppress all normal output\n" |
| " -s --clearstrings clear kernel string table\n" |
| " -u --unicode force conversion to Unicode\n" |
| " -v --verbose report the changes\n" |
| " -V --version print version number\n"), |
| PACKAGE_VERSION, progname, DEFMAP); |
| exit(EXIT_FAILURE); |
| } |
| |
| static inline const char * |
| set_progname(const char *name) |
| { |
| char *p; |
| p = strrchr(name, '/'); |
| return (p && p + 1 ? p + 1 : name); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| const char *const short_opts = "abcC:dhmpsuqvV"; |
| const struct option const 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' }, |
| { "unicode", no_argument, NULL, 'u' }, |
| { "quiet", no_argument, NULL, 'q' }, |
| { "verbose", no_argument, NULL, 'v' }, |
| { "version", no_argument, NULL, 'V' }, |
| { NULL, 0, NULL, 0 } |
| }; |
| |
| 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) |
| }; |
| int options = 0; |
| |
| const char *const *dirpath; |
| const char *dirpath2[] = { 0, 0 }; |
| |
| 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; |
| lkfile_t f; |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE_NAME, LOCALEDIR); |
| textdomain(PACKAGE_NAME); |
| |
| progname = set_progname(argv[0]); |
| |
| ctx = lk_init(); |
| if (!ctx) { |
| exit(EXIT_FAILURE); |
| } |
| |
| while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { |
| switch (c) { |
| 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 'v': |
| lk_set_log_priority(ctx, LOG_INFO); |
| break; |
| case 'V': |
| fprintf(stdout, _("%s from %s\n"), progname, PACKAGE_STRING); |
| exit(0); |
| case 'h': |
| case '?': |
| usage(); |
| } |
| } |
| |
| if ((options & OPT_U) && (options & OPT_A)) { |
| fprintf(stderr, |
| _("%s: Options --unicode and --ascii are mutually exclusive\n"), |
| progname); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (!(options & OPT_M) && !(options & OPT_B)) { |
| /* 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) || |
| ioctl(fd, KDGETMODE, &kd_mode)) { |
| fprintf(stderr, _("%s: error reading keyboard mode: %m\n"), |
| progname); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (kbd_mode == K_UNICODE) { |
| if (options & OPT_A) { |
| fprintf(stderr, |
| _("%s: warning: loading non-Unicode keymap on Unicode console\n" |
| " (perhaps you want to do `kbd_mode -a'?)\n"), |
| progname); |
| } 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) { |
| fprintf(stderr, |
| _("%s: warning: loading Unicode keymap on non-Unicode console\n" |
| " (perhaps you want to do `kbd_mode -u'?)\n"), |
| progname); |
| } |
| } |
| |
| lk_set_parser_flags(ctx, flags); |
| |
| dirpath = dirpath1; |
| if ((ev = getenv("LOADKEYS_KEYMAP_PATH")) != NULL) { |
| dirpath2[0] = ev; |
| dirpath = dirpath2; |
| } |
| |
| if (options & OPT_D) { |
| /* first read default map - search starts in . */ |
| |
| if (lk_findfile(DEFMAP, dirpath, suffixes, &f)) { |
| fprintf(stderr, _("Cannot find %s\n"), DEFMAP); |
| exit(EXIT_FAILURE); |
| } |
| |
| if ((rc = lk_parse_keymap(ctx, &f)) == -1) |
| goto fail; |
| |
| } else if (optind == argc) { |
| f.fd = stdin; |
| strcpy(f.pathname, "<stdin>"); |
| |
| if ((rc = lk_parse_keymap(ctx, &f)) == -1) |
| goto fail; |
| } |
| |
| for (i = optind; argv[i]; i++) { |
| if (!strcmp(argv[i], "-")) { |
| f.fd = stdin; |
| strcpy(f.pathname, "<stdin>"); |
| |
| } else if (lk_findfile(argv[i], dirpath, suffixes, &f)) { |
| fprintf(stderr, _("cannot open file %s\n"), argv[i]); |
| goto fail; |
| } |
| |
| if ((rc = lk_parse_keymap(ctx, &f)) == -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 { |
| rc = lk_load_keymap(ctx, fd, kbd_mode); |
| } |
| } |
| |
| fail: |
| lk_free(ctx); |
| lk_fpclose(&f); |
| |
| if (fd >= 0) |
| close(fd); |
| |
| if (rc < 0) |
| exit(EXIT_FAILURE); |
| |
| exit(EXIT_SUCCESS); |
| } |