4.4BSD/usr/src/contrib/X11R5-lib/lib/X/Xsi/XLocalIM.c

Compare this file to the similar file:
Show the results in this format:

/*
 * $XConsortium: XLocalIM.c,v 1.11 92/10/22 14:26:20 rws Exp $
 */

/*
 * Copyright 1990, 1991 by OMRON Corporation
 * Copyright 1991 by the Massachusetts Institute of Technology
 *
 * 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 names of OMRON and MIT not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  OMRON and MIT make no representations
 * about the suitability of this software for any purpose.  It is provided
 * "as is" without express or implied warranty.
 *
 * OMRON AND MIT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL OMRON OR MIT 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
 * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE. 
 *
 *	Author:	Seiji Kuwari	OMRON Corporation
 *				kuwa@omron.co.jp
 *				kuwa%omron.co.jp@uunet.uu.net
 */				

#include <stdio.h>

#define NEED_EVENTS
#include "Xlibint.h"
#include "Xi18nint.h"
#include "XIMlibint.h"
#include <X11/Xos.h>
#include <X11/keysymdef.h>
#if NeedVarargsPrototypes
# include <stdarg.h>
# define Va_start(a,b) va_start(a,b)
#else
# include <varargs.h>
# define Va_start(a,b) va_start(a)
#endif
#ifndef X_NOT_POSIX
#ifdef _POSIX_SOURCE
#include <limits.h>
#else
#define _POSIX_SOURCE
#include <limits.h>
#undef _POSIX_SOURCE
#endif
#endif
#ifndef PATH_MAX
#include <sys/param.h>
#ifndef PATH_MAX
#ifdef MAXPATHLEN
#define PATH_MAX MAXPATHLEN
#else
#define PATH_MAX 1024
#endif
#endif
#endif

#ifdef X_NOT_STDC_ENV
extern char *getenv();
#endif

#if __STDC__ && !defined(NORCONST)
#define RConst const
#else
#define RConst /**/
#endif

#define	offset(field)	XOffsetOf(XipLocalIMRec, field)

static int compiled_resources;

static XIMResource im_resources[] = {
    { XNQueryInputStyle, sizeof(XIMStyles), offset(values.input_styles),
      (unsigned short)IMResourceRead, (int)IMQueryInputStyle },
#ifdef	XML
    { XNQueryLanguage, sizeof(char *), offset(values.supported_language),
      (unsigned short)IMResourceRead, (int)IMQueryLanguage }
#endif	/* XML */
};

#undef offset

#define	offset(field)	XOffsetOf(XipLocalICRec, field)

static XIMResource ic_resources[] = {
    { XNInputStyle, sizeof(XIMStyle), offset(core.input_style),
      (unsigned short)IMResourceReadWrite, ICInputStyle },
    { XNClientWindow, sizeof(Window), offset(core.client_window),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNFocusWindow, sizeof(Window), offset(core.focus_window),
      (unsigned short)IMResourceReadWrite, ICFocusWindow },
    { XNResourceName, sizeof(char *), offset(values.res_name),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNResourceClass, sizeof(char *), offset(values.res_class),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNFilterEvents, sizeof(long), offset(core.filter_events),
      (unsigned short)IMResourceRead, ICFilterEvents },
    { XNPreeditAttributes, sizeof(ICAttributes *), offset(core.preedit_attr),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNStatusAttributes, sizeof(ICAttributes *), offset(core.status_attr),
      (unsigned short)IMResourceReadWrite, -1 }
#ifdef	XML
    ,
    { XNUsingLanguage, sizeof(char *), offset(values.using_language),
      (unsigned short)IMResourceReadWrite, ICUsingLanguage },
    { XNCurrentLanguage, sizeof(char *), offset(values.current_language),
      (unsigned short)IMResourceReadWrite, ICCurrentLanguage },
    { XNChangeLocaleCB, sizeof(char **), offset(values.ch_locale_cb),
      (unsigned short)IMResourceReadWrite, ICChangeLocaleCB },
#endif	/* XML */
};

#undef	offset

#define	attroffset(field)	XOffsetOf(ICAttributes, field)

static XIMResource attr_resources[] = {
    { XNArea, sizeof(XRectangle), attroffset(area),
      (unsigned short)IMResourceReadWrite, ICArea },
    { XNAreaNeeded, sizeof(XRectangle), attroffset(area_needed),
      (unsigned short)IMResourceReadWrite, ICAreaNeeded },
    { XNSpotLocation, (sizeof(XPoint) + 4), attroffset(spot_location),
      (unsigned short)IMResourceReadWrite, ICSpotLocation },
    { XNColormap, sizeof(Colormap), attroffset(colormap),
      (unsigned short)IMResourceReadWrite, ICColormap },
    { XNStdColormap, sizeof(Atom), attroffset(std_colormap),
      (unsigned short)IMResourceReadWrite, ICStdColormap },
    { XNForeground, sizeof(long), attroffset(foreground),
      (unsigned short)IMResourceReadWrite, ICForeground },
    { XNBackground, sizeof(long), attroffset(background),
      (unsigned short)IMResourceReadWrite, ICBackground },
    { XNBackgroundPixmap, sizeof(Pixmap), attroffset(background_pixmap),
      (unsigned short)IMResourceReadWrite, ICBackgroundPixmap },
    { XNFontSet, sizeof(XFontSet *), attroffset(fontset),
      (unsigned short)IMResourceReadWrite, ICFontSet },
    { XNLineSpace, sizeof(int), attroffset(line_space),
      (unsigned short)IMResourceReadWrite, ICLineSpace },
    { XNCursor, sizeof(Cursor), attroffset(cursor),
      (unsigned short)IMResourceReadWrite, ICCursor },
    { XNPreeditStartCallback, sizeof(XIMCallback), attroffset(callbacks.start),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNPreeditDoneCallback, sizeof(XIMCallback), attroffset(callbacks.done),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNPreeditDrawCallback, sizeof(XIMCallback), attroffset(callbacks.draw),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNPreeditCaretCallback, sizeof(XIMCallback), attroffset(callbacks.caret),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNStatusStartCallback, sizeof(XIMCallback), attroffset(callbacks.start),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNStatusDoneCallback, sizeof(XIMCallback), attroffset(callbacks.done),
      (unsigned short)IMResourceReadWrite, -1 },
    { XNStatusDrawCallback, sizeof(XIMCallback), attroffset(callbacks.draw),
      (unsigned short)IMResourceReadWrite, -1 }
};

