a2a2a7ffc25452d40ceb3bc7c6f5af872c131455
[platform/upstream/kbd.git] / src / libkeymap / loadkeys.c
1 #include <errno.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/ioctl.h>
5 #include <linux/kd.h>
6 #include <linux/keyboard.h>
7 #include <unistd.h>
8
9 #include "nls.h"
10 #include "kbd.h"
11 #include "keymap.h"
12 #include "ksyms.h"
13
14 static int
15 defkeys(struct lk_ctx *ctx, int fd, int kbd_mode)
16 {
17         struct kbentry ke;
18         int ct = 0;
19         int i, j, fail;
20
21         if (ctx->flags & LK_FLAG_UNICODE_MODE) {
22                 /* temporarily switch to K_UNICODE while defining keys */
23                 if (ioctl(fd, KDSKBMODE, K_UNICODE)) {
24                         ERR(ctx, _("KDSKBMODE: %s: could not switch to Unicode mode"),
25                                 strerror(errno));
26                         goto fail;
27                 }
28         }
29
30         for (i = 0; i < MAX_NR_KEYMAPS; i++) {
31                 unsigned int exist = lk_map_exists(ctx, i);
32
33                 if (exist) {
34                         for (j = 0; j < NR_KEYS; j++) {
35                                 if (!lk_key_exists(ctx, i, j))
36                                         continue;
37
38                                 ke.kb_index = j;
39                                 ke.kb_table = i;
40                                 ke.kb_value = lk_get_key(ctx, i, j);
41
42                                 fail = ioctl(fd, KDSKBENT, (unsigned long)&ke);
43
44                                 if (fail) {
45                                         if (errno == EPERM) {
46                                                 ERR(ctx, _("Keymap %d: Permission denied"), i);
47                                                 j = NR_KEYS;
48                                                 continue;
49                                         }
50                                         ERR(ctx, "%s", strerror(errno));
51                                 } else
52                                         ct++;
53
54                                 INFO(ctx, _("keycode %d, table %d = %d%s"),
55                                         j, i, lk_get_key(ctx,i, j), fail ? _("    FAILED") : "");
56
57                                 if (fail)
58                                         WARN(ctx, _("failed to bind key %d to value %d"),
59                                              j, lk_get_key(ctx, i, j));
60                         }
61
62                 } else if ((ctx->keywords & LK_KEYWORD_KEYMAPS) && !exist) {
63                         /* deallocate keymap */
64                         ke.kb_index = 0;
65                         ke.kb_table = i;
66                         ke.kb_value = K_NOSUCHMAP;
67
68                         DBG(ctx, _("deallocate keymap %d"), i);
69
70                         if (ioctl(fd, KDSKBENT, (unsigned long)&ke)) {
71                                 if (errno != EINVAL) {
72                                         ERR(ctx, _("KDSKBENT: %s: could not deallocate keymap %d"),
73                                                 strerror(errno), i);
74                                         goto fail;
75                                 }
76                                 /* probably an old kernel */
77                                 /* clear keymap by hand */
78                                 for (j = 0; j < NR_KEYS; j++) {
79                                         ke.kb_index = j;
80                                         ke.kb_table = i;
81                                         ke.kb_value = K_HOLE;
82
83                                         if (ioctl(fd, KDSKBENT, (unsigned long)&ke)) {
84                                                 if (errno == EINVAL && i >= 16)
85                                                         break;  /* old kernel */
86
87                                                 ERR(ctx, _("KDSKBENT: %s: cannot deallocate or clear keymap"),
88                                                         strerror(errno));
89                                                 goto fail;
90                                         }
91                                 }
92                         }
93                 }
94         }
95
96         if ((ctx->flags & LK_FLAG_UNICODE_MODE) && ioctl(fd, KDSKBMODE, kbd_mode)) {
97                 ERR(ctx, _("KDSKBMODE: %s: could not return to original keyboard mode"),
98                         strerror(errno));
99                 goto fail;
100         }
101
102         return ct;
103
104  fail:  return -1;
105 }
106
107
108 static char *
109 ostr(struct lk_ctx *ctx, char *s)
110 {
111         int lth = strlen(s);
112         char *ns0 = malloc(4 * lth + 1);
113         char *ns = ns0;
114
115         if (ns == NULL) {
116                 ERR(ctx, _("out of memory"));
117                 return NULL;
118         }
119
120         while (*s) {
121                 switch (*s) {
122                 case '\n':
123                         *ns++ = '\\';
124                         *ns++ = 'n';
125                         break;
126                 case '\033':
127                         *ns++ = '\\';
128                         *ns++ = '0';
129                         *ns++ = '3';
130                         *ns++ = '3';
131                         break;
132                 default:
133                         *ns++ = *s;
134                 }
135                 s++;
136         }
137         *ns = 0;
138         return ns0;
139 }
140
141 static int
142 deffuncs(struct lk_ctx *ctx, int fd)
143 {
144         int i, ct = 0;
145         char *ptr, *s;
146         struct kbsentry kbs;
147
148         for (i = 0; i < MAX_NR_FUNC; i++) {
149                 kbs.kb_func = i;
150
151                 ptr = lk_array_get_ptr(ctx->func_table, i);
152
153                 if (ptr) {
154                         strcpy((char *)kbs.kb_string, ptr);
155                         if (ioctl(fd, KDSKBSENT, (unsigned long)&kbs)) {
156                                 s = ostr(ctx, (char *)kbs.kb_string);
157                                 if (s == NULL)
158                                         return -1;
159                                 ERR(ctx, _("failed to bind string '%s' to function %s"),
160                                         s, syms[KT_FN].table[kbs.kb_func]);
161                                 free(s);
162                         } else {
163                                 ct++;
164                         }
165                 } else if (ctx->flags & LK_FLAG_CLEAR_STRINGS) {
166                         kbs.kb_string[0] = 0;
167
168                         if (ioctl(fd, KDSKBSENT, (unsigned long)&kbs)) {
169                                 ERR(ctx, _("failed to clear string %s"),
170                                         syms[KT_FN].table[kbs.kb_func]);
171                         } else {
172                                 ct++;
173                         }
174                 }
175         }
176         return ct;
177 }
178
179 static int
180 defdiacs(struct lk_ctx *ctx, int fd)
181 {
182         unsigned int i, count;
183         struct kb_diacr *ptr;
184
185         count = ctx->accent_table->count;
186         if (count > MAX_DIACR) {
187                 count = MAX_DIACR;
188                 ERR(ctx, _("too many compose definitions"));
189         }
190 #ifdef KDSKBDIACRUC
191         if (ctx->flags & LK_FLAG_PREFER_UNICODE) {
192                 struct kbdiacrsuc kdu;
193
194                 kdu.kb_cnt = count;
195
196                 for (i = 0; i < kdu.kb_cnt; i++) {
197                         ptr = lk_array_get_ptr(ctx->accent_table, i);
198                         if (!ptr) {
199                                 /* It can't be happen */
200                                 ERR(ctx, _("unable to get compose definitions"));
201                                 return -1;
202                         }
203
204                         kdu.kbdiacruc[i].diacr  = ptr->diacr;
205                         kdu.kbdiacruc[i].base   = ptr->base;
206                         kdu.kbdiacruc[i].result = ptr->result;
207                 }
208
209                 if (ioctl(fd, KDSKBDIACRUC, (unsigned long)&kdu)) {
210                         ERR(ctx, "KDSKBDIACRUC: %s", strerror(errno));
211                         return -1;
212                 }
213         } else
214 #endif
215         {
216                 struct kbdiacrs kd;
217
218                 kd.kb_cnt = count;
219
220                 for (i = 0; i < kd.kb_cnt; i++) {
221                         ptr = lk_array_get_ptr(ctx->accent_table, i);
222                         if (!ptr) {
223                                 ERR(ctx, _("unable to get compose definitions"));
224                                 return -1;
225                         }
226                         kd.kbdiacr[i].diacr  = ptr->diacr;
227                         kd.kbdiacr[i].base   = ptr->base;
228                         kd.kbdiacr[i].result = ptr->result;
229                 }
230
231                 if (ioctl(fd, KDSKBDIACR, (unsigned long)&kd)) {
232                         ERR(ctx, "KDSKBDIACR: %s", strerror(errno));
233                         return -1;
234                 }
235         }
236
237         return count;
238 }
239
240 int
241 lk_load_keymap(struct lk_ctx *ctx, int fd, int kbd_mode)
242 {
243         int keyct, funcct, diacct;
244
245         if (lk_add_constants(ctx) < 0)
246                 return -1;
247
248         if ((keyct = defkeys(ctx, fd, kbd_mode)) < 0 || (funcct = deffuncs(ctx, fd)) < 0)
249                 return -1;
250
251         INFO(ctx, _("\nChanged %d %s and %d %s"),
252                 keyct, (keyct == 1) ? _("key") : _("keys"),
253                 funcct, (funcct == 1) ? _("string") : _("strings"));
254
255         if (ctx->accent_table->count > 0 || ctx->flags & LK_FLAG_CLEAR_COMPOSE) {
256                 diacct = defdiacs(ctx, fd);
257
258                 if (diacct < 0)
259                         return -1;
260
261                 INFO(ctx, _("Loaded %d compose %s"),
262                         diacct, (diacct == 1) ? _("definition") : _("definitions"));
263
264         } else {
265                 INFO(ctx, _("(No change in compose definitions)"));
266         }
267
268         return 0;
269 }