imLcIm.c revision 61b2299d
11ab64890Smrg/* $Xorg: imLcIm.c,v 1.3 2000/08/17 19:45:14 cpqbld Exp $ */
21ab64890Smrg/******************************************************************
31ab64890Smrg
41ab64890Smrg          Copyright 1992, 1993, 1994 by FUJITSU LIMITED
51ab64890Smrg          Copyright 1993 by Digital Equipment Corporation
61ab64890Smrg
71ab64890SmrgPermission to use, copy, modify, distribute, and sell this software
81ab64890Smrgand its documentation for any purpose is hereby granted without fee,
91ab64890Smrgprovided that the above copyright notice appear in all copies and that
101ab64890Smrgboth that copyright notice and this permission notice appear in
111ab64890Smrgsupporting documentation, and that the name of FUJITSU LIMITED and
121ab64890SmrgDigital Equipment Corporation not be used in advertising or publicity
131ab64890Smrgpertaining to distribution of the software without specific, written
141ab64890Smrgprior permission.  FUJITSU LIMITED and Digital Equipment Corporation
151ab64890Smrgmakes no representations about the suitability of this software for
161ab64890Smrgany purpose.  It is provided "as is" without express or implied
171ab64890Smrgwarranty.
181ab64890Smrg
1961b2299dSmrgFUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION DISCLAIM ALL
2061b2299dSmrgWARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
2161b2299dSmrgWARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2261b2299dSmrgFUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR
2361b2299dSmrgANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2461b2299dSmrgWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2561b2299dSmrgIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2661b2299dSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
271ab64890SmrgTHIS SOFTWARE.
281ab64890Smrg
2961b2299dSmrg  Author:    Takashi Fujiwara     FUJITSU LIMITED
301ab64890Smrg                               	  fujiwara@a80.tech.yk.fujitsu.co.jp
311ab64890Smrg  Modifier:  Franky Ling          Digital Equipment Corporation
321ab64890Smrg	                          frankyling@hgrd01.enet.dec.com
331ab64890Smrg
341ab64890Smrg******************************************************************/
351ab64890Smrg/* $XFree86: xc/lib/X11/imLcIm.c,v 1.12 2003/09/06 14:06:32 pascal Exp $ */
361ab64890Smrg
371ab64890Smrg#ifdef HAVE_CONFIG_H
381ab64890Smrg#include <config.h>
391ab64890Smrg#endif
401ab64890Smrg#include <stdio.h>
411ab64890Smrg
421ab64890Smrg#include <X11/Xmd.h>
431ab64890Smrg#include <X11/Xatom.h>
441ab64890Smrg#include <X11/Xos.h>
451ab64890Smrg#include "Xlibint.h"
461ab64890Smrg#include "Xlcint.h"
471ab64890Smrg#include "XlcPublic.h"
481ab64890Smrg#include "XlcPubI.h"
491ab64890Smrg#include "Ximint.h"
501ab64890Smrg#include <ctype.h>
511ab64890Smrg#include <assert.h>
521ab64890Smrg
531ab64890Smrg#ifdef COMPOSECACHE
541ab64890Smrg#  include <sys/types.h>
551ab64890Smrg#  include <sys/stat.h>
561ab64890Smrg#  include <sys/mman.h>
571ab64890Smrg#  include <langinfo.h>
581ab64890Smrg#endif
591ab64890Smrg
601ab64890Smrg
611ab64890Smrg#ifdef COMPOSECACHE
621ab64890Smrg
631ab64890Smrg/* include trailing '/' for cache directory, file prefix otherwise */
641ab64890Smrg#define XIM_GLOBAL_CACHE_DIR "/var/cache/libx11/compose/"
651ab64890Smrg#define XIM_HOME_CACHE_DIR   "/.compose-cache/"
661ab64890Smrg#define XIM_CACHE_MAGIC      ('X' | 'i'<<8 | 'm'<<16 | 'C'<<24)
671ab64890Smrg#define XIM_CACHE_VERSION    4
681ab64890Smrg#define XIM_CACHE_TREE_ALIGNMENT 4
691ab64890Smrg
701ab64890Smrg#define XIM_HASH_PRIME_1 13
711ab64890Smrg#define XIM_HASH_PRIME_2 1234096939
721ab64890Smrg
731ab64890Smrgtypedef INT32 DTStructIndex;
741ab64890Smrgstruct _XimCacheStruct {
751ab64890Smrg    INT32           id;
761ab64890Smrg    INT32           version;
771ab64890Smrg    DTStructIndex   tree;
781ab64890Smrg    DTStructIndex   mb;
791ab64890Smrg    DTStructIndex   wc;
801ab64890Smrg    DTStructIndex   utf8;
811ab64890Smrg    DTStructIndex   size;
821ab64890Smrg    DTIndex         top;
831ab64890Smrg    DTIndex         treeused;
841ab64890Smrg    DTCharIndex     mbused;
851ab64890Smrg    DTCharIndex     wcused;
861ab64890Smrg    DTCharIndex     utf8used;
871ab64890Smrg    char            fname[1];
881ab64890Smrg    /* char encoding[1] */
891ab64890Smrg};
901ab64890Smrg
911ab64890SmrgPrivate struct  _XimCacheStruct* _XimCache_mmap = NULL;
921ab64890SmrgPrivate DefTreeBase _XimCachedDefaultTreeBase;
931ab64890SmrgPrivate int     _XimCachedDefaultTreeRefcount = 0;
941ab64890Smrg
951ab64890Smrg#endif
961ab64890Smrg
971ab64890Smrg
981ab64890SmrgPublic Bool
9961b2299dSmrg_XimCheckIfLocalProcessing(Xim im)
1001ab64890Smrg{
1011ab64890Smrg    FILE        *fp;
1021ab64890Smrg    char        *name;
1031ab64890Smrg
1041ab64890Smrg    if(strcmp(im->core.im_name, "") == 0) {
1051ab64890Smrg	name = _XlcFileName(im->core.lcd, COMPOSE_FILE);
1061ab64890Smrg	if (name != (char *)NULL) {
1071ab64890Smrg	    fp = _XFopenFile (name, "r");
1081ab64890Smrg	    Xfree(name);
1091ab64890Smrg	    if (fp != (FILE *)NULL) {
1101ab64890Smrg		fclose(fp);
1111ab64890Smrg		return(True);
1121ab64890Smrg	    }
1131ab64890Smrg	}
1141ab64890Smrg	return(False);
1151ab64890Smrg    } else if(strcmp(im->core.im_name, "local") == 0 ||
1161ab64890Smrg	      strcmp(im->core.im_name, "none" ) == 0 ) {
1171ab64890Smrg	return(True);
1181ab64890Smrg    }
1191ab64890Smrg    return(False);
1201ab64890Smrg}
1211ab64890Smrg
1221ab64890SmrgPrivate void
1231ab64890SmrgXimFreeDefaultTree(
1241ab64890Smrg    DefTreeBase *b)
1251ab64890Smrg{
1261ab64890Smrg    if (!b) return;
1271ab64890Smrg    if (b->tree == NULL) return;
1281ab64890Smrg#ifdef COMPOSECACHE
1291ab64890Smrg    if (b->tree == _XimCachedDefaultTreeBase.tree) {
1301ab64890Smrg        _XimCachedDefaultTreeRefcount--;
1311ab64890Smrg        /* No deleting, it's a cache after all. */
1321ab64890Smrg        return;
1331ab64890Smrg    }
1341ab64890Smrg#endif
1351ab64890Smrg    Xfree (b->tree);
1361ab64890Smrg    if (b->mb)    Xfree (b->mb);
1371ab64890Smrg    if (b->wc)    Xfree (b->wc);
1381ab64890Smrg    if (b->utf8)  Xfree (b->utf8);
1391ab64890Smrg    b->tree = NULL;
1401ab64890Smrg    b->mb   = NULL;
1411ab64890Smrg    b->wc   = NULL;
1421ab64890Smrg    b->utf8 = NULL;
1431ab64890Smrg    b->treeused = b->treesize = 0;
1441ab64890Smrg    b->mbused   = b->mbsize   = 0;
1451ab64890Smrg    b->wcused   = b->wcsize   = 0;
1461ab64890Smrg    b->utf8used = b->utf8size = 0;
1471ab64890Smrg}
1481ab64890Smrg
1491ab64890SmrgPublic void
1501ab64890Smrg_XimLocalIMFree(
1511ab64890Smrg    Xim		im)
1521ab64890Smrg{
1531ab64890Smrg    XimFreeDefaultTree(&im->private.local.base);
1541ab64890Smrg    im->private.local.top = 0;
1551ab64890Smrg
1561ab64890Smrg    if(im->core.im_resources) {
1571ab64890Smrg	Xfree(im->core.im_resources);
1581ab64890Smrg	im->core.im_resources = NULL;
1591ab64890Smrg    }
1601ab64890Smrg    if(im->core.ic_resources) {
1611ab64890Smrg	Xfree(im->core.ic_resources);
1621ab64890Smrg	im->core.ic_resources = NULL;
1631ab64890Smrg    }
1641ab64890Smrg    if(im->core.im_values_list) {
1651ab64890Smrg	Xfree(im->core.im_values_list);
1661ab64890Smrg	im->core.im_values_list = NULL;
1671ab64890Smrg    }
1681ab64890Smrg    if(im->core.ic_values_list) {
1691ab64890Smrg	Xfree(im->core.ic_values_list);
1701ab64890Smrg	im->core.ic_values_list = NULL;
1711ab64890Smrg    }
1721ab64890Smrg    if(im->core.styles) {
1731ab64890Smrg	Xfree(im->core.styles);
1741ab64890Smrg	im->core.styles = NULL;
1751ab64890Smrg    }
1761ab64890Smrg    if(im->core.res_name) {
1771ab64890Smrg	Xfree(im->core.res_name);
1781ab64890Smrg	im->core.res_name = NULL;
1791ab64890Smrg    }
1801ab64890Smrg    if(im->core.res_class) {
1811ab64890Smrg	Xfree(im->core.res_class);
1821ab64890Smrg	im->core.res_class = NULL;
1831ab64890Smrg    }
1841ab64890Smrg    if(im->core.im_name) {
1851ab64890Smrg	Xfree(im->core.im_name);
1861ab64890Smrg	im->core.im_name = NULL;
1871ab64890Smrg    }
1881ab64890Smrg    if (im->private.local.ctom_conv) {
1891ab64890Smrg	_XlcCloseConverter(im->private.local.ctom_conv);
1901ab64890Smrg        im->private.local.ctom_conv = NULL;
1911ab64890Smrg    }
1921ab64890Smrg    if (im->private.local.ctow_conv) {
1931ab64890Smrg	_XlcCloseConverter(im->private.local.ctow_conv);
1941ab64890Smrg	im->private.local.ctow_conv = NULL;
1951ab64890Smrg    }
1961ab64890Smrg    if (im->private.local.ctoutf8_conv) {
1971ab64890Smrg	_XlcCloseConverter(im->private.local.ctoutf8_conv);
1981ab64890Smrg	im->private.local.ctoutf8_conv = NULL;
1991ab64890Smrg    }
2001ab64890Smrg    if (im->private.local.cstomb_conv) {
2011ab64890Smrg	_XlcCloseConverter(im->private.local.cstomb_conv);
2021ab64890Smrg        im->private.local.cstomb_conv = NULL;
2031ab64890Smrg    }
2041ab64890Smrg    if (im->private.local.cstowc_conv) {
2051ab64890Smrg	_XlcCloseConverter(im->private.local.cstowc_conv);
2061ab64890Smrg	im->private.local.cstowc_conv = NULL;
2071ab64890Smrg    }
2081ab64890Smrg    if (im->private.local.cstoutf8_conv) {
2091ab64890Smrg	_XlcCloseConverter(im->private.local.cstoutf8_conv);
2101ab64890Smrg	im->private.local.cstoutf8_conv = NULL;
2111ab64890Smrg    }
2121ab64890Smrg    if (im->private.local.ucstoc_conv) {
2131ab64890Smrg	_XlcCloseConverter(im->private.local.ucstoc_conv);
2141ab64890Smrg	im->private.local.ucstoc_conv = NULL;
2151ab64890Smrg    }
2161ab64890Smrg    if (im->private.local.ucstoutf8_conv) {
2171ab64890Smrg	_XlcCloseConverter(im->private.local.ucstoutf8_conv);
2181ab64890Smrg	im->private.local.ucstoutf8_conv = NULL;
2191ab64890Smrg    }
2201ab64890Smrg    return;
2211ab64890Smrg}
2221ab64890Smrg
2231ab64890SmrgPrivate Status
2241ab64890Smrg_XimLocalCloseIM(
2251ab64890Smrg    XIM		xim)
2261ab64890Smrg{
2271ab64890Smrg    Xim		im = (Xim)xim;
2281ab64890Smrg    XIC		ic;
2291ab64890Smrg    XIC		next;
2301ab64890Smrg
2311ab64890Smrg    ic = im->core.ic_chain;
2321ab64890Smrg    im->core.ic_chain = NULL;
2331ab64890Smrg    while (ic) {
2341ab64890Smrg	(*ic->methods->destroy) (ic);
2351ab64890Smrg	next = ic->core.next;
2361ab64890Smrg	Xfree ((char *) ic);
2371ab64890Smrg	ic = next;
2381ab64890Smrg    }
2391ab64890Smrg    _XimLocalIMFree(im);
2401ab64890Smrg    _XimDestroyIMStructureList(im);
2411ab64890Smrg    return(True);
2421ab64890Smrg}
2431ab64890Smrg
2441ab64890SmrgPublic char *
2451ab64890Smrg_XimLocalGetIMValues(
2461ab64890Smrg    XIM			 xim,
2471ab64890Smrg    XIMArg		*values)
2481ab64890Smrg{
2491ab64890Smrg    Xim			 im = (Xim)xim;
2501ab64890Smrg    XimDefIMValues	 im_values;
2511ab64890Smrg
2521ab64890Smrg    _XimGetCurrentIMValues(im, &im_values);
2531ab64890Smrg    return(_XimGetIMValueData(im, (XPointer)&im_values, values,
2541ab64890Smrg			im->core.im_resources, im->core.im_num_resources));
2551ab64890Smrg}
2561ab64890Smrg
2571ab64890SmrgPublic char *
2581ab64890Smrg_XimLocalSetIMValues(
2591ab64890Smrg    XIM			 xim,
2601ab64890Smrg    XIMArg		*values)
2611ab64890Smrg{
2621ab64890Smrg    Xim			 im = (Xim)xim;
2631ab64890Smrg    XimDefIMValues	 im_values;
2641ab64890Smrg    char		*name = (char *)NULL;
2651ab64890Smrg
2661ab64890Smrg    _XimGetCurrentIMValues(im, &im_values);
2671ab64890Smrg    name = _XimSetIMValueData(im, (XPointer)&im_values, values,
2681ab64890Smrg		im->core.im_resources, im->core.im_num_resources);
2691ab64890Smrg    _XimSetCurrentIMValues(im, &im_values);
2701ab64890Smrg    return(name);
2711ab64890Smrg}
2721ab64890Smrg
2731ab64890Smrg
2741ab64890Smrg#ifdef COMPOSECACHE
2751ab64890Smrg
2761ab64890SmrgPrivate Bool
2771ab64890Smrg_XimReadCachedDefaultTree(
2781ab64890Smrg    int          fd_cache,
2791ab64890Smrg    const char  *name,
2801ab64890Smrg    const char  *encoding,
2811ab64890Smrg    DTStructIndex size)
2821ab64890Smrg{
2831ab64890Smrg    struct _XimCacheStruct* m;
2841ab64890Smrg    int namelen = strlen (name) + 1;
2851ab64890Smrg    int encodinglen = strlen (encoding) + 1;
2861ab64890Smrg
2871ab64890Smrg    m = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd_cache, 0);
2881ab64890Smrg    if (m == NULL || m == MAP_FAILED)
2891ab64890Smrg        return False;
2901ab64890Smrg    assert (m->id == XIM_CACHE_MAGIC);
2911ab64890Smrg    assert (m->version == XIM_CACHE_VERSION);
2921ab64890Smrg    if (size != m->size ||
2931ab64890Smrg	size < XOffsetOf (struct _XimCacheStruct, fname) + namelen + encodinglen) {
2941ab64890Smrg	fprintf (stderr, "Ignoring broken XimCache %s [%s]\n", name, encoding);
2951ab64890Smrg        munmap (m, size);
2961ab64890Smrg        return False;
2971ab64890Smrg    }
2981ab64890Smrg    if (strncmp (name, m->fname, namelen) != 0) {
2991ab64890Smrg	/* m->fname may *not* be terminated - but who cares here */
3001ab64890Smrg	fprintf (stderr, "Filename hash clash - expected %s, got %s\n",
3011ab64890Smrg		 name, m->fname);
3021ab64890Smrg        munmap (m, size);
3031ab64890Smrg        return False;
3041ab64890Smrg    }
3051ab64890Smrg    if (strncmp (encoding, m->fname + namelen, encodinglen) != 0) {
3061ab64890Smrg	/* m->fname+namelen may *not* be terminated - but who cares here */
3071ab64890Smrg	fprintf (stderr, "Enoding hash clash - expected %s, got %s\n",
3081ab64890Smrg		 encoding, m->fname + namelen);
3091ab64890Smrg        munmap (m, size);
3101ab64890Smrg        return False;
3111ab64890Smrg    }
3121ab64890Smrg    _XimCache_mmap    = m;
3131ab64890Smrg    _XimCachedDefaultTreeBase.tree = (DefTree *) (((char *) m) + m->tree);
3141ab64890Smrg    _XimCachedDefaultTreeBase.mb   =             (((char *) m) + m->mb);
3151ab64890Smrg    _XimCachedDefaultTreeBase.wc   = (wchar_t *) (((char *) m) + m->wc);
3161ab64890Smrg    _XimCachedDefaultTreeBase.utf8 =             (((char *) m) + m->utf8);
3171ab64890Smrg    _XimCachedDefaultTreeBase.treeused = m->treeused;
3181ab64890Smrg    _XimCachedDefaultTreeBase.mbused   = m->mbused;
3191ab64890Smrg    _XimCachedDefaultTreeBase.wcused   = m->wcused;
3201ab64890Smrg    _XimCachedDefaultTreeBase.utf8used = m->utf8used;
3211ab64890Smrg    /* treesize etc. is ignored because only used during parsing */
3221ab64890Smrg    _XimCachedDefaultTreeRefcount = 0;
3231ab64890Smrg/* fprintf (stderr, "read cached tree at %p: %s\n", (void *) m, name); */
3241ab64890Smrg    return True;
3251ab64890Smrg}
3261ab64890Smrg
3271ab64890SmrgPrivate unsigned int strToHash (
3281ab64890Smrg    const char *name)
3291ab64890Smrg{
3301ab64890Smrg    unsigned int hash = 0;
3311ab64890Smrg    while (*name)
3321ab64890Smrg	hash = hash * XIM_HASH_PRIME_1 + *(unsigned const char *)name++;
3331ab64890Smrg    return hash % XIM_HASH_PRIME_2;
3341ab64890Smrg}
3351ab64890Smrg
3361ab64890Smrg
3371ab64890Smrg/* Returns read-only fd of cache file, -1 if none.
3381ab64890Smrg * Sets *res to cache filename if safe. Sets *size to file size of cache. */
3391ab64890SmrgPrivate int _XimCachedFileName (
3401ab64890Smrg    const char *dir, const char *name,
3411ab64890Smrg    const char *intname, const char *encoding,
3421ab64890Smrg    uid_t uid, int isglobal, char **res, off_t *size)
3431ab64890Smrg{
3441ab64890Smrg    struct stat st_name, st;
3451ab64890Smrg    int    fd;
3461ab64890Smrg    unsigned int len, hash, hash2;
3471ab64890Smrg    struct _XimCacheStruct *m;
3481ab64890Smrg    /* There are some races here with 'dir', but we are either in our own home
3491ab64890Smrg     * or the global cache dir, and not inside some public writable dir */
3501ab64890Smrg/* fprintf (stderr, "XimCachedFileName for dir %s name %s intname %s encoding %s uid %d\n", dir, name, intname, encoding, uid); */
3511ab64890Smrg    if (stat (name, &st_name) == -1 || ! S_ISREG (st_name.st_mode)
3521ab64890Smrg       || stat (dir, &st) == -1 || ! S_ISDIR (st.st_mode) || st.st_uid != uid
3531ab64890Smrg       || (st.st_mode & 0022) != 0000) {
3541ab64890Smrg       *res = NULL;
3551ab64890Smrg       return -1;
3561ab64890Smrg    }
3571ab64890Smrg    len   = strlen (dir);
3581ab64890Smrg    hash  = strToHash (intname);
3591ab64890Smrg    hash2 = strToHash (encoding);
3601ab64890Smrg    *res  = Xmalloc (len + 1 + 27 + 1);  /* Max VERSION 9999 */
3611ab64890Smrg
3621ab64890Smrg    if (len == 0 || dir [len-1] != '/')
3631ab64890Smrg       sprintf (*res, "%s/%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(),
3641ab64890Smrg		XIM_CACHE_VERSION, sizeof (DefTree), hash, hash2);
3651ab64890Smrg    else
3661ab64890Smrg       sprintf (*res, "%s%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(),
3671ab64890Smrg		XIM_CACHE_VERSION, sizeof (DefTree), hash, hash2);
36861b2299dSmrg
3691ab64890Smrg/* fprintf (stderr, "-> %s\n", *res); */
3701ab64890Smrg    if ( (fd = _XOpenFile (*res, O_RDONLY)) == -1)
3711ab64890Smrg       return -1;
3721ab64890Smrg
3731ab64890Smrg    if (fstat (fd, &st) == -1) {
3741ab64890Smrg       Xfree (*res);
3751ab64890Smrg       *res = NULL;
3761ab64890Smrg       close (fd);
3771ab64890Smrg       return -1;
3781ab64890Smrg    }
3791ab64890Smrg    *size = st.st_size;
3801ab64890Smrg
3811ab64890Smrg    if (! S_ISREG (st.st_mode) || st.st_uid != uid
3821ab64890Smrg       || (st.st_mode & 0022) != 0000 || st.st_mtime <= st_name.st_mtime
3831ab64890Smrg       || (st.st_mtime < time (NULL) - 24*60*60 && ! isglobal)) {
3841ab64890Smrg
3851ab64890Smrg       close (fd);
3861ab64890Smrg       if (unlink (*res) != 0) {
3871ab64890Smrg           Xfree (*res);
3881ab64890Smrg           *res = NULL;                /* cache is not safe */
3891ab64890Smrg       }
3901ab64890Smrg       return -1;
3911ab64890Smrg    }
3921ab64890Smrg
3931ab64890Smrg    m = mmap (NULL, sizeof (struct _XimCacheStruct), PROT_READ, MAP_PRIVATE,
3941ab64890Smrg	      fd, 0);
3951ab64890Smrg    if (m == NULL || m == MAP_FAILED) {
3961ab64890Smrg	close (fd);
3971ab64890Smrg	Xfree (*res);
3981ab64890Smrg	*res = NULL;
3991ab64890Smrg        return -1;
4001ab64890Smrg    }
4011ab64890Smrg    if (*size < sizeof (struct _XimCacheStruct) || m->id != XIM_CACHE_MAGIC) {
4021ab64890Smrg	munmap (m, sizeof (struct _XimCacheStruct));
4031ab64890Smrg	close (fd);
4041ab64890Smrg	fprintf (stderr, "Ignoring broken XimCache %s\n", *res);
4051ab64890Smrg	Xfree (*res);
4061ab64890Smrg	*res = NULL;
4071ab64890Smrg        return -1;
4081ab64890Smrg    }
4091ab64890Smrg    if (m->version != XIM_CACHE_VERSION) {
4101ab64890Smrg	munmap (m, sizeof (struct _XimCacheStruct));
4111ab64890Smrg	close (fd);
4121ab64890Smrg	if (unlink (*res) != 0) {
4131ab64890Smrg	    Xfree (*res);
4141ab64890Smrg	    *res = NULL;                /* cache is not safe */
4151ab64890Smrg	}
4161ab64890Smrg	return -1;
4171ab64890Smrg    }
4181ab64890Smrg    munmap (m, sizeof (struct _XimCacheStruct));
41961b2299dSmrg
4201ab64890Smrg    return fd;
4211ab64890Smrg}
4221ab64890Smrg
4231ab64890Smrg
4241ab64890SmrgPrivate Bool _XimLoadCache (
4251ab64890Smrg    int         fd,
4261ab64890Smrg    const char *name,
4271ab64890Smrg    const char *encoding,
4281ab64890Smrg    off_t       size,
4291ab64890Smrg    Xim         im)
4301ab64890Smrg{
4311ab64890Smrg    if (_XimCache_mmap ||
4321ab64890Smrg       _XimReadCachedDefaultTree (fd, name, encoding, size)) {
4331ab64890Smrg       _XimCachedDefaultTreeRefcount++;
4341ab64890Smrg       memcpy (&im->private.local.base, &_XimCachedDefaultTreeBase,
4351ab64890Smrg	       sizeof (_XimCachedDefaultTreeBase));
4361ab64890Smrg       im->private.local.top = _XimCache_mmap->top;
4371ab64890Smrg       return True;
4381ab64890Smrg    }
4391ab64890Smrg
4401ab64890Smrg    return False;
4411ab64890Smrg}
4421ab64890Smrg
4431ab64890Smrg
4441ab64890SmrgPrivate void
4451ab64890Smrg_XimWriteCachedDefaultTree(
4461ab64890Smrg    const char *name,
4471ab64890Smrg    const char *encoding,
4481ab64890Smrg    const char *cachename,
4491ab64890Smrg    Xim                im)
4501ab64890Smrg{
4511ab64890Smrg    int   fd;
4521ab64890Smrg    FILE *fp;
4531ab64890Smrg    struct _XimCacheStruct *m;
4541ab64890Smrg    int   msize = (XOffsetOf(struct _XimCacheStruct, fname)
4551ab64890Smrg		   + strlen(name) + strlen(encoding) + 2
4561ab64890Smrg		   + XIM_CACHE_TREE_ALIGNMENT-1) & -XIM_CACHE_TREE_ALIGNMENT;
4571ab64890Smrg    DefTreeBase *b = &im->private.local.base;
4581ab64890Smrg
4591ab64890Smrg    if (! b->tree && ! (b->tree = Xmalloc (sizeof(DefTree))) )
4601ab64890Smrg	return;
4611ab64890Smrg    if (! b->mb   && ! (b->mb   = Xmalloc (1)) )
4621ab64890Smrg	return;
4631ab64890Smrg    if (! b->wc   && ! (b->wc   = Xmalloc (sizeof(wchar_t))) )
4641ab64890Smrg	return;
4651ab64890Smrg    if (! b->utf8 && ! (b->utf8 = Xmalloc (1)) )
4661ab64890Smrg	return;
4671ab64890Smrg
4681ab64890Smrg    /* First entry is always unused */
4691ab64890Smrg    memset (b->tree, 0, sizeof(DefTree));
4701ab64890Smrg    b->mb[0]   = 0;
4711ab64890Smrg    b->wc[0]   = 0;
4721ab64890Smrg    b->utf8[0] = 0;
4731ab64890Smrg
4741ab64890Smrg    m = Xmalloc (msize);
4751ab64890Smrg    memset (m, 0, msize);
4761ab64890Smrg    m->id       = XIM_CACHE_MAGIC;
4771ab64890Smrg    m->version  = XIM_CACHE_VERSION;
4781ab64890Smrg    m->top      = im->private.local.top;
4791ab64890Smrg    m->treeused = b->treeused;
4801ab64890Smrg    m->mbused   = b->mbused;
4811ab64890Smrg    m->wcused   = b->wcused;
4821ab64890Smrg    m->utf8used = b->utf8used;
4831ab64890Smrg    /* Tree first, then wide chars, then the rest due to alignment */
4841ab64890Smrg    m->tree     = msize;
4851ab64890Smrg    m->wc       = msize   + sizeof (DefTree) * m->treeused;
4861ab64890Smrg    m->mb       = m->wc   + sizeof (wchar_t) * m->wcused;
4871ab64890Smrg    m->utf8     = m->mb   +                    m->mbused;
4881ab64890Smrg    m->size     = m->utf8 +                    m->utf8used;
4891ab64890Smrg    strcpy (m->fname, name);
4901ab64890Smrg    strcpy (m->fname+strlen(name)+1, encoding);
4911ab64890Smrg
4921ab64890Smrg    /* This STILL might be racy on NFS */
4931ab64890Smrg    if ( (fd = _XOpenFileMode (cachename, O_WRONLY | O_CREAT | O_EXCL,
4941ab64890Smrg			       0600)) < 0)
4951ab64890Smrg       return;
4961ab64890Smrg    if (! (fp = fdopen (fd, "wb")) ) {
4971ab64890Smrg       close (fd);
4981ab64890Smrg       return;
4991ab64890Smrg    }
5001ab64890Smrg    fwrite (m, msize, 1, fp);
5011ab64890Smrg    fwrite (im->private.local.base.tree, sizeof(DefTree), m->treeused, fp);
5021ab64890Smrg    fwrite (im->private.local.base.wc,   sizeof(wchar_t), m->wcused,   fp);
5031ab64890Smrg    fwrite (im->private.local.base.mb,   1,               m->mbused,   fp);
5041ab64890Smrg    fwrite (im->private.local.base.utf8, 1,               m->utf8used, fp);
5051ab64890Smrg    if (fclose (fp) != 0)
5061ab64890Smrg	unlink (cachename);
5071ab64890Smrg    _XimCache_mmap = m;
5081ab64890Smrg    memcpy (&_XimCachedDefaultTreeBase, &im->private.local.base,
5091ab64890Smrg	    sizeof (_XimCachedDefaultTreeBase));
5101ab64890Smrg/* fprintf (stderr, "wrote tree %s size %ld to %s\n", name, m->size, cachename); */
5111ab64890Smrg}
5121ab64890Smrg
5131ab64890Smrg#endif
5141ab64890Smrg
5151ab64890Smrg
5161ab64890SmrgPrivate void
5171ab64890Smrg_XimCreateDefaultTree(
5181ab64890Smrg    Xim		im)
5191ab64890Smrg{
5201ab64890Smrg    FILE *fp = NULL;
5211ab64890Smrg    char *name, *tmpname = NULL, *intname;
5221ab64890Smrg    char *cachename = NULL;
5231ab64890Smrg    /* Should use getpwent() instead of $HOME (cross-platform?) */
5241ab64890Smrg    char *home = getenv("HOME");
5251ab64890Smrg    char *cachedir = NULL;
5261ab64890Smrg    char *tmpcachedir = NULL;
5271ab64890Smrg    int   hl = home ? strlen (home) : 0;
5281ab64890Smrg#ifdef COMPOSECACHE
5291ab64890Smrg    const char *encoding = nl_langinfo (CODESET);
5301ab64890Smrg    uid_t euid = geteuid ();
5311ab64890Smrg    gid_t egid = getegid ();
5321ab64890Smrg    int   cachefd = -1;
5331ab64890Smrg    off_t size;
5341ab64890Smrg#endif
5351ab64890Smrg
5361ab64890Smrg    name = getenv("XCOMPOSEFILE");
5371ab64890Smrg    if (name == (char *) NULL) {
5381ab64890Smrg    	if (home != (char *) NULL) {
5391ab64890Smrg            tmpname = name = Xmalloc(hl + 10 + 1);
5401ab64890Smrg            if (name != (char *) NULL) {
5411ab64890Smrg		int fd;
5421ab64890Smrg            	strcpy(name, home);
5431ab64890Smrg            	strcpy(name + hl, "/.XCompose");
5441ab64890Smrg		if ( (fd = _XOpenFile (name, O_RDONLY)) < 0) {
5451ab64890Smrg		    Xfree (name);
5461ab64890Smrg		    name = tmpname = NULL;
5471ab64890Smrg		} else
5481ab64890Smrg		    close (fd);
5491ab64890Smrg            }
5501ab64890Smrg        }
5511ab64890Smrg    }
5521ab64890Smrg
5531ab64890Smrg    if (name == (char *) NULL) {
5541ab64890Smrg        tmpname = name = _XlcFileName(im->core.lcd, COMPOSE_FILE);
5551ab64890Smrg    }
5561ab64890Smrg    intname = name;
55761b2299dSmrg
5581ab64890Smrg#ifdef COMPOSECACHE
5591ab64890Smrg    if (getuid () == euid && getgid () == egid && euid != 0) {
5601ab64890Smrg	char *c;
5611ab64890Smrg	/* Usage: XCOMPOSECACHE=<cachedir>[=<filename>]
5621ab64890Smrg	 * cachedir: directory of cache files
5631ab64890Smrg	 * filename: internally used name for cache file */
5641ab64890Smrg        cachedir = getenv("XCOMPOSECACHE");
5651ab64890Smrg	if (cachedir && (c = strchr (cachedir, '='))) {
5661ab64890Smrg	    tmpcachedir = strdup (cachedir);
5671ab64890Smrg	    intname = tmpcachedir + (c-cachedir) + 1;
5681ab64890Smrg	    tmpcachedir[c-cachedir] = '\0';
5691ab64890Smrg	    cachedir = tmpcachedir;
5701ab64890Smrg	}
5711ab64890Smrg    }
5721ab64890Smrg
5731ab64890Smrg    if (! cachedir) {
5741ab64890Smrg	cachefd = _XimCachedFileName (XIM_GLOBAL_CACHE_DIR, name, intname,
5751ab64890Smrg				      encoding, 0, 1, &cachename, &size);
5761ab64890Smrg	if (cachefd != -1) {
5771ab64890Smrg	    if (_XimLoadCache (cachefd, intname, encoding, size, im)) {
5781ab64890Smrg		if (tmpcachedir)
5791ab64890Smrg		    Xfree  (tmpcachedir);
5801ab64890Smrg		if (tmpname)
5811ab64890Smrg		    Xfree (tmpname);
5821ab64890Smrg		if (cachename)
5831ab64890Smrg		    Xfree (cachename);
5841ab64890Smrg		close (cachefd);
5851ab64890Smrg		return;
5861ab64890Smrg	    }
5871ab64890Smrg	    close (cachefd);
5881ab64890Smrg	}
5891ab64890Smrg	if (cachename)
5901ab64890Smrg	    Xfree (cachename);
5911ab64890Smrg	cachename = NULL;
5921ab64890Smrg    }
59361b2299dSmrg
5941ab64890Smrg    if (getuid () == euid && getgid () == egid && euid != 0 && home) {
5951ab64890Smrg
5961ab64890Smrg	if (! cachedir) {
5971ab64890Smrg	    tmpcachedir = cachedir = Xmalloc (hl+strlen(XIM_HOME_CACHE_DIR)+1);
5981ab64890Smrg	    strcpy (cachedir, home);
5991ab64890Smrg	    strcat (cachedir, XIM_HOME_CACHE_DIR);
6001ab64890Smrg	}
6011ab64890Smrg	cachefd = _XimCachedFileName (cachedir, name, intname, encoding,
6021ab64890Smrg				      euid, 0, &cachename, &size);
6031ab64890Smrg	if (cachefd != -1) {
6041ab64890Smrg	    if (_XimLoadCache (cachefd, intname, encoding, size, im)) {
6051ab64890Smrg		if (tmpcachedir)
6061ab64890Smrg		    Xfree  (tmpcachedir);
6071ab64890Smrg		if (tmpname)
6081ab64890Smrg		    Xfree (tmpname);
6091ab64890Smrg		if (cachename)
6101ab64890Smrg		    Xfree (cachename);
6111ab64890Smrg		close (cachefd);
6121ab64890Smrg		return;
6131ab64890Smrg	    }
6141ab64890Smrg	    close (cachefd);
6151ab64890Smrg	}
6161ab64890Smrg    }
6171ab64890Smrg#endif
6181ab64890Smrg
6191ab64890Smrg    if (! (fp = _XFopenFile (name, "r"))) {
6201ab64890Smrg	if (tmpcachedir)
6211ab64890Smrg	    Xfree  (tmpcachedir);
6221ab64890Smrg	if (tmpname)
6231ab64890Smrg	    Xfree (tmpname);
6241ab64890Smrg	if (cachename)
6251ab64890Smrg	    Xfree (cachename);
6261ab64890Smrg        return;
6271ab64890Smrg    }
6281ab64890Smrg    _XimParseStringFile(fp, im);
6291ab64890Smrg    fclose(fp);
6301ab64890Smrg
6311ab64890Smrg#ifdef COMPOSECACHE
6321ab64890Smrg    if (cachename) {
6331ab64890Smrg	assert (euid != 0);
6341ab64890Smrg	_XimWriteCachedDefaultTree (intname, encoding, cachename, im);
6351ab64890Smrg    }
6361ab64890Smrg#endif
63761b2299dSmrg
6381ab64890Smrg    if (tmpcachedir)
6391ab64890Smrg	Xfree  (tmpcachedir);
6401ab64890Smrg    if (tmpname)
6411ab64890Smrg	Xfree (tmpname);
6421ab64890Smrg    if (cachename)
6431ab64890Smrg	Xfree (cachename);
6441ab64890Smrg}
6451ab64890Smrg
6461ab64890SmrgPrivate XIMMethodsRec      Xim_im_local_methods = {
6471ab64890Smrg    _XimLocalCloseIM,           /* close */
6481ab64890Smrg    _XimLocalSetIMValues,       /* set_values */
6491ab64890Smrg    _XimLocalGetIMValues,       /* get_values */
6501ab64890Smrg    _XimLocalCreateIC,          /* create_ic */
6511ab64890Smrg    _XimLcctstombs,		/* ctstombs */
6521ab64890Smrg    _XimLcctstowcs,		/* ctstowcs */
6531ab64890Smrg    _XimLcctstoutf8		/* ctstoutf8 */
6541ab64890Smrg};
6551ab64890Smrg
6561ab64890SmrgPublic Bool
6571ab64890Smrg_XimLocalOpenIM(
6581ab64890Smrg    Xim			 im)
6591ab64890Smrg{
6601ab64890Smrg    XLCd		 lcd = im->core.lcd;
6611ab64890Smrg    XlcConv		 conv;
6621ab64890Smrg    XimDefIMValues	 im_values;
6631ab64890Smrg    XimLocalPrivateRec*  private = &im->private.local;
6641ab64890Smrg
6651ab64890Smrg    _XimInitialResourceInfo();
6661ab64890Smrg    if(_XimSetIMResourceList(&im->core.im_resources,
6671ab64890Smrg		 		&im->core.im_num_resources) == False) {
6681ab64890Smrg	goto Open_Error;
6691ab64890Smrg    }
6701ab64890Smrg    if(_XimSetICResourceList(&im->core.ic_resources,
6711ab64890Smrg				&im->core.ic_num_resources) == False) {
6721ab64890Smrg	goto Open_Error;
6731ab64890Smrg    }
6741ab64890Smrg
6751ab64890Smrg    _XimSetIMMode(im->core.im_resources, im->core.im_num_resources);
6761ab64890Smrg
6771ab64890Smrg    _XimGetCurrentIMValues(im, &im_values);
6781ab64890Smrg    if(_XimSetLocalIMDefaults(im, (XPointer)&im_values,
6791ab64890Smrg		im->core.im_resources, im->core.im_num_resources) == False) {
6801ab64890Smrg	goto Open_Error;
6811ab64890Smrg    }
6821ab64890Smrg    _XimSetCurrentIMValues(im, &im_values);
6831ab64890Smrg
6841ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNCompoundText, lcd, XlcNMultiByte)))
6851ab64890Smrg	goto Open_Error;
6861ab64890Smrg    private->ctom_conv = conv;
6871ab64890Smrg
6881ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNCompoundText, lcd, XlcNWideChar)))
6891ab64890Smrg	goto Open_Error;
6901ab64890Smrg    private->ctow_conv = conv;
6911ab64890Smrg
6921ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNCompoundText, lcd, XlcNUtf8String)))
6931ab64890Smrg	goto Open_Error;
6941ab64890Smrg    private->ctoutf8_conv = conv;
6951ab64890Smrg
6961ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNMultiByte)))
6971ab64890Smrg	goto Open_Error;
6981ab64890Smrg    private->cstomb_conv = conv;
6991ab64890Smrg
7001ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNWideChar)))
7011ab64890Smrg	goto Open_Error;
7021ab64890Smrg    private->cstowc_conv = conv;
7031ab64890Smrg
7041ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNUtf8String)))
7051ab64890Smrg	goto Open_Error;
7061ab64890Smrg    private->cstoutf8_conv = conv;
7071ab64890Smrg
7081ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNUcsChar, lcd, XlcNChar)))
7091ab64890Smrg	goto Open_Error;
7101ab64890Smrg    private->ucstoc_conv = conv;
7111ab64890Smrg
7121ab64890Smrg    if (!(conv = _XlcOpenConverter(lcd,	XlcNUcsChar, lcd, XlcNUtf8String)))
7131ab64890Smrg	goto Open_Error;
7141ab64890Smrg    private->ucstoutf8_conv = conv;
7151ab64890Smrg
7161ab64890Smrg    private->base.treeused = 1;
7171ab64890Smrg    private->base.mbused   = 1;
7181ab64890Smrg    private->base.wcused   = 1;
7191ab64890Smrg    private->base.utf8used = 1;
7201ab64890Smrg
7211ab64890Smrg    _XimCreateDefaultTree(im);
7221ab64890Smrg
7231ab64890Smrg    im->methods = &Xim_im_local_methods;
7241ab64890Smrg    private->current_ic = (XIC)NULL;
7251ab64890Smrg
7261ab64890Smrg    return(True);
7271ab64890Smrg
7281ab64890SmrgOpen_Error :
7291ab64890Smrg    _XimLocalIMFree(im);
7301ab64890Smrg    return(False);
7311ab64890Smrg}
732