#undef	attroffset


#define ENTRY_CNT 256

#define BITONP(h, i) (h[i / BITSIZ] &  (1 << (i % BITSIZ)))
#define BITOFP(h, i) (!BITONP(h, i))
#define BIT_UP(h, i) (h[i / BITSIZ] |= (1 << (i % BITSIZ)))
#define BITDWN(h, i) (h[i / BITSIZ] &= ~(1 << (i % BITSIZ)))

#define div_up(a, b) ((a + b - 1) / b)

#ifndef XNLSPATHDEFAULT
#define XNLSPATHDEFAULT "/usr/lib/X11/nls"
#endif

#ifndef LOCAL_CVT_TBL_DIR
#define LOCAL_CVT_TBL_DIR	"/local_im_tbl/"
#endif

typedef struct {
    char *name;
    unsigned int mask;
} StateTbl;

static StateTbl state_tbl[] = {
    { "Lock",	LockMask },
    { "Control",	ControlMask },
    { "Mod1",	Mod1Mask },
    { "Mod2",	Mod2Mask },
    { "Mod3",	Mod3Mask },
    { "Mod4",	Mod4Mask },
    { "Mod5",	Mod5Mask },
    { NULL,	0 }
};

typedef struct {
    char *name;
    Bool (*func)();
    int (*init_func)();
} FuncTbl;

static int convert_on();
static int convert_off();
static int convert_on_init();
static int no_filter();

static FuncTbl func_tbl[] = {
    { "ConvertOn",	convert_on,	convert_on_init },
    { "ConvertOff",	convert_off,	NULL },
    { "NoFilter",	NULL,	no_filter }
};

static unsigned int
is_state(name)
register char *name;
{
    register StateTbl *p;

    for (p = state_tbl; p->name; p++) {
	if (!strcmp(p->name, name)) return(p->mask);
    }
    return(0);
}

static int
parse_bslash(buf, work)
register char *buf;
register unsigned char *work;
{
    register int i;
    switch(*buf) {
	case 'x': /* 16 */
	    for (buf++, *work = '\0', i = 1; i >= 0; i--, buf++) {
		if (*buf >= '0' && *buf <= '9') {
		    *work |= ((1 << (i * 4)) * (*buf - '0'));
		} else if (*buf >= 'A' && *buf <= 'F') {
		    *work |= ((1 << (i * 4)) * (*buf - 'A' + 10));
		} else if (*buf >= 'a' && *buf <= 'f') {
		    *work |= ((1 << (i * 4)) * (*buf - 'a' + 10));
		} else {
		    return(0);
		}
	    }
	    return(3);
	case 'o': /* 8 */
	    for (buf++, *work = '\0', i = 2; i >= 0; i--, buf++) {
		if (*buf >= '0' && *buf <= '7') {
		    *work |= ((1 << (i * 3)) * (*buf - '0'));
		} else {
		    return(0);
		}
	    }
	    return(4);
	case 'n': /*  */
	    *work = '\n'; return(1);
	case 't': /* */
	    *work = '\t'; return(1);
	case 'b': /* */
	    *work = '\b'; return(1);
	case 'r': /* */
	    *work = '\r'; return(1);
	case 'f': /* */
	    *work = '\f'; return(1);
	case 'e': /* */
	case 'E': /* */
	    *work = '\033'; return(1);
	case '\\': /* */
	    *work = '\\'; return(1);
	default:
	    for (*work = '\0', i = 2; i >= 0; i--, buf++) {
		if (*buf >= '0' && *buf <= '7') {
		    *work |= ((1 << (i * 3)) * (*buf - '0'));
		} else {
		    return(*buf);
		}
	    }
	    return(3);
    }
}

