Add information about the total number of elements
[platform/upstream/kbd.git] / src / libkeymap / kmap.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "nls.h"
5 #include "kbd.h"
6
7 #include "keymap.h"
8
9 #include "contextP.h"
10 #include "ksyms.h"
11 #include "modifiers.h"
12
13 int
14 lk_map_exists(struct lk_ctx *ctx, unsigned int k_table)
15 {
16         return (lk_array_get_ptr(ctx->keymap, k_table) != NULL);
17 }
18
19 int
20 lk_get_keys_total(struct lk_ctx *ctx, unsigned int k_table)
21 {
22         struct lk_array *map;
23         map = lk_array_get_ptr(ctx->keymap, k_table);
24         if (!map) {
25                 return 0;
26         }
27         return map->total;
28 }
29
30 int
31 lk_key_exists(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
32 {
33         struct lk_array *map;
34         unsigned int *key;
35
36         map = lk_array_get_ptr(ctx->keymap, k_table);
37         if (!map) {
38                 return 0;
39         }
40
41         key = lk_array_get(map, k_index);
42         if (!key) {
43                 return 0;
44         }
45
46         return (*key > 0);
47 }
48
49 int
50 lk_add_map(struct lk_ctx *ctx, unsigned int k_table)
51 {
52         struct lk_array *keys;
53
54         if (lk_map_exists(ctx, k_table)) {
55                 return 0;
56         }
57
58         keys = malloc(sizeof(struct lk_array));
59         if (!keys) {
60                 ERR(ctx, _("out of memory"));
61                 return -1;
62         }
63
64         lk_array_init(keys, sizeof(unsigned int), 0);
65
66         if (lk_array_set(ctx->keymap, k_table, &keys) < 0) {
67                 free(keys);
68                 ERR(ctx, _("out of memory"));
69                 return -1;
70         }
71
72         return 0;
73 }
74
75 int
76 lk_get_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
77 {
78         struct lk_array *map;
79         unsigned int *key;
80
81         map = lk_array_get_ptr(ctx->keymap, k_table);
82         if (!map) {
83                 ERR(ctx, _("unable to get keymap %d"), k_table);
84                 return -1;
85         }
86
87         key = lk_array_get(map, k_index);
88         if (!key || *key == 0) {
89                 return K_HOLE;
90         }
91
92         return (*key)-1;
93 }
94
95 int
96 lk_del_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index)
97 {
98         struct lk_array *map;
99
100         map = lk_array_get_ptr(ctx->keymap, k_table);
101         if (!map) {
102                 ERR(ctx, _("unable to get keymap %d"), k_table);
103                 return -1;
104         }
105
106         if (!lk_array_exists(map, k_index))
107                 return 0;
108
109         if (lk_array_unset(map, k_index) < 0) {
110                 ERR(ctx, _("unable to unset key %d for table %d"),
111                         k_index, k_table);
112                 return -1;
113         }
114
115         return 0;
116 }
117
118 int
119 lk_add_key(struct lk_ctx *ctx, unsigned int k_table, unsigned int k_index, int keycode)
120 {
121         struct lk_array *map;
122         unsigned int code = keycode + 1;
123
124         if (keycode == CODE_FOR_UNKNOWN_KSYM) {
125                 /* is safer not to be silent in this case, 
126                  * it can be caused by coding errors as well. */
127                 ERR(ctx, _("lk_add_key called with bad keycode %d"), keycode);
128                 return -1;
129         }
130
131         if (!k_index && keycode == K_NOSUCHMAP)
132                 return 0;
133
134         map = lk_array_get_ptr(ctx->keymap, k_table);
135         if (!map) {
136                 if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
137                         ERR(ctx, _("adding map %d violates explicit keymaps line"),
138                             k_table);
139                         return -1;
140                 }
141
142                 if (lk_add_map(ctx, k_table) < 0)
143                         return -1;
144         }
145
146         if ((ctx->keywords & LK_KEYWORD_ALTISMETA) && keycode == K_HOLE &&
147             lk_key_exists(ctx, k_table, k_index))
148                 return 0;
149
150         map = lk_array_get_ptr(ctx->keymap, k_table);
151
152         if (lk_array_set(map, k_index, &code) < 0) {
153                 ERR(ctx, _("unable to set key %d for table %d"),
154                         k_index, k_table);
155                 return -1;
156         }
157
158         if (ctx->keywords & LK_KEYWORD_ALTISMETA) {
159                 unsigned int alttable = k_table | M_ALT;
160                 int type = KTYP(keycode);
161                 int val = KVAL(keycode);
162
163                 if (alttable != k_table && lk_map_exists(ctx, alttable) &&
164                     !lk_key_exists(ctx, alttable, k_index) &&
165                     (type == KT_LATIN || type == KT_LETTER) &&
166                     val < 128) {
167                         if (lk_add_key(ctx, alttable, k_index, K(KT_META, val)) < 0)
168                                 return -1;
169                 }
170         }
171
172         return 0;
173 }
174
175 int
176 lk_get_func(struct lk_ctx *ctx, struct kbsentry *kbs)
177 {
178         char *s;
179
180         s = lk_array_get_ptr(ctx->func_table, kbs->kb_func);
181         if (!s) {
182                 ERR(ctx, _("func %d not allocated"), kbs->kb_func);
183                 return -1;
184         }
185
186         strncpy((char *)kbs->kb_string, s, sizeof(kbs->kb_string));
187         kbs->kb_string[sizeof(kbs->kb_string) - 1] = 0;
188
189         return 0;
190 }
191
192
193 int
194 lk_add_func(struct lk_ctx *ctx, struct kbsentry kbs)
195 {
196         char *s;
197
198         s = lk_array_get_ptr(ctx->func_table, kbs.kb_func);
199         if (s)
200                 free(s);
201
202         s = strdup((char *)kbs.kb_string);
203
204         if (lk_array_set(ctx->func_table, kbs.kb_func, &s) < 0) {
205                 free(s);
206                 ERR(ctx, _("out of memory"));
207                 return -1;
208         }
209
210         return 0;
211 }
212
213 int
214 lk_add_diacr(struct lk_ctx *ctx, unsigned int diacr, unsigned int base, unsigned int res)
215 {
216         struct kb_diacr *ptr;
217
218         ptr = malloc(sizeof(struct kb_diacr));
219         if (!ptr) {
220                 ERR(ctx, _("out of memory"));
221                 return -1;
222         }
223
224         ptr->diacr  = diacr;
225         ptr->base   = base;
226         ptr->result = res;
227
228         lk_array_append(ctx->accent_table, &ptr);
229
230         return 0;
231 }
232
233 int
234 lk_add_compose(struct lk_ctx *ctx,
235                unsigned int diacr,
236                unsigned int base,
237                unsigned int res)
238 {
239         int direction = TO_8BIT;
240
241 #ifdef KDSKBDIACRUC
242         if (ctx->flags & LK_FLAG_PREFER_UNICODE)
243                 direction = TO_UNICODE;
244 #endif
245         return lk_add_diacr(ctx,
246                 convert_code(ctx, diacr, direction),
247                 convert_code(ctx, base, direction),
248                 convert_code(ctx, res, direction)
249         );
250 }
251
252 static int
253 do_constant_key(struct lk_ctx *ctx, int i, u_short key)
254 {
255         int typ, val;
256         unsigned int j;
257
258         typ = KTYP(key);
259         val = KVAL(key);
260
261         if ((typ == KT_LATIN || typ == KT_LETTER) &&
262             ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'))) {
263                 u_short defs[16];
264                 defs[0] = K(KT_LETTER, val);
265                 defs[1] = K(KT_LETTER, val ^ 32);
266                 defs[2] = defs[0];
267                 defs[3] = defs[1];
268
269                 for (j = 4; j < 8; j++)
270                         defs[j] = K(KT_LATIN, val & ~96);
271
272                 for (j = 8; j < 16; j++)
273                         defs[j] = K(KT_META, KVAL(defs[j - 8]));
274
275                 for (j = 0; j < ctx->keymap->total; j++) {
276                         if (!lk_map_exists(ctx, j))
277                                 continue;
278
279                         if (j > 0 && lk_key_exists(ctx, j, i))
280                                 continue;
281
282                         if (lk_add_key(ctx, j, i, defs[j % 16]) < 0)
283                                 return -1;
284                 }
285
286         } else {
287                 /* do this also for keys like Escape,
288                    as promised in the man page */
289                 for (j = 1; j < ctx->keymap->total; j++) {
290                         if (!lk_map_exists(ctx, j))
291                                 continue;
292
293                         if (lk_key_exists(ctx, j, i))
294                                 continue;
295
296                         if (lk_add_key(ctx, j, i, key) < 0)
297                                 return -1;
298                 }
299         }
300         return 0;
301 }
302
303 int
304 lk_add_constants(struct lk_ctx *ctx)
305 {
306         unsigned int i, r0 = 0;
307
308         if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
309                 while (r0 < ctx->keymap->total && !lk_map_exists(ctx, r0))
310                         r0++;
311         }
312
313         for (i = 0; i < ctx->key_constant->total; i++) {
314                 char *constant;
315                 u_short key;
316
317                 constant = lk_array_get(ctx->key_constant, i);
318                 if (!constant || !(*constant))
319                         continue;
320
321                 if (!lk_map_exists(ctx, r0)) {
322                         ERR(ctx, _("impossible error in lk_add_constants"));
323                         return -1;
324                 }
325
326                 key = lk_get_key(ctx, r0, i);
327
328                 if (do_constant_key(ctx, i, key) < 0)
329                         return -1;
330         }
331         return 0;
332 }