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