static XipLocalKeySymTbl *
get_string(buf, tbl)
register char *buf;
XipLocalKeySymTbl *tbl;
{
    XipLocalKeySymTbl work_tbl[8], *p, *t;
    unsigned char work[32], *str;
    register int i = 0, total = 0, ret;

    for (p = work_tbl, total = 0; *buf; p++, total++, buf++) {
	if ((buf = index(buf, '{')) == NULL) {
	    break;
	}
	buf++;
	for ( i = 0; *buf != '}';) {
	    if (*buf == (char)0x5c) {
		buf++;
		if (!(ret = parse_bslash(buf, &work[i]))) {
		    return(NULL);
		}
		buf += ret;
		i++;
	    } else {
		work[i++] = *buf;
		buf++;
	    }
	    if (!*buf) return(NULL);
	}
	if (i == 0) return(NULL);
	work[i] = '\0';
	str = (unsigned char *) Xmalloc(i + 1);
	strcpy((char *)str, (char *)work);
	p->str = str;
	p->keysym = NoSymbol;
	p->state = 0;
	total++;
    }
    if (total < 1) return(NULL);
    p->str = NULL;
    p->keysym = XK_VoidSymbol;
    p->state = 0;
    if (tbl) {
	for (i = 0, t = tbl, p = work_tbl;
	     t->keysym != XK_VoidSymbol && i < total; i++, t++, p++) {
	    t->str = p->str;
	}
    } else {
	tbl = (XipLocalKeySymTbl *) Xmalloc((sizeof(XipLocalKeySymTbl)
					    * (total + 1)));
	if (!tbl) return (NULL);
	bcopy((char *)work_tbl, (char *)tbl,
	      sizeof(XipLocalKeySymTbl) * (total + 1));
    }
    return(tbl);
}

static XipLocalKeySymTbl *
get_keysym(buf, len)
char *buf;
int *len;
{
    int cnt, total = 0;
    int i;
    XipLocalKeySymTbl work_tbl[8], *keysym_tbl, *p;
    char *k[8];

    *len = 0;
    for (cnt = 0; ; cnt++) {
	if ((buf = index(buf, '<')) == NULL) {
	    break;
	}
	k[cnt] = ++buf;
	if (buf = index(buf, '>')) {
	    *buf = '\0';
	    buf++;
	}
    }
    if (cnt < 1)
	return (NULL);

    for (i = 0, p = work_tbl, total = 0; i < cnt; i++, p++) {
	if (p->state = is_state(k[i])) {
	    i++;
	}
	if ((p->keysym = XStringToKeysym(k[i])) == 0) {
	    fprintf(stderr,
		    "Can't convert to KeySym \"%s\".", k[i]);
	    return (NULL);
	}
	p->str = NULL;
	total++;
    }
    p->keysym = XK_VoidSymbol;
    p->str = NULL;
    total++;
    keysym_tbl = (XipLocalKeySymTbl *) Xmalloc((sizeof(XipLocalKeySymTbl)
						* total));
    if (!keysym_tbl)
	return (NULL);
    bcopy((char *)work_tbl, (char *)keysym_tbl,
	  sizeof(XipLocalKeySymTbl) * total);
    *len = (total - 1);
    return (keysym_tbl);
}


static int
is_comment(c)
char c;
{
    if (c == '#')
	return (1);
    return (0);
}

static int
is_command(c)
char c;
{
    if (c != '<' && c != '{')
	return (1);
    return (0);
}

static int
is_keysym(c)
char c;
{
    if (c == '<')
	return (1);
    return (0);
}

static int
is_state_command(xcvt, f, t)
XipLocalCvt *xcvt;
char *f, *t;
{
    if (!*f || !*t) return(0);
    if (!strcmp(f, "InitialState"))
	if (!strcmp(t, "OnState"))
	    xcvt->off = False;
	else if (!strcmp(t, "OffState"))
	    xcvt->off = True;
	else return(0);
    return(1);
}

static FuncTbl *
get_command(name)
char *name;
{
    register FuncTbl *p;

    for (p = func_tbl; p->name; p++) {
	if (!strcmp(p->name, name)) {
	    return(p);
	}
    }
    fprintf(stderr, "Sorry, \"%s\" is not a supported command.\n", name);
    fprintf(stderr, "XIM supported commands are \n");
    for (p = func_tbl; p->name; p++) {
	fprintf(stderr, " %s \n", p->name);
    }
    return(NULL);
}

static Bool
convert_on(xcvt)
XipLocalCvt *xcvt;
{
    xcvt->off = False;
    return(1);
}

static Bool
convert_off(xcvt)
XipLocalCvt *xcvt;
{
    xcvt->off = True;
    return(True);
}

static int
convert_on_init(xcvt, tbl, len)
XipLocalCvt *xcvt;
XipLocalCvtTbl *tbl;
int len;
{
    register XipLocalKeySymTbl *to, *from, *p;

    p = (XipLocalKeySymTbl *) Xmalloc(sizeof(XipLocalKeySymTbl) * (len + 1));
    if (!p) return(-1);
    for (to = p, from = tbl->fromkey; len > 0; to++, from++, len--) {
	to->keysym = from->keysym;
	to->state = from->state;
    }
    to->keysym = XK_VoidSymbol;
    to->state = 0;
    xcvt->off_tbl.to.func = tbl->to.func;
    xcvt->off_tbl.com = True;
    xcvt->off_tbl.fromkey = p;
    return(0);
}

static int
no_filter(xcvt, tbl, len)
XipLocalCvt *xcvt;
XipLocalCvtTbl *tbl;
int len;
{
    XipLocalNestedKeySym *nested_keysym;

    nested_keysym = (XipLocalNestedKeySym *)
      Xmalloc(sizeof(XipLocalNestedKeySym));
    if (!nested_keysym) return(-1);
    nested_keysym->keysym = tbl->fromkey->keysym;
    nested_keysym->next = xcvt->no_filter;
    xcvt->no_filter = nested_keysym;
    return(1);
}

static Bool
is_nofilter(xcvt, keysym)
XipLocalCvt *xcvt;
KeySym keysym;
{
    XipLocalNestedKeySym *p;

    for (p = xcvt->no_filter; p; p = p->next) {
	if (p->keysym == keysym) return(True);
    }
    return(False);
}

