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