diff options
Diffstat (limited to 'libX11/modules/im/ximcp/imLcIm.c')
-rw-r--r-- | libX11/modules/im/ximcp/imLcIm.c | 732 |
1 files changed, 732 insertions, 0 deletions
diff --git a/libX11/modules/im/ximcp/imLcIm.c b/libX11/modules/im/ximcp/imLcIm.c new file mode 100644 index 000000000..b1bbce5b1 --- /dev/null +++ b/libX11/modules/im/ximcp/imLcIm.c @@ -0,0 +1,732 @@ +/* $Xorg: imLcIm.c,v 1.3 2000/08/17 19:45:14 cpqbld Exp $ */ +/****************************************************************** + + Copyright 1992, 1993, 1994 by FUJITSU LIMITED + Copyright 1993 by Digital Equipment Corporation + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of FUJITSU LIMITED and +Digital Equipment Corporation not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. FUJITSU LIMITED and Digital Equipment Corporation +makes no representations about the suitability of this software for +any purpose. It is provided "as is" without express or implied +warranty. + +FUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION DISCLAIM ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +FUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + Author: Takashi Fujiwara FUJITSU LIMITED + fujiwara@a80.tech.yk.fujitsu.co.jp + Modifier: Franky Ling Digital Equipment Corporation + frankyling@hgrd01.enet.dec.com + +******************************************************************/ +/* $XFree86: xc/lib/X11/imLcIm.c,v 1.12 2003/09/06 14:06:32 pascal Exp $ */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> + +#include <X11/Xmd.h> +#include <X11/Xatom.h> +#include <X11/Xos.h> +#include "Xlibint.h" +#include "Xlcint.h" +#include "XlcPublic.h" +#include "XlcPubI.h" +#include "Ximint.h" +#include <ctype.h> +#include <assert.h> + +#ifdef COMPOSECACHE +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/mman.h> +# include <langinfo.h> +#endif + + +#ifdef COMPOSECACHE + +/* include trailing '/' for cache directory, file prefix otherwise */ +#define XIM_GLOBAL_CACHE_DIR "/var/cache/libx11/compose/" +#define XIM_HOME_CACHE_DIR "/.compose-cache/" +#define XIM_CACHE_MAGIC ('X' | 'i'<<8 | 'm'<<16 | 'C'<<24) +#define XIM_CACHE_VERSION 4 +#define XIM_CACHE_TREE_ALIGNMENT 4 + +#define XIM_HASH_PRIME_1 13 +#define XIM_HASH_PRIME_2 1234096939 + +typedef INT32 DTStructIndex; +struct _XimCacheStruct { + INT32 id; + INT32 version; + DTStructIndex tree; + DTStructIndex mb; + DTStructIndex wc; + DTStructIndex utf8; + DTStructIndex size; + DTIndex top; + DTIndex treeused; + DTCharIndex mbused; + DTCharIndex wcused; + DTCharIndex utf8used; + char fname[1]; + /* char encoding[1] */ +}; + +Private struct _XimCacheStruct* _XimCache_mmap = NULL; +Private DefTreeBase _XimCachedDefaultTreeBase; +Private int _XimCachedDefaultTreeRefcount = 0; + +#endif + + +Public Bool +_XimCheckIfLocalProcessing(im) + Xim im; +{ + FILE *fp; + char *name; + + if(strcmp(im->core.im_name, "") == 0) { + name = _XlcFileName(im->core.lcd, COMPOSE_FILE); + if (name != (char *)NULL) { + fp = _XFopenFile (name, "r"); + Xfree(name); + if (fp != (FILE *)NULL) { + fclose(fp); + return(True); + } + } + return(False); + } else if(strcmp(im->core.im_name, "local") == 0 || + strcmp(im->core.im_name, "none" ) == 0 ) { + return(True); + } + return(False); +} + +Private void +XimFreeDefaultTree( + DefTreeBase *b) +{ + if (!b) return; + if (b->tree == NULL) return; +#ifdef COMPOSECACHE + if (b->tree == _XimCachedDefaultTreeBase.tree) { + _XimCachedDefaultTreeRefcount--; + /* No deleting, it's a cache after all. */ + return; + } +#endif + Xfree (b->tree); + if (b->mb) Xfree (b->mb); + if (b->wc) Xfree (b->wc); + if (b->utf8) Xfree (b->utf8); + b->tree = NULL; + b->mb = NULL; + b->wc = NULL; + b->utf8 = NULL; + b->treeused = b->treesize = 0; + b->mbused = b->mbsize = 0; + b->wcused = b->wcsize = 0; + b->utf8used = b->utf8size = 0; +} + +Public void +_XimLocalIMFree( + Xim im) +{ + XimFreeDefaultTree(&im->private.local.base); + im->private.local.top = 0; + + if(im->core.im_resources) { + Xfree(im->core.im_resources); + im->core.im_resources = NULL; + } + if(im->core.ic_resources) { + Xfree(im->core.ic_resources); + im->core.ic_resources = NULL; + } + if(im->core.im_values_list) { + Xfree(im->core.im_values_list); + im->core.im_values_list = NULL; + } + if(im->core.ic_values_list) { + Xfree(im->core.ic_values_list); + im->core.ic_values_list = NULL; + } + if(im->core.styles) { + Xfree(im->core.styles); + im->core.styles = NULL; + } + if(im->core.res_name) { + Xfree(im->core.res_name); + im->core.res_name = NULL; + } + if(im->core.res_class) { + Xfree(im->core.res_class); + im->core.res_class = NULL; + } + if(im->core.im_name) { + Xfree(im->core.im_name); + im->core.im_name = NULL; + } + if (im->private.local.ctom_conv) { + _XlcCloseConverter(im->private.local.ctom_conv); + im->private.local.ctom_conv = NULL; + } + if (im->private.local.ctow_conv) { + _XlcCloseConverter(im->private.local.ctow_conv); + im->private.local.ctow_conv = NULL; + } + if (im->private.local.ctoutf8_conv) { + _XlcCloseConverter(im->private.local.ctoutf8_conv); + im->private.local.ctoutf8_conv = NULL; + } + if (im->private.local.cstomb_conv) { + _XlcCloseConverter(im->private.local.cstomb_conv); + im->private.local.cstomb_conv = NULL; + } + if (im->private.local.cstowc_conv) { + _XlcCloseConverter(im->private.local.cstowc_conv); + im->private.local.cstowc_conv = NULL; + } + if (im->private.local.cstoutf8_conv) { + _XlcCloseConverter(im->private.local.cstoutf8_conv); + im->private.local.cstoutf8_conv = NULL; + } + if (im->private.local.ucstoc_conv) { + _XlcCloseConverter(im->private.local.ucstoc_conv); + im->private.local.ucstoc_conv = NULL; + } + if (im->private.local.ucstoutf8_conv) { + _XlcCloseConverter(im->private.local.ucstoutf8_conv); + im->private.local.ucstoutf8_conv = NULL; + } + return; +} + +Private Status +_XimLocalCloseIM( + XIM xim) +{ + Xim im = (Xim)xim; + XIC ic; + XIC next; + + ic = im->core.ic_chain; + im->core.ic_chain = NULL; + while (ic) { + (*ic->methods->destroy) (ic); + next = ic->core.next; + Xfree ((char *) ic); + ic = next; + } + _XimLocalIMFree(im); + _XimDestroyIMStructureList(im); + return(True); +} + +Public char * +_XimLocalGetIMValues( + XIM xim, + XIMArg *values) +{ + Xim im = (Xim)xim; + XimDefIMValues im_values; + + _XimGetCurrentIMValues(im, &im_values); + return(_XimGetIMValueData(im, (XPointer)&im_values, values, + im->core.im_resources, im->core.im_num_resources)); +} + +Public char * +_XimLocalSetIMValues( + XIM xim, + XIMArg *values) +{ + Xim im = (Xim)xim; + XimDefIMValues im_values; + char *name = (char *)NULL; + + _XimGetCurrentIMValues(im, &im_values); + name = _XimSetIMValueData(im, (XPointer)&im_values, values, + im->core.im_resources, im->core.im_num_resources); + _XimSetCurrentIMValues(im, &im_values); + return(name); +} + + +#ifdef COMPOSECACHE + +Private Bool +_XimReadCachedDefaultTree( + int fd_cache, + const char *name, + const char *encoding, + DTStructIndex size) +{ + struct _XimCacheStruct* m; + int namelen = strlen (name) + 1; + int encodinglen = strlen (encoding) + 1; + + m = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd_cache, 0); + if (m == NULL || m == MAP_FAILED) + return False; + assert (m->id == XIM_CACHE_MAGIC); + assert (m->version == XIM_CACHE_VERSION); + if (size != m->size || + size < XOffsetOf (struct _XimCacheStruct, fname) + namelen + encodinglen) { + fprintf (stderr, "Ignoring broken XimCache %s [%s]\n", name, encoding); + munmap (m, size); + return False; + } + if (strncmp (name, m->fname, namelen) != 0) { + /* m->fname may *not* be terminated - but who cares here */ + fprintf (stderr, "Filename hash clash - expected %s, got %s\n", + name, m->fname); + munmap (m, size); + return False; + } + if (strncmp (encoding, m->fname + namelen, encodinglen) != 0) { + /* m->fname+namelen may *not* be terminated - but who cares here */ + fprintf (stderr, "Enoding hash clash - expected %s, got %s\n", + encoding, m->fname + namelen); + munmap (m, size); + return False; + } + _XimCache_mmap = m; + _XimCachedDefaultTreeBase.tree = (DefTree *) (((char *) m) + m->tree); + _XimCachedDefaultTreeBase.mb = (((char *) m) + m->mb); + _XimCachedDefaultTreeBase.wc = (wchar_t *) (((char *) m) + m->wc); + _XimCachedDefaultTreeBase.utf8 = (((char *) m) + m->utf8); + _XimCachedDefaultTreeBase.treeused = m->treeused; + _XimCachedDefaultTreeBase.mbused = m->mbused; + _XimCachedDefaultTreeBase.wcused = m->wcused; + _XimCachedDefaultTreeBase.utf8used = m->utf8used; + /* treesize etc. is ignored because only used during parsing */ + _XimCachedDefaultTreeRefcount = 0; +/* fprintf (stderr, "read cached tree at %p: %s\n", (void *) m, name); */ + return True; +} + +Private unsigned int strToHash ( + const char *name) +{ + unsigned int hash = 0; + while (*name) + hash = hash * XIM_HASH_PRIME_1 + *(unsigned const char *)name++; + return hash % XIM_HASH_PRIME_2; +} + + +/* Returns read-only fd of cache file, -1 if none. + * Sets *res to cache filename if safe. Sets *size to file size of cache. */ +Private int _XimCachedFileName ( + const char *dir, const char *name, + const char *intname, const char *encoding, + uid_t uid, int isglobal, char **res, off_t *size) +{ + struct stat st_name, st; + int fd; + unsigned int len, hash, hash2; + struct _XimCacheStruct *m; + /* There are some races here with 'dir', but we are either in our own home + * or the global cache dir, and not inside some public writable dir */ +/* fprintf (stderr, "XimCachedFileName for dir %s name %s intname %s encoding %s uid %d\n", dir, name, intname, encoding, uid); */ + if (stat (name, &st_name) == -1 || ! S_ISREG (st_name.st_mode) + || stat (dir, &st) == -1 || ! S_ISDIR (st.st_mode) || st.st_uid != uid + || (st.st_mode & 0022) != 0000) { + *res = NULL; + return -1; + } + len = strlen (dir); + hash = strToHash (intname); + hash2 = strToHash (encoding); + *res = Xmalloc (len + 1 + 27 + 1); /* Max VERSION 9999 */ + + if (len == 0 || dir [len-1] != '/') + sprintf (*res, "%s/%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(), + XIM_CACHE_VERSION, sizeof (DefTree), hash, hash2); + else + sprintf (*res, "%s%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(), + XIM_CACHE_VERSION, sizeof (DefTree), hash, hash2); + +/* fprintf (stderr, "-> %s\n", *res); */ + if ( (fd = _XOpenFile (*res, O_RDONLY)) == -1) + return -1; + + if (fstat (fd, &st) == -1) { + Xfree (*res); + *res = NULL; + close (fd); + return -1; + } + *size = st.st_size; + + if (! S_ISREG (st.st_mode) || st.st_uid != uid + || (st.st_mode & 0022) != 0000 || st.st_mtime <= st_name.st_mtime + || (st.st_mtime < time (NULL) - 24*60*60 && ! isglobal)) { + + close (fd); + if (unlink (*res) != 0) { + Xfree (*res); + *res = NULL; /* cache is not safe */ + } + return -1; + } + + m = mmap (NULL, sizeof (struct _XimCacheStruct), PROT_READ, MAP_PRIVATE, + fd, 0); + if (m == NULL || m == MAP_FAILED) { + close (fd); + Xfree (*res); + *res = NULL; + return -1; + } + if (*size < sizeof (struct _XimCacheStruct) || m->id != XIM_CACHE_MAGIC) { + munmap (m, sizeof (struct _XimCacheStruct)); + close (fd); + fprintf (stderr, "Ignoring broken XimCache %s\n", *res); + Xfree (*res); + *res = NULL; + return -1; + } + if (m->version != XIM_CACHE_VERSION) { + munmap (m, sizeof (struct _XimCacheStruct)); + close (fd); + if (unlink (*res) != 0) { + Xfree (*res); + *res = NULL; /* cache is not safe */ + } + return -1; + } + munmap (m, sizeof (struct _XimCacheStruct)); + + return fd; +} + + +Private Bool _XimLoadCache ( + int fd, + const char *name, + const char *encoding, + off_t size, + Xim im) +{ + if (_XimCache_mmap || + _XimReadCachedDefaultTree (fd, name, encoding, size)) { + _XimCachedDefaultTreeRefcount++; + memcpy (&im->private.local.base, &_XimCachedDefaultTreeBase, + sizeof (_XimCachedDefaultTreeBase)); + im->private.local.top = _XimCache_mmap->top; + return True; + } + + return False; +} + + +Private void +_XimWriteCachedDefaultTree( + const char *name, + const char *encoding, + const char *cachename, + Xim im) +{ + int fd; + FILE *fp; + struct _XimCacheStruct *m; + int msize = (XOffsetOf(struct _XimCacheStruct, fname) + + strlen(name) + strlen(encoding) + 2 + + XIM_CACHE_TREE_ALIGNMENT-1) & -XIM_CACHE_TREE_ALIGNMENT; + DefTreeBase *b = &im->private.local.base; + + if (! b->tree && ! (b->tree = Xmalloc (sizeof(DefTree))) ) + return; + if (! b->mb && ! (b->mb = Xmalloc (1)) ) + return; + if (! b->wc && ! (b->wc = Xmalloc (sizeof(wchar_t))) ) + return; + if (! b->utf8 && ! (b->utf8 = Xmalloc (1)) ) + return; + + /* First entry is always unused */ + memset (b->tree, 0, sizeof(DefTree)); + b->mb[0] = 0; + b->wc[0] = 0; + b->utf8[0] = 0; + + m = Xmalloc (msize); + memset (m, 0, msize); + m->id = XIM_CACHE_MAGIC; + m->version = XIM_CACHE_VERSION; + m->top = im->private.local.top; + m->treeused = b->treeused; + m->mbused = b->mbused; + m->wcused = b->wcused; + m->utf8used = b->utf8used; + /* Tree first, then wide chars, then the rest due to alignment */ + m->tree = msize; + m->wc = msize + sizeof (DefTree) * m->treeused; + m->mb = m->wc + sizeof (wchar_t) * m->wcused; + m->utf8 = m->mb + m->mbused; + m->size = m->utf8 + m->utf8used; + strcpy (m->fname, name); + strcpy (m->fname+strlen(name)+1, encoding); + + /* This STILL might be racy on NFS */ + if ( (fd = _XOpenFileMode (cachename, O_WRONLY | O_CREAT | O_EXCL, + 0600)) < 0) + return; + if (! (fp = fdopen (fd, "wb")) ) { + close (fd); + return; + } + fwrite (m, msize, 1, fp); + fwrite (im->private.local.base.tree, sizeof(DefTree), m->treeused, fp); + fwrite (im->private.local.base.wc, sizeof(wchar_t), m->wcused, fp); + fwrite (im->private.local.base.mb, 1, m->mbused, fp); + fwrite (im->private.local.base.utf8, 1, m->utf8used, fp); + if (fclose (fp) != 0) + unlink (cachename); + _XimCache_mmap = m; + memcpy (&_XimCachedDefaultTreeBase, &im->private.local.base, + sizeof (_XimCachedDefaultTreeBase)); +/* fprintf (stderr, "wrote tree %s size %ld to %s\n", name, m->size, cachename); */ +} + +#endif + + +Private void +_XimCreateDefaultTree( + Xim im) +{ + FILE *fp = NULL; + char *name, *tmpname = NULL, *intname; + char *cachename = NULL; + /* Should use getpwent() instead of $HOME (cross-platform?) */ + char *home = getenv("HOME"); + char *cachedir = NULL; + char *tmpcachedir = NULL; + int hl = home ? strlen (home) : 0; +#ifdef COMPOSECACHE + const char *encoding = nl_langinfo (CODESET); + uid_t euid = geteuid (); + gid_t egid = getegid (); + int cachefd = -1; + off_t size; +#endif + + name = getenv("XCOMPOSEFILE"); + if (name == (char *) NULL) { + if (home != (char *) NULL) { + tmpname = name = Xmalloc(hl + 10 + 1); + if (name != (char *) NULL) { + int fd; + strcpy(name, home); + strcpy(name + hl, "/.XCompose"); + if ( (fd = _XOpenFile (name, O_RDONLY)) < 0) { + Xfree (name); + name = tmpname = NULL; + } else + close (fd); + } + } + } + + if (name == (char *) NULL) { + tmpname = name = _XlcFileName(im->core.lcd, COMPOSE_FILE); + } + intname = name; + +#ifdef COMPOSECACHE + if (getuid () == euid && getgid () == egid && euid != 0) { + char *c; + /* Usage: XCOMPOSECACHE=<cachedir>[=<filename>] + * cachedir: directory of cache files + * filename: internally used name for cache file */ + cachedir = getenv("XCOMPOSECACHE"); + if (cachedir && (c = strchr (cachedir, '='))) { + tmpcachedir = strdup (cachedir); + intname = tmpcachedir + (c-cachedir) + 1; + tmpcachedir[c-cachedir] = '\0'; + cachedir = tmpcachedir; + } + } + + if (! cachedir) { + cachefd = _XimCachedFileName (XIM_GLOBAL_CACHE_DIR, name, intname, + encoding, 0, 1, &cachename, &size); + if (cachefd != -1) { + if (_XimLoadCache (cachefd, intname, encoding, size, im)) { + if (tmpcachedir) + Xfree (tmpcachedir); + if (tmpname) + Xfree (tmpname); + if (cachename) + Xfree (cachename); + close (cachefd); + return; + } + close (cachefd); + } + if (cachename) + Xfree (cachename); + cachename = NULL; + } + + if (getuid () == euid && getgid () == egid && euid != 0 && home) { + + if (! cachedir) { + tmpcachedir = cachedir = Xmalloc (hl+strlen(XIM_HOME_CACHE_DIR)+1); + strcpy (cachedir, home); + strcat (cachedir, XIM_HOME_CACHE_DIR); + } + cachefd = _XimCachedFileName (cachedir, name, intname, encoding, + euid, 0, &cachename, &size); + if (cachefd != -1) { + if (_XimLoadCache (cachefd, intname, encoding, size, im)) { + if (tmpcachedir) + Xfree (tmpcachedir); + if (tmpname) + Xfree (tmpname); + if (cachename) + Xfree (cachename); + close (cachefd); + return; + } + close (cachefd); + } + } +#endif + + if (! (fp = _XFopenFile (name, "r"))) { + if (tmpcachedir) + Xfree (tmpcachedir); + if (tmpname) + Xfree (tmpname); + if (cachename) + Xfree (cachename); + return; + } + _XimParseStringFile(fp, im); + fclose(fp); + +#ifdef COMPOSECACHE + if (cachename) { + assert (euid != 0); + _XimWriteCachedDefaultTree (intname, encoding, cachename, im); + } +#endif + + if (tmpcachedir) + Xfree (tmpcachedir); + if (tmpname) + Xfree (tmpname); + if (cachename) + Xfree (cachename); +} + +Private XIMMethodsRec Xim_im_local_methods = { + _XimLocalCloseIM, /* close */ + _XimLocalSetIMValues, /* set_values */ + _XimLocalGetIMValues, /* get_values */ + _XimLocalCreateIC, /* create_ic */ + _XimLcctstombs, /* ctstombs */ + _XimLcctstowcs, /* ctstowcs */ + _XimLcctstoutf8 /* ctstoutf8 */ +}; + +Public Bool +_XimLocalOpenIM( + Xim im) +{ + XLCd lcd = im->core.lcd; + XlcConv conv; + XimDefIMValues im_values; + XimLocalPrivateRec* private = &im->private.local; + + _XimInitialResourceInfo(); + if(_XimSetIMResourceList(&im->core.im_resources, + &im->core.im_num_resources) == False) { + goto Open_Error; + } + if(_XimSetICResourceList(&im->core.ic_resources, + &im->core.ic_num_resources) == False) { + goto Open_Error; + } + + _XimSetIMMode(im->core.im_resources, im->core.im_num_resources); + + _XimGetCurrentIMValues(im, &im_values); + if(_XimSetLocalIMDefaults(im, (XPointer)&im_values, + im->core.im_resources, im->core.im_num_resources) == False) { + goto Open_Error; + } + _XimSetCurrentIMValues(im, &im_values); + + if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNMultiByte))) + goto Open_Error; + private->ctom_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNWideChar))) + goto Open_Error; + private->ctow_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNCompoundText, lcd, XlcNUtf8String))) + goto Open_Error; + private->ctoutf8_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNMultiByte))) + goto Open_Error; + private->cstomb_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNWideChar))) + goto Open_Error; + private->cstowc_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNCharSet, lcd, XlcNUtf8String))) + goto Open_Error; + private->cstoutf8_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNUcsChar, lcd, XlcNChar))) + goto Open_Error; + private->ucstoc_conv = conv; + + if (!(conv = _XlcOpenConverter(lcd, XlcNUcsChar, lcd, XlcNUtf8String))) + goto Open_Error; + private->ucstoutf8_conv = conv; + + private->base.treeused = 1; + private->base.mbused = 1; + private->base.wcused = 1; + private->base.utf8used = 1; + + _XimCreateDefaultTree(im); + + im->methods = &Xim_im_local_methods; + private->current_ic = (XIC)NULL; + + return(True); + +Open_Error : + _XimLocalIMFree(im); + return(False); +} |