static FILE *
open_convert_file(lang, filename)
char *lang;
char *filename;
{
    FILE	*fp;
    char	nlspath[PATH_MAX];
    char	*path;
    char	*dir;
    char	*env;

    if ((env = getenv("XNLSPATH")) == NULL) {
	env = XNLSPATHDEFAULT;
    }
    path = nlspath;
    strcpy(path, env);
    while (1) {
	if (path == NULL) {
	    fprintf(stderr, "%s \"%s\".\n%s%s%s.\n",
		    "XIM: Couldn't find any convert table for lang", lang,
		    "Please, create xnls_dir", LOCAL_CVT_TBL_DIR, lang);
	    return(NULL);
	}
	dir = path;
	if ((dir = index(dir, ':')) != NULL) {
	    *dir++ = '\0';
	}
	strcpy(filename, path);
	strcat(filename, LOCAL_CVT_TBL_DIR);
	strcat(filename, lang);
	if (fp = fopen(filename, "r")) {
	    return(fp);
	}
	path = dir;
    }
}

static XipLocalCvt *
_XipLocalCvtSetUp(xlc)
XLocale	xlc;
{
    char	filename[PATH_MAX];
    char	tmp_buf[32], *p;
    FILE	*fp;
    char buf[256], tobuf[256], frombuf[256], tostr[256];
    int	 cnt = 0;
    int len;
    int k;
    XipLocalCvt *cvt;
    KeySym bs;
    FuncTbl *func_tbl;
    int line = 0;
    int ret;

    strcpy(tmp_buf, xlc->xlc_db->lc_name);
    for (p = tmp_buf; *p && *p != '@'; p++);
    if (*p)  *p = '\0';

    if(CHANGE_MAX < div_up(ENTRY_CNT, BITSIZ)){
	fprintf(stderr, "XIM: %s%s%d%s",
		"Sorry, please set CHANGE_MAX(in file ",
		"Xi18nint.h) larger than ",
		div_up(ENTRY_CNT, BITSIZ) - 1,
		",\r\nand recompile.\r\n");
	return(NULL);
    }

    
    if(!(fp = open_convert_file(tmp_buf, filename))) return(NULL);
    if (!(cvt = (XipLocalCvt *) Xmalloc(sizeof(XipLocalCvt)))) {
	fprintf(stderr, "XIM: Malloc failed\n");
	goto _err_ret2;
    }
    if (!(cvt->tbl = (XipLocalCvtTbl *) Xmalloc(sizeof(XipLocalCvtTbl) * ENTRY_CNT))) {
	fprintf(stderr, "XIM: Malloc failed\n");
	goto _err_ret1;
    }

    cnt = 0;
    cvt->nmax = 0;
    cvt->no_filter = NULL;
    cvt->off = False;
    while(fgets(buf, BUFSIZ, fp)) {
	line++;
	if(is_comment(*buf) || 
	   (k = sscanf(buf, "%s %s %s", frombuf, tobuf, tostr)) <= 0)
	    continue;
	if (k < 2) {
	    goto _err_ret;
	}
	if(!(cvt->tbl[cnt].fromkey = get_keysym(frombuf, &len))){
	    if (!is_state_command(cvt, frombuf, tobuf))
		goto _err_ret;
	    continue;
	}
	if (len > cvt->nmax) cvt->nmax = len;
	if (is_command(*tobuf)) {
	    if(!(func_tbl = get_command(tobuf))) {
		goto _err_ret;
	    }
	    cvt->tbl[cnt].to.func = func_tbl->func;
	    cvt->tbl[cnt].com = True;
	    if (func_tbl->init_func) {
		if ((ret = (*func_tbl->init_func)(cvt, &cvt->tbl[cnt], len))
		     == -1)
		    goto _err_ret;
		else if (ret == 0)
		    continue;
	    }
	} else {
	    if (is_keysym(*tobuf)) {
		if(!(cvt->tbl[cnt].to.tokey = get_keysym(tobuf, &len))){
		    goto _err_ret;
		}
		if (k > 2) {
		    if(!(get_string(tostr, cvt->tbl[cnt].to.tokey))){
			goto _err_ret;
		    }
		}
	    } else {
		if(!(cvt->tbl[cnt].to.tokey = get_string(tobuf, NULL))){
		    goto _err_ret;
		}
	    }
	    cvt->tbl[cnt].com = False;
	}
	cnt++;

    }
    cvt->cnt = cnt;
    cvt->buf = (XipLocalKeySymTbl *) Xmalloc(sizeof(XipLocalKeySymTbl)
					     * (cvt->nmax + 1));
    cvt->buf_cnt = 0;
    cvt->bs = ((bs = XStringToKeysym("BackSpace"))? bs: 0x8);
    fclose(fp);
    return(cvt);
_err_ret:
    fprintf(stderr, "XIM: Error occurred at line %d in file \"%s\".\n",
	    line, filename);
    Xfree(cvt->tbl);
_err_ret1:
    Xfree(cvt);
_err_ret2:
    fclose(fp);
    return(NULL);
}

