diff options
Diffstat (limited to 'nx-X11/lib/X11/imLcIm.c')
-rw-r--r-- | nx-X11/lib/X11/imLcIm.c | 469 |
1 files changed, 431 insertions, 38 deletions
diff --git a/nx-X11/lib/X11/imLcIm.c b/nx-X11/lib/X11/imLcIm.c index fa73f43ba..81645e5bd 100644 --- a/nx-X11/lib/X11/imLcIm.c +++ b/nx-X11/lib/X11/imLcIm.c @@ -15,17 +15,17 @@ 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 +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 + Author: Takashi Fujiwara FUJITSU LIMITED fujiwara@a80.tech.yk.fujitsu.co.jp Modifier: Franky Ling Digital Equipment Corporation frankyling@hgrd01.enet.dec.com @@ -48,10 +48,55 @@ THIS SOFTWARE. #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; +_XimCheckIfLocalProcessing(Xim im) { FILE *fp; char *name; @@ -76,23 +121,37 @@ _XimCheckIfLocalProcessing(im) Private void XimFreeDefaultTree( - DefTree *top) + DefTreeBase *b) { - if (!top) return; - if (top->succession) XimFreeDefaultTree(top->succession); - if (top->next) XimFreeDefaultTree(top->next); - if (top->mb) Xfree(top->mb); - if (top->wc) Xfree(top->wc); - if (top->utf8) Xfree(top->utf8); - Xfree(top); + 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.top); - im->private.local.top = NULL; + XimFreeDefaultTree(&im->private.local.base); + im->private.local.top = 0; if(im->core.im_resources) { Xfree(im->core.im_resources); @@ -211,28 +270,282 @@ _XimLocalSetIMValues( 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, (unsigned int)sizeof (DefTree), hash, hash2); + else + sprintf (*res, "%s%c%d_%03x_%08x_%08x", dir, _XimGetMyEndian(), + XIM_CACHE_VERSION, (unsigned int)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; + 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) { - char *home = getenv("HOME"); if (home != (char *) NULL) { - int hl = strlen(home); tmpname = name = Xmalloc(hl + 10 + 1); if (name != (char *) NULL) { + int fd; strcpy(name, home); strcpy(name + hl, "/.XCompose"); - fp = _XFopenFile (name, "r"); - if (fp == (FILE *) NULL) { - Xfree(name); - name = tmpname = NULL; - } + if ( (fd = _XOpenFile (name, O_RDONLY)) < 0) { + Xfree (name); + name = tmpname = NULL; + } else + close (fd); } } } @@ -240,19 +553,94 @@ _XimCreateDefaultTree( 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 (name == (char *) NULL) - return; - if (fp == (FILE *) NULL) { - fp = _XFopenFile (name, "r"); + 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 (tmpname != (char *) NULL) { - Xfree(tmpname); + + 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; } - if (fp == (FILE *) NULL) - 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 = { @@ -325,6 +713,11 @@ _XimLocalOpenIM( 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; |