1 /*
2
3 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31 */
32
33 #include <config.h>
34
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <sys/param.h>
41 #include <locale.h>
42 #include <errno.h>
43
44 #include <X11/keysym.h>
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47
48 #include <glib.h>
49
50 #include "gtk-im-uim.h"
51 #include "compose.h"
52
53 #define COMPOSE_FILE "Compose"
54 #define COMPOSE_DIR_FILE "X11/locale/compose.dir"
55 #define XLOCALE_DIR "X11/locale"
56 #define FALLBACK_XLIB_DIR "/usr/X11R6/lib"
57
58 #define XLC_BUFSIZE 256
59 #define iscomment(ch) ((ch) == '#' || (ch) == '\0')
60
61 #ifdef GDK_WINDOWING_X11
62 int compose_handle_key(GdkEventKey *event, IMUIMContext *uic);
63
64 static int parse_line(char *line, char **argv, int argsize);
65 static unsigned int KeySymToUcs4(KeySym keysym);
66 static int get_compose_filename(char *, size_t);
67 static void ParseComposeStringFile(FILE *fp);
68 static int get_lang_region(char *, size_t);
69 static int TransFileName(char *, const char *, size_t);
70
71 static DefTree *g_tree;
72
73 Compose *
im_uim_compose_new()74 im_uim_compose_new()
75 {
76 DefTree *top = g_tree;
77 Compose *p;
78
79 p = malloc(sizeof(Compose));
80 if (p) {
81 p->m_composed = NULL;
82 p->m_top = top;
83 p->m_context = top;
84 }
85
86 return p;
87 }
88
89 static int
handleKey(unsigned int xkeysym,unsigned int xkeystate,int is_push,IMUIMContext * uic)90 handleKey(unsigned int xkeysym, unsigned int xkeystate, int is_push,
91 IMUIMContext *uic)
92 {
93 DefTree *p;
94 DefTree *m_top = uic->compose->m_top;
95 DefTree *m_context = uic->compose->m_context;
96
97 if ((is_push == 0) || m_top == NULL)
98 return 0;
99
100 if (IsModifierKey(xkeysym))
101 return 0;
102
103 for (p = m_context; p ; p = p->next) {
104 if (((xkeystate & p->modifier_mask) == p->modifier) &&
105 (xkeysym == p->keysym)) {
106 break;
107 }
108 }
109
110 if (p) { /* Matched */
111 if (p->succession) { /* Intermediate */
112 uic->compose->m_context = p->succession;
113 return 1;
114 } else { /* Terminate (reached to leaf) */
115 uic->compose->m_composed = p;
116 /* commit string here */
117 im_uim_commit_string(uic, uic->compose->m_composed->utf8);
118 /* initialize internal state for next key sequence */
119 uic->compose->m_context = m_top;
120 return 1;
121 }
122 } else { /* Unmatched */
123 if (m_context == m_top)
124 return 0;
125 /* Error (Sequence Unmatch occurred) */
126 uic->compose->m_context = m_top;
127 return 1;
128 }
129 }
130
131 void
im_uim_compose_reset(Compose * compose)132 im_uim_compose_reset(Compose *compose)
133 {
134 compose->m_context = compose->m_top;
135 compose->m_composed = NULL;
136 }
137
138 static int
nextch(FILE * fp,int * lastch)139 nextch(FILE *fp, int *lastch)
140 {
141 int c;
142
143 if (*lastch != 0) {
144 c = *lastch;
145 *lastch = 0;
146 } else {
147 c = getc(fp);
148 if (c == '\\') {
149 c = getc(fp);
150 if (c == '\n') {
151 c = getc(fp);
152 } else {
153 ungetc(c, fp);
154 c = '\\';
155 }
156 }
157 }
158 return(c);
159 }
160
161 static void
putbackch(int c,int * lastch)162 putbackch(int c, int *lastch)
163 {
164 *lastch = c;
165 }
166
167
168 #define ENDOFFILE 0
169 #define ENDOFLINE 1
170 #define COLON 2
171 #define LESS 3
172 #define GREATER 4
173 #define EXCLAM 5
174 #define TILDE 6
175 #define STRING 7
176 #define KEY 8
177 #define ERROR 9
178
179
180 #ifndef isalnum
181 #define isalnum(c) \
182 (('0' <= (c) && (c) <= '9') || \
183 ('A' <= (c) && (c) <= 'Z') || \
184 ('a' <= (c) && (c) <= 'z'))
185 #endif
186
187 static int
nexttoken(FILE * fp,char ** tokenbuf,int * lastch,size_t * buflen)188 nexttoken(FILE *fp, char **tokenbuf, int *lastch, size_t *buflen)
189 {
190 int c;
191 int token;
192 char *p;
193 int i, j;
194 size_t len = 0;
195
196 while ((c = nextch(fp, lastch)) == ' ' || c == '\t') {
197 }
198 switch (c) {
199 case EOF:
200 token = ENDOFFILE;
201 break;
202 case '\n':
203 token = ENDOFLINE;
204 break;
205 case '<':
206 token = LESS;
207 break;
208 case '>':
209 token = GREATER;
210 break;
211 case ':':
212 token = COLON;
213 break;
214 case '!':
215 token = EXCLAM;
216 break;
217 case '~':
218 token = TILDE;
219 break;
220 case '"':
221 p = *tokenbuf;
222 while ((c = nextch(fp, lastch)) != '"') {
223 if (len >= *buflen - 1) {
224 *buflen += BUFSIZ;
225 *tokenbuf = (char *)realloc(*tokenbuf, *buflen);
226 p = *tokenbuf + len;
227 }
228 if (c == '\n' || c == EOF) {
229 putbackch(c, lastch);
230 token = ERROR;
231 goto string_error;
232 } else if (c == '\\') {
233 c = nextch(fp, lastch);
234 switch (c) {
235 case '\\':
236 case '"':
237 *p++ = c;
238 len++;
239 break;
240 case 'n':
241 *p++ = '\n';
242 len++;
243 break;
244 case 'r':
245 *p++ = '\r';
246 len++;
247 break;
248 case 't':
249 *p++ = '\t';
250 len++;
251 break;
252 case '0':
253 case '1':
254 case '2':
255 case '3':
256 case '4':
257 case '5':
258 case '6':
259 case '7':
260 i = c - '0';
261 c = nextch(fp, lastch);
262 for (j = 0; j < 2 && c >= '0' && c <= '7'; j++) {
263 i <<= 3;
264 i += c - '0';
265 c = nextch(fp, lastch);
266 }
267 putbackch(c, lastch);
268 *p++ = (char)i;
269 len++;
270 break;
271 case 'X':
272 case 'x':
273 i = 0;
274 for (j = 0; j < 2; j++) {
275 c = nextch(fp, lastch);
276 i <<= 4;
277 if (c >= '0' && c <= '9') {
278 i += c - '0';
279 } else if (c >= 'A' && c <= 'F') {
280 i += c - 'A' + 10;
281 } else if (c >= 'a' && c <= 'f') {
282 i += c - 'a' + 10;
283 } else {
284 putbackch(c, lastch);
285 i >>= 4;
286 break;
287 }
288 }
289 if (j == 0) {
290 token = ERROR;
291 goto string_error;
292 }
293 *p++ = (char)i;
294 len++;
295 break;
296 case EOF:
297 putbackch(c, lastch);
298 token = ERROR;
299 goto string_error;
300 default:
301 *p++ = c;
302 len++;
303 break;
304 }
305 } else {
306 *p++ = c;
307 len++;
308 }
309 }
310 *p = '\0';
311 token = STRING;
312 break;
313 case '#':
314 while ((c = nextch(fp, lastch)) != '\n' && c != EOF) {
315 }
316 if (c == '\n') {
317 token = ENDOFLINE;
318 } else {
319 token = ENDOFFILE;
320 }
321 break;
322 default:
323 if (isalnum(c) || c == '_' || c == '-') {
324 if (len >= *buflen - 1) {
325 *buflen += BUFSIZ;
326 *tokenbuf = (char *)realloc(*tokenbuf, *buflen);
327 }
328 p = *tokenbuf;
329 *p++ = c;
330 len++;
331 c = nextch(fp, lastch);
332 while (isalnum(c) || c == '_' || c == '-') {
333 if (len >= *buflen - 1) {
334 *buflen += BUFSIZ;
335 *tokenbuf = (char *)realloc(*tokenbuf, *buflen);
336 p = *tokenbuf + len;
337 }
338 *p++ = c;
339 len++;
340 c = nextch(fp, lastch);
341 }
342 *p = '\0';
343 putbackch(c, lastch);
344 token = KEY;
345 } else {
346 token = ERROR;
347 }
348 break;
349 }
350 string_error:
351 return(token);
352 }
353
354 static long
modmask(char * name)355 modmask(char *name)
356 {
357 long mask;
358
359 struct _modtbl {
360 const char *name;
361 long mask;
362 };
363 struct _modtbl *p;
364
365 static struct _modtbl tbl[] = {
366 { "Ctrl", ControlMask },
367 { "Lock", LockMask },
368 { "Caps", LockMask },
369 { "Shift", ShiftMask },
370 { "Alt", Mod1Mask },
371 { "Meta", Mod1Mask },
372 { NULL, 0 }};
373
374 p = tbl;
375 mask = 0;
376 for (p = tbl; p->name != NULL; p++) {
377 if (strcmp(name, p->name) == 0) {
378 mask = p->mask;
379 break;
380 }
381 }
382 return(mask);
383 }
384
385 static int
TransFileName(char * transname,const char * name,size_t len)386 TransFileName(char *transname, const char *name, size_t len)
387 {
388 char *home = NULL;
389 char lcCompose[MAXPATHLEN];
390 const char *i = name;
391 char *j;
392 char ret[MAXPATHLEN];
393
394 j = ret;
395 i = name;
396 lcCompose[0] = ret[0] = '\0';
397 while (*i && j - ret < MAXPATHLEN - 1) {
398 if (*i == '%') {
399 i++;
400 switch (*i) {
401 case '%':
402 *j++ = '%';
403 break;
404 case 'H':
405 home = getenv("HOME");
406 if (home) {
407 strlcat(ret, home, sizeof(ret));
408 j += strlen(home);
409 }
410 break;
411 case 'L':
412 get_compose_filename(lcCompose, sizeof(lcCompose));
413 if (lcCompose[0] != '\0') {
414 strlcat(ret, lcCompose, sizeof(ret));
415 j += strlen(lcCompose);
416 }
417 break;
418 }
419 i++;
420 } else {
421 *j++ = *i++;
422 }
423 *j = '\0';
424 }
425 strlcpy(transname, ret, len);
426
427 return 1;
428 }
429
430 #ifndef MB_LEN_MAX
431 #define MB_LEN_MAX 6
432 #endif
433
434 static int
get_mb_string(char * buf,KeySym ks)435 get_mb_string(char *buf, KeySym ks)
436 {
437 int len;
438 char local_buf[MB_LEN_MAX];
439 char *mb;
440 unsigned int ucs;
441
442 ucs = KeySymToUcs4(ks);
443 len = g_unichar_to_utf8(ucs, local_buf);
444 local_buf[len] = '\0';
445 mb = g_locale_from_utf8(local_buf, -1, NULL, NULL, NULL);
446 if (!mb)
447 return 0;
448 len = strlen(mb);
449 strlcpy(buf, mb, MB_LEN_MAX + 1);
450 g_free(mb);
451
452 return len;
453 }
454
455 #define AllMask (ShiftMask | LockMask | ControlMask | Mod1Mask)
456 #define LOCAL_UTF8_BUFSIZE 256
457 #define SEQUENCE_MAX 10
458
459 static int
parse_compose_line(FILE * fp,char ** tokenbuf,size_t * buflen)460 parse_compose_line(FILE *fp, char **tokenbuf, size_t *buflen)
461 {
462 int token;
463 unsigned modifier_mask;
464 unsigned modifier;
465 unsigned tmp;
466 KeySym keysym = NoSymbol;
467 DefTree **top = &g_tree;
468 DefTree *p = NULL;
469 Bool exclam, tilde;
470 KeySym rhs_keysym = 0;
471 char *rhs_string_mb;
472 int l = 0;
473 int lastch = 0;
474 char local_mb_buf[MB_LEN_MAX + 1];
475 char *rhs_string_utf8;
476
477 struct DefBuffer {
478 unsigned modifier_mask;
479 unsigned modifier;
480 KeySym keysym;
481 };
482
483 struct DefBuffer buf[SEQUENCE_MAX];
484 int i, n;
485 const char *encoding;
486 g_get_charset(&encoding);
487
488 do {
489 token = nexttoken(fp, tokenbuf, &lastch, buflen);
490 } while (token == ENDOFLINE);
491
492 if (token == ENDOFFILE) {
493 return(-1);
494 }
495
496 n = 0;
497 do {
498 if ((token == KEY) && (strcmp("include", *tokenbuf) == 0)) {
499 char filename[MAXPATHLEN];
500 FILE *infp;
501 token = nexttoken(fp, tokenbuf, &lastch, buflen);
502 if (token != KEY && token != STRING)
503 goto error;
504
505 if (!TransFileName(filename, *tokenbuf, sizeof(filename)) || filename[0] == '\0')
506 goto error;
507 infp = fopen(filename, "r");
508 if (infp == NULL)
509 goto error;
510 ParseComposeStringFile(infp);
511 fclose(infp);
512 return 0;
513 } else if ((token == KEY) && (strcmp("None", *tokenbuf) == 0)) {
514 modifier = 0;
515 modifier_mask = AllMask;
516 token = nexttoken(fp, tokenbuf, &lastch, buflen);
517 } else {
518 modifier_mask = modifier = 0;
519 exclam = False;
520 if (token == EXCLAM) {
521 exclam = True;
522 token = nexttoken(fp, tokenbuf, &lastch, buflen);
523 }
524 while (token == TILDE || token == KEY) {
525 tilde = False;
526 if (token == TILDE) {
527 tilde = True;
528 token = nexttoken(fp, tokenbuf, &lastch, buflen);
529 if (token != KEY)
530 goto error;
531 }
532 tmp = modmask(*tokenbuf);
533 if (!tmp) {
534 goto error;
535 }
536 modifier_mask |= tmp;
537 if (tilde) {
538 modifier &= ~tmp;
539 } else {
540 modifier |= tmp;
541 }
542 token = nexttoken(fp, tokenbuf, &lastch, buflen);
543 }
544 if (exclam) {
545 modifier_mask = AllMask;
546
547 }
548 }
549
550 if (token != LESS) {
551 goto error;
552 }
553
554 token = nexttoken(fp, tokenbuf, &lastch, buflen);
555 if (token != KEY) {
556 goto error;
557 }
558
559 token = nexttoken(fp, tokenbuf, &lastch, buflen);
560 if (token != GREATER) {
561 goto error;
562 }
563
564 keysym = XStringToKeysym(*tokenbuf);
565 if (keysym == NoSymbol) {
566 goto error;
567 }
568
569 buf[n].keysym = keysym;
570 buf[n].modifier = modifier;
571 buf[n].modifier_mask = modifier_mask;
572 n++;
573 if (n >= SEQUENCE_MAX)
574 goto error;
575 token = nexttoken(fp, tokenbuf, &lastch, buflen);
576 } while (token != COLON);
577
578 token = nexttoken(fp, tokenbuf, &lastch, buflen);
579 if (token == STRING) {
580 if ((rhs_string_mb = (char *)malloc(strlen(*tokenbuf) + 1)) == NULL)
581 goto error;
582 strcpy(rhs_string_mb, *tokenbuf);
583 token = nexttoken(fp, tokenbuf, &lastch, buflen);
584 if (token == KEY) {
585 rhs_keysym = XStringToKeysym(*tokenbuf);
586 if (rhs_keysym == NoSymbol) {
587 free(rhs_string_mb);
588 goto error;
589 }
590 token = nexttoken(fp, tokenbuf, &lastch, buflen);
591 }
592 if (token != ENDOFLINE && token != ENDOFFILE) {
593 free(rhs_string_mb);
594 goto error;
595 }
596 } else if (token == KEY) {
597 rhs_keysym = XStringToKeysym(*tokenbuf);
598 if (rhs_keysym == NoSymbol) {
599 goto error;
600 }
601 token = nexttoken(fp, tokenbuf, &lastch, buflen);
602 if (token != ENDOFLINE && token != ENDOFFILE) {
603 goto error;
604 }
605
606 l = get_mb_string(local_mb_buf, rhs_keysym);
607 if (l == 0) {
608 rhs_string_mb = (char *)malloc(1);
609 } else {
610 rhs_string_mb = (char *)malloc(l + 1);
611 }
612 if (rhs_string_mb == NULL) {
613 goto error;
614 }
615 memcpy(rhs_string_mb, local_mb_buf, l);
616 rhs_string_mb[l] = '\0';
617 } else {
618 goto error;
619 }
620
621 {
622 char *result;
623 result = g_locale_to_utf8(rhs_string_mb, -1, NULL, NULL, NULL);
624 if (!result)
625 rhs_string_utf8 = strdup("");
626 else
627 rhs_string_utf8 = strdup(result);
628 g_free(result);
629 }
630
631 for (i = 0; i < n; i++) {
632 for (p = *top; p; p = p->next) {
633 if (buf[i].keysym == p->keysym &&
634 buf[i].modifier == p->modifier &&
635 buf[i].modifier_mask == p->modifier_mask) {
636 break;
637 }
638 }
639 if (p) {
640 top = &p->succession;
641 } else {
642 if ((p = (DefTree*)malloc(sizeof(DefTree))) == NULL) {
643 free(rhs_string_mb);
644 goto error;
645 }
646 p->keysym = buf[i].keysym;
647 p->modifier = buf[i].modifier;
648 p->modifier_mask = buf[i].modifier_mask;
649 p->succession = NULL;
650 p->next = *top;
651 p->mb = NULL;
652 p->utf8 = NULL;
653 p->ks = NoSymbol;
654 *top = p;
655 top = &p->succession;
656 }
657 }
658
659 free(p->mb);
660 p->mb = rhs_string_mb;
661 free(p->utf8);
662 p->utf8 = rhs_string_utf8;
663 p->ks = rhs_keysym;
664 return n;
665 error:
666 while (token != ENDOFLINE && token != ENDOFFILE) {
667 token = nexttoken(fp, tokenbuf, &lastch, buflen);
668 }
669 return 0;
670 }
671
672 static void
ParseComposeStringFile(FILE * fp)673 ParseComposeStringFile(FILE *fp)
674 {
675 char *tbp, *p[1];
676 struct stat st;
677 size_t buflen = BUFSIZ;
678
679 if (fstat(fileno(fp), &st) != -1 && S_ISREG(st.st_mode) &&
680 st.st_size > 0) {
681
682 tbp = (char *)malloc(buflen);
683 p[0] = tbp;
684 if (tbp != NULL) {
685 while (parse_compose_line(fp, p, &buflen) >= 0) {
686 }
687 free(p[0]);
688 }
689 }
690 }
691
692 static int
get_lang_region(char * locale,size_t len)693 get_lang_region(char *locale, size_t len)
694 {
695 char *p;
696
697 strlcpy(locale, setlocale(LC_CTYPE, NULL), len);
698 if (locale[0] == '\0') {
699 return 0;
700 }
701
702 p = strrchr(locale, '.');
703 if (p)
704 *p = '\0';
705
706 return 1;
707 }
708
im_uim_create_compose_tree()709 void im_uim_create_compose_tree()
710 {
711 FILE *fp = NULL;
712 char name[MAXPATHLEN];
713 char lang_region[BUFSIZ];
714 const char *encoding;
715 char *compose_env;
716 int ret;
717
718 name[0] = '\0';
719 compose_env = getenv("XCOMPOSEFILE");
720
721 if (compose_env != NULL) {
722 strlcpy(name, compose_env, sizeof(name));
723 } else {
724 char *home = getenv("HOME");
725 if (home != NULL) {
726 snprintf(name, sizeof(name), "%s/.XCompose", home);
727 fp = fopen(name, "r");
728 if (fp == NULL)
729 name[0] = '\0';
730 }
731 }
732
733 if (name[0] == '\0' && !get_compose_filename(name, sizeof(name))) {
734 if (fp)
735 fclose(fp);
736 return;
737 }
738
739 if (fp == NULL && ((fp = fopen(name, "r")) == NULL))
740 return;
741
742 ret = get_lang_region(lang_region, sizeof(lang_region));
743 g_get_charset(&encoding);
744 if (!ret || encoding == NULL) {
745 fprintf(stderr, "Warning: locale name is NULL\n");
746 fclose(fp);
747 return;
748 }
749
750 ParseComposeStringFile(fp);
751 fclose(fp);
752 }
753
754 static void
FreeComposeTree(DefTree * top)755 FreeComposeTree(DefTree *top)
756 {
757 if (!top)
758 return;
759
760 if (top->succession)
761 FreeComposeTree(top->succession);
762 if (top->next)
763 FreeComposeTree(top->next);
764 free(top->mb);
765 free(top->utf8);
766 free(top);
767 }
768
769 void
im_uim_release_compose_tree()770 im_uim_release_compose_tree()
771 {
772 FreeComposeTree(g_tree);
773 }
774
775 static int
get_compose_filename(char * filename,size_t len)776 get_compose_filename(char *filename, size_t len)
777 {
778 char compose_dir_file[MAXPATHLEN], name[MAXPATHLEN];
779 char locale[BUFSIZ];
780 const char *encoding;
781 char lang_region[BUFSIZ];
782 int ret;
783
784 FILE *fp;
785 char buf[XLC_BUFSIZE];
786 const char *xlib_dir = XLIB_DIR ;
787
788 ret = get_lang_region(lang_region, sizeof(lang_region));
789 g_get_charset(&encoding);
790
791 if (!ret || encoding == NULL)
792 return 0;
793
794 snprintf(locale, sizeof(locale), "%s.%s", lang_region, encoding);
795 snprintf(compose_dir_file, sizeof(compose_dir_file), "%s/%s", XLIB_DIR, COMPOSE_DIR_FILE);
796
797 fp = fopen(compose_dir_file, "r");
798 if (fp == NULL) {
799 /* retry with fallback file */
800 if (strcmp(FALLBACK_XLIB_DIR, XLIB_DIR)) {
801 snprintf(compose_dir_file, sizeof(compose_dir_file), "%s/%s",
802 FALLBACK_XLIB_DIR, COMPOSE_DIR_FILE);
803 fp = fopen(compose_dir_file, "r");
804 if (fp == NULL)
805 return 0;
806 xlib_dir = FALLBACK_XLIB_DIR;
807 } else
808 return 0;
809 }
810
811 name[0] = '\0';
812 while (fgets(buf, XLC_BUFSIZE, fp) != NULL) {
813 char *p = buf;
814 int n;
815 char *args[2], *from, *to;
816 while (isspace((unsigned char)*p)) {
817 ++p;
818 }
819 if (iscomment(*p)) {
820 continue;
821 }
822 n = parse_line(p, args, 2);
823 if (n != 2) {
824 continue;
825 }
826 from = args[1], to = args[0];
827 if (!strcmp(from, locale)) {
828 strlcpy(name, to, sizeof(name));
829 break;
830 }
831 }
832 fclose(fp);
833
834 if (name[0] == '\0')
835 return 0;
836
837 snprintf(filename, len, "%s/%s/%s", xlib_dir, XLOCALE_DIR, name);
838
839 return 1;
840 }
841
842 static int
parse_line(char * line,char ** argv,int argsize)843 parse_line(char *line, char **argv, int argsize)
844 {
845 int argc = 0;
846 char *p = line;
847
848 while (argc < argsize) {
849 while (isspace((unsigned char)*p)) {
850 ++p;
851 }
852 if (*p == '\0') {
853 break;
854 }
855 argv[argc++] = p;
856 while (*p != ':' && *p != '\n' && *p != '\0') {
857 ++p;
858 }
859 if (*p == '\0') {
860 break;
861 }
862 *p++ = '\0';
863 }
864
865 return argc;
866 }
867
868 static unsigned short const keysym_to_unicode_1a1_1ff[] = {
869 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, /* 0x01a0-0x01a7 */
870 0x0000, 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, /* 0x01a8-0x01af */
871 0x0000, 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, /* 0x01b0-0x01b7 */
872 0x0000, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* 0x01b8-0x01bf */
873 0x0154, 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, /* 0x01c0-0x01c7 */
874 0x010c, 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, /* 0x01c8-0x01cf */
875 0x0110, 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, /* 0x01d0-0x01d7 */
876 0x0158, 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, /* 0x01d8-0x01df */
877 0x0155, 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, /* 0x01e0-0x01e7 */
878 0x010d, 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, /* 0x01e8-0x01ef */
879 0x0111, 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, /* 0x01f0-0x01f7 */
880 0x0159, 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 /* 0x01f8-0x01ff */
881 };
882
883 static unsigned short const keysym_to_unicode_2a1_2fe[] = {
884 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, /* 0x02a0-0x02a7 */
885 0x0000, 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, /* 0x02a8-0x02af */
886 0x0000, 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, /* 0x02b0-0x02b7 */
887 0x0000, 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, /* 0x02b8-0x02bf */
888 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, /* 0x02c0-0x02c7 */
889 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02c8-0x02cf */
890 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, /* 0x02d0-0x02d7 */
891 0x011c, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, /* 0x02d8-0x02df */
892 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, /* 0x02e0-0x02e7 */
893 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02e8-0x02ef */
894 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, /* 0x02f0-0x02f7 */
895 0x011d, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d /* 0x02f8-0x02ff */
896 };
897
898 static unsigned short const keysym_to_unicode_3a2_3fe[] = {
899 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, /* 0x03a0-0x03a7 */
900 0x0000, 0x0000, 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, /* 0x03a8-0x03af */
901 0x0000, 0x0000, 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, /* 0x03b0-0x03b7 */
902 0x0000, 0x0000, 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, /* 0x03b8-0x03bf */
903 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, /* 0x03c0-0x03c7 */
904 0x0000, 0x0000, 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, /* 0x03c8-0x03cf */
905 0x0000, 0x0145, 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03d0-0x03d7 */
906 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, /* 0x03d8-0x03df */
907 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, /* 0x03e0-0x03e7 */
908 0x0000, 0x0000, 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, /* 0x03e8-0x03ef */
909 0x0000, 0x0146, 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03f0-0x03f7 */
910 0x0000, 0x0173, 0x0000, 0x0000, 0x0000, 0x0169, 0x016b /* 0x03f8-0x03ff */
911 };
912
913 static unsigned short const keysym_to_unicode_4a1_4df[] = {
914 0x3002, 0x3008, 0x3009, 0x3001, 0x30fb, 0x30f2, 0x30a1, /* 0x04a0-0x04a7 */
915 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, /* 0x04a8-0x04af */
916 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, /* 0x04b0-0x04b7 */
917 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, /* 0x04b8-0x04bf */
918 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, /* 0x04c0-0x04c7 */
919 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, /* 0x04c8-0x04cf */
920 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, /* 0x04d0-0x04d7 */
921 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c /* 0x04d8-0x04df */
922 };
923
924 static unsigned short const keysym_to_unicode_590_5fe[] = {
925 0x06f0, 0x06f1, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06f6, 0x06f7, /* 0x0590-0x0597 */
926 0x06f8, 0x06f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x0598-0x059f */
927 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x066a, 0x0670, 0x0679, /* 0x05a0-0x05a7 */
928
929 0x067e, 0x0686, 0x0688, 0x0691, 0x060c, 0x0000, 0x06d4, 0x0000, /* 0x05ac-0x05af */
930 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, /* 0x05b0-0x05b7 */
931 0x0668, 0x0669, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, /* 0x05b8-0x05bf */
932 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* 0x05c0-0x05c7 */
933 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* 0x05c8-0x05cf */
934 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, /* 0x05d0-0x05d7 */
935 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x05d8-0x05df */
936 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, /* 0x05e0-0x05e7 */
937 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, /* 0x05e8-0x05ef */
938 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0698, 0x06a4, /* 0x05f0-0x05f7 */
939 0x06a9, 0x06af, 0x06ba, 0x06be, 0x06cc, 0x06d2, 0x06c1 /* 0x05f8-0x05fe */
940 };
941
942 static unsigned short keysym_to_unicode_680_6ff[] = {
943 0x0492, 0x0496, 0x049a, 0x049c, 0x04a2, 0x04ae, 0x04b0, 0x04b2, /* 0x0680-0x0687 */
944 0x04b6, 0x04b8, 0x04ba, 0x0000, 0x04d8, 0x04e2, 0x04e8, 0x04ee, /* 0x0688-0x068f */
945 0x0493, 0x0497, 0x049b, 0x049d, 0x04a3, 0x04af, 0x04b1, 0x04b3, /* 0x0690-0x0697 */
946 0x04b7, 0x04b9, 0x04bb, 0x0000, 0x04d9, 0x04e3, 0x04e9, 0x04ef, /* 0x0698-0x069f */
947 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, /* 0x06a0-0x06a7 */
948 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0491, 0x045e, 0x045f, /* 0x06a8-0x06af */
949 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, /* 0x06b0-0x06b7 */
950 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0490, 0x040e, 0x040f, /* 0x06b8-0x06bf */
951 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, /* 0x06c0-0x06c7 */
952 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, /* 0x06c8-0x06cf */
953 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, /* 0x06d0-0x06d7 */
954 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, /* 0x06d8-0x06df */
955 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, /* 0x06e0-0x06e7 */
956 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, /* 0x06e8-0x06ef */
957 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, /* 0x06f0-0x06f7 */
958 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a /* 0x06f8-0x06ff */
959 };
960
961 static unsigned short const keysym_to_unicode_7a1_7f9[] = {
962 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, /* 0x07a0-0x07a7 */
963 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, /* 0x07a8-0x07af */
964 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, /* 0x07b0-0x07b7 */
965 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07b8-0x07bf */
966 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* 0x07c0-0x07c7 */
967 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, /* 0x07c8-0x07cf */
968 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* 0x07d0-0x07d7 */
969 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07d8-0x07df */
970 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* 0x07e0-0x07e7 */
971 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, /* 0x07e8-0x07ef */
972 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* 0x07f0-0x07f7 */
973 0x03c8, 0x03c9 /* 0x07f8-0x07ff */
974 };
975
976 static unsigned short const keysym_to_unicode_8a4_8fe[] = {
977 0x2320, 0x2321, 0x0000, 0x231c, /* 0x08a0-0x08a7 */
978 0x231d, 0x231e, 0x231f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08a8-0x08af */
979 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08b0-0x08b7 */
980 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, /* 0x08b8-0x08bf */
981 0x2234, 0x0000, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, /* 0x08c0-0x08c7 */
982 0x2245, 0x2246, 0x0000, 0x0000, 0x0000, 0x0000, 0x22a2, 0x0000, /* 0x08c8-0x08cf */
983 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, /* 0x08d0-0x08d7 */
984 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 0x08d8-0x08df */
985 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e0-0x08e7 */
986 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e8-0x08ef */
987 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, /* 0x08f0-0x08f7 */
988 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 /* 0x08f8-0x08ff */
989 };
990
991 static unsigned short const keysym_to_unicode_9df_9f8[] = {
992 0x2422, /* 0x09d8-0x09df */
993 0x2666, 0x25a6, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000, /* 0x09e0-0x09e7 */
994 0x240a, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2500, /* 0x09e8-0x09ef */
995 0x0000, 0x0000, 0x0000, 0x0000, 0x251c, 0x2524, 0x2534, 0x252c, /* 0x09f0-0x09f7 */
996 0x2502 /* 0x09f8-0x09ff */
997 };
998
999 static unsigned short const keysym_to_unicode_aa1_afe[] = {
1000 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, /* 0x0aa0-0x0aa7 */
1001 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, /* 0x0aa8-0x0aaf */
1002 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, /* 0x0ab0-0x0ab7 */
1003 0x2105, 0x0000, 0x0000, 0x2012, 0x2039, 0x2024, 0x203a, 0x0000, /* 0x0ab8-0x0abf */
1004 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, /* 0x0ac0-0x0ac7 */
1005 0x0000, 0x2122, 0x2120, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25ad, /* 0x0ac8-0x0acf */
1006 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, /* 0x0ad0-0x0ad7 */
1007 0x0000, 0x271d, 0x0000, 0x220e, 0x25c2, 0x2023, 0x25cf, 0x25ac, /* 0x0ad8-0x0adf */
1008 0x25e6, 0x25ab, 0x25ae, 0x25b5, 0x25bf, 0x2606, 0x2022, 0x25aa, /* 0x0ae0-0x0ae7 */
1009 0x25b4, 0x25be, 0x261a, 0x261b, 0x2663, 0x2666, 0x2665, 0x0000, /* 0x0ae8-0x0aef */
1010 0x2720, 0x2020, 0x2021, 0x2713, 0x2612, 0x266f, 0x266d, 0x2642, /* 0x0af0-0x0af7 */
1011 0x2640, 0x2121, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e /* 0x0af8-0x0aff */
1012 };
1013
1014 /* none of the APL keysyms match the Unicode characters */
1015
1016 static unsigned short const keysym_to_unicode_cdf_cfa[] = {
1017 0x2017, /* 0x0cd8-0x0cdf */
1018 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, /* 0x0ce0-0x0ce7 */
1019 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, /* 0x0ce8-0x0cef */
1020 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, /* 0x0cf0-0x0cf7 */
1021 0x05e8, 0x05e9, 0x05ea /* 0x0cf8-0x0cff */
1022 };
1023
1024 static unsigned short const keysym_to_unicode_da1_df9[] = {
1025 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, /* 0x0da0-0x0da7 */
1026 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, /* 0x0da8-0x0daf */
1027 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, /* 0x0db0-0x0db7 */
1028 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, /* 0x0db8-0x0dbf */
1029 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, /* 0x0dc0-0x0dc7 */
1030 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, /* 0x0dc8-0x0dcf */
1031 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, /* 0x0dd0-0x0dd7 */
1032 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0e3e, 0x0e3f, /* 0x0dd8-0x0ddf */
1033 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, /* 0x0de0-0x0de7 */
1034 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, /* 0x0de8-0x0def */
1035 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, /* 0x0df0-0x0df7 */
1036 0x0e58, 0x0e59 /* 0x0df8-0x0dff */
1037 };
1038
1039 static unsigned short const keysym_to_unicode_ea0_eff[] = {
1040 0x0000, 0x1101, 0x1101, 0x11aa, 0x1102, 0x11ac, 0x11ad, 0x1103, /* 0x0ea0-0x0ea7 */
1041 0x1104, 0x1105, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, /* 0x0ea8-0x0eaf */
1042 0x11b6, 0x1106, 0x1107, 0x1108, 0x11b9, 0x1109, 0x110a, 0x110b, /* 0x0eb0-0x0eb7 */
1043 0x110c, 0x110d, 0x110e, 0x110f, 0x1110, 0x1111, 0x1112, 0x1161, /* 0x0eb8-0x0ebf */
1044 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, /* 0x0ec0-0x0ec7 */
1045 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f, 0x1170, 0x1171, /* 0x0ec8-0x0ecf */
1046 0x1172, 0x1173, 0x1174, 0x1175, 0x11a8, 0x11a9, 0x11aa, 0x11ab, /* 0x0ed0-0x0ed7 */
1047 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, /* 0x0ed8-0x0edf */
1048 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, /* 0x0ee0-0x0ee7 */
1049 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x0000, /* 0x0ee8-0x0eef */
1050 0x0000, 0x0000, 0x1140, 0x0000, 0x0000, 0x1159, 0x119e, 0x0000, /* 0x0ef0-0x0ef7 */
1051 0x11eb, 0x0000, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9, /* 0x0ef8-0x0eff */
1052 };
1053
1054 static unsigned short keysym_to_unicode_12a1_12fe[] = {
1055 0x1e02, 0x1e03, 0x0000, 0x0000, 0x0000, 0x1e0a, 0x0000, /* 0x12a0-0x12a7 */
1056 0x1e80, 0x0000, 0x1e82, 0x1e0b, 0x1ef2, 0x0000, 0x0000, 0x0000, /* 0x12a8-0x12af */
1057 0x1e1e, 0x1e1f, 0x0000, 0x0000, 0x1e40, 0x1e41, 0x0000, 0x1e56, /* 0x12b0-0x12b7 */
1058 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, /* 0x12b8-0x12bf */
1059 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c0-0x12c7 */
1060 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c8-0x12cf */
1061 0x0174, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6a, /* 0x12d0-0x12d7 */
1062 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0176, 0x0000, /* 0x12d8-0x12df */
1063 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e0-0x12e7 */
1064 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e8-0x12ef */
1065 0x0175, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6b, /* 0x12f0-0x12f7 */
1066 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0177 /* 0x12f0-0x12ff */
1067 };
1068
1069 static unsigned short const keysym_to_unicode_13bc_13be[] = {
1070 0x0152, 0x0153, 0x0178 /* 0x13b8-0x13bf */
1071 };
1072
1073 static unsigned short keysym_to_unicode_14a1_14ff[] = {
1074 0x2741, 0x00a7, 0x0589, 0x0029, 0x0028, 0x00bb, 0x00ab, /* 0x14a0-0x14a7 */
1075 0x2014, 0x002e, 0x055d, 0x002c, 0x2013, 0x058a, 0x2026, 0x055c, /* 0x14a8-0x14af */
1076 0x055b, 0x055e, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, /* 0x14b0-0x14b7 */
1077 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, /* 0x14b8-0x14bf */
1078 0x0538, 0x0568, 0x0539, 0x0569, 0x053a, 0x056a, 0x053b, 0x056b, /* 0x14c0-0x14c7 */
1079 0x053c, 0x056c, 0x053d, 0x056d, 0x053e, 0x056e, 0x053f, 0x056f, /* 0x14c8-0x14cf */
1080 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, /* 0x14d0-0x14d7 */
1081 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, /* 0x14d8-0x14df */
1082 0x0548, 0x0578, 0x0549, 0x0579, 0x054a, 0x057a, 0x054b, 0x057b, /* 0x14e0-0x14e7 */
1083 0x054c, 0x057c, 0x054d, 0x057d, 0x054e, 0x057e, 0x054f, 0x057f, /* 0x14e8-0x14ef */
1084 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, /* 0x14f0-0x14f7 */
1085 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x2019, 0x0027, /* 0x14f8-0x14ff */
1086 };
1087
1088 static unsigned short keysym_to_unicode_15d0_15f6[] = {
1089 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, /* 0x15d0-0x15d7 */
1090 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, /* 0x15d8-0x15df */
1091 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, /* 0x15e0-0x15e7 */
1092 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, /* 0x15e8-0x15ef */
1093 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6 /* 0x15f0-0x15f7 */
1094 };
1095
1096 static unsigned short keysym_to_unicode_16a0_16f6[] = {
1097 0x0000, 0x0000, 0xf0a2, 0x1e8a, 0x0000, 0xf0a5, 0x012c, 0xf0a7, /* 0x16a0-0x16a7 */
1098 0xf0a8, 0x01b5, 0x01e6, 0x0000, 0x0000, 0x0000, 0x0000, 0x019f, /* 0x16a8-0x16af */
1099 0x0000, 0x0000, 0xf0b2, 0x1e8b, 0x01d1, 0xf0b5, 0x012d, 0xf0b7, /* 0x16b0-0x16b7 */
1100 0xf0b8, 0x01b6, 0x01e7, 0x0000, 0x0000, 0x01d2, 0x0000, 0x0275, /* 0x16b8-0x16bf */
1101 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018f, 0x0000, /* 0x16c0-0x16c7 */
1102 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16c8-0x16cf */
1103 0x0000, 0x1e36, 0xf0d2, 0xf0d3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d0-0x16d7 */
1104 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d8-0x16df */
1105 0x0000, 0x1e37, 0xf0e2, 0xf0e3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e0-0x16e7 */
1106 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e8-0x16ef */
1107 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259 /* 0x16f0-0x16f6 */
1108 };
1109
1110 static unsigned short const keysym_to_unicode_1e9f_1eff[] = {
1111 0x0303,
1112 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, /* 0x1ea0-0x1ea7 */
1113 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, /* 0x1ea8-0x1eaf */
1114 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, /* 0x1eb0-0x1eb7 */
1115 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, /* 0x1eb8-0x1ebf */
1116 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, /* 0x1ec0-0x1ec7 */
1117 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, /* 0x1ec8-0x1ecf */
1118 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, /* 0x1ed0-0x1ed7 */
1119 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, /* 0x1ed8-0x1edf */
1120 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, /* 0x1ee0-0x1ee7 */
1121 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, /* 0x1ee8-0x1eef */
1122 0x1ef0, 0x1ef1, 0x0300, 0x0301, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, /* 0x1ef0-0x1ef7 */
1123 0x1ef8, 0x1ef9, 0x01a0, 0x01a1, 0x01af, 0x01b0, 0x0309, 0x0323 /* 0x1ef8-0x1eff */
1124 };
1125
1126 static unsigned short const keysym_to_unicode_20a0_20ac[] = {
1127 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7, /* 0x20a0-0x20a7 */
1128 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */
1129 };
1130
1131 static unsigned int
KeySymToUcs4(KeySym keysym)1132 KeySymToUcs4(KeySym keysym)
1133 {
1134 /* 'Unicode keysym' */
1135 if ((keysym & 0xff000000) == 0x01000000)
1136 return (keysym & 0x00ffffff);
1137
1138 if (keysym > 0 && keysym < 0x100)
1139 return keysym;
1140 else if (keysym > 0x1a0 && keysym < 0x200)
1141 return keysym_to_unicode_1a1_1ff[keysym - 0x1a1];
1142 else if (keysym > 0x2a0 && keysym < 0x2ff)
1143 return keysym_to_unicode_2a1_2fe[keysym - 0x2a1];
1144 else if (keysym > 0x3a1 && keysym < 0x3ff)
1145 return keysym_to_unicode_3a2_3fe[keysym - 0x3a2];
1146 else if (keysym > 0x4a0 && keysym < 0x4e0)
1147 return keysym_to_unicode_4a1_4df[keysym - 0x4a1];
1148 else if (keysym > 0x589 && keysym < 0x5ff)
1149 return keysym_to_unicode_590_5fe[keysym - 0x590];
1150 else if (keysym > 0x67f && keysym < 0x700)
1151 return keysym_to_unicode_680_6ff[keysym - 0x680];
1152 else if (keysym > 0x7a0 && keysym < 0x7fa)
1153 return keysym_to_unicode_7a1_7f9[keysym - 0x7a1];
1154 else if (keysym > 0x8a3 && keysym < 0x8ff)
1155 return keysym_to_unicode_8a4_8fe[keysym - 0x8a4];
1156 else if (keysym > 0x9de && keysym < 0x9f9)
1157 return keysym_to_unicode_9df_9f8[keysym - 0x9df];
1158 else if (keysym > 0xaa0 && keysym < 0xaff)
1159 return keysym_to_unicode_aa1_afe[keysym - 0xaa1];
1160 else if (keysym > 0xcde && keysym < 0xcfb)
1161 return keysym_to_unicode_cdf_cfa[keysym - 0xcdf];
1162 else if (keysym > 0xda0 && keysym < 0xdfa)
1163 return keysym_to_unicode_da1_df9[keysym - 0xda1];
1164 else if (keysym > 0xe9f && keysym < 0xf00)
1165 return keysym_to_unicode_ea0_eff[keysym - 0xea0];
1166 else if (keysym > 0x12a0 && keysym < 0x12ff)
1167 return keysym_to_unicode_12a1_12fe[keysym - 0x12a1];
1168 else if (keysym > 0x13bb && keysym < 0x13bf)
1169 return keysym_to_unicode_13bc_13be[keysym - 0x13bc];
1170 else if (keysym > 0x14a0 && keysym < 0x1500)
1171 return keysym_to_unicode_14a1_14ff[keysym - 0x14a1];
1172 else if (keysym > 0x15cf && keysym < 0x15f7)
1173 return keysym_to_unicode_15d0_15f6[keysym - 0x15d0];
1174 else if (keysym > 0x169f && keysym < 0x16f7)
1175 return keysym_to_unicode_16a0_16f6[keysym - 0x16a0];
1176 else if (keysym > 0x1e9e && keysym < 0x1f00)
1177 return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f];
1178 else if (keysym > 0x209f && keysym < 0x20ad)
1179 return keysym_to_unicode_20a0_20ac[keysym - 0x20a0];
1180 else
1181 return 0;
1182 }
1183
compose_handle_key(GdkEventKey * event,IMUIMContext * uic)1184 int compose_handle_key(GdkEventKey *event, IMUIMContext *uic)
1185 {
1186 unsigned int keysym, mod;
1187 int is_push, rv;
1188
1189 keysym = event->keyval;
1190 mod = event->state;
1191 is_push = event->type == GDK_KEY_PRESS ? 1 : 0;
1192 rv = handleKey(keysym, mod, is_push, uic);
1193
1194 return rv ? 0 : 1;
1195 }
1196 #endif /* GDK_WINDOWING_X11 */
1197
1198 /*
1199 * Local variables:
1200 * c-indent-level: 4
1201 * c-basic-offset: 4
1202 * End:
1203 */
1204