static XipLocalCvt *
_XipLocalDupCvt(cvt)
XipLocalCvt *cvt;
{
    XipLocalCvt *new;

    if (!(new = (XipLocalCvt *) Xmalloc(sizeof(XipLocalCvt)))) {
	return(NULL);
    }
    new->tbl = cvt->tbl;
    new->off_tbl = cvt->off_tbl;
    new->no_filter = cvt->no_filter;
    new->bs = cvt->bs;
    new->cnt = cvt->cnt;
    new->nmax = cvt->nmax;
    new->buf = (XipLocalKeySymTbl *) Xmalloc(sizeof(XipLocalKeySymTbl)
					     * (new->nmax + 1));
    new->buf_cnt = 0;
    new->off = cvt->off;
    return(new);
}

static void
_XipLocalFreeCvt(cvt)
XipLocalCvt *cvt;
{
    register int i, j;
    XipLocalCvtTbl *tbl;

    tbl = cvt->tbl;
    for (i = 0; i < cvt->cnt; i++, tbl++) {
	Xfree((*tbl).fromkey);
	if ((*tbl).com != True) {
	    for (j = 0; (*tbl).to.tokey[j].str; j++)
		Xfree((*tbl).to.tokey[j].str);
	    Xfree((*tbl).to.tokey);
	}
    }
    Xfree(cvt->tbl);
    Xfree(cvt);
}

/*
 * Close the connection to the input manager, and free the private data
 */
static Status
_XipLocalCloseIM(supim)
    XIM supim;
{
    XipLocalIM im = (XipLocalIM)supim;
    _XlcFreeLocale(im->xlc);
    if (im->xcvt) _XipLocalFreeCvt(im->xcvt);
    return(Success);
}

static RConst XIMMethodsRec im_methods = {
    _XipLocalCloseIM,
    _XipLocalGetIMValues,
    _XipLocalCreateIC
};

XIM 
_XipLocalOpenIM(lcd, display, rdb, res_name, res_class)
    XLCd lcd;
    Display *display;
    XrmDatabase rdb;
    char *res_name;
    char *res_class;
{
    XipLocalIM		xim;
    XLocale		xlc = ((XsiLCd)lcd)->xlc;
    XipLocalCvt		*xcvt;
    XIMStyle		*supported_styles;

    if ((xcvt = _XipLocalCvtSetUp(xlc)) == NULL) return(NULL);
    /*
     * Attempt to allocate a XIM structure. Return NULL if allocation
     * failed.
     */
    if ((xim = (XipLocalIM)Xmalloc(sizeof(XipLocalIMRec))) == NULL) {
	return(NULL);
    }
    xim->methods = (XIMMethods)&im_methods;
    xim->core.lcd = lcd;
    xim->core.ic_chain = NULL;
    xim->core.display = display;
    xim->core.rdb = rdb;
    xim->core.res_name = res_name;
    xim->core.res_class = res_class;

    if (!compiled_resources) {
	_XIMCompileResourceList(im_resources, XIMNumber(im_resources));
	_XIMCompileResourceList(ic_resources, XIMNumber(ic_resources));
	_XIMCompileResourceList(attr_resources, XIMNumber(attr_resources));
	compiled_resources = 1;
    }
    xim->resources = (XIMrmResourceList)im_resources;
    xim->num_resources = XIMNumber(im_resources);
    xim->core.ic_resources = (XIMrmResourceList)ic_resources;
    xim->core.ic_num_resources = XIMNumber(ic_resources);
    xim->core.ic_attr_resources = (XIMrmResourceList)attr_resources;
    xim->core.ic_num_attr_resources = XIMNumber(attr_resources);

    if ((supported_styles = (XIMStyle *)Xmalloc((unsigned)(sizeof(XIMStyle))))
	== NULL) {
	return(NULL);
    }
    supported_styles[0] = (XIMPreeditNothing | XIMStatusNothing);
    xim->values.input_styles.supported_styles = supported_styles;
    xim->values.input_styles.count_styles = 1;
    xim->xlc = _XlcDupLocale(xlc);
    xim->xcvt = xcvt;

    return((XIM)xim);
}

int
_XipLocalCallCallbacks(ic)
    XipIC ic;
{
    return(0);
}

static int
key_check(cvt)
XipLocalCvt *cvt;
{
    int		dist, base;
    XipLocalKeySymTbl	*code_p;
    int		i;

    for(base = 0; cvt->buf[base].keysym != XK_VoidSymbol; base++) {
	for(dist = 0; dist < cvt->cnt; dist++) {
	    if(BITONP(cvt->check_flg, dist) &&
	       cvt->tbl[dist].fromkey->keysym != XK_VoidSymbol){
		code_p = cvt->tbl[dist].fromkey + base;
		if((code_p->keysym == cvt->buf[base].keysym) &&
		   ((!(code_p->state | (cvt->buf[base].state & ~ShiftMask))) ||
		    (code_p->state == (cvt->buf[base].state & ~ShiftMask)))) {
		    if((code_p + 1)->keysym == (KeySym)XK_VoidSymbol){
			/* matched */
			for(i = 0, base++;
			    (cvt->buf[i].keysym = cvt->buf[base].keysym) != XK_VoidSymbol;
			    i++, base++);
			return(dist);
		    }
			/* Not yet matched */
		} else {
		    BITDWN(cvt->check_flg, dist); /* off bit vecter */
		}
	    }
	}
    }

    /* Check bit vercters */
    for(i = 0; i < cvt->cnt / BITSIZ; i++){
	if(cvt->check_flg[i]) return(-1);
    }
    if((cvt->cnt % BITSIZ) &&
       (cvt->check_flg[i]& ~(~0 << (cvt->cnt % BITSIZ))))
	return(-1); /* posiblity */
    return(-2);	/* Not matched */
}

