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