imLcIm.c revision 2d67cb4f
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 = Xcalloc (1, 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 b->mb[0] = 0; 461 b->wc[0] = 0; 462 b->utf8[0] = 0; 463 464 m = Xcalloc (1, msize); 465 m->id = XIM_CACHE_MAGIC; 466 m->version = XIM_CACHE_VERSION; 467 m->top = im->private.local.top; 468 m->treeused = b->treeused; 469 m->mbused = b->mbused; 470 m->wcused = b->wcused; 471 m->utf8used = b->utf8used; 472 /* Tree first, then wide chars, then the rest due to alignment */ 473 m->tree = msize; 474 m->wc = msize + sizeof (DefTree) * m->treeused; 475 m->mb = m->wc + sizeof (wchar_t) * m->wcused; 476 m->utf8 = m->mb + m->mbused; 477 m->size = m->utf8 + m->utf8used; 478 strcpy (m->fname, name); 479 strcpy (m->fname+strlen(name)+1, encoding); 480 481 /* This STILL might be racy on NFS */ 482 if ( (fd = _XOpenFileMode (cachename, O_WRONLY | O_CREAT | O_EXCL, 483 0600)) < 0) { 484 Xfree(m); 485 return; 486 } 487 if (! (fp = fdopen (fd, "wb")) ) { 488 close (fd); 489 Xfree(m); 490 return; 491 } 492 fwrite (m, msize, 1, fp); 493 fwrite (im->private.local.base.tree, sizeof(DefTree), m->treeused, fp); 494 fwrite (im->private.local.base.wc, sizeof(wchar_t), m->wcused, fp); 495 fwrite (im->private.local.base.mb, 1, m->mbused, fp); 496 fwrite (im->private.local.base.utf8, 1, m->utf8used, fp); 497 if (fclose (fp) != 0) 498 unlink (cachename); 499 _XimCache_mmap = m; 500 memcpy (&_XimCachedDefaultTreeBase, &im->private.local.base, 501 sizeof (_XimCachedDefaultTreeBase)); 502/* fprintf (stderr, "wrote tree %s size %ld to %s\n", name, m->size, cachename); */ 503} 504 505#endif 506 507 508static void 509_XimCreateDefaultTree( 510 Xim im) 511{ 512 FILE *fp = NULL; 513 char *name, *tmpname = NULL, *intname; 514 char *cachename = NULL; 515 /* Should use getpwent() instead of $HOME (cross-platform?) */ 516 char *home = getenv("HOME"); 517 char *cachedir = NULL; 518 char *tmpcachedir = NULL; 519 int hl = home ? strlen (home) : 0; 520#ifdef COMPOSECACHE 521 const char *encoding = nl_langinfo (CODESET); 522 uid_t euid = geteuid (); 523 gid_t egid = getegid (); 524 int cachefd = -1; 525 off_t size; 526#endif 527 528 name = getenv("XCOMPOSEFILE"); 529 if (name == (char *) NULL) { 530 if (home != (char *) NULL) { 531 tmpname = name = Xmalloc(hl + 10 + 1); 532 if (name != (char *) NULL) { 533 int fd; 534 strcpy(name, home); 535 strcpy(name + hl, "/.XCompose"); 536 if ( (fd = _XOpenFile (name, O_RDONLY)) < 0) { 537 Xfree (name); 538 name = tmpname = NULL; 539 } else 540 close (fd); 541 } 542 } 543 } 544 545 if (name == (char *) NULL) { 546 tmpname = name = _XlcFileName(im->core.lcd, COMPOSE_FILE); 547 } 548 intname = name; 549 550#ifdef COMPOSECACHE 551 if (getuid () == euid && getgid () == egid && euid != 0) { 552 char *c; 553 /* Usage: XCOMPOSECACHE=<cachedir>[=<filename>] 554 * cachedir: directory of cache files 555 * filename: internally used name for cache file */ 556 cachedir = getenv("XCOMPOSECACHE"); 557 if (cachedir && (c = strchr (cachedir, '='))) { 558 tmpcachedir = strdup (cachedir); 559 intname = tmpcachedir + (c-cachedir) + 1; 560 tmpcachedir[c-cachedir] = '\0'; 561 cachedir = tmpcachedir; 562 } 563 } 564 565 if (! cachedir) { 566 cachefd = _XimCachedFileName (XIM_GLOBAL_CACHE_DIR, name, intname, 567 encoding, 0, 1, &cachename, &size); 568 if (cachefd != -1) { 569 if (_XimLoadCache (cachefd, intname, encoding, size, im)) { 570 Xfree (tmpcachedir); 571 Xfree (tmpname); 572 Xfree (cachename); 573 close (cachefd); 574 return; 575 } 576 close (cachefd); 577 } 578 Xfree (cachename); 579 cachename = NULL; 580 } 581 582 if (getuid () == euid && getgid () == egid && euid != 0 && home) { 583 584 if (! cachedir) { 585 tmpcachedir = cachedir = Xmalloc (hl+strlen(XIM_HOME_CACHE_DIR)+1); 586 strcpy (cachedir, home); 587 strcat (cachedir, XIM_HOME_CACHE_DIR); 588 } 589 cachefd = _XimCachedFileName (cachedir, name, intname, encoding, 590 euid, 0, &cachename, &size); 591 if (cachefd != -1) { 592 if (_XimLoadCache (cachefd, intname, encoding, size, im)) { 593 Xfree (tmpcachedir); 594 Xfree (tmpname); 595 Xfree (cachename); 596 close (cachefd); 597 return; 598 } 599 close (cachefd); 600 } 601 } 602#endif 603 604 if (! (fp = _XFopenFile (name, "r"))) { 605 Xfree (tmpcachedir); 606 Xfree (tmpname); 607 Xfree (cachename); 608 return; 609 } 610 _XimParseStringFile(fp, im); 611 fclose(fp); 612 613#ifdef COMPOSECACHE 614 if (cachename) { 615 assert (euid != 0); 616 _XimWriteCachedDefaultTree (intname, encoding, cachename, im); 617 } 618#endif 619 620 Xfree (tmpcachedir); 621 Xfree (tmpname); 622 Xfree (cachename); 623} 624 625static XIMMethodsRec Xim_im_local_methods = { 626 _XimLocalCloseIM, /* close */ 627 _XimLocalSetIMValues, /* set_values */ 628 _XimLocalGetIMValues, /* get_values */ 629 _XimLocalCreateIC, /* create_ic */ 630 _XimLcctstombs, /* ctstombs */ 631 _XimLcctstowcs, /* ctstowcs */ 632 _XimLcctstoutf8 /* ctstoutf8 */ 633}; 634 635Bool 636_XimLocalOpenIM( 637 Xim im) 638{ 639 XLCd lcd = im->core.lcd; 640 XlcConv conv; 641 XimDefIMValues im_values; 642 XimLocalPrivateRec* private = &im->private.local; 643 644 _XimInitialResourceInfo(); 645 if(_XimSetIMResourceList(&im->core.im_resources, 646 &im->core.im_num_resources) == False) { 647 goto Open_Error; 648 } 649 if(_XimSetICResourceList(&im->core.ic_resources, 650 &im->core.ic_num_resources) == False) { 651 goto Open_Error; 652 } 653 654 _XimSetIMMode(im->core.im_resources, im->core.im_num_resources); 655 656 _XimGetCurrentIMValues(im, &im_values); 657 if(_XimSetLocalIMDefaults(im, (XPointer)&im_values, 658 im->core.im_resources, im->core.im_num_resources) == False) { 659 goto Open_Error; 660 } 661 _XimSetCurrentIMValues(im, &im_values); 662 663 if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNMultiByte))) 664 goto Open_Error; 665 private->ctom_conv = conv; 666 667 if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNWideChar))) 668 goto Open_Error; 669 private->ctow_conv = conv; 670 671 if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNUtf8String))) 672 goto Open_Error; 673 private->ctoutf8_conv = conv; 674 675 if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte))) 676 goto Open_Error; 677 private->cstomb_conv = conv; 678 679 if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNWideChar))) 680 goto Open_Error; 681 private->cstowc_conv = conv; 682 683 if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNUtf8String))) 684 goto Open_Error; 685 private->cstoutf8_conv = conv; 686 687 if (!(conv = _XlcOpenConverter(lcd, XlcNUcsChar, lcd, XlcNChar))) 688 goto Open_Error; 689 private->ucstoc_conv = conv; 690 691 if (!(conv = _XlcOpenConverter(lcd, XlcNUcsChar, lcd, XlcNUtf8String))) 692 goto Open_Error; 693 private->ucstoutf8_conv = conv; 694 695 private->base.treeused = 1; 696 private->base.mbused = 1; 697 private->base.wcused = 1; 698 private->base.utf8used = 1; 699 700 _XimCreateDefaultTree(im); 701 702 im->methods = &Xim_im_local_methods; 703 private->current_ic = (XIC)NULL; 704 705 return(True); 706 707Open_Error : 708 _XimLocalIMFree(im); 709 return(False); 710} 711