static int
off_key_check(cvt)
XipLocalCvt *cvt;
{
    int		base;
    XipLocalKeySymTbl	*code_p = cvt->off_tbl.fromkey;
    int		i;

    for(base = 0; cvt->buf[base].keysym != XK_VoidSymbol; base++) {
	if((code_p->keysym == cvt->buf[base].keysym) &&
	   ((!(code_p->state | (cvt->buf[base].state & ~ShiftMask))) ||
	   (code_p->state == (cvt->buf[base].state & ~ShiftMask)))) {
	    if((code_p + 1)->keysym == (KeySym)XK_VoidSymbol){
		/* matched */
		for(i = 0, base++;
		    (cvt->buf[i].keysym = cvt->buf[base].keysym) != XK_VoidSymbol;
		    i++, base++);
		return(0);
	    }
	} else {
	    return(-2);
	}
    }
    return(-1); /* posiblity */
}

static void
_XipLocalClearCvt(cvt)
XipLocalCvt *cvt;
{
    register int i;

    for(i = 0; i < div_up(cvt->cnt, BITSIZ); cvt->check_flg[i++] = ~0);
}

Bool
_XipLocalBackEndFilter(display, window, ev, client_data)
    Display *display;
    Window window;
    XEvent *ev;
    XPointer client_data;
{
    register XipLocalIC	ic = (XipLocalIC)client_data;
    XipLocalCvt		*xcvt = ic->xcvt;
    KeySym keysym;
    int keycode;
    int	i, c;		/* work */
    char str[256];
    XEvent dummy_ev;

    if (xcvt->cnt == 0)
	return(False);

    if (ev->xkey.keycode == 0) {
	if (_XipTypeOfNextICQueue((XipIC)ic) == XIM_KEYSYM){
	    if ((keycode = XKeysymToKeycode(display,
			    _XipKeySymOfNextICQueue((XipIC)ic))) != 0
		&& _XipStringOfNextICQueue((XipIC)ic) == NULL){
		ev->xkey.state = _XipStateOfNextICQueue((XipIC)ic);
		ev->xkey.keycode = keycode;
		_XipFreeNextICQueue((XipIC)ic);
	    }
	}
	return(False);
    }

    if (ic->out) ic->out = NULL;
    
    (void)XLookupString(ev, str, 256, &keysym, NULL);

    if (keysym == NoSymbol/* || nbytes < 1 */) {
	return(True);
    }
    if (is_nofilter(xcvt, keysym)) return(False);
    if (keysym == xcvt->bs) {
	if (xcvt->buf_cnt == 0) {
	    return(False);
	}
	xcvt->buf[xcvt->buf_cnt - 1].keysym = xcvt->buf[xcvt->buf_cnt].keysym;
	xcvt->buf[xcvt->buf_cnt - 1].state = xcvt->buf[xcvt->buf_cnt].state;
	_XipLocalClearCvt(xcvt);
	if (--xcvt->buf_cnt > 0) {
	    key_check(xcvt);
	}
	return(True);
    }
    if (xcvt->buf_cnt == 0) {
	_XipLocalClearCvt(xcvt);
    }
    xcvt->buf[xcvt->buf_cnt].keysym = keysym;
    xcvt->buf[xcvt->buf_cnt].state = ev->xkey.state;
    xcvt->buf[++xcvt->buf_cnt].keysym = XK_VoidSymbol;
    bcopy((char *)ev, (char *)&dummy_ev, sizeof(XEvent));
    dummy_ev.type = KeyPress;
    dummy_ev.xkey.state = 0;
    dummy_ev.xkey.keycode = 0;

    if (xcvt->off == True) {
	if ((c = off_key_check(xcvt)) == 0) {
	    xcvt->buf_cnt = 0;
	    (*xcvt->off_tbl.to.func)(xcvt);
	    _XipLocalClearCvt(xcvt);
	    return(True);
	}
    } else {
	c = key_check(xcvt);
    }
    switch (c) {
    case -1: /* Event was filtered */
	return (True);
    case -2: /* No match */
	for (i = 0; i < xcvt->buf_cnt; i++) {
	     if (_XipPutICQueue(ic, XIM_KEYSYM, 0, xcvt->buf[i].keysym,
				xcvt->buf[i].state, 0, NULL) < 0)
	       return(False);
	}
	ev->xkey.state = 0;
	ev->xkey.keycode = 0;
	if ((keycode = XKeysymToKeycode(display,
				_XipKeySymOfNextICQueue((XipIC)ic))) != 0
	    && _XipStringOfNextICQueue((XipIC)ic) == NULL) {
	    ev->xkey.state = _XipStateOfNextICQueue((XipIC)ic);
	    ev->xkey.keycode = keycode;
	    _XipFreeNextICQueue((XipIC)ic);
	}
	for (i = 1; i < xcvt->buf_cnt; i++) {
	    XPutBackEvent(display, &dummy_ev);
	}
	xcvt->buf_cnt = 0;
	_XipLocalClearCvt(xcvt);
	return (False);
    default: /* matched */
        xcvt->buf_cnt = 0;
	if (xcvt->tbl[c].com == True) {
	    if ((*xcvt->tbl[c].to.func)(xcvt) == True) {
		_XipLocalClearCvt(xcvt);
		return(True);
	    }
	}
	for (i = 0; xcvt->tbl[c].to.tokey[i].keysym != XK_VoidSymbol; i++) {
	     if (_XipPutICQueue(ic, XIM_KEYSYM, 0,
				xcvt->tbl[c].to.tokey[i].keysym,
				xcvt->tbl[c].to.tokey[i].state, 1,
				xcvt->tbl[c].to.tokey[i].str) < 0)
	       return(False);
	}
	ev->xkey.state = 0;
	ev->xkey.keycode = 0;
	if ((keycode = XKeysymToKeycode(display,
				_XipKeySymOfNextICQueue((XipIC)ic))) != 0
	    && _XipStringOfNextICQueue((XipIC)ic) == NULL) {
	    ev->xkey.state = _XipStateOfNextICQueue((XipIC)ic);
	    ev->xkey.keycode = keycode;
	    _XipFreeNextICQueue((XipIC)ic);
	}
	for (i = 1; xcvt->tbl[c].to.tokey[i].keysym != XK_VoidSymbol; i++) {
	    XPutBackEvent(display, &dummy_ev);
	}
	xcvt->buf_cnt = 0;
	_XipLocalClearCvt(xcvt);
	return(False);
    }
}

