imLcIm.c revision 0f8248bf
1/****************************************************************** 2 3 Copyright 1992, 1993, 1994 by FUJITSU LIMITED 4 Copyright 1993 by Digital Equipment Corporation 5 6Permission to use, copy, modify, distribute, and sell this software 7and its documentation for any purpose is hereby granted without fee, 8provided that the above copyright notice appear in all copies and that 9both that copyright notice and this permission notice appear in 10supporting documentation, and that the name of FUJITSU LIMITED and 11Digital Equipment Corporation not be used in advertising or publicity 12pertaining to distribution of the software without specific, written 13prior permission. FUJITSU LIMITED and Digital Equipment Corporation 14makes no representations about the suitability of this software for 15any purpose. It is provided "as is" without express or implied 16warranty. 17 18FUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION DISCLAIM ALL 19WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED 20WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 21FUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR 22ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 23WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 24IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 25ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 26THIS SOFTWARE. 27 28 Author: Takashi Fujiwara FUJITSU LIMITED 29 fujiwara@a80.tech.yk.fujitsu.co.jp 30 Modifier: Franky Ling Digital Equipment Corporation 31 frankyling@hgrd01.enet.dec.com 32 33******************************************************************/ 34 35#ifdef HAVE_CONFIG_H 36#include <config.h> 37#endif 38#include <stdio.h> 39 40#include <X11/Xmd.h> 41#include <X11/Xatom.h> 42#include <X11/Xos.h> 43#include "Xlibint.h" 44#include "Xlcint.h" 45#include "XlcPublic.h" 46#include "XlcPubI.h" 47#include "Ximint.h" 48#include <ctype.h> 49#include <assert.h> 50 51#ifdef COMPOSECACHE 52# include <sys/types.h> 53# include <sys/stat.h> 54# include <sys/mman.h> 55# include <langinfo.h> 56#endif 57 58 59#ifdef COMPOSECACHE 60 61/* include trailing '/' for cache directory, file prefix otherwise */ 62#define XIM_GLOBAL_CACHE_DIR "/var/cache/libx11/compose/" 63#define XIM_HOME_CACHE_DIR "/.compose-cache/" 64#define XIM_CACHE_MAGIC ('X' | 'i'<<8 | 'm'<<16 | 'C'<<24) 65#define XIM_CACHE_VERSION 4 66#define XIM_CACHE_TREE_ALIGNMENT 4 67 68#define XIM_HASH_PRIME_1 13 69#define XIM_HASH_PRIME_2 1234096939 70 71typedef INT32 DTStructIndex; 72struct _XimCacheStruct { 73 INT32 id; 74 INT32 version; 75 DTStructIndex tree; 76 DTStructIndex mb; 77 DTStructIndex wc; 78 DTStructIndex utf8; 79 DTStructIndex size; 80 DTIndex top; 81 DTIndex treeused; 82 DTCharIndex mbused; 83 DTCharIndex wcused; 84 DTCharIndex utf8used; 85 char fname[1]; 86 /* char encoding[1] */ 87}; 88 89static struct _XimCacheStruct* _XimCache_mmap = NULL; 90static DefTreeBase _XimCachedDefaultTreeBase; 91static int _XimCachedDefaultTreeRefcount = 0; 92 93#endif 94 95 96Bool 97_XimCheckIfLocalProcessing(Xim im) 98{ 99 FILE *fp; 100 char *name; 101 102 if(strcmp(im->core.im_name, "") == 0) { 103 name = _XlcFileName(im->core.lcd, COMPOSE_FILE); 104 if (name != (char *)NULL) { 105 fp = _XFopenFile (name, "r"); 106 Xfree(name); 107 if (fp != (FILE *)NULL) { 108 fclose(fp); 109 return(True); 110 } 111 } 112 return(False); 113 } else if(strcmp(im->core.im_name, "local") == 0 || 114 strcmp(im->core.im_name, "none" ) == 0 ) { 115 return(True); 116 } 117 return(False); 118} 119 120static void 121XimFreeDefaultTree( 122 DefTreeBase *b) 123{ 124 if (!b) return; 125 if (b->tree == NULL) return; 126#ifdef COMPOSECACHE 127 if (b->tree == _XimCachedDefaultTreeBase.tree) { 128 _XimCachedDefaultTreeRefcount--; 129 /* No deleting, it's a cache after all. */ 130 return; 131 } 132#endif 133 Xfree (b->tree); 134 b->tree = NULL; 135 Xfree (b->mb); 136 b->mb = NULL; 137 Xfree (b->wc); 138 b->wc = NULL; 139 Xfree (b->utf8); 140 b->utf8 = NULL; 141 142 b->treeused = b->treesize = 0; 143 b->mbused = b->mbsize = 0; 144 b->wcused = b->wcsize = 0; 145 b->utf8used = b->utf8size = 0; 146} 147 148void 149_XimLocalIMFree( 150 Xim im) 151{ 152 XimFreeDefaultTree(&im->private.local.base); 153 im->private.local.top = 0; 154 155 Xfree(im->core.im_resources); 156 im->core.im_resources = NULL; 157 158 Xfree(im->core.ic_resources); 159 im->core.ic_resources = NULL; 160 161 Xfree(im->core.im_values_list); 162 im->core.im_values_list = NULL; 163 164 Xfree(im->core.ic_values_list); 165 im->core.ic_values_list = NULL; 166 167 Xfree(im->core.styles); 168 im->core.styles = NULL; 169 170 Xfree(im->core.res_name); 171 im->core.res_name = NULL; 172 173 Xfree(im->core.res_class); 174 im->core.res_class = NULL; 175 176 Xfree(im->core.im_name); 177 im->core.im_name = NULL; 178 179 if (im->private.local.ctom_conv) { 180 _XlcCloseConverter(im->private.local.ctom_conv); 181 im->private.local.ctom_conv = NULL; 182 } 183 if (im->private.local.ctow_conv) { 184 _XlcCloseConverter(im->private.local.ctow_conv); 185 im->private.local.ctow_conv = NULL; 186 } 187 if (im->private.local.ctoutf8_conv) { 188 _XlcCloseConverter(im->private.local.ctoutf8_conv); 189 im->private.local.ctoutf8_conv = NULL; 190 } 191 if (im->private.local.cstomb_conv) { 192 _XlcCloseConverter(im->private.local.cstomb_conv); 193 im->private.local.cstomb_conv = NULL; 194 } 195 if (im->private.local.cstowc_conv) { 196 _XlcCloseConverter(im->private.local.cstowc_conv); 197 im->private.local.cstowc_conv = NULL; 198 } 199 if (im->private.local.cstoutf8_conv) { 200 _XlcCloseConverter(im->private.local.cstoutf8_conv); 201 im->private.local.cstoutf8_conv = NULL; 202 } 203 if (im->private.local.ucstoc_conv) { 204 _XlcCloseConverter(im->private.local.ucstoc_conv); 205 im->private.local.ucstoc_conv = NULL; 206 } 207 if (im->private.local.ucstoutf8_conv) { 208 _XlcCloseConverter(im->private.local.ucstoutf8_conv); 209 im->private.local.ucstoutf8_conv = NULL; 210 } 211 return; 212} 213 214static Status 215_XimLocalCloseIM( 216 XIM xim) 217{ 218 Xim im = (Xim)xim; 219 XIC ic; 220 XIC next; 221 222 ic = im->core.ic_chain; 223 im->core.ic_chain = NULL; 224 while (ic) { 225 (*ic->methods->destroy) (ic); 226 next = ic->core.next; 227 Xfree (ic); 228 ic = next; 229 } 230 _XimLocalIMFree(im); 231 _XimDestroyIMStructureList(im); 232 return(True); 233} 234 235char * 236_XimLocalGetIMValues( 237 XIM xim, 238 XIMArg *values) 239{ 240 Xim im = (Xim)xim; 241 XimDefIMValues im_values; 242 243 _XimGetCurrentIMValues(im, &im_values); 244 return(_XimGetIMValueData(im, (XPointer)&im_values, values, 245 im->core.im_resources, im->core.im_num_resources)); 246} 247 248char * 249_XimLocalSetIMValues( 250 XIM xim, 251 XIMArg *values) 252{ 253 Xim im = (Xim)xim; 254 XimDefIMValues im_values; 255 char *name = (char *)NULL; 256 257 _XimGetCurrentIMValues(im, &im_values); 258 name = _XimSetIMValueData(im, (XPointer)&im_values, values, 259 im->core.im_resources, im->core.im_num_resources); 260 _XimSetCurrentIMValues(im, &im_values); 261 return(name); 262} 263 264 265#ifdef COMPOSECACHE 266 267static Bool 268_XimReadCachedDefaultTree( 269 int fd_cache, 270 const char *name, 271 const char *encoding, 272 DTStructIndex size) 273{ 274 struct _XimCacheStruct* m; 275 int namelen = strlen (name) + 1; 276 int encodinglen = strlen (encoding) + 1; 277 278 m = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd_cache, 0); 279 if (m == NULL || m == MAP_FAILED) 280 return False; 281 assert (m->id == XIM_CACHE_MAGIC); 282 assert (m->version == XIM_CACHE_VERSION); 283 if (size != m->size || 284 size < XOffsetOf (struct _XimCacheStruct, fname) + namelen + encodinglen) { 285 fprintf (stderr, "Ignoring broken XimCache %s [%s]\n", name, encoding); 286 munmap (m, size); 287 return False; 288 } 289 if (strncmp (name, m->fname, namelen) != 0) { 290 /* m->fname may *not* be terminated - but who cares here */ 291 fprintf (stderr, "Filename hash clash - expected %s, got %s\n", 292 name, m->fname); 293 munmap (m, size); 294 return False; 295 } 296 if (strncmp (encoding, m->fname + namelen, encodinglen) != 0) { 297 /* m->fname+namelen may *not* be terminated - but who cares here */ 298 fprintf (stderr, "Enoding hash clash - expected %s, got %s\n", 299 encoding, m->fname + namelen); 300 munmap (m, size); 301 return False; 302 } 303 _XimCache_mmap = m; 304 _XimCachedDefaultTreeBase.tree = (DefTree *) (((char *) m) + m->tree); 305 _XimCachedDefaultTreeBase.mb = (((char *) m) + m->mb); 306 _XimCachedDefaultTreeBase.wc = (wchar_t *) (((char *) m) + m->wc); 307 _XimCachedDefaultTreeBase.utf8 = (((char *) m) + m->utf8); 308 _XimCachedDefaultTreeBase.treeused = m->treeused; 309 _XimCachedDefaultTreeBase.mbused = m->mbused; 310 _XimCachedDefaultTreeBase.wcused = m->wcused; 311 _XimCachedDefaultTreeBase.utf8used = m->utf8used; 312 /* treesize etc. is ignored because only used during parsing */ 313 _XimCachedDefaultTreeRefcount = 0; 314/* fprintf (stderr, "read cached tree at %p: %s\n", (void *) m, name); */ 315 return True; 316} 317 318static unsigned int strToHash ( 319 const char *name) 320{ 321 unsigned int hash = 0; 322 while (*name) 323 hash = hash * XIM_HASH_PRIME_1 + *(unsigned const char *)name++; 324 return hash % XIM_HASH_PRIME_2; 325} 326 327 328/* Returns read-only fd of cache file, -1 if none. 329 * Sets *res to cache filename if safe. Sets *size to file size of cache. */ 330static int _XimCachedFileName ( 331 const char *dir, const char *name, 332 const char *intname, const char *encoding, 333 uid_t uid, int isglobal, char **res, off_t *size) 334{ 335 struct stat st_name, st; 336 int fd; 337 unsigned int len, hash, hash2; 338 struct _XimCacheStruct *m; 339 /* There are some races here with 'dir', but we are either in our own home 340 * or the global cache dir, and not inside some public writable dir */ 341/* fprintf (stderr, "XimCachedFileName for dir %s name %s intname %s encoding %s uid %d\n", dir, name, intname, encoding, uid); */ 342 if (stat (name, &st_name) == -1 || ! S_ISREG (st_name.st_mode) 343 || stat (dir, &st) == -1 || ! S_ISDIR (st.st_mode) || st.st_uid != uid 344 || (st.st_mode & 0022) != 0000) { 345 *res = NULL; 346 return -1; 347 } 348 len = strlen (dir); 349 hash = strToHash (intname); 350 hash2 = strToHash (encoding); 351 *res = Xmalloc (len + 1 + 27 + 1); /* Max VERSION 9999 */ 352 353 if (len == 0 || dir [len-1] != '/') 354 sprintf (*res, "%s/%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(), 355 XIM_CACHE_VERSION, (unsigned int)sizeof (DefTree), hash, hash2); 356 else 357 sprintf (*res, "%s%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(), 358 XIM_CACHE_VERSION, (unsigned int)sizeof (DefTree), hash, hash2); 359 360/* fprintf (stderr, "-> %s\n", *res); */ 361 if ( (fd = _XOpenFile (*res, O_RDONLY)) == -1) 362 return -1; 363 364 if (fstat (fd, &st) == -1) { 365 Xfree (*res); 366 *res = NULL; 367 close (fd); 368 return -1; 369 } 370 *size = st.st_size; 371 372 if (! S_ISREG (st.st_mode) || st.st_uid != uid 373 || (st.st_mode & 0022) != 0000 || st.st_mtime <= st_name.st_mtime 374 || (st.st_mtime < time (NULL) - 24*60*60 && ! isglobal)) { 375 376 close (fd); 377 if (unlink (*res) != 0) { 378 Xfree (*res); 379 *res = NULL; /* cache is not safe */ 380 } 381 return -1; 382 } 383 384 m = mmap (NULL, sizeof (struct _XimCacheStruct), PROT_READ, MAP_PRIVATE, 385 fd, 0); 386 if (m == NULL || m == MAP_FAILED) { 387 close (fd); 388 Xfree (*res); 389 *res = NULL; 390 return -1; 391 } 392 if (*size < sizeof (struct _XimCacheStruct) || m->id != XIM_CACHE_MAGIC) { 393 munmap (m, sizeof (struct _XimCacheStruct)); 394 close (fd); 395 fprintf (stderr, "Ignoring broken XimCache %s\n", *res); 396 Xfree (*res); 397 *res = NULL; 398 return -1; 399 } 400 if (m->version != XIM_CACHE_VERSION) { 401 munmap (m, sizeof (struct _XimCacheStruct)); 402 close (fd); 403 if (unlink (*res) != 0) { 404 Xfree (*res); 405 *res = NULL; /* cache is not safe */ 406 } 407 return -1; 408 } 409 munmap (m, sizeof (struct _XimCacheStruct)); 410 411 return fd; 412} 413 414 415static Bool _XimLoadCache ( 416 int fd, 417 const char *name, 418 const char *encoding, 419 off_t size, 420 Xim im) 421{ 422 if (_XimCache_mmap || 423 _XimReadCachedDefaultTree (fd, name, encoding, size)) { 424 _XimCachedDefaultTreeRefcount++; 425 memcpy (&im->private.local.base, &_XimCachedDefaultTreeBase, 426 sizeof (_XimCachedDefaultTreeBase)); 427 im->private.local.top = _XimCache_mmap->top; 428 return True; 429 } 430 431 return False; 432} 433 434 435static void 436_XimWriteCachedDefaultTree( 437 const char *name, 438 const char *encoding, 439 const char *cachename, 440 Xim im) 441{ 442 int fd; 443 FILE *fp; 444 struct _XimCacheStruct *m; 445 int msize = (XOffsetOf(struct _XimCacheStruct, fname) 446 + strlen(name) + strlen(encoding) + 2 447 + XIM_CACHE_TREE_ALIGNMENT-1) & -XIM_CACHE_TREE_ALIGNMENT; 448 DefTreeBase *b = &im->private.local.base; 449 450 if (! b->tree && ! (b->tree = Xmalloc (sizeof(DefTree))) ) 451 return; 452 if (! b->mb && ! (b->mb = Xmalloc (1)) ) 453 return; 454 if (! b->wc && ! (b->wc = Xmalloc (sizeof(wchar_t))) ) 455 return; 456 if (! b->utf8 && ! (b->utf8 = Xmalloc (1)) ) 457 return; 458 459 /* First entry is always unused */ 460 memset (b->tree, 0, sizeof(DefTree)); 461 b->mb[0] = 0; 462 b->wc[0] = 0; 463 b->utf8[0] = 0; 464 465 m = Xmalloc (msize); 466 memset (m, 0, msize); 467 m->id = XIM_CACHE_MAGIC; 468 m->version = XIM_CACHE_VERSION; 469 m->top = im->private.local.top; 470 m->treeused = b->treeused; 471 m->mbused = b->mbused; 472 m->wcused = b->wcused; 473 m->utf8used = b->utf8used; 474 /* Tree first, then wide chars, then the rest due to alignment */ 475 m->tree = msize; 476 m->wc = msize + sizeof (DefTree) * m->treeused; 477 m->mb = m->wc + sizeof (wchar_t) * m->wcused; 478 m->utf8 = m->mb + m->mbused; 479 m->size = m->utf8 + m->utf8used; 480 strcpy (m->fname, name); 481 strcpy (m->fname+strlen(name)+1, encoding); 482 483 /* This STILL might be racy on NFS */ 484 if ( (fd = _XOpenFileMode (cachename, O_WRONLY | O_CREAT | O_EXCL, 485 0600)) < 0) { 486 Xfree(m); 487 return; 488 } 489 if (! (fp = fdopen (fd, "wb")) ) { 490 close (fd); 491 Xfree(m); 492 return; 493 } 494 fwrite (m, msize, 1, fp); 495 fwrite (im->private.local.base.tree, sizeof(DefTree), m->treeused, fp); 496 fwrite (im->private.local.base.wc, sizeof(wchar_t), m->wcused, fp); 497 fwrite (im->private.local.base.mb, 1, m->mbused, fp); 498 fwrite (im->private.local.base.utf8, 1, m->utf8used, fp); 499 if (fclose (fp) != 0) 500 unlink (cachename); 501 _XimCache_mmap = m; 502 memcpy (&_XimCachedDefaultTreeBase, &im->private.local.base, 503 sizeof (_XimCachedDefaultTreeBase)); 504/* fprintf (stderr, "wrote tree %s size %ld to %s\n", name, m->size, cachename); */ 505} 506 507#endif 508 509 510static void 511_XimCreateDefaultTree( 512 Xim im) 513{ 514 FILE *fp = NULL; 515 char *name, *tmpname = NULL, *intname; 516 char *cachename = NULL; 517 /* Should use getpwent() instead of $HOME (cross-platform?) */ 518 char *home = getenv("HOME"); 519 char *cachedir = NULL; 520 char *tmpcachedir = NULL; 521 int hl = home ? strlen (home) : 0; 522#ifdef COMPOSECACHE 523 const char *encoding = nl_langinfo (CODESET); 524 uid_t euid = geteuid (); 525 gid_t egid = getegid (); 526 int cachefd = -1; 527 off_t size; 528#endif 529 530 name = getenv("XCOMPOSEFILE"); 531 if (name == (char *) NULL) { 532 if (home != (char *) NULL) { 533 tmpname = name = Xmalloc(hl + 10 + 1); 534 if (name != (char *) NULL) { 535 int fd; 536 strcpy(name, home); 537 strcpy(name + hl, "/.XCompose"); 538 if ( (fd = _XOpenFile (name, O_RDONLY)) < 0) { 539 Xfree (name); 540 name = tmpname = NULL; 541 } else 542 close (fd); 543 } 544 } 545 } 546 547 if (name == (char *) NULL) { 548 tmpname = name = _XlcFileName(im->core.lcd, COMPOSE_FILE); 549 } 550 intname = name; 551 552#ifdef COMPOSECACHE 553 if (getuid () == euid && getgid () == egid && euid != 0) { 554 char *c; 555 /* Usage: XCOMPOSECACHE=<cachedir>[=<filename>] 556 * cachedir: directory of cache files 557 * filename: internally used name for cache file */ 558 cachedir = getenv("XCOMPOSECACHE"); 559 if (cachedir && (c = strchr (cachedir, '='))) { 560 tmpcachedir = strdup (cachedir); 561 intname = tmpcachedir + (c-cachedir) + 1; 562 tmpcachedir[c-cachedir] = '\0'; 563 cachedir = tmpcachedir; 564 } 565 } 566 567 if (! cachedir) { 568 cachefd = _XimCachedFileName (XIM_GLOBAL_CACHE_DIR, name, intname, 569 encoding, 0, 1, &cachename, &size); 570 if (cachefd != -1) { 571 if (_XimLoadCache (cachefd, intname, encoding, size, im)) { 572 Xfree (tmpcachedir); 573 Xfree (tmpname); 574 Xfree (cachename); 575 close (cachefd); 576 return; 577 } 578 close (cachefd); 579 } 580 Xfree (cachename); 581 cachename = NULL; 582 } 583 584 if (getuid () == euid && getgid () == egid && euid != 0 && home) { 585 586 if (! cachedir) { 587 tmpcachedir = cachedir = Xmalloc (hl+strlen(XIM_HOME_CACHE_DIR)+1); 588 strcpy (cachedir, home); 589 strcat (cachedir, XIM_HOME_CACHE_DIR); 590 } 591 cachefd = _XimCachedFileName (cachedir, name, intname, encoding, 592 euid, 0, &cachename, &size); 593 if (cachefd != -1) { 594 if (_XimLoadCache (cachefd, intname, encoding, size, im)) { 595 Xfree (tmpcachedir); 596 Xfree (tmpname); 597 Xfree (cachename); 598 close (cachefd); 599 return; 600 } 601 close (cachefd); 602 } 603 } 604#endif 605 606 if (! (fp = _XFopenFile (name, "r"))) { 607 Xfree (tmpcachedir); 608 Xfree (tmpname); 609 Xfree (cachename); 610 return; 611 } 612 _XimParseStringFile(fp, im); 613 fclose(fp); 614 615#ifdef COMPOSECACHE 616 if (cachename) { 617 assert (euid != 0); 618 _XimWriteCachedDefaultTree (intname, encoding, cachename, im); 619 } 620#endif 621 622 Xfree (tmpcachedir); 623 Xfree (tmpname); 624 Xfree (cachename); 625} 626 627static XIMMethodsRec Xim_im_local_methods = { 628 _XimLocalCloseIM, /* close */ 629 _XimLocalSetIMValues, /* set_values */ 630 _XimLocalGetIMValues, /* get_values */ 631 _XimLocalCreateIC, /* create_ic */ 632 _XimLcctstombs, /* ctstombs */ 633 _XimLcctstowcs, /* ctstowcs */ 634 _XimLcctstoutf8 /* ctstoutf8 */ 635}; 636 637Bool 638_XimLocalOpenIM( 639 Xim im) 640{ 641 XLCd lcd = im->core.lcd; 642 XlcConv conv; 643 XimDefIMValues im_values; 644 XimLocalPrivateRec* private = &im->private.local; 645 646 _XimInitialResourceInfo(); 647 if(_XimSetIMResourceList(&im->core.im_resources, 648 &im->core.im_num_resources) == False) { 649 goto Open_Error; 650 } 651 if(_XimSetICResourceList(&im->core.ic_resources, 652 &im->core.ic_num_resources) == False) { 653 goto Open_Error; 654 } 655 656 _XimSetIMMode(im->core.im_resources, im->core.im_num_resources); 657 658 _XimGetCurrentIMValues(im, &im_values); 659 if(_XimSetLocalIMDefaults(im, (XPointer)&im_values, 660 im->core.im_resources, im->core.im_num_resources) == False) { 661 goto Open_Error; 662 } 663 _XimSetCurrentIMValues(im, &im_values); 664 665 if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNMultiByte))) 666 goto Open_Error; 667 private->ctom_conv = conv; 668 669 if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNWideChar))) 670 goto Open_Error; 671 private->ctow_conv = conv; 672 673 if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNUtf8String))) 674 goto Open_Error; 675 private->ctoutf8_conv = conv; 676 677 if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte))) 678 goto Open_Error; 679 private->cstomb_conv = conv; 680 681 if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNWideChar))) 682 goto Open_Error; 683 private->cstowc_conv = conv; 684 685 if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNUtf8String))) 686 goto Open_Error; 687 private->cstoutf8_conv = conv; 688 689 if (!(conv = _XlcOpenConverter(lcd, XlcNUcsChar, lcd, XlcNChar))) 690 goto Open_Error; 691 private->ucstoc_conv = conv; 692 693 if (!(conv = _XlcOpenConverter(lcd, XlcNUcsChar, lcd, XlcNUtf8String))) 694 goto Open_Error; 695 private->ucstoutf8_conv = conv; 696 697 private->base.treeused = 1; 698 private->base.mbused = 1; 699 private->base.wcused = 1; 700 private->base.utf8used = 1; 701 702 _XimCreateDefaultTree(im); 703 704 im->methods = &Xim_im_local_methods; 705 private->current_ic = (XIC)NULL; 706 707 return(True); 708 709Open_Error : 710 _XimLocalIMFree(im); 711 return(False); 712} 713