Set charset through the struct kmap
[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 syms_entry
33 const 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 struct cs {
57         const char *charset;
58         sym *charnames;
59         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 int
120 lk_set_charset(struct keymap *kmap, const char *charset) {
121         unsigned int i;
122
123         for (i = 1; i < charsets_size; i++) {
124                 if (!strcasecmp(charsets[i].charset, charset)) {
125                         kmap->charset = i;
126                         return 0;
127                 }
128         }
129         return 1;
130 }
131
132 const char *
133 codetoksym(struct keymap *kmap, int code) {
134         unsigned int i;
135         int j;
136         sym *p;
137
138         if (code < 0)
139                 return NULL;
140
141         if (code < 0x1000) {    /* "traditional" keysym */
142                 if (code < 0x80)
143                         return iso646_syms[code];
144
145                 if (KTYP(code) == KT_META)
146                         return NULL;
147
148                 if (KTYP(code) == KT_LETTER)
149                         code = K(KT_LATIN, KVAL(code));
150
151                 if (KTYP(code) > KT_LATIN)
152                         return syms[KTYP(code)].table[KVAL(code)];
153
154                 i = kmap->charset;
155                 while (1) {
156                         p = charsets[i].charnames;
157                         if (p) {
158                                 p += KVAL(code) - charsets[i].start;
159
160                                 if (p->name[0])
161                                         return p->name;
162                         }
163
164                         i++;
165
166                         if (i == charsets_size)
167                                 i = 0;
168                         if (i == kmap->charset)
169                                 break;
170                 }
171         }
172
173         else {                  /* Unicode keysym */
174                 code ^= 0xf000;
175
176                 if (code < 0x80)
177                         return iso646_syms[code];
178
179                 i = kmap->charset;
180                 while (1) {
181                         p = charsets[i].charnames;
182                         if (p) {
183                                 for (j = charsets[i].start; j < 256; j++, p++) {
184                                         if (p->uni == code && p->name[0])
185                                                 return p->name;
186                                 }
187                         }
188
189                         i++;
190
191                         if (i == charsets_size)
192                                 i = 0;
193                         if (i == kmap->charset)
194                                 break;
195                 }
196
197         }
198
199         return NULL;
200 }
201
202 /* Functions for loadkeys. */
203
204 static int
205 kt_latin(struct keymap *kmap, const char *s, int direction) {
206         int i, max;
207
208         if (kmap->charset) {
209                 sym *p = charsets[kmap->charset].charnames;
210
211                 for (i = charsets[kmap->charset].start; i < 256; i++, p++) {
212                         if(p->name[0] && !strcmp(s, p->name))
213                                 return K(KT_LATIN, i);
214                 }
215         }
216
217         max = (direction == TO_UNICODE ? 128 : syms[KT_LATIN].size);
218
219         for (i = 0; i < max; i++) {
220                 if (!strcmp(s, syms[KT_LATIN].table[i]))
221                         return K(KT_LATIN, i);
222         }
223
224         return -1;
225 }
226
227 int
228 ksymtocode(struct keymap *kmap, const char *s, int direction) {
229         unsigned int i;
230         int n, j;
231         int keycode;
232         sym *p;
233
234         if (direction == TO_AUTO)
235                 direction = kmap->prefer_unicode ? TO_UNICODE : TO_8BIT;
236
237         if (!strncmp(s, "Meta_", 5)) {
238                 keycode = ksymtocode(kmap, s+5, TO_8BIT);
239                 if (KTYP(keycode) == KT_LATIN)
240                         return K(KT_META, KVAL(keycode));
241
242                 /* Avoid error messages for Meta_acute with UTF-8 */
243                 else if(direction == TO_UNICODE)
244                         return (0);
245
246                 /* fall through to error printf */
247         }
248
249         if ((n = kt_latin(kmap, s, direction)) >= 0) {
250                 return n;
251         }
252
253         for (i = 1; i < syms_size; i++) {
254                 for (j = 0; j < syms[i].size; j++) {
255                         if (!strcmp(s,syms[i].table[j]))
256                                 return K(i, j);
257                 }
258         }
259
260         for (i = 0; i < syn_size; i++)
261                 if (!strcmp(s, synonyms[i].synonym))
262                         return ksymtocode(kmap, synonyms[i].official_name, direction);
263
264         if (direction == TO_UNICODE) {
265                 i = kmap->charset;
266
267                 while (1) {
268                         p = charsets[i].charnames;
269                         if (p) {
270                                 for (j = charsets[i].start; j < 256; j++, p++) {
271                                         if (!strcmp(s,p->name))
272                                                 return (p->uni ^ 0xf000);
273                                 }
274                         }
275
276                         i++;
277
278                         if (i == charsets_size)
279                                 i = 0;
280                         if (i == kmap->charset)
281                                 break;
282                 }
283         } else /* if (!chosen_charset[0]) */ {
284                 /* note: some keymaps use latin1 but with euro,
285                    so set_charset() would fail */
286                 /* note: some keymaps with charset line still use
287                    symbols from more than one character set,
288                    so we cannot have the  `if (!chosen_charset[0])'  here */
289
290                 for (i = 0; i < 256 - 160; i++)
291                         if (!strcmp(s, latin1_syms[i].name)) {
292                                 log_verbose(kmap, LOG_VERBOSE1,
293                                         _("assuming iso-8859-1 %s\n"), s);
294                                 return K(KT_LATIN, 160 + i);
295                         }
296
297                 for (i = 0; i < 256 - 160; i++)
298                         if (!strcmp(s, iso_8859_15_syms[i].name)) {
299                                 log_verbose(kmap, LOG_VERBOSE1,
300                                         _("assuming iso-8859-15 %s\n"), s);
301                                 return K(KT_LATIN, 160 + i);
302                         }
303
304                 for (i = 0; i < 256 - 160; i++)
305                         if (!strcmp(s, latin2_syms[i].name)) {
306                                 log_verbose(kmap, LOG_VERBOSE1,
307                                         _("assuming iso-8859-2 %s\n"), s);
308                                 return K(KT_LATIN, 160 + i);
309                         }
310
311                 for (i = 0; i < 256 - 160; i++)
312                         if (!strcmp(s, latin3_syms[i].name)) {
313                                 log_verbose(kmap, LOG_VERBOSE1,
314                                         _("assuming iso-8859-3 %s\n"), s);
315                                 return K(KT_LATIN, 160 + i);
316                         }
317
318                 for (i = 0; i < 256 - 160; i++)
319                         if (!strcmp(s, latin4_syms[i].name)) {
320                                 log_verbose(kmap, LOG_VERBOSE1,
321                                         _("assuming iso-8859-4 %s\n"), s);
322                                 return K(KT_LATIN, 160 + i);
323                         }
324         }
325
326         log_error(kmap, _("unknown keysym '%s'\n"), s);
327
328         return CODE_FOR_UNKNOWN_KSYM;
329 }
330
331 int
332 convert_code(struct keymap *kmap, int code, int direction)
333 {
334         const char *ksym;
335         int unicode_forced = (direction == TO_UNICODE);
336         int input_is_unicode = (code >= 0x1000);
337         int result;
338
339         if (direction == TO_AUTO)
340                 direction = kmap->prefer_unicode ? TO_UNICODE : TO_8BIT;
341
342         if (KTYP(code) == KT_META)
343                 return code;
344         else if (!input_is_unicode && code < 0x80)
345                 /* basic ASCII is fine in every situation */
346                 return code;
347         else if (input_is_unicode && (code ^ 0xf000) < 0x80)
348                 /* so is Unicode "Basic Latin" */
349                 return code ^ 0xf000;
350         else if ((input_is_unicode && direction == TO_UNICODE) ||
351                  (!input_is_unicode && direction == TO_8BIT))
352                 /* no conversion necessary */
353                 result = code;
354         else {
355                 /* depending on direction, this will give us either an 8-bit
356                  * K(KTYP, KVAL) or a Unicode keysym xor 0xf000 */
357                 ksym = codetoksym(kmap, code);
358                 if (ksym)
359                         result = ksymtocode(kmap, ksym, direction);
360                 else
361                         result = code;
362         }
363
364         /* if direction was TO_UNICODE from the beginning, we return the true
365          * Unicode value (without the 0xf000 mask) */
366         if (unicode_forced && result >= 0x1000)
367                 return result ^ 0xf000;
368         else
369                 return result;
370 }
371
372 int
373 add_capslock(struct keymap *kmap, int code)
374 {
375         if (KTYP(code) == KT_LATIN && (!(kmap->prefer_unicode) || code < 0x80))
376                 return K(KT_LETTER, KVAL(code));
377         else if ((code ^ 0xf000) < 0x100)
378                 /* Unicode Latin-1 Supplement */
379                 /* a bit dirty to use KT_LETTER here, but it should work */
380                 return K(KT_LETTER, code ^ 0xf000);
381         else
382                 return convert_code(kmap, code, TO_AUTO);
383 }