/*
 * Free the input context.
 */
void
_XipLocalDestroyIC(supic)
    XIC supic;
{
    XipLocalIC ic = (XipLocalIC)supic;
    XipLocalIM im = (XipLocalIM)ic->core.im;

    _XUnregisterFilter(im->core.display, ic->core.focus_window,
		       ic->prototype_filter, (XPointer)ic);

#ifdef	XML
    if (ic->xlc_num > 0) {
	int i;

	for (i = 0; i < ic->xlc_num; i++) {
	    _XlcFreeLocale(ic->mb_temp[i]);
	    _XlcFreeLocale(ic->wc_temp[i]);
	    _XipLocalFreeCvt(ic->xcvt);
	}
    }
    if (ic->values.using_language) Xfree(ic->values.using_language);
#endif	/* XML */
}

static RConst XICMethodsRec ic_methods = {
    _XipLocalDestroyIC,
    _XipLocalSetICFocus,
    _XipLocalUnsetICFocus,
    _XipLocalSetICValues,
    _XipLocalGetICValues,
    _XipLocalmbResetIC,
    _XipLocalwcResetIC,
    _XipmbLookupString,
    _XipwcLookupString
};

/*
 * Create an input context within the input method, 
 * and return a pointer the input context ti the caller.
 */
XIC
_XipLocalCreateIC(supim, args)
    XIM supim;
    XIMArg *args;
{
    XipLocalIM		im = (XipLocalIM)supim;
    XipLocalIC		ic;
    unsigned long	mask = 0L;
#ifdef	XML
    char		**nls_list, **l;
    XLocale		xlc;
#endif	/* XML */

    if ((ic = (XipLocalIC)Xcalloc(1, sizeof(XipLocalICRec))) == NULL) {
	return(NULL);
    }

    ic->methods = (XICMethods) &ic_methods;
    ic->prototype_filter = _XipLocalBackEndFilter;
    ic->core.im = supim;
    (void)_XipICSetValues(ic, args, &mask);

#ifdef	XML
    if (im->xlc != NULL) {
#endif	/* XML */
	ic->mb = _XlcDupLocale(im->xlc);
	ic->wc = _XlcDupLocale(im->xlc);
	ic->xcvt = _XipLocalDupCvt(im->xcvt);
#ifdef	XML
	ic->xlc_num = 0;
	ic->mb_temp = NULL;
	ic->wc_temp = NULL;
	ic->xcvt_temp = NULL;
    } else {
	ic->mb = NULL;
	ic->wc = NULL;
	ic->xcvt_temp = NULL;
	ic->xlc_num = 0;
	if ((ic->mb_temp = (XLocale*)Xmalloc(sizeof(XLocale) * 32)) == NULL) {
	    return(NULL);
	}
	if ((ic->wc_temp = (XLocale*)Xmalloc(sizeof(XLocale) * 32)) == NULL) {
	    return(NULL);
	}
	if ((ic->xcvt_temp = (XipLocalCvt**)
	     Xmalloc(sizeof(XipLocalCvt*) * 32)) == NULL) {
	    return(NULL);
	}
	_XlcListLocale(&nls_list);
	for (l = nls_list; *l; l++) {
	    xlc = _XlcMakeLocale(*l);
	    if (!xlc)
		continue;
	    if ((ic->xcvt_temp[ic->xlc_num] = _XipLocalCvtSetUp(xlc)) == NULL){
		_XlcFreeLocale(xlc);
	        continue;
	    }
	    ic->mb_temp[ic->xlc_num] = xlc;
	    ic->wc_temp[ic->xlc_num] = _XlcDupLocale(xlc);
	    ic->xlc_num++;
	}
	Xfree((char *)nls_list);
	ic->mb = ic->mb_temp[0];
	ic->wc = ic->wc_temp[0];
	ic->xcvt = ic->xcvt_temp[0];
    }
#endif /* XML */
    return((XIC)ic);
}

/*
 * Reset the input context. 
 */
wchar_t *
_XipLocalwcResetIC(supic)
    XIC supic;		/* specified the input context to reset*/
{
    register XipLocalIC	ic = (XipLocalIC)supic;

    ic->xcvt->buf_cnt = 0;
    _XipLocalClearCvt(ic->xcvt);
    return((wchar_t *)NULL);
}

