8a247ba0e11fd837d1b5ef909b2f9959fa297d9d
[platform/upstream/kbd.git] / src / loadkeys.c
1 /* loadkeys.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-2012  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
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <getopt.h>
17 #include <unistd.h>
18 #include <sys/ioctl.h>
19
20 #include "../config.h"
21 #include "nls.h"
22 #include "kbd.h"
23 #include "paths.h"
24 #include "getfd.h"
25
26 #include "keymap.h"
27
28 static const char *progname = NULL;
29 static const char *const dirpath1[] = { "", DATADIR "/" KEYMAPDIR "/**", KERNDIR "/", 0 };
30 static const char *const suffixes[] = { "", ".kmap", ".map", 0 };
31
32 static void __attribute__ ((noreturn))
33 usage(void)
34 {
35         fprintf(stderr, _("loadkeys version %s\n"
36                           "\n"
37                           "Usage: %s [option...] [mapfile...]\n"
38                           "\n"
39                           "Valid options are:\n"
40                           "\n"
41                           "  -a --ascii         force conversion to ASCII\n"
42                           "  -b --bkeymap       output a binary keymap to stdout\n"
43                           "  -c --clearcompose  clear kernel compose table\n"
44                           "  -C --console=file\n"
45                           "                     the console device to be used\n"
46                           "  -d --default       load \"%s\"\n"
47                           "  -h --help          display this help text\n"
48                           "  -m --mktable       output a \"defkeymap.c\" to stdout\n"
49                           "  -q --quiet         suppress all normal output\n"
50                           "  -s --clearstrings  clear kernel string table\n"
51                           "  -u --unicode       force conversion to Unicode\n"
52                           "  -v --verbose       report the changes\n"),
53                 PACKAGE_VERSION, progname, DEFMAP);
54         exit(EXIT_FAILURE);
55 }
56
57 static inline const char *
58 set_progname(const char *name)
59 {
60         char *p;
61         p = strrchr(name, '/');
62         return (p && p + 1 ? p + 1 : name);
63 }
64
65 int
66 main(int argc, char *argv[])
67 {
68         const char *const short_opts = "abcC:dhmsuqvV";
69         const struct option const long_opts[] = {
70                 { "console", required_argument, NULL, 'C'},
71                 { "ascii",              no_argument, NULL, 'a' },
72                 { "bkeymap",            no_argument, NULL, 'b' },
73                 { "clearcompose",       no_argument, NULL, 'c' },
74                 { "default",            no_argument, NULL, 'd' },
75                 { "help",               no_argument, NULL, 'h' },
76                 { "mktable",            no_argument, NULL, 'm' },
77                 { "clearstrings",       no_argument, NULL, 's' },
78                 { "unicode",            no_argument, NULL, 'u' },
79                 { "quiet",              no_argument, NULL, 'q' },
80                 { "verbose",            no_argument, NULL, 'v' },
81                 { "version",            no_argument, NULL, 'V' },
82                 { NULL, 0, NULL, 0 }
83         };
84
85         enum options {
86                 OPT_A = (1 << 1),
87                 OPT_B = (1 << 2),
88                 OPT_D = (1 << 3),
89                 OPT_M = (1 << 4),
90                 OPT_U = (1 << 5)
91         };
92         int options = 0;
93
94         const char *const *dirpath;
95         const char *dirpath2[] = { 0, 0 };
96
97         struct lk_ctx ctx;
98         lk_flags flags = 0;
99
100         int c, i, rc = -1;
101         int fd;
102         int kbd_mode;
103         int kd_mode;
104         char *console = NULL;
105         char *ev;
106         lkfile_t f;
107
108         setlocale(LC_ALL, "");
109         bindtextdomain(PACKAGE_NAME, LOCALEDIR);
110         textdomain(PACKAGE_NAME);
111
112         progname = set_progname(argv[0]);
113
114         lk_init(&ctx);
115
116         while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
117                 switch (c) {
118                 case 'a':
119                         options |= OPT_A;
120                         break;
121                 case 'b':
122                         options |= OPT_B;
123                         break;
124                 case 'c':
125                         ctx.flags |= LK_FLAG_CLEAR_COMPOSE;
126                         break;
127                 case 'C':
128                         console = optarg;
129                         break;
130                 case 'd':
131                         options |= OPT_D;
132                         break;
133                 case 'm':
134                         options |= OPT_M;
135                         break;
136                 case 's':
137                         flags |= LK_FLAG_CLEAR_STRINGS;
138                         break;
139                 case 'u':
140                         options |= OPT_U;
141                         flags |= LK_FLAG_UNICODE_MODE;
142                         flags |= LK_FLAG_PREFER_UNICODE;
143                         break;
144                 case 'q':
145                         lk_set_log_priority(&ctx, LOG_ERR);
146                         break;
147                 case 'v':
148                         lk_set_log_priority(&ctx, LOG_INFO);
149                         break;
150                 case 'V':
151                         fprintf(stdout, _("%s from %s\n"), progname, PACKAGE_STRING);
152                         exit(0);
153                 case 'h':
154                 case '?':
155                         usage();
156                 }
157         }
158
159         if ((options & OPT_U) && (options & OPT_A)) {
160                 fprintf(stderr,
161                         _("%s: Options --unicode and --ascii are mutually exclusive\n"),
162                         progname);
163                 exit(EXIT_FAILURE);
164         }
165
166         /* get console */
167         fd = getfd(console);
168
169         if (!(options & OPT_M) && !(options & OPT_B)) {
170                 /* check whether the keyboard is in Unicode mode */
171                 if (ioctl(fd, KDGKBMODE, &kbd_mode) ||
172                     ioctl(fd, KDGETMODE, &kd_mode)) {
173                         fprintf(stderr, _("%s: error reading keyboard mode: %m\n"),
174                                 progname);
175                         exit(EXIT_FAILURE);
176                 }
177
178                 if (kbd_mode == K_UNICODE) {
179                         if (options & OPT_A) {
180                                 fprintf(stderr,
181                                         _("%s: warning: loading non-Unicode keymap on Unicode console\n"
182                                           "    (perhaps you want to do `kbd_mode -a'?)\n"),
183                                         progname);
184                         } else {
185                                 flags |= LK_FLAG_PREFER_UNICODE;
186                         }
187
188                         /* reset -u option if keyboard is in K_UNICODE anyway */
189                         flags ^= LK_FLAG_UNICODE_MODE;
190
191                 } else if (options & OPT_U && kd_mode != KD_GRAPHICS) {
192                         fprintf(stderr,
193                                 _("%s: warning: loading Unicode keymap on non-Unicode console\n"
194                                   "    (perhaps you want to do `kbd_mode -u'?)\n"),
195                                 progname);
196                 }
197         }
198
199         lk_set_parser_flags(&ctx, flags);
200
201         dirpath = dirpath1;
202         if ((ev = getenv("LOADKEYS_KEYMAP_PATH")) != NULL) {
203                 dirpath2[0] = ev;
204                 dirpath = dirpath2;
205         }
206
207         if (options & OPT_D) {
208                 /* first read default map - search starts in . */
209
210                 if (lk_findfile(DEFMAP, dirpath, suffixes, &f)) {
211                         fprintf(stderr, _("Cannot find %s\n"), DEFMAP);
212                         exit(EXIT_FAILURE);
213                 }
214
215                 if ((rc = lk_parse_keymap(&ctx, &f)) == -1)
216                         goto fail;
217
218
219         } else if (optind == argc) {
220                 f.fd = stdin;
221                 strcpy(f.pathname, "<stdin>");
222
223                 if ((rc = lk_parse_keymap(&ctx, &f)) == -1)
224                         goto fail;
225         }
226
227         for (i = optind; argv[i]; i++) {
228                 if (!strcmp(argv[i], "-")) {
229                         f.fd = stdin;
230                         strcpy(f.pathname, "<stdin>");
231
232                 } else if (lk_findfile(argv[i], dirpath, suffixes, &f)) {
233                         fprintf(stderr, _("cannot open file %s\n"), argv[i]);
234                         goto fail;
235                 }
236
237                 if ((rc = lk_parse_keymap(&ctx, &f)) == -1)
238                         goto fail;
239         }
240
241         if (options & OPT_B) {
242                 rc = lk_dump_bkeymap(&ctx, stdout);
243         } else if (options & OPT_M) {
244                 rc = lk_dump_ctable(&ctx, stdout);
245         } else {
246                 rc = lk_load_keymap(&ctx, fd, kbd_mode);
247         }
248
249  fail:  lk_free(&ctx);
250         lk_fpclose(&f);
251         close(fd);
252
253         if (rc < 0)
254                 exit(EXIT_FAILURE);
255
256         exit(EXIT_SUCCESS);
257 }