Add lk_get_charset function
[platform/upstream/kbd.git] / src / libkeymap / ksyms.c
1 #include <linux/keyboard.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "ksyms.h"
6 #include "nls.h"
7
8 #include "keymap.h"
9
10 #include "syms.cp1250.h"
11 #include "syms.ethiopic.h"
12 #include "syms.iso8859_15.h"
13 #include "syms.iso8859_5.h"
14 #include "syms.iso8859_7.h"
15 #include "syms.iso8859_8.h"
16 #include "syms.iso8859_9.h"
17 #include "syms.koi8.h"
18 #include "syms.latin1.h"
19 #include "syms.latin2.h"
20 #include "syms.latin3.h"
21 #include "syms.latin4.h"
22 #include "syms.mazovia.h"
23 #include "syms.sami.h"
24 #include "syms.thai.h"
25
26 #include "syms.synonyms.h"
27
28 #include "syms.ktyp.h"
29
30 #define E(x) { x, sizeof(x) / sizeof(x[0]) }
31
32 const syms_entry
33 syms[] = {
34         E(iso646_syms),         /* KT_LATIN */
35         E(fn_syms),             /* KT_FN */
36         E(spec_syms),           /* KT_SPEC */
37         E(pad_syms),            /* KT_PAD */
38         E(dead_syms),           /* KT_DEAD */
39         E(cons_syms),           /* KT_CONS */
40         E(cur_syms),            /* KT_CUR */
41         E(shift_syms),          /* KT_SHIFT */
42         { 0, 0 },               /* KT_META */
43         E(ascii_syms),          /* KT_ASCII */
44         E(lock_syms),           /* KT_LOCK */
45         { 0, 0 },               /* KT_LETTER */
46         E(sticky_syms),         /* KT_SLOCK */
47         { 0, 0 },               /*  */
48         E(brl_syms)             /* KT_BRL */
49 };
50
51 #undef E
52
53 const unsigned int syms_size = sizeof(syms) / sizeof(syms_entry);
54 const unsigned int syn_size = sizeof(synonyms) / sizeof(synonyms[0]);
55
56 const struct cs {
57         const char *charset;
58         const sym *charnames;
59         const int start;
60 } charsets[] = {
61         { "",             NULL,                0 },
62         { "iso-8859-1",   latin1_syms,       160 },
63         { "iso-8859-2",   latin2_syms,       160 },
64         { "iso-8859-3",   latin3_syms,       160 },
65         { "iso-8859-4",   latin4_syms,       160 },
66         { "iso-8859-5",   iso_8859_5_syms,   160 },
67         { "iso-8859-7",   iso_8859_7_syms,   160 },
68         { "iso-8859-8",   iso_8859_8_syms,   160 },
69         { "iso-8859-9",   iso_8859_9_syms,   208 },
70         { "iso-8859-10",  latin6_syms,       160 },
71         { "iso-8859-15",  iso_8859_15_syms,  160 },
72         { "mazovia",      mazovia_syms,      128 },
73         { "cp-1250",      cp1250_syms,       128 },
74         { "koi8-r",       koi8_syms,         128 },
75         { "koi8-u",       koi8_syms,         128 },
76         { "tis-620",      tis_620_syms,      160 }, /* thai */
77         { "iso-10646-18", iso_10646_18_syms, 159 }, /* ethiopic */
78         { "iso-ir-197",   iso_ir_197_syms,   160 }, /* sami */
79         { "iso-ir-209",   iso_ir_209_syms,   160 }, /* sami */
80 };
81
82 static unsigned int charsets_size = sizeof(charsets) / sizeof(charsets[0]);
83
84 /* Functions for both dumpkeys and loadkeys. */
85
86 void
87 lk_list_charsets(FILE *f) {
88         int lth,ct;
89         unsigned int i, j;
90         char *mm[] = { "iso-8859-", "koi8-" };
91
92         for (j=0; j<sizeof(mm)/sizeof(mm[0]); j++) {
93                 if(j)
94                         fprintf(f, ",");
95                 fprintf(f, "%s{", mm[j]);
96                 ct = 0;
97                 lth = strlen(mm[j]);
98                 for(i=1; i < charsets_size; i++) {
99                         if(!strncmp(charsets[i].charset, mm[j], lth)) {
100                                 if(ct++)
101                                         fprintf(f, ",");
102                                 fprintf(f, "%s", charsets[i].charset+lth);
103                         }
104                 }
105                 fprintf(f, "}");
106         }
107         for(i=1; i < charsets_size; i++) {
108                 for (j=0; j<sizeof(mm)/sizeof(mm[0]); j++) {
109                         lth = strlen(mm[j]);
110                         if(!strncmp(charsets[i].charset, mm[j], lth))
111                                 goto nxti;
112                 }
113                 fprintf(f, ",%s", charsets[i].charset);
114         nxti:;
115         }
116         fprintf(f, "\n");
117 }
118
119 const char *
120 lk_get_charset(struct keymap *kmap)
121 {
122         if (!kmap || !kmap->charset || kmap->charset >= charsets_size)
123                 return NULL;
124
125         return charsets[kmap->charset].charset;
126 }
127
128 int
129 lk_set_charset(struct keymap *kmap, const char *charset) {
130         unsigned int i;
131
132         for (i = 1; i < charsets_size; i++) {
133                 if (!strcasecmp(charsets[i].charset, charset)) {
134                         kmap->charset = i;
135                         return 0;
136                 }
137         }
138         return 1;
139 }
140
141 const char *
142 codetoksym(struct keymap *kmap, int code) {
143         unsigned int i;
144         int j;
145         sym *p;
146
147         if (code < 0)
148                 return NULL;
149
150         if (code < 0x1000) {    /* "traditional" keysym */
151                 if (code < 0x80)
152                         return iso646_syms[code];
153
154                 if (KTYP(code) == KT_META)
155                         return NULL;
156
157                 if (KTYP(code) == KT_LETTER)
158                         code = K(KT_LATIN, KVAL(code));
159
160                 if (KTYP(code) > KT_LATIN)
161                         return syms[KTYP(code)].table[KVAL(code)];
162
163                 i = kmap->charset;
164                 while (1) {
165                         p = (sym *) charsets[i].charnames;
166                         if (p) {
167                                 p += KVAL(code) - charsets[i].start;
168
169                                 if (p->name[0])
170                                         return p->name;
171                         }
172
173                         i++;
174
175                         if (i == charsets_size)
176                                 i = 0;
177                         if (i == kmap->charset)
178                                 break;
179                 }
180         }
181
182         else {                  /* Unicode keysym */
183                 code ^= 0xf000;
184
185                 if (code < 0x80)
186                         return iso646_syms[code];
187
188                 i = kmap->charset;
189                 while (1) {
190                         p = (sym *) charsets[i].charnames;
191                         if (p) {
192                                 for (j = charsets[i].start; j < 256; j++, p++) {
193                                         if (p->uni == code && p->name[0])
194                                                 return p->name;
195                                 }
196                         }
197
198                         i++;
199
200                         if (i == charsets_size)
201                                 i = 0;
202                         if (i == kmap->charset)
203                                 break;
204                 }
205
206         }
207
208         return NULL;
209 }
210
211 /* Functions for loadkeys. */
212
213 static int
214 kt_latin(struct keymap *kmap, const char *s, int direction) {
215         int i, max;
216
217         if (kmap->charset) {
218                 sym *p = (sym *) charsets[kmap->charset].charnames;
219
220                 for (i = charsets[kmap->charset].start; i < 256; i++, p++) {
221                         if(p->name[0] && !strcmp(s, p->name))
222                                 return K(KT_LATIN, i);
223                 }
224         }
225
226         max = (direction == TO_UNICODE ? 128 : syms[KT_LATIN].size);
227
228         for (i = 0; i < max; i++) {
229                 if (!strcmp(s, syms[KT_LATIN].table[i]))
230                         return K(KT_LATIN, i);
231         }
232
233         return -1;
234 }
235
236 int
237 ksymtocode(struct keymap *kmap, const char *s, int direction) {
238         unsigned int i;
239         int n, j;
240         int keycode;
241         sym *p;
242
243         if (direction == TO_AUTO)
244                 direction = kmap->prefer_unicode ? TO_UNICODE : TO_8BIT;
245
246         if (!strncmp(s, "Meta_", 5)) {
247                 keycode = ksymtocode(kmap, s+5, TO_8BIT);
248                 if (KTYP(keycode) == KT_LATIN)
249                         return K(KT_META, KVAL(keycode));
250
251                 /* Avoid error messages for Meta_acute with UTF-8 */
252                 else if(direction == TO_UNICODE)
253                         return (0);
254
255                 /* fall through to error printf */
256         }
257
258         if ((n = kt_latin(kmap, s, direction)) >= 0) {
259                 return n;
260         }
261
262         for (i = 1; i < syms_size; i++) {
263                 for (j = 0; j < syms[i].size; j++) {
264                         if (!strcmp(s,syms[i].table[j]))
265                                 return K(i, j);
266                 }
267         }
268
269         for (i = 0; i < syn_size; i++)
270                 if (!strcmp(s, synonyms[i].synonym))
271                         return ksymtocode(kmap, synonyms[i].official_name, direction);
272
273         if (direction == TO_UNICODE) {
274                 i = kmap->charset;
275
276                 while (1) {
277                         p = (sym *) charsets[i].charnames;
278                         if (p) {
279                                 for (j = charsets[i].start; j < 256; j++, p++) {
280                                         if (!strcmp(s,p->name))
281                                                 return (p->uni ^ 0xf000);
282                                 }
283                         }
284
285                         i++;
286
287                         if (i == charsets_size)
288                                 i = 0;
289                         if (i == kmap->charset)
290                                 break;
291                 }
292         } else /* if (!chosen_charset[0]) */ {
293                 /* note: some keymaps use latin1 but with euro,
294                    so set_charset() would fail */
295                 /* note: some keymaps with charset line still use
296                    symbols from more than one character set,
297                    so we cannot have the  `if (!chosen_charset[0])'  here */
298
299                 for (i = 0; i < 256 - 160; i++)
300                         if (!strcmp(s, latin1_syms[i].name)) {
301                                 INFO(kmap, _("assuming iso-8859-1 %s"), s);
302                                 return K(KT_LATIN, 160 + i);
303                         }
304
305                 for (i = 0; i < 256 - 160; i++)
306                         if (!strcmp(s, iso_8859_15_syms[i].name)) {
307                                 INFO(kmap, _("assuming iso-8859-15 %s"), s);
308                                 return K(KT_LATIN, 160 + i);
309                         }
310
311                 for (i = 0; i < 256 - 160; i++)
312                         if (!strcmp(s, latin2_syms[i].name)) {
313                                 INFO(kmap, _("assuming iso-8859-2 %s"), s);
314                                 return K(KT_LATIN, 160 + i);
315                         }
316
317                 for (i = 0; i < 256 - 160; i++)
318                         if (!strcmp(s, latin3_syms[i].name)) {
319                                 INFO(kmap, _("assuming iso-8859-3 %s"), s);
320                                 return K(KT_LATIN, 160 + i);
321                         }
322
323                 for (i = 0; i < 256 - 160; i++)
324                         if (!strcmp(s, latin4_syms[i].name)) {
325                                 INFO(kmap, _("assuming iso-8859-4 %s"), s);
326                                 return K(KT_LATIN, 160 + i);
327                         }
328         }
329
330         ERR(kmap, _("unknown keysym '%s'\n"), s);
331
332         return CODE_FOR_UNKNOWN_KSYM;
333 }
334
335 int
336 convert_code(struct keymap *kmap, int code, int direction)
337 {
338         const char *ksym;
339         int unicode_forced = (direction == TO_UNICODE);
340         int input_is_unicode = (code >= 0x1000);
341         int result;
342
343         if (direction == TO_AUTO)
344                 direction = kmap->prefer_unicode ? TO_UNICODE : TO_8BIT;
345
346         if (KTYP(code) == KT_META)
347                 return code;
348         else if (!input_is_unicode && code < 0x80)
349                 /* basic ASCII is fine in every situation */
350                 return code;
351         else if (input_is_unicode && (code ^ 0xf000) < 0x80)
352                 /* so is Unicode "Basic Latin" */
353                 return code ^ 0xf000;
354         else if ((input_is_unicode && direction == TO_UNICODE) ||
355                  (!input_is_unicode && direction == TO_8BIT))
356                 /* no conversion necessary */
357                 result = code;
358         else {
359                 /* depending on direction, this will give us either an 8-bit
360                  * K(KTYP, KVAL) or a Unicode keysym xor 0xf000 */
361                 ksym = codetoksym(kmap, code);
362                 if (ksym)
363                         result = ksymtocode(kmap, ksym, direction);
364                 else
365                         result = code;
366         }
367
368         /* if direction was TO_UNICODE from the beginning, we return the true
369          * Unicode value (without the 0xf000 mask) */
370         if (unicode_forced && result >= 0x1000)
371                 return result ^ 0xf000;
372         else
373                 return result;
374 }
375
376 int
377 add_capslock(struct keymap *kmap, int code)
378 {
379         if (KTYP(code) == KT_LATIN && (!(kmap->prefer_unicode) || code < 0x80))
380                 return K(KT_LETTER, KVAL(code));
381         else if ((code ^ 0xf000) < 0x100)
382                 /* Unicode Latin-1 Supplement */
383                 /* a bit dirty to use KT_LETTER here, but it should work */
384                 return K(KT_LETTER, code ^ 0xf000);
385         else
386                 return convert_code(kmap, code, TO_AUTO);
387 }