char *
_XipLocalmbResetIC(supic)
    XIC supic;		/* specified the input context to reset*/
{
    register XipLocalIC	ic = (XipLocalIC)supic;

    ic->xcvt->buf_cnt = 0;
    _XipLocalClearCvt(ic->xcvt);
    return(NULL);
}

/*
 * Query Input Method.
 */
static char *
_IMGetValues(im, args)
    register XipLocalIM im;
    register XIMArg *args;
{
    register XIMArg		*arg;
    register int		i;
    register XrmName		Name;
    register XIMrmResourceList	xrmres;
    unsigned int		num_resources = im->num_resources;
    XrmQuark			query_input =
				     XrmPermStringToQuark(XNQueryInputStyle);

    for (arg = args; arg->name && *(arg->name); arg++) {
	Name = XrmStringToName(arg->name);
	for (xrmres = im->resources, i = 0;
	     i < num_resources; i++, xrmres++) {
	    if (Name == xrmres->xrm_name) {
		if (Name == query_input) {
		    char *p;
		    XIMStyles *styles;
		    int size = sizeof(XIMStyle)
			       * im->values.input_styles.count_styles;
		    int all_size = sizeof(XIMStyles) + size;
		    if ((p = Xmalloc((unsigned)all_size)) == NULL) {
			continue;
		    }
		    styles = (XIMStyles *)p;
		    styles->count_styles = im->values.input_styles.count_styles;
		    styles->supported_styles =
					(XIMStyle *)(p + sizeof(XIMStyles));
		    bcopy((char *)im->values.input_styles.supported_styles,
			  (char *)styles->supported_styles, size);
		    bcopy((char *)&styles, (char *)arg->value,
			  sizeof(XIMStyles *));
		} else {
		    (void) _XCopyToArg((char *)im - xrmres->xrm_offset - 1,
				       &arg->value,
				       (unsigned int)xrmres->xrm_size);
		}
		break;
	    }
	}
	if (i >= num_resources) return(arg->name);
    }
    return NULL;
}

char *
_XipLocalGetIMValues(supim, args)
    XIM supim;
    XIMArg *args;
{
    XipLocalIM im = (XipLocalIM)supim;

    return(_IMGetValues(im, args));
}

/*
 * Require the input manager to focus the focus window attached to the ic
 * argument.
 */
void
_XipLocalSetICFocus(supic)
    XIC supic;
{
    XipLocalIC		ic = (XipLocalIC)supic;
    XipLocalIM		im = ipLocalIMofIC(ic);

    _XRegisterFilterByMask(im->core.display, ic->core.focus_window,
			   KeyPressMask, ic->prototype_filter, (XPointer)ic);
}

/*
 * Require the input manager to unfocus the focus window attached to the ic
 * argument.
 */
void
_XipLocalUnsetICFocus(supic)
    XIC supic;
{
    XipLocalIC		ic = (XipLocalIC)supic;
    XipLocalIM		im = ipLocalIMofIC(ic);
    _XUnregisterFilter(im->core.display, ic->core.focus_window,
		       ic->prototype_filter, (XPointer)ic);
}

char*
_XipLocalGetICValues(supic, args)
    XIC supic;
    XIMArg *args;
{
    XipLocalIC		ic = (XipLocalIC)supic;
    unsigned long	mask = 0L;

    return(_XipICGetValues((XipIC)ic, args, &mask, 0));
}

#ifdef	XML
void
_XipLocalChangeLocale(ic, lc_name)
    XipLocalIC ic;
    char *lc_name;
{
    XLocale xlc;
    int i;

    for (i = 0; i < ic->xlc_num; i++) {
	if ((!strcmp(lc_name, ic->mb_temp[i]->lc_lang)) ||
	    (!strcmp(lc_name, ic->mb_temp[i]->xlc_db->lc_name))) {
	    ic->mb = ic->mb_temp[i];
	    ic->wc = ic->wc_temp[i];
	    ic->xcvt = ic->xcvt_temp[i];
	    return;
	}
    }
    xlc = _XlcMakeLocale(lc_name);
    if (xlc) {
	if ((ic->xcvt = ic->xcvt_temp[ic->xlc_num] = _XipLocalCvtSetUp(xlc))
	    == NULL) {
	    _XlcFreeLocale(xlc);
	    return;
	}
	ic->mb = ic->mb_temp[ic->xlc_num] = xlc;
	ic->wc = ic->wc_temp[ic->xlc_num] = _XlcDupLocale(xlc);
	ic->xlc_num++;
    }
}
#endif	/* XML */

char *
_XipLocalSetICValues(supic, args)
    XIC supic;
    XIMArg *args;
{
    XipLocalIC		ic = (XipLocalIC)supic;
    XipLocalIM		im = ipLocalIMofIC(ic);
    unsigned long	mask = 0L;
    Window		old_focus_window;
    char		*err = NULL;

    old_focus_window = ic->core.focus_window;

    err = _XipICSetValues((XipIC)ic, args, &mask);
    if (err)
	return(err);
    
    if (mask & (1L << ICFocusWindow)) {
	_XUnregisterFilter(im->core.display, old_focus_window,
			   ic->prototype_filter, (XPointer)ic);
	_XRegisterFilterByMask(im->core.display, ic->core.focus_window,
			       KeyPressMask,
			       ic->prototype_filter, (XPointer)ic);
    }
#ifdef	XML
    if (mask & (1L << ICCurrentLanguage)) {
	_XipLocalChangeLocale(ic, ic->values.current_language);
    }
#endif	/* XML */

    return(NULL);
}