diff lib/Sj3.c @ 0:92745d501b9a

initial import from kinput2-v3.1
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 08 Mar 2010 04:44:30 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Sj3.c	Mon Mar 08 04:44:30 2010 +0900
@@ -0,0 +1,1282 @@
+#ifndef lint
+static char *rcsid = "$Id: Sj3.c,v 2.10 1999/05/25 08:13:05 ishisone Exp $";
+#endif
+/*
+ * Copyright (c) 1990  Software Research Associates, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, 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 Software Research Associates not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  Software Research
+ * Associates makes no representations about the suitability of this software
+ * for any purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
+ */
+/*
+ * Copyright 1991 Sony 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 Sony not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  Sony makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SONY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SONY
+ * 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: Naoshi Suzuki, SONY Corporation.  (nao@sm.sony.co.jp)
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#if XtSpecificationRelease > 4
+#include <X11/Xfuncs.h>
+#endif
+#include <X11/Xmu/Atoms.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#ifdef X_LOCALE
+#include <X11/Xlocale.h>
+#else /* X_LOCALE */
+#include <locale.h>
+#endif /* X_LOCALE */
+#include <pwd.h>
+#include "Sj3P.h"
+
+static XtResource resources[] = {
+#define offset(field) XtOffset(Sj3Object, sj3.field)
+    { XtNsj3serv, XtCSj3serv, XtRString, sizeof(String),
+    offset(sj3serv), XtRString, NULL },
+    { XtNsj3serv2, XtCSj3serv2, XtRString, sizeof(String),
+    offset(sj3serv2), XtRString, NULL },
+    { XtNsj3user, XtCSj3user, XtRString, sizeof(String),
+    offset(sj3user), XtRString, NULL },
+    { XtNrcfile, XtCRcfile, XtRString, sizeof(String),
+    offset(rcfile), XtRString, NULL },
+    { XtNsbfile, XtCSbfile, XtRString, sizeof(String),
+    offset(sbfile), XtRString, NULL },
+    { XtNrkfile, XtCRkfile, XtRString, sizeof(String),
+    offset(rkfile), XtRString, NULL },
+    { XtNhkfile, XtCHkfile, XtRString, sizeof(String),
+    offset(hkfile), XtRString, NULL },
+    { XtNzhfile, XtCZhfile, XtRString, sizeof(String),
+    offset(zhfile), XtRString, NULL },
+#undef offset
+};
+
+static void             ClassInitialize();
+static void             Initialize(),   Destroy();
+static Boolean          SetValues();
+static int              InputEvent();
+static ICString        *GetMode();
+static int              CursorPos();
+static int              NumSegments();
+static ICString        *GetSegment();
+static int              CompareSegment();
+static ICString        *GetItemList();
+static int              SelectItem();
+static int              ConvertedString();
+static int              ClearConversion();
+static ICString        *GetAuxSegments();
+static int              PreeditString();
+static int              StatusString();
+
+Sj3ClassRec sj3ClassRec = {
+  { /* object fields */
+    /* superclass       */          (WidgetClass) &inputConvClassRec,
+    /* class_name       */          "Sj3",
+    /* widget_size      */          sizeof(Sj3Rec),
+    /* class_initialize */          ClassInitialize,
+    /* class_part_initialize    */  NULL,
+    /* class_inited     */          FALSE,
+    /* initialize       */          Initialize,
+    /* initialize_hook  */          NULL,
+    /* obj1             */          NULL,
+    /* obj2             */          NULL,
+    /* obj3             */          0,
+    /* resources        */          resources,
+    /* num_resources    */          XtNumber(resources),
+    /* xrm_class        */          NULLQUARK,
+    /* obj4             */          FALSE,
+    /* obj5             */          FALSE,
+    /* obj6             */          FALSE,
+    /* obj7             */          FALSE,
+    /* destroy          */          Destroy,
+    /* obj8             */          NULL,
+    /* obj9             */          NULL,
+    /* set_values       */          SetValues,
+    /* set_values_hook  */          NULL,
+    /* obj10            */          NULL,
+    /* get_values_hook  */          NULL,
+    /* obj11            */          NULL,
+    /* version          */          XtVersion,
+    /* callback_private */          NULL,
+    /* obj12            */          NULL,
+    /* obj13            */          NULL,
+    /* obj14            */          NULL,
+    /* extension        */          NULL
+  },
+  { /* inputConv fields */
+    /* InputEvent       */          InputEvent,
+    /* GetMode          */          GetMode,
+    /* CursorPos        */          CursorPos,
+    /* NumSegments      */          NumSegments,
+    /* GetSegment       */          GetSegment,
+    /* CompareSegment   */          CompareSegment,
+    /* GetItemList      */          GetItemList,
+    /* SelectItem       */          SelectItem,
+    /* GetConvertedString   */      ConvertedString,
+    /* ClearConversion  */          ClearConversion,
+    /* GetAuxSegments   */          GetAuxSegments,
+    /* SupportMultipleObjects   */  True,
+    /* GetTriggerKeys		*/  XtInheritGetTriggerKeys,
+    /* num_trigger_keys	*/          0,
+    /* trigger_keys	*/          NULL,
+    /* GetPreeditString */          PreeditString,
+    /* GetStatusString */           StatusString,
+    /* NoMoreObjects    */          False,
+  },
+  { /* sj3 fields */
+    /* foo              */          (int)NULL,
+  }
+};
+
+WidgetClass sj3ObjectClass = (WidgetClass)&sj3ClassRec;
+
+static void             startCandidate();
+static void             startSymbol();
+static void             startHinsi();
+static void             moveSelection();
+static int              endSelection();
+static int              insertSelection();
+static void             hinsiInit();
+static void             symbolInit();
+static void             allocCandlist();
+static void             startRegistration();
+static void             changeRegistration();
+static void             endRegistration();
+static void             setLocale();
+static void             setUser();
+
+static void             addObject();
+static void             deleteObject();
+static void             bell();
+
+static ICString        *SymbolList = NULL;
+static int              NumSymbol;
+static ICString        *HinsiList = NULL;
+static int              NumHinsi;
+
+static int              clcount = 0;
+
+static int              usr_code;
+static char             home[256];
+static char             uname[32];
+
+/*
+ * ClassInitialize()
+ *  Initialize common resource.
+ */
+static void
+ClassInitialize()
+{
+    setLocale();
+    setUser();
+
+    Xsj3cSetInLang(usr_code);
+    Xsj3cSetOutLang(JP_EUC);
+}
+
+/*
+ * setLocale()
+ *  Set locale and decide file code for all set-up files.
+ */
+static void
+setLocale()
+{
+    char    *loc;
+
+#ifdef X_LOCALE
+    if (loc = _Xsetlocale (LC_CTYPE, "")) {
+#else /* X_LOCALE */
+    if (loc = setlocale (LC_CTYPE, "")) {
+#endif /* X_LOCALE */
+        if (!strcmp(loc, "ja_JP.SJIS")||!strcmp(loc, "ja_JP.mscode"))
+            usr_code = JP_SJIS;
+        else if (!strcmp(loc, "ja_JP.jis7"))
+            usr_code = JP_JIS7;
+        else if (!strcmp(loc, "ja_JP.jis8"))
+            usr_code = JP_JIS8;
+        else 
+            usr_code = JP_EUC;
+    } else
+        usr_code = JP_EUC;
+#ifdef FORCE_SJIS
+    usr_code = JP_SJIS;
+#endif
+#ifdef FORCE_JIS8
+    usr_code = JP_JIS8;
+#endif
+#ifdef FORCE_JIS7
+    usr_code = JP_JIS7;
+#endif
+}
+
+/*
+ * setUser()
+ *  Set user name and home directory.
+ */
+static void
+setUser()
+{
+    extern char             *getenv(),  *getlogin();
+    char                    *login;
+    struct passwd           *pwd,   *getpwnam(),    *getpwuid();
+
+
+    if (login = getlogin())
+        strcpy(uname, login);
+    setpwent();
+    if (!uname || *uname == '\0') {
+        if (pwd = getpwuid(getuid())) {
+            strcpy(uname, pwd->pw_name);
+        }
+    } else {
+        pwd = getpwnam(uname);
+    }
+    if (pwd)
+        strcpy(home, pwd->pw_dir);
+    else
+        strcpy(home, getenv("HOME"));
+    endpwent();
+}
+
+/*
+ * InputEvent()
+ *  KeyPress event dispatch routine
+ */
+static int
+InputEvent(w, ev)
+    Widget      w;
+    XEvent     *ev;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    int                     ret = 0,    len,    nbytes;
+    unsigned char           *pre;
+    unsigned long           modmask;
+    KeySym                  ks;
+    register Xsj3cEvent     value,      select,     dict;
+
+    /* KeyPress$B0J30$O<N$F$k(B */
+    if (ev->type != KeyPress)
+        return ret;
+    
+    pre = Xsj3cGetPreeditArea(buf, &len);
+
+    /* $B%$%Y%s%H$rJ8;zNs5Z$S(B KeySym $B$KJQ49$9$k(B */
+    nbytes = XmuLookupKana((XKeyPressedEvent *)ev, (char *)pre, len, &ks, NULL);
+    modmask = ev->xkey.state & 0xff;
+
+    value = Xsj3cKeyConv(buf, nbytes, modmask, ks);
+
+    if (select = (value & KEY_SELECT)) {
+        switch (select) {
+        case KEY_CAND_START:
+            startCandidate(obj);
+            break;
+        case KEY_SYMBOL_START:
+            startSymbol(obj);
+            break;
+        case KEY_HINSI_START:
+            startHinsi(obj);
+            break;
+        case KEY_SELECT_RIGHT:
+            moveSelection(obj, ICMoveRight);
+            break;
+        case KEY_SELECT_LEFT:
+            moveSelection(obj, ICMoveLeft);
+            break;
+        case KEY_SELECT_UP:
+            moveSelection(obj, ICMoveUp);
+            break;
+        case KEY_SELECT_DOWN:
+            moveSelection(obj, ICMoveDown);
+            break;
+        case KEY_SELECT_FIRST:
+            moveSelection(obj, ICMoveFirst);
+            break;
+        case KEY_SELECT_LAST:
+            moveSelection(obj, ICMoveLast);
+            break;
+        case KEY_SELECT_NEXTP:
+            moveSelection(obj, ICMoveNextPage);
+            break;
+        case KEY_SELECT_PREVP:
+            moveSelection(obj, ICMovePrevPage);
+            break;
+        case KEY_SELECT_RIGHTMOST:
+            moveSelection(obj, ICMoveRightMost);
+            break;
+        case KEY_SELECT_LEFTMOST:
+            moveSelection(obj, ICMoveLeftMost);
+            break;
+        case KEY_SELECT_END:
+            endSelection(obj, False);
+            break;
+        case KEY_SELECT_ABORT:
+            endSelection(obj, True);
+            break;
+        default:
+            break;
+        }
+    } 
+    if (dict = (value & KEY_DICT)) {
+        switch (dict) {
+        case KEY_DICT_START:
+            startRegistration(obj);
+            break;
+        case KEY_DICT_CHANGE:
+            changeRegistration(obj);
+            break;
+        case KEY_DICT_REGISTER:
+            Xsj3cDictRegister(buf);
+            changeRegistration(obj);
+            break;
+        case KEY_DICT_CLEAR:
+            Xsj3cDictClear(buf);
+            changeRegistration(obj);
+            break;
+        case KEY_DICT_END:
+            endRegistration(obj);
+            break;
+        default:
+            break;
+        }
+    }
+    if (value & KEY_CONTROL || value == KEY_NULL)
+        ret = 1;
+    if (value & KEY_CHANGE){
+        if (value & KEY_MODE_CHANGE) {
+        /* Change display mode string       */
+            XtCallCallbackList(w, obj->inputConv.modechangecallback,
+               (XtPointer)NULL);
+        }
+        if (value & KEY_TEXT_FIXED) {
+        /* Fix converting strings           */
+            XtCallCallbackList(w, obj->inputConv.fixcallback,
+               (XtPointer)NULL);
+            Xsj3cFixBuffer(buf);
+        } else if (value & KEY_TEXT_FLUSH) {
+        /* Fix & Input strings at same time */
+            XtCallCallbackList(w, obj->inputConv.fixcallback,
+               (XtPointer)NULL);
+            Xsj3cFlushBuffer(buf);
+        }
+        if (value & KEY_TEXT_CHANGE) {
+        /* Change  converting strings       */
+            XtCallCallbackList(w, obj->inputConv.textchangecallback,
+               (XtPointer)NULL);
+        }
+        if (value & KEY_HENKAN_END) {
+        /* End conversion                   */
+            XtCallCallbackList((Widget)obj, obj->inputConv.endcallback,
+                   (XtPointer)NULL);
+            Xsj3cClearBuffer(buf);
+        }
+    } 
+    if  (value & KEY_BELL){
+        bell(obj);
+        return ret;
+    } else if (value & KEY_RECONNECT) {
+        Xsj3cConnect(buf, obj->sj3.sj3serv,
+                obj->sj3.sj3serv2, obj->sj3.sj3user);
+        Xsj3cClearBuffer(buf);
+        return ret;
+    }
+    return ret;
+}
+
+static ICString *
+GetMode(w)
+    Widget                  w;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    int                     len;
+    static ICString         icstr;
+
+    icstr.data = (char *)Xsj3cGetModeStr(buf, &len);
+    icstr.nchars = len;
+    icstr.nbytes = icstr.nchars * sizeof(wchar);
+    icstr.attr = ICAttrNormalString;
+    return &icstr;
+}
+
+static int
+CursorPos(w, nsegp, ncharp)
+    Widget                  w;
+    Cardinal                *nsegp;
+    Cardinal                *ncharp;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+
+    return(Xsj3cGetPosition(buf, nsegp, ncharp));
+}
+
+static int
+NumSegments(w)
+Widget                      w;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+
+    return (Xsj3cGetSegNum(buf));
+}
+
+static ICString *
+GetSegment(w, n)
+    Widget                  w;
+    Cardinal                n;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    static                  ICString seg;
+    int                     len, attr;
+
+    seg.data = (char *)Xsj3cGetSeg(buf, n, &len, &attr);
+    seg.nchars = len;
+    seg.nbytes = seg.nchars * sizeof(wchar);
+    switch (attr) {
+    case SEG_REVERSED:
+        seg.attr = ICAttrConverted|ICAttrCurrentSegment;
+        break;
+    case SEG_UNDER_LINE:
+        seg.attr = ICAttrNotConverted;
+        break;
+    case SEG_NORMAL:
+        seg.attr = ICAttrConverted;
+        break;
+    default:
+        seg.attr = ICAttrConverted;
+        break;
+    }
+
+    return &seg;
+}
+
+/* ARGSUSED */
+static int
+CompareSegment(w, seg1, seg2, n)
+    Widget                  w;
+    ICString               *seg1;
+    ICString               *seg2;
+    Cardinal               *n;
+{
+    register unsigned char  *p,     *q;
+    register int            len,    nsame = 0;
+    int                     result = ICSame;
+
+    if (seg1->attr != seg2->attr)
+        result |= ICAttrChanged;
+
+    len = seg1->nbytes > seg2->nbytes ? seg2->nbytes : seg1->nbytes;
+    p = (unsigned char *)seg1->data;
+    q = (unsigned char *)seg2->data;
+    while (nsame < len && *p++ == *q++) nsame++;
+
+    if (nsame != len || len != seg1->nbytes
+        || len != seg2->nbytes || seg1->data != seg2->data)
+        result |= ICStringChanged;
+
+    if (n)
+        *n = nsame / sizeof(wchar);
+
+    return result;
+
+}
+
+static ICString *
+GetItemList(w, n)
+    Widget                  w;
+    Cardinal               *n;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    
+    switch (obj->sj3.state) {
+    case candidate_state:
+        *n = obj->sj3.numcand;
+        return obj->sj3.candlist;
+    case symbol_state:
+        *n = NumSymbol;
+        return obj->sj3.symbollist;
+    case hinsi_state:
+        *n = NumHinsi;
+        return obj->sj3.hinsilist;
+    default:
+        *n = 0;
+        return NULL;    /* no item available */
+    }
+    /* NOTREACHED */
+
+}
+
+static int
+SelectItem(w, n)
+    Widget                  w;
+    int                     n;
+{
+    Sj3Object   obj = (Sj3Object)w;
+    Xsj3cBuf    buf = obj->sj3.sj3buf;
+    int         ret = 0,    changed = False,    flush = False;
+
+    if (obj->sj3.state == normal_state )
+        return -1;
+    else if (n >= 0)
+        ret = insertSelection(obj, n, &changed, &flush);
+    
+    switch (obj->sj3.state) {
+    case candidate_state:
+        Xsj3cEndCandidate(buf, changed);
+        break;
+    case symbol_state:
+        Xsj3cEndSymbol(buf);
+        break;
+    case hinsi_state:
+        Xsj3cEndHinsi(buf);
+        break;
+    default:
+        XtAppWarning(XtWidgetToApplicationContext((Widget)obj),
+             "sj3 Object: Unknown ConvMode state");
+        break;
+    }
+    obj->sj3.state = normal_state;
+
+    if (changed) {
+        if (flush) {
+            XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
+               (XtPointer)NULL);
+            Xsj3cFlushBuffer(buf);
+        }
+        XtCallCallbackList((Widget)obj,
+               obj->inputConv.textchangecallback,
+               (XtPointer)NULL);
+    }
+
+    return ret;
+
+}
+
+static int
+ConvertedString(w, encoding, format, length, string)
+    Widget                  w;
+    Atom                   *encoding;
+    int                    *format;
+    int                    *length;
+    XtPointer              *string;
+{
+    Sj3Object   obj = (Sj3Object)w;
+    Xsj3cBuf    buf = obj->sj3.sj3buf;
+    wchar      *wbuf, *wp;
+    wchar      *data;
+    int         len, wlen;
+    extern int  convJWStoCT();
+
+    wlen = Xsj3cGetConvertedLength(buf);
+    wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
+
+    if ((Xsj3cGetConvertedStr(buf, wbuf)) == NULL) {
+        XtAppWarning(XtWidgetToApplicationContext(w),
+             "sj3 Object: Could not get converted string");
+        return -1;
+    }
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject((Widget)obj));
+    *format = 8;
+
+    for (wp = wbuf; *wp != 0; wp++) {
+        if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+
+    XtFree((char *)wbuf);
+    
+    return 0;
+}
+
+static int
+ClearConversion(w)
+    Widget                  w;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+
+    Xsj3cClearBuffer(buf);
+    XtCallCallbackList(w, obj->inputConv.textchangecallback, (XtPointer)NULL);
+    return 0;
+}
+
+static ICString *
+GetAuxSegments(w, n, ns, nc)
+    Widget                  w;
+    Cardinal               *n, *ns, *nc;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    register int            i;
+    register Xsj3cDictMsg   p;
+    register ICString      *seg;
+    static ICString        *ics;
+
+    *n = Xsj3cGetDictMsgNum(buf);
+    if (!ics) {
+        ics = (ICString *)XtCalloc(*n, sizeof(ICString));
+    } else { 
+        ics = (ICString *)XtRealloc((char *)ics, *n * sizeof(ICString));
+    }
+    bzero(ics, *n * sizeof(ICString));
+    for (i = 0, seg = ics, p = Xsj3cGetDictMsgs(buf);
+            i < *n; i++, seg++) {
+        seg->data = (char *)p[i].data;
+        seg->nchars = p[i].len;
+        seg->nbytes = seg->nchars * sizeof(wchar);
+        switch (p[i].attr) {
+        case SEG_REVERSED:
+            seg->attr = ICAttrConverted|ICAttrCurrentSegment;
+            break;
+        case SEG_UNDER_LINE:
+            seg->attr = ICAttrNotConverted;
+            break;
+        case SEG_NORMAL:
+            seg->attr = ICAttrConverted;
+            break;
+        default:
+            seg->attr = ICAttrNotConverted;
+            break;
+        }
+    }
+    *ns = *n - 1;
+    *nc = 0;
+
+    return ics;
+}
+
+/* ARGSUSED */
+static int
+PreeditString(w, segn, offset, encoding, format, length, string)
+Widget w;
+int segn;
+int offset;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+{
+    Sj3Object obj = (Sj3Object)w;
+    Xsj3cBuf buf = obj->sj3.sj3buf;
+    int segnum = Xsj3cGetSegNum(buf);
+    int seglen, junk;
+    wchar *segdata;
+    Boolean deleted;
+    int i;
+    wchar *wbuf, *wp;
+    int len, wlen;
+    extern int convJWStoCT();
+
+    if (segn < segnum) {
+	segdata = Xsj3cGetSeg(buf, segn, &seglen, &junk);
+	if (offset >= seglen) {
+	    /* $B%;%0%a%s%H$N:G8e(B */
+	    ++segn;
+	    offset = 0;
+	}
+    }
+    if (segn >= segnum) {
+	deleted = True;
+    }
+    else {
+	segdata = Xsj3cGetSeg(buf, segn, &seglen, &junk);
+	deleted = (offset >= seglen);
+    }
+    if (deleted) {
+	/* $B:o=|$5$l$?(B */
+	*encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+	*format = 8;
+	*length = 0;
+	*string = (XtPointer)XtMalloc(1);
+	return 0;
+    }
+
+    wlen = 0;
+    for (i = segn; i < segnum; i++) {
+	segdata = Xsj3cGetSeg(buf, i, &seglen, &junk);
+	wlen += seglen;
+    }
+    wlen -= offset;
+
+    wp = wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
+    segdata = Xsj3cGetSeg(buf, segn, &seglen, &junk);
+    len = seglen - offset;
+    (void)bcopy((char *)(segdata + offset), (char *)wp, sizeof(wchar) * len);
+    wp += len;
+    for (i = segn + 1; i < segnum; i++) {
+	segdata = Xsj3cGetSeg(buf, i, &seglen, &junk);
+	(void)bcopy((char *)segdata, (char *)wp, sizeof(wchar) * seglen);
+	wp += seglen;
+    }
+    wbuf[wlen] = 0;
+
+    /*
+     * Sj3 $B%*%V%8%'%/%H$O(B COMPOUND_TEXT $B%(%s%3!<%G%#%s%0$7$+%5%]!<%H$7$J$$(B
+     * COMPOUND_TEXT $B$KJQ49$9$k(B
+     */
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+    *format = 8;
+
+    /* COMPOUND_TEXT $B$O(B \r $B$,Aw$l$J$$$N$G(B \n $B$KJQ49$7$F$*$/(B */
+    for (wp = wbuf; *wp != 0; wp++) {
+	if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = (XtPointer)XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+
+    /* wbuf $B$r(B free $B$7$F$*$/(B */
+    XtFree((char *)wbuf);
+
+    return 0;
+}
+
+/* ARGSUSED */
+static int
+StatusString(w, encoding, format, length, string, nchars)
+Widget w;
+Atom *encoding;
+int *format;
+int *length;
+XtPointer *string;
+int *nchars;
+{
+    ICString *seg;
+    wchar *wbuf, *wp;
+    int len, wlen;
+    extern int convJWStoCT();
+
+    seg = GetMode(w);
+    if (seg == NULL) {
+	*length = *nchars = 0;
+	return -1;
+    }
+
+    wlen = seg->nchars;
+    if (wlen <= 0) {
+	*length = *nchars = 0;
+	return -1;
+    }
+
+    /*
+     * data $B$KF~$C$F$$$kJQ49%F%-%9%H$O(B null $B%?!<%_%M!<%H$5$l$F$$$J$$$+$b(B
+     * $B$7$l$J$$$N$G!"$^$:%3%T!<$7$F(B null $B%?!<%_%M!<%H$9$k(B
+     */
+    wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
+    (void)bcopy(seg->data, (char *)wbuf, sizeof(wchar) * wlen);
+    wbuf[wlen] = 0;
+
+    /*
+     * Sj3 $B%*%V%8%'%/%H$O(B COMPOUND_TEXT $B%(%s%3!<%G%#%s%0$7$+%5%]!<%H$7$J$$(B
+     * COMPOUND_TEXT $B$KJQ49$9$k(B
+     */
+    *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
+    *format = 8;
+
+    /* COMPOUND_TEXT $B$O(B \r $B$,Aw$l$J$$$N$G(B \n $B$KJQ49$7$F$*$/(B */
+    for (wp = wbuf; *wp != 0; wp++) {
+	if (*wp == '\r') *wp = '\n';
+    }
+
+    *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
+    *string = XtMalloc(len + 1);
+    (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
+    *nchars = seg->nchars;
+
+    /* wbuf $B$r(B free $B$7$F$*$/(B */
+    XtFree((char *)wbuf);
+
+    return 0;
+}
+
+/* ARGSUSED */
+static void
+Initialize(req, new, args, num_args)
+    Widget                  req;
+    Widget                  new;
+    ArgList                 args;
+    Cardinal               *num_args;
+{
+    Sj3Object               obj = (Sj3Object)new;
+    Xsj3cBuf                buf = NULL;
+    int                     min_keycode,  max_keycode,  keysyms_per_keycode;
+    register int            i,  j,  k;
+    unsigned long           kanamod = 0;
+    KeySym                 *keymap;
+    XModifierKeymap        *modmap;
+
+    obj->sj3.symbollist = SymbolList;
+    obj->sj3.hinsilist = HinsiList;
+    obj->sj3.candlist = NULL;
+    obj->sj3.numcand = 0;
+    obj->sj3.curcand = 0;
+    obj->sj3.cursymbol = 0;
+    obj->sj3.curhinsi = 0;
+    obj->sj3.candlistsize = 0;
+    obj->sj3.state = normal_state;
+    obj->sj3.selectionending = False;
+
+    if (!obj->sj3.sj3user || *obj->sj3.sj3user == '\0') 
+        obj->sj3.sj3user = uname;
+
+    if (!clcount++) {
+        /* Get kana lock modmask   */
+        XDisplayKeycodes (XtDisplayOfObject((Widget)obj),
+                &min_keycode, &max_keycode);
+        keymap = XGetKeyboardMapping (XtDisplayOfObject((Widget)obj),
+                min_keycode, (max_keycode - min_keycode + 1),
+                &keysyms_per_keycode);
+        XFree(keymap);
+
+        if (keysyms_per_keycode == 4) {
+            modmap = XGetModifierMapping(XtDisplayOfObject((Widget)obj));
+            k = 0;
+            for (i = 0; i < 8; i++) {
+                for (j = 0; j < modmap->max_keypermod; j++) {
+                    if (XK_Mode_switch ==
+                        XKeycodeToKeysym(XtDisplayOfObject((Widget)obj),
+                            modmap->modifiermap[k], 0)) {
+                        kanamod |= 1 << i;
+                    }
+                    k++;
+                }
+            }
+            XFreeModifiermap(modmap);
+        }
+
+        /* Set kana lock modmask   */
+        Xsj3cSetKanaMod(kanamod);
+
+    }
+
+    /* Making buffer for Xsj3clib   */
+    buf = obj->sj3.sj3buf = Xsj3cCreateBuffer();
+    if (!buf) {
+        XtAppError(XtWidgetToApplicationContext(new),
+            "sj3 Object: Failed to allocate buffers");
+    }
+
+    /* Read user resource customize file and set flags    */
+    (void)Xsj3cRCInit(buf, obj->sj3.rcfile, home);
+
+    /* Convertion table initialization    */
+    Xsj3cInitializeTables(buf, home, obj->sj3.rkfile, obj->sj3.hkfile,
+            obj->sj3.zhfile, obj->sj3.sbfile);
+
+    /* Connect to Kana-kanji conversion server  */
+    if ((Xsj3cOpen(buf, obj->sj3.sj3serv,
+                obj->sj3.sj3user, False, False)) != CONNECT_OK) {
+        XtAppWarning(XtWidgetToApplicationContext(new),
+     "sj3 Object: Failed to connect first server, then try to second server");
+        if ((Xsj3cOpen(buf, obj->sj3.sj3serv2,
+                obj->sj3.sj3user, False, True)) != CONNECT_OK) {
+            XtAppError(XtWidgetToApplicationContext(new),
+                 "sj3 Object: Failed to connect to second server");
+        }
+    };
+    
+    addObject(obj);
+}
+
+static void
+Destroy(w)
+    Widget                  w;
+{
+    Sj3Object               obj = (Sj3Object)w;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    
+    Xsj3cClose(buf, False);
+    Xsj3cFreeBuffer(buf);
+    deleteObject(obj);
+}
+
+static void
+symbolInit(obj)
+    Sj3Object obj;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    register ICString      *strp;
+    register int            i;
+    register Xsj3cSymbol    p;
+
+    for (i = 0, strp = SymbolList, p = Xsj3cGetSymbols(buf);
+            i < NumSymbol; i++, strp++) {
+        strp->data = (char *)p[i].data;
+        strp->nchars = p[i].len;
+        strp->nbytes = strp->nchars * sizeof(wchar);
+        strp->attr = ICAttrNormalString;
+    }
+}
+
+static void
+startSymbol(obj)
+    Sj3Object obj;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    ICSelectionControlArg   arg;
+    
+    /* Symbol list initialization   */
+    if (!SymbolList) {
+        NumSymbol = Xsj3cGetSymbolNum(buf, &obj->sj3.cursymbol);
+        SymbolList = (ICString *)XtMalloc(NumSymbol * sizeof(ICString));
+        symbolInit(obj);
+        obj->sj3.symbollist = SymbolList;
+    } else if (!obj->sj3.symbollist) {
+        obj->sj3.symbollist = SymbolList;
+    }
+
+    obj->sj3.state = symbol_state;
+
+    arg.command = ICSelectionStart;
+    arg.u.selection_kind = ICSelectionCandidates;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+
+    /* set current item */
+    arg.command = ICSelectionSet;
+    arg.u.current_item = obj->sj3.cursymbol;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+}
+
+static void
+startCandidate(obj)
+    Sj3Object obj;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    ICSelectionControlArg   arg;
+    register ICString      *strp;
+    register int            i;
+    int                     ncand,  curcand;
+    register Xsj3cCand      p;
+    
+    if ((ncand = Xsj3cGetCandidateNum(buf, &curcand)) <= 0) {
+        bell(obj);
+        return;
+    }
+    obj->sj3.curcand = curcand;
+    obj->sj3.numcand = ncand;
+
+    allocCandlist(obj, obj->sj3.numcand);
+    
+    for (i = 0, strp = obj->sj3.candlist, p = Xsj3cGetCandidates(buf);
+            i < obj->sj3.numcand; i++, strp++) {
+        strp->data = (char *)p[i].data;
+        strp->nchars = p[i].len;
+        strp->nbytes = strp->nchars * sizeof(wchar);
+        strp->attr = ICAttrNormalString;
+    }
+
+    obj->sj3.state = candidate_state;
+
+    arg.command = ICSelectionStart;
+    arg.u.selection_kind = ICSelectionCandidates;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+
+    /* set current candidate */
+    arg.command = ICSelectionSet;
+    arg.u.current_item = curcand;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+}
+
+static void
+hinsiInit(obj)
+    Sj3Object obj;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    register ICString      *strp;
+    register int            i;
+    register Xsj3cHinsi     p;
+
+    for (i = 0, strp = HinsiList, p = Xsj3cGetHinsis(buf);
+            i < NumHinsi; i++, strp++) {
+        strp->data = (char *)p[i].data;
+        strp->nchars = p[i].len;
+        strp->nbytes = strp->nchars * sizeof(wchar);
+        strp->attr = ICAttrNormalString;
+    }
+}
+
+static void
+startHinsi(obj) 
+    Sj3Object obj;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    ICSelectionControlArg   arg;
+    
+    /* Hinsi list initialization    */
+    if (!HinsiList) {
+        NumHinsi = Xsj3cGetHinsiNum(buf, &obj->sj3.curhinsi);
+        HinsiList = (ICString *)XtMalloc(NumHinsi * sizeof(ICString));
+        hinsiInit(obj);
+        obj->sj3.hinsilist = HinsiList;
+    } else if (!obj->sj3.hinsilist) {
+        obj->sj3.hinsilist = HinsiList;
+    }
+
+    obj->sj3.state = hinsi_state;
+
+    arg.command = ICSelectionStart;
+    arg.u.selection_kind = ICSelectionCandidates;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+
+    /* set current item */
+    arg.command = ICSelectionSet;
+    arg.u.current_item = obj->sj3.curhinsi;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+}
+
+static void
+moveSelection(obj, dir)
+    Sj3Object               obj;
+    int                     dir;
+{
+    ICSelectionControlArg   arg;
+
+    if (obj->sj3.state == normal_state) return;
+    arg.command = ICSelectionMove;
+    arg.u.dir = dir;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+}
+
+static int
+endSelection(obj, abort)
+    Sj3Object               obj;
+    int                     abort;
+{
+    ICSelectionControlArg   arg;
+    int                     selected;
+    int                     ret = 0,    changed = False,    flush = False;
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+
+    if (obj->sj3.selectionending)
+        return 0;
+
+    if (obj->sj3.state == normal_state)
+        return -1;
+
+    arg.command = ICSelectionEnd;
+    arg.u.current_item = -1;
+    XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
+               (XtPointer)&arg);
+
+    if (!abort && (selected = arg.u.current_item) >= 0) {
+        ret = insertSelection(obj, selected, &changed, &flush);
+    }
+
+    switch (obj->sj3.state) {
+    case candidate_state:
+        Xsj3cEndCandidate(buf, changed);
+        break;
+    case symbol_state:
+        Xsj3cEndSymbol(buf);
+        break;
+    case hinsi_state:
+        Xsj3cEndHinsi(buf);
+        break;
+    default:
+        XtAppWarning(XtWidgetToApplicationContext((Widget)obj),
+             "sj3 Object: Unknow ConvMode state");
+        break;
+    }
+    obj->sj3.state = normal_state;
+
+    if (changed) {
+        if (flush) {
+            XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
+               (XtPointer)NULL);
+            Xsj3cFlushBuffer(buf);
+        }
+        XtCallCallbackList((Widget)obj,
+               obj->inputConv.textchangecallback,
+               (XtPointer)NULL);
+    }
+
+    return ret;
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues(cur, req, wid, args, num_args)
+    Widget                  cur;
+    Widget                  req;
+    Widget                  wid;
+    ArgList                 args;
+    Cardinal                *num_args;
+{
+    return False;        
+}
+
+static int
+insertSelection(obj, selected, changed, flush)
+    Sj3Object               obj;
+    int                     selected;
+    int                    *changed;
+    int                    *flush;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    int                     ret = 0;
+
+    obj->sj3.selectionending = True;
+    switch (obj->sj3.state) {
+    case candidate_state:
+        obj->sj3.curcand = selected;
+        ret = Xsj3cSetCandidate(buf, selected, changed, flush);
+        break;
+    case symbol_state:
+        obj->sj3.cursymbol = selected;
+        ret = Xsj3cSetSymbol(buf, selected, changed, flush);
+        break;
+    case hinsi_state:
+        obj->sj3.curhinsi = selected;
+        ret = Xsj3cSetHinsi(buf, selected, changed, flush);
+        break;
+    }
+    obj->sj3.selectionending = False;
+
+    return ret;
+}
+
+static void
+allocCandlist(obj, n)
+    Sj3Object               obj;
+    int                     n;
+{
+    ICString *p;
+
+    if (n <= obj->sj3.candlistsize)
+        return;
+
+    if (obj->sj3.candlistsize == 0) {
+        p = (ICString *)XtMalloc(n * sizeof(ICString));
+    } else {
+        p = (ICString *)XtRealloc((char *)obj->sj3.candlist,
+                  n * sizeof(ICString));
+    }
+
+    obj->sj3.candlist = p;
+    obj->sj3.candlistsize = n;
+}
+
+static void
+startRegistration(obj)
+    Sj3Object   obj;
+{
+    ICAuxControlArg         arg;
+
+    arg.command = ICAuxStart;
+    XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+               (XtPointer)&arg);
+}
+
+static void
+changeRegistration(obj)
+    Sj3Object               obj;
+{
+    ICAuxControlArg         arg;
+
+    arg.command = ICAuxChange;
+    XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+               (XtPointer)&arg);
+}
+
+static void
+endRegistration(obj)
+    Sj3Object   obj;
+{
+    Xsj3cBuf                buf = obj->sj3.sj3buf;
+    ICAuxControlArg         arg;
+
+    arg.command = ICAuxEnd;
+    XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
+               (XtPointer)&arg);
+    Xsj3cEndDict(buf);
+}
+
+/*
+ * keeping list of objects
+ */
+typedef struct _oblist_ {
+    Sj3Object               obj;
+    struct _oblist_        *next;
+} ObjRec;
+
+static ObjRec *ObjList = NULL;
+
+static void
+addObject(obj)
+    Sj3Object               obj;
+{
+    ObjRec                 *objp = XtNew(ObjRec);
+
+    objp->obj = obj;
+    objp->next = ObjList;
+    ObjList = objp;
+}
+
+static void
+deleteObject(obj)
+    Sj3Object obj;
+{
+    ObjRec                 *objp, *objp0;
+
+    for (objp0 = NULL, objp = ObjList;
+            objp != NULL;
+            objp0 = objp, objp = objp->next) {
+        if (objp->obj == obj) {
+            if (objp0 == NULL) {
+                ObjList = objp->next;
+            } else {
+                objp0->next = objp->next;
+            }
+            XtFree((char *)objp);
+            return;
+        }
+    }
+}
+
+static void
+bell(obj)
+    Sj3Object               obj;
+{
+    XBell(XtDisplayOfObject((Widget)obj), 0);
+}