1 #ifndef lint
2 static char *rcsid = "$Id: Sj3.c,v 2.10 1999/05/25 08:13:05 ishisone Exp $";
3 #endif
4 /*
5  * Copyright (c) 1990  Software Research Associates, Inc.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted, provided
9  * that the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of Software Research Associates not be
12  * used in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.  Software Research
14  * Associates makes no representations about the suitability of this software
15  * for any purpose.  It is provided "as is" without express or implied
16  * warranty.
17  *
18  * Author:  Makoto Ishisone, Software Research Associates, Inc., Japan
19  */
20 /*
21  * Copyright 1991 Sony Corporation
22  *
23  * Permission to use, copy, modify, distribute, and sell this software and its
24  * documentation for any purpose is hereby granted without fee, provided that
25  * the above copyright notice appear in all copies and that both that
26  * copyright notice and this permission notice appear in supporting
27  * documentation, and that the name of Sony not be used in advertising or
28  * publicity pertaining to distribution of the software without specific,
29  * written prior permission.  Sony makes no representations about the
30  * suitability of this software for any purpose.  It is provided "as is"
31  * without express or implied warranty.
32  *
33  * SONY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SONY
35  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
37  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
38  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39  */
40 /*
41  * Author: Naoshi Suzuki, SONY Corporation.  (nao@sm.sony.co.jp)
42  */
43 
44 #include <X11/IntrinsicP.h>
45 #include <X11/StringDefs.h>
46 #if XtSpecificationRelease > 4
47 #include <X11/Xfuncs.h>
48 #endif
49 #include <X11/Xmu/Atoms.h>
50 #include <X11/Xutil.h>
51 #include <X11/keysym.h>
52 #ifdef X_LOCALE
53 #include <X11/Xlocale.h>
54 #else /* X_LOCALE */
55 #include <locale.h>
56 #endif /* X_LOCALE */
57 #include <pwd.h>
58 #include "Sj3P.h"
59 
60 static XtResource resources[] = {
61 #define offset(field) XtOffset(Sj3Object, sj3.field)
62     { XtNsj3serv, XtCSj3serv, XtRString, sizeof(String),
63     offset(sj3serv), XtRString, NULL },
64     { XtNsj3serv2, XtCSj3serv2, XtRString, sizeof(String),
65     offset(sj3serv2), XtRString, NULL },
66     { XtNsj3user, XtCSj3user, XtRString, sizeof(String),
67     offset(sj3user), XtRString, NULL },
68     { XtNrcfile, XtCRcfile, XtRString, sizeof(String),
69     offset(rcfile), XtRString, NULL },
70     { XtNsbfile, XtCSbfile, XtRString, sizeof(String),
71     offset(sbfile), XtRString, NULL },
72     { XtNrkfile, XtCRkfile, XtRString, sizeof(String),
73     offset(rkfile), XtRString, NULL },
74     { XtNhkfile, XtCHkfile, XtRString, sizeof(String),
75     offset(hkfile), XtRString, NULL },
76     { XtNzhfile, XtCZhfile, XtRString, sizeof(String),
77     offset(zhfile), XtRString, NULL },
78 #undef offset
79 };
80 
81 static void             ClassInitialize();
82 static void             Initialize(),   Destroy();
83 static Boolean          SetValues();
84 static int              InputEvent();
85 static ICString        *GetMode();
86 static int              CursorPos();
87 static int              NumSegments();
88 static ICString        *GetSegment();
89 static int              CompareSegment();
90 static ICString        *GetItemList();
91 static int              SelectItem();
92 static int              ConvertedString();
93 static int              ClearConversion();
94 static ICString        *GetAuxSegments();
95 static int              PreeditString();
96 static int              StatusString();
97 
98 Sj3ClassRec sj3ClassRec = {
99   { /* object fields */
100     /* superclass       */          (WidgetClass) &inputConvClassRec,
101     /* class_name       */          "Sj3",
102     /* widget_size      */          sizeof(Sj3Rec),
103     /* class_initialize */          ClassInitialize,
104     /* class_part_initialize    */  NULL,
105     /* class_inited     */          FALSE,
106     /* initialize       */          Initialize,
107     /* initialize_hook  */          NULL,
108     /* obj1             */          NULL,
109     /* obj2             */          NULL,
110     /* obj3             */          0,
111     /* resources        */          resources,
112     /* num_resources    */          XtNumber(resources),
113     /* xrm_class        */          NULLQUARK,
114     /* obj4             */          FALSE,
115     /* obj5             */          FALSE,
116     /* obj6             */          FALSE,
117     /* obj7             */          FALSE,
118     /* destroy          */          Destroy,
119     /* obj8             */          NULL,
120     /* obj9             */          NULL,
121     /* set_values       */          SetValues,
122     /* set_values_hook  */          NULL,
123     /* obj10            */          NULL,
124     /* get_values_hook  */          NULL,
125     /* obj11            */          NULL,
126     /* version          */          XtVersion,
127     /* callback_private */          NULL,
128     /* obj12            */          NULL,
129     /* obj13            */          NULL,
130     /* obj14            */          NULL,
131     /* extension        */          NULL
132   },
133   { /* inputConv fields */
134     /* InputEvent       */          InputEvent,
135     /* GetMode          */          GetMode,
136     /* CursorPos        */          CursorPos,
137     /* NumSegments      */          NumSegments,
138     /* GetSegment       */          GetSegment,
139     /* CompareSegment   */          CompareSegment,
140     /* GetItemList      */          GetItemList,
141     /* SelectItem       */          SelectItem,
142     /* GetConvertedString   */      ConvertedString,
143     /* ClearConversion  */          ClearConversion,
144     /* GetAuxSegments   */          GetAuxSegments,
145     /* SupportMultipleObjects   */  True,
146     /* GetTriggerKeys		*/  XtInheritGetTriggerKeys,
147     /* num_trigger_keys	*/          0,
148     /* trigger_keys	*/          NULL,
149     /* GetPreeditString */          PreeditString,
150     /* GetStatusString */           StatusString,
151     /* NoMoreObjects    */          False,
152   },
153   { /* sj3 fields */
154     /* foo              */          (int)NULL,
155   }
156 };
157 
158 WidgetClass sj3ObjectClass = (WidgetClass)&sj3ClassRec;
159 
160 static void             startCandidate();
161 static void             startSymbol();
162 static void             startHinsi();
163 static void             moveSelection();
164 static int              endSelection();
165 static int              insertSelection();
166 static void             hinsiInit();
167 static void             symbolInit();
168 static void             allocCandlist();
169 static void             startRegistration();
170 static void             changeRegistration();
171 static void             endRegistration();
172 static void             setLocale();
173 static void             setUser();
174 
175 static void             addObject();
176 static void             deleteObject();
177 static void             bell();
178 
179 static ICString        *SymbolList = NULL;
180 static int              NumSymbol;
181 static ICString        *HinsiList = NULL;
182 static int              NumHinsi;
183 
184 static int              clcount = 0;
185 
186 static int              usr_code;
187 static char             home[256];
188 static char             uname[32];
189 
190 /*
191  * ClassInitialize()
192  *  Initialize common resource.
193  */
194 static void
ClassInitialize()195 ClassInitialize()
196 {
197     setLocale();
198     setUser();
199 
200     Xsj3cSetInLang(usr_code);
201     Xsj3cSetOutLang(JP_EUC);
202 }
203 
204 /*
205  * setLocale()
206  *  Set locale and decide file code for all set-up files.
207  */
208 static void
setLocale()209 setLocale()
210 {
211     char    *loc;
212 
213 #ifdef X_LOCALE
214     if (loc = _Xsetlocale (LC_CTYPE, "")) {
215 #else /* X_LOCALE */
216     if (loc = setlocale (LC_CTYPE, "")) {
217 #endif /* X_LOCALE */
218         if (!strcmp(loc, "ja_JP.SJIS")||!strcmp(loc, "ja_JP.mscode"))
219             usr_code = JP_SJIS;
220         else if (!strcmp(loc, "ja_JP.jis7"))
221             usr_code = JP_JIS7;
222         else if (!strcmp(loc, "ja_JP.jis8"))
223             usr_code = JP_JIS8;
224         else
225             usr_code = JP_EUC;
226     } else
227         usr_code = JP_EUC;
228 #ifdef FORCE_SJIS
229     usr_code = JP_SJIS;
230 #endif
231 #ifdef FORCE_JIS8
232     usr_code = JP_JIS8;
233 #endif
234 #ifdef FORCE_JIS7
235     usr_code = JP_JIS7;
236 #endif
237 }
238 
239 /*
240  * setUser()
241  *  Set user name and home directory.
242  */
243 static void
244 setUser()
245 {
246     extern char             *getenv(),  *getlogin();
247     char                    *login;
248     struct passwd           *pwd,   *getpwnam(),    *getpwuid();
249 
250 
251     if (login = getlogin())
252         strcpy(uname, login);
253     setpwent();
254     if (!uname || *uname == '\0') {
255         if (pwd = getpwuid(getuid())) {
256             strcpy(uname, pwd->pw_name);
257         }
258     } else {
259         pwd = getpwnam(uname);
260     }
261     if (pwd)
262         strcpy(home, pwd->pw_dir);
263     else
264         strcpy(home, getenv("HOME"));
265     endpwent();
266 }
267 
268 /*
269  * InputEvent()
270  *  KeyPress event dispatch routine
271  */
272 static int
273 InputEvent(w, ev)
274     Widget      w;
275     XEvent     *ev;
276 {
277     Sj3Object               obj = (Sj3Object)w;
278     Xsj3cBuf                buf = obj->sj3.sj3buf;
279     int                     ret = 0,    len,    nbytes;
280     unsigned char           *pre;
281     unsigned long           modmask;
282     KeySym                  ks;
283     register Xsj3cEvent     value,      select,     dict;
284 
285     /* KeyPress$B0J30$O<N$F$k(B */
286     if (ev->type != KeyPress)
287         return ret;
288 
289     pre = Xsj3cGetPreeditArea(buf, &len);
290 
291     /* $B%$%Y%s%H$rJ8;zNs5Z$S(B KeySym $B$KJQ49$9$k(B */
292     nbytes = XmuLookupKana((XKeyPressedEvent *)ev, (char *)pre, len, &ks, NULL);
293     modmask = ev->xkey.state & 0xff;
294 
295     value = Xsj3cKeyConv(buf, nbytes, modmask, ks);
296 
297     if (select = (value & KEY_SELECT)) {
298         switch (select) {
299         case KEY_CAND_START:
300             startCandidate(obj);
301             break;
302         case KEY_SYMBOL_START:
303             startSymbol(obj);
304             break;
305         case KEY_HINSI_START:
306             startHinsi(obj);
307             break;
308         case KEY_SELECT_RIGHT:
309             moveSelection(obj, ICMoveRight);
310             break;
311         case KEY_SELECT_LEFT:
312             moveSelection(obj, ICMoveLeft);
313             break;
314         case KEY_SELECT_UP:
315             moveSelection(obj, ICMoveUp);
316             break;
317         case KEY_SELECT_DOWN:
318             moveSelection(obj, ICMoveDown);
319             break;
320         case KEY_SELECT_FIRST:
321             moveSelection(obj, ICMoveFirst);
322             break;
323         case KEY_SELECT_LAST:
324             moveSelection(obj, ICMoveLast);
325             break;
326         case KEY_SELECT_NEXTP:
327             moveSelection(obj, ICMoveNextPage);
328             break;
329         case KEY_SELECT_PREVP:
330             moveSelection(obj, ICMovePrevPage);
331             break;
332         case KEY_SELECT_RIGHTMOST:
333             moveSelection(obj, ICMoveRightMost);
334             break;
335         case KEY_SELECT_LEFTMOST:
336             moveSelection(obj, ICMoveLeftMost);
337             break;
338         case KEY_SELECT_END:
339             endSelection(obj, False);
340             break;
341         case KEY_SELECT_ABORT:
342             endSelection(obj, True);
343             break;
344         default:
345             break;
346         }
347     }
348     if (dict = (value & KEY_DICT)) {
349         switch (dict) {
350         case KEY_DICT_START:
351             startRegistration(obj);
352             break;
353         case KEY_DICT_CHANGE:
354             changeRegistration(obj);
355             break;
356         case KEY_DICT_REGISTER:
357             Xsj3cDictRegister(buf);
358             changeRegistration(obj);
359             break;
360         case KEY_DICT_CLEAR:
361             Xsj3cDictClear(buf);
362             changeRegistration(obj);
363             break;
364         case KEY_DICT_END:
365             endRegistration(obj);
366             break;
367         default:
368             break;
369         }
370     }
371     if (value & KEY_CONTROL || value == KEY_NULL)
372         ret = 1;
373     if (value & KEY_CHANGE){
374         if (value & KEY_MODE_CHANGE) {
375         /* Change display mode string       */
376             XtCallCallbackList(w, obj->inputConv.modechangecallback,
377                (XtPointer)NULL);
378         }
379         if (value & KEY_TEXT_FIXED) {
380         /* Fix converting strings           */
381             XtCallCallbackList(w, obj->inputConv.fixcallback,
382                (XtPointer)NULL);
383             Xsj3cFixBuffer(buf);
384         } else if (value & KEY_TEXT_FLUSH) {
385         /* Fix & Input strings at same time */
386             XtCallCallbackList(w, obj->inputConv.fixcallback,
387                (XtPointer)NULL);
388             Xsj3cFlushBuffer(buf);
389         }
390         if (value & KEY_TEXT_CHANGE) {
391         /* Change  converting strings       */
392             XtCallCallbackList(w, obj->inputConv.textchangecallback,
393                (XtPointer)NULL);
394         }
395         if (value & KEY_HENKAN_END) {
396         /* End conversion                   */
397             XtCallCallbackList((Widget)obj, obj->inputConv.endcallback,
398                    (XtPointer)NULL);
399             Xsj3cClearBuffer(buf);
400         }
401     }
402     if  (value & KEY_BELL){
403         bell(obj);
404         return ret;
405     } else if (value & KEY_RECONNECT) {
406         Xsj3cConnect(buf, obj->sj3.sj3serv,
407                 obj->sj3.sj3serv2, obj->sj3.sj3user);
408         Xsj3cClearBuffer(buf);
409         return ret;
410     }
411     return ret;
412 }
413 
414 static ICString *
415 GetMode(w)
416     Widget                  w;
417 {
418     Sj3Object               obj = (Sj3Object)w;
419     Xsj3cBuf                buf = obj->sj3.sj3buf;
420     int                     len;
421     static ICString         icstr;
422 
423     icstr.data = (char *)Xsj3cGetModeStr(buf, &len);
424     icstr.nchars = len;
425     icstr.nbytes = icstr.nchars * sizeof(wchar);
426     icstr.attr = ICAttrNormalString;
427     return &icstr;
428 }
429 
430 static int
431 CursorPos(w, nsegp, ncharp)
432     Widget                  w;
433     Cardinal                *nsegp;
434     Cardinal                *ncharp;
435 {
436     Sj3Object               obj = (Sj3Object)w;
437     Xsj3cBuf                buf = obj->sj3.sj3buf;
438 
439     return(Xsj3cGetPosition(buf, nsegp, ncharp));
440 }
441 
442 static int
443 NumSegments(w)
444 Widget                      w;
445 {
446     Sj3Object               obj = (Sj3Object)w;
447     Xsj3cBuf                buf = obj->sj3.sj3buf;
448 
449     return (Xsj3cGetSegNum(buf));
450 }
451 
452 static ICString *
453 GetSegment(w, n)
454     Widget                  w;
455     Cardinal                n;
456 {
457     Sj3Object               obj = (Sj3Object)w;
458     Xsj3cBuf                buf = obj->sj3.sj3buf;
459     static                  ICString seg;
460     int                     len, attr;
461 
462     seg.data = (char *)Xsj3cGetSeg(buf, n, &len, &attr);
463     seg.nchars = len;
464     seg.nbytes = seg.nchars * sizeof(wchar);
465     switch (attr) {
466     case SEG_REVERSED:
467         seg.attr = ICAttrConverted|ICAttrCurrentSegment;
468         break;
469     case SEG_UNDER_LINE:
470         seg.attr = ICAttrNotConverted;
471         break;
472     case SEG_NORMAL:
473         seg.attr = ICAttrConverted;
474         break;
475     default:
476         seg.attr = ICAttrConverted;
477         break;
478     }
479 
480     return &seg;
481 }
482 
483 /* ARGSUSED */
484 static int
485 CompareSegment(w, seg1, seg2, n)
486     Widget                  w;
487     ICString               *seg1;
488     ICString               *seg2;
489     Cardinal               *n;
490 {
491     register unsigned char  *p,     *q;
492     register int            len,    nsame = 0;
493     int                     result = ICSame;
494 
495     if (seg1->attr != seg2->attr)
496         result |= ICAttrChanged;
497 
498     len = seg1->nbytes > seg2->nbytes ? seg2->nbytes : seg1->nbytes;
499     p = (unsigned char *)seg1->data;
500     q = (unsigned char *)seg2->data;
501     while (nsame < len && *p++ == *q++) nsame++;
502 
503     if (nsame != len || len != seg1->nbytes
504         || len != seg2->nbytes || seg1->data != seg2->data)
505         result |= ICStringChanged;
506 
507     if (n)
508         *n = nsame / sizeof(wchar);
509 
510     return result;
511 
512 }
513 
514 static ICString *
515 GetItemList(w, n)
516     Widget                  w;
517     Cardinal               *n;
518 {
519     Sj3Object               obj = (Sj3Object)w;
520 
521     switch (obj->sj3.state) {
522     case candidate_state:
523         *n = obj->sj3.numcand;
524         return obj->sj3.candlist;
525     case symbol_state:
526         *n = NumSymbol;
527         return obj->sj3.symbollist;
528     case hinsi_state:
529         *n = NumHinsi;
530         return obj->sj3.hinsilist;
531     default:
532         *n = 0;
533         return NULL;    /* no item available */
534     }
535     /* NOTREACHED */
536 
537 }
538 
539 static int
540 SelectItem(w, n)
541     Widget                  w;
542     int                     n;
543 {
544     Sj3Object   obj = (Sj3Object)w;
545     Xsj3cBuf    buf = obj->sj3.sj3buf;
546     int         ret = 0,    changed = False,    flush = False;
547 
548     if (obj->sj3.state == normal_state )
549         return -1;
550     else if (n >= 0)
551         ret = insertSelection(obj, n, &changed, &flush);
552 
553     switch (obj->sj3.state) {
554     case candidate_state:
555         Xsj3cEndCandidate(buf, changed);
556         break;
557     case symbol_state:
558         Xsj3cEndSymbol(buf);
559         break;
560     case hinsi_state:
561         Xsj3cEndHinsi(buf);
562         break;
563     default:
564         XtAppWarning(XtWidgetToApplicationContext((Widget)obj),
565              "sj3 Object: Unknown ConvMode state");
566         break;
567     }
568     obj->sj3.state = normal_state;
569 
570     if (changed) {
571         if (flush) {
572             XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
573                (XtPointer)NULL);
574             Xsj3cFlushBuffer(buf);
575         }
576         XtCallCallbackList((Widget)obj,
577                obj->inputConv.textchangecallback,
578                (XtPointer)NULL);
579     }
580 
581     return ret;
582 
583 }
584 
585 static int
586 ConvertedString(w, encoding, format, length, string)
587     Widget                  w;
588     Atom                   *encoding;
589     int                    *format;
590     int                    *length;
591     XtPointer              *string;
592 {
593     Sj3Object   obj = (Sj3Object)w;
594     Xsj3cBuf    buf = obj->sj3.sj3buf;
595     wchar      *wbuf, *wp;
596     wchar      *data;
597     int         len, wlen;
598     extern int  convJWStoCT();
599 
600     wlen = Xsj3cGetConvertedLength(buf);
601     wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
602 
603     if ((Xsj3cGetConvertedStr(buf, wbuf)) == NULL) {
604         XtAppWarning(XtWidgetToApplicationContext(w),
605              "sj3 Object: Could not get converted string");
606         return -1;
607     }
608     *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject((Widget)obj));
609     *format = 8;
610 
611     for (wp = wbuf; *wp != 0; wp++) {
612         if (*wp == '\r') *wp = '\n';
613     }
614 
615     *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
616     *string = XtMalloc(len + 1);
617     (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
618 
619     XtFree((char *)wbuf);
620 
621     return 0;
622 }
623 
624 static int
625 ClearConversion(w)
626     Widget                  w;
627 {
628     Sj3Object               obj = (Sj3Object)w;
629     Xsj3cBuf                buf = obj->sj3.sj3buf;
630 
631     Xsj3cClearBuffer(buf);
632     XtCallCallbackList(w, obj->inputConv.textchangecallback, (XtPointer)NULL);
633     return 0;
634 }
635 
636 static ICString *
637 GetAuxSegments(w, n, ns, nc)
638     Widget                  w;
639     Cardinal               *n, *ns, *nc;
640 {
641     Sj3Object               obj = (Sj3Object)w;
642     Xsj3cBuf                buf = obj->sj3.sj3buf;
643     register int            i;
644     register Xsj3cDictMsg   p;
645     register ICString      *seg;
646     static ICString        *ics;
647 
648     *n = Xsj3cGetDictMsgNum(buf);
649     if (!ics) {
650         ics = (ICString *)XtCalloc(*n, sizeof(ICString));
651     } else {
652         ics = (ICString *)XtRealloc((char *)ics, *n * sizeof(ICString));
653     }
654     bzero(ics, *n * sizeof(ICString));
655     for (i = 0, seg = ics, p = Xsj3cGetDictMsgs(buf);
656             i < *n; i++, seg++) {
657         seg->data = (char *)p[i].data;
658         seg->nchars = p[i].len;
659         seg->nbytes = seg->nchars * sizeof(wchar);
660         switch (p[i].attr) {
661         case SEG_REVERSED:
662             seg->attr = ICAttrConverted|ICAttrCurrentSegment;
663             break;
664         case SEG_UNDER_LINE:
665             seg->attr = ICAttrNotConverted;
666             break;
667         case SEG_NORMAL:
668             seg->attr = ICAttrConverted;
669             break;
670         default:
671             seg->attr = ICAttrNotConverted;
672             break;
673         }
674     }
675     *ns = *n - 1;
676     *nc = 0;
677 
678     return ics;
679 }
680 
681 /* ARGSUSED */
682 static int
683 PreeditString(w, segn, offset, encoding, format, length, string)
684 Widget w;
685 int segn;
686 int offset;
687 Atom *encoding;
688 int *format;
689 int *length;
690 XtPointer *string;
691 {
692     Sj3Object obj = (Sj3Object)w;
693     Xsj3cBuf buf = obj->sj3.sj3buf;
694     int segnum = Xsj3cGetSegNum(buf);
695     int seglen, junk;
696     wchar *segdata;
697     Boolean deleted;
698     int i;
699     wchar *wbuf, *wp;
700     int len, wlen;
701     extern int convJWStoCT();
702 
703     if (segn < segnum) {
704 	segdata = Xsj3cGetSeg(buf, segn, &seglen, &junk);
705 	if (offset >= seglen) {
706 	    /* $B%;%0%a%s%H$N:G8e(B */
707 	    ++segn;
708 	    offset = 0;
709 	}
710     }
711     if (segn >= segnum) {
712 	deleted = True;
713     }
714     else {
715 	segdata = Xsj3cGetSeg(buf, segn, &seglen, &junk);
716 	deleted = (offset >= seglen);
717     }
718     if (deleted) {
719 	/* $B:o=|$5$l$?(B */
720 	*encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
721 	*format = 8;
722 	*length = 0;
723 	*string = (XtPointer)XtMalloc(1);
724 	return 0;
725     }
726 
727     wlen = 0;
728     for (i = segn; i < segnum; i++) {
729 	segdata = Xsj3cGetSeg(buf, i, &seglen, &junk);
730 	wlen += seglen;
731     }
732     wlen -= offset;
733 
734     wp = wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
735     segdata = Xsj3cGetSeg(buf, segn, &seglen, &junk);
736     len = seglen - offset;
737     (void)bcopy((char *)(segdata + offset), (char *)wp, sizeof(wchar) * len);
738     wp += len;
739     for (i = segn + 1; i < segnum; i++) {
740 	segdata = Xsj3cGetSeg(buf, i, &seglen, &junk);
741 	(void)bcopy((char *)segdata, (char *)wp, sizeof(wchar) * seglen);
742 	wp += seglen;
743     }
744     wbuf[wlen] = 0;
745 
746     /*
747      * Sj3 $B%*%V%8%'%/%H$O(B COMPOUND_TEXT $B%(%s%3!<%G%#%s%0$7$+%5%]!<%H$7$J$$(B
748      * COMPOUND_TEXT $B$KJQ49$9$k(B
749      */
750     *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
751     *format = 8;
752 
753     /* COMPOUND_TEXT $B$O(B \r $B$,Aw$l$J$$$N$G(B \n $B$KJQ49$7$F$*$/(B */
754     for (wp = wbuf; *wp != 0; wp++) {
755 	if (*wp == '\r') *wp = '\n';
756     }
757 
758     *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
759     *string = (XtPointer)XtMalloc(len + 1);
760     (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
761 
762     /* wbuf $B$r(B free $B$7$F$*$/(B */
763     XtFree((char *)wbuf);
764 
765     return 0;
766 }
767 
768 /* ARGSUSED */
769 static int
770 StatusString(w, encoding, format, length, string, nchars)
771 Widget w;
772 Atom *encoding;
773 int *format;
774 int *length;
775 XtPointer *string;
776 int *nchars;
777 {
778     ICString *seg;
779     wchar *wbuf, *wp;
780     int len, wlen;
781     extern int convJWStoCT();
782 
783     seg = GetMode(w);
784     if (seg == NULL) {
785 	*length = *nchars = 0;
786 	return -1;
787     }
788 
789     wlen = seg->nchars;
790     if (wlen <= 0) {
791 	*length = *nchars = 0;
792 	return -1;
793     }
794 
795     /*
796      * data $B$KF~$C$F$$$kJQ49%F%-%9%H$O(B null $B%?!<%_%M!<%H$5$l$F$$$J$$$+$b(B
797      * $B$7$l$J$$$N$G!"$^$:%3%T!<$7$F(B null $B%?!<%_%M!<%H$9$k(B
798      */
799     wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar));
800     (void)bcopy(seg->data, (char *)wbuf, sizeof(wchar) * wlen);
801     wbuf[wlen] = 0;
802 
803     /*
804      * Sj3 $B%*%V%8%'%/%H$O(B COMPOUND_TEXT $B%(%s%3!<%G%#%s%0$7$+%5%]!<%H$7$J$$(B
805      * COMPOUND_TEXT $B$KJQ49$9$k(B
806      */
807     *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w));
808     *format = 8;
809 
810     /* COMPOUND_TEXT $B$O(B \r $B$,Aw$l$J$$$N$G(B \n $B$KJQ49$7$F$*$/(B */
811     for (wp = wbuf; *wp != 0; wp++) {
812 	if (*wp == '\r') *wp = '\n';
813     }
814 
815     *length = len = convJWStoCT(wbuf, (unsigned char *)NULL, 0);
816     *string = XtMalloc(len + 1);
817     (void)convJWStoCT(wbuf, (unsigned char *)*string, 0);
818     *nchars = seg->nchars;
819 
820     /* wbuf $B$r(B free $B$7$F$*$/(B */
821     XtFree((char *)wbuf);
822 
823     return 0;
824 }
825 
826 /* ARGSUSED */
827 static void
828 Initialize(req, new, args, num_args)
829     Widget                  req;
830     Widget                  new;
831     ArgList                 args;
832     Cardinal               *num_args;
833 {
834     Sj3Object               obj = (Sj3Object)new;
835     Xsj3cBuf                buf = NULL;
836     int                     min_keycode,  max_keycode,  keysyms_per_keycode;
837     register int            i,  j,  k;
838     unsigned long           kanamod = 0;
839     KeySym                 *keymap;
840     XModifierKeymap        *modmap;
841 
842     obj->sj3.symbollist = SymbolList;
843     obj->sj3.hinsilist = HinsiList;
844     obj->sj3.candlist = NULL;
845     obj->sj3.numcand = 0;
846     obj->sj3.curcand = 0;
847     obj->sj3.cursymbol = 0;
848     obj->sj3.curhinsi = 0;
849     obj->sj3.candlistsize = 0;
850     obj->sj3.state = normal_state;
851     obj->sj3.selectionending = False;
852 
853     if (!obj->sj3.sj3user || *obj->sj3.sj3user == '\0')
854         obj->sj3.sj3user = uname;
855 
856     if (!clcount++) {
857         /* Get kana lock modmask   */
858         XDisplayKeycodes (XtDisplayOfObject((Widget)obj),
859                 &min_keycode, &max_keycode);
860         keymap = XGetKeyboardMapping (XtDisplayOfObject((Widget)obj),
861                 min_keycode, (max_keycode - min_keycode + 1),
862                 &keysyms_per_keycode);
863         XFree(keymap);
864 
865         if (keysyms_per_keycode == 4) {
866             modmap = XGetModifierMapping(XtDisplayOfObject((Widget)obj));
867             k = 0;
868             for (i = 0; i < 8; i++) {
869                 for (j = 0; j < modmap->max_keypermod; j++) {
870                     if (XK_Mode_switch ==
871                         XKeycodeToKeysym(XtDisplayOfObject((Widget)obj),
872                             modmap->modifiermap[k], 0)) {
873                         kanamod |= 1 << i;
874                     }
875                     k++;
876                 }
877             }
878             XFreeModifiermap(modmap);
879         }
880 
881         /* Set kana lock modmask   */
882         Xsj3cSetKanaMod(kanamod);
883 
884     }
885 
886     /* Making buffer for Xsj3clib   */
887     buf = obj->sj3.sj3buf = Xsj3cCreateBuffer();
888     if (!buf) {
889         XtAppError(XtWidgetToApplicationContext(new),
890             "sj3 Object: Failed to allocate buffers");
891     }
892 
893     /* Read user resource customize file and set flags    */
894     (void)Xsj3cRCInit(buf, obj->sj3.rcfile, home);
895 
896     /* Convertion table initialization    */
897     Xsj3cInitializeTables(buf, home, obj->sj3.rkfile, obj->sj3.hkfile,
898             obj->sj3.zhfile, obj->sj3.sbfile);
899 
900     /* Connect to Kana-kanji conversion server  */
901     if ((Xsj3cOpen(buf, obj->sj3.sj3serv,
902                 obj->sj3.sj3user, False, False)) != CONNECT_OK) {
903         XtAppWarning(XtWidgetToApplicationContext(new),
904      "sj3 Object: Failed to connect first server, then try to second server");
905         if ((Xsj3cOpen(buf, obj->sj3.sj3serv2,
906                 obj->sj3.sj3user, False, True)) != CONNECT_OK) {
907             XtAppError(XtWidgetToApplicationContext(new),
908                  "sj3 Object: Failed to connect to second server");
909         }
910     };
911 
912     addObject(obj);
913 }
914 
915 static void
916 Destroy(w)
917     Widget                  w;
918 {
919     Sj3Object               obj = (Sj3Object)w;
920     Xsj3cBuf                buf = obj->sj3.sj3buf;
921 
922     Xsj3cClose(buf, False);
923     Xsj3cFreeBuffer(buf);
924     deleteObject(obj);
925 }
926 
927 static void
928 symbolInit(obj)
929     Sj3Object obj;
930 {
931     Xsj3cBuf                buf = obj->sj3.sj3buf;
932     register ICString      *strp;
933     register int            i;
934     register Xsj3cSymbol    p;
935 
936     for (i = 0, strp = SymbolList, p = Xsj3cGetSymbols(buf);
937             i < NumSymbol; i++, strp++) {
938         strp->data = (char *)p[i].data;
939         strp->nchars = p[i].len;
940         strp->nbytes = strp->nchars * sizeof(wchar);
941         strp->attr = ICAttrNormalString;
942     }
943 }
944 
945 static void
946 startSymbol(obj)
947     Sj3Object obj;
948 {
949     Xsj3cBuf                buf = obj->sj3.sj3buf;
950     ICSelectionControlArg   arg;
951 
952     /* Symbol list initialization   */
953     if (!SymbolList) {
954         NumSymbol = Xsj3cGetSymbolNum(buf, &obj->sj3.cursymbol);
955         SymbolList = (ICString *)XtMalloc(NumSymbol * sizeof(ICString));
956         symbolInit(obj);
957         obj->sj3.symbollist = SymbolList;
958     } else if (!obj->sj3.symbollist) {
959         obj->sj3.symbollist = SymbolList;
960     }
961 
962     obj->sj3.state = symbol_state;
963 
964     arg.command = ICSelectionStart;
965     arg.u.selection_kind = ICSelectionCandidates;
966     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
967                (XtPointer)&arg);
968 
969     /* set current item */
970     arg.command = ICSelectionSet;
971     arg.u.current_item = obj->sj3.cursymbol;
972     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
973                (XtPointer)&arg);
974 }
975 
976 static void
977 startCandidate(obj)
978     Sj3Object obj;
979 {
980     Xsj3cBuf                buf = obj->sj3.sj3buf;
981     ICSelectionControlArg   arg;
982     register ICString      *strp;
983     register int            i;
984     int                     ncand,  curcand;
985     register Xsj3cCand      p;
986 
987     if ((ncand = Xsj3cGetCandidateNum(buf, &curcand)) <= 0) {
988         bell(obj);
989         return;
990     }
991     obj->sj3.curcand = curcand;
992     obj->sj3.numcand = ncand;
993 
994     allocCandlist(obj, obj->sj3.numcand);
995 
996     for (i = 0, strp = obj->sj3.candlist, p = Xsj3cGetCandidates(buf);
997             i < obj->sj3.numcand; i++, strp++) {
998         strp->data = (char *)p[i].data;
999         strp->nchars = p[i].len;
1000         strp->nbytes = strp->nchars * sizeof(wchar);
1001         strp->attr = ICAttrNormalString;
1002     }
1003 
1004     obj->sj3.state = candidate_state;
1005 
1006     arg.command = ICSelectionStart;
1007     arg.u.selection_kind = ICSelectionCandidates;
1008     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
1009                (XtPointer)&arg);
1010 
1011     /* set current candidate */
1012     arg.command = ICSelectionSet;
1013     arg.u.current_item = curcand;
1014     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
1015                (XtPointer)&arg);
1016 }
1017 
1018 static void
1019 hinsiInit(obj)
1020     Sj3Object obj;
1021 {
1022     Xsj3cBuf                buf = obj->sj3.sj3buf;
1023     register ICString      *strp;
1024     register int            i;
1025     register Xsj3cHinsi     p;
1026 
1027     for (i = 0, strp = HinsiList, p = Xsj3cGetHinsis(buf);
1028             i < NumHinsi; i++, strp++) {
1029         strp->data = (char *)p[i].data;
1030         strp->nchars = p[i].len;
1031         strp->nbytes = strp->nchars * sizeof(wchar);
1032         strp->attr = ICAttrNormalString;
1033     }
1034 }
1035 
1036 static void
1037 startHinsi(obj)
1038     Sj3Object obj;
1039 {
1040     Xsj3cBuf                buf = obj->sj3.sj3buf;
1041     ICSelectionControlArg   arg;
1042 
1043     /* Hinsi list initialization    */
1044     if (!HinsiList) {
1045         NumHinsi = Xsj3cGetHinsiNum(buf, &obj->sj3.curhinsi);
1046         HinsiList = (ICString *)XtMalloc(NumHinsi * sizeof(ICString));
1047         hinsiInit(obj);
1048         obj->sj3.hinsilist = HinsiList;
1049     } else if (!obj->sj3.hinsilist) {
1050         obj->sj3.hinsilist = HinsiList;
1051     }
1052 
1053     obj->sj3.state = hinsi_state;
1054 
1055     arg.command = ICSelectionStart;
1056     arg.u.selection_kind = ICSelectionCandidates;
1057     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
1058                (XtPointer)&arg);
1059 
1060     /* set current item */
1061     arg.command = ICSelectionSet;
1062     arg.u.current_item = obj->sj3.curhinsi;
1063     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
1064                (XtPointer)&arg);
1065 }
1066 
1067 static void
1068 moveSelection(obj, dir)
1069     Sj3Object               obj;
1070     int                     dir;
1071 {
1072     ICSelectionControlArg   arg;
1073 
1074     if (obj->sj3.state == normal_state) return;
1075     arg.command = ICSelectionMove;
1076     arg.u.dir = dir;
1077     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
1078                (XtPointer)&arg);
1079 }
1080 
1081 static int
1082 endSelection(obj, abort)
1083     Sj3Object               obj;
1084     int                     abort;
1085 {
1086     ICSelectionControlArg   arg;
1087     int                     selected;
1088     int                     ret = 0,    changed = False,    flush = False;
1089     Xsj3cBuf                buf = obj->sj3.sj3buf;
1090 
1091     if (obj->sj3.selectionending)
1092         return 0;
1093 
1094     if (obj->sj3.state == normal_state)
1095         return -1;
1096 
1097     arg.command = ICSelectionEnd;
1098     arg.u.current_item = -1;
1099     XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback,
1100                (XtPointer)&arg);
1101 
1102     if (!abort && (selected = arg.u.current_item) >= 0) {
1103         ret = insertSelection(obj, selected, &changed, &flush);
1104     }
1105 
1106     switch (obj->sj3.state) {
1107     case candidate_state:
1108         Xsj3cEndCandidate(buf, changed);
1109         break;
1110     case symbol_state:
1111         Xsj3cEndSymbol(buf);
1112         break;
1113     case hinsi_state:
1114         Xsj3cEndHinsi(buf);
1115         break;
1116     default:
1117         XtAppWarning(XtWidgetToApplicationContext((Widget)obj),
1118              "sj3 Object: Unknow ConvMode state");
1119         break;
1120     }
1121     obj->sj3.state = normal_state;
1122 
1123     if (changed) {
1124         if (flush) {
1125             XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback,
1126                (XtPointer)NULL);
1127             Xsj3cFlushBuffer(buf);
1128         }
1129         XtCallCallbackList((Widget)obj,
1130                obj->inputConv.textchangecallback,
1131                (XtPointer)NULL);
1132     }
1133 
1134     return ret;
1135 }
1136 
1137 /* ARGSUSED */
1138 static Boolean
1139 SetValues(cur, req, wid, args, num_args)
1140     Widget                  cur;
1141     Widget                  req;
1142     Widget                  wid;
1143     ArgList                 args;
1144     Cardinal                *num_args;
1145 {
1146     return False;
1147 }
1148 
1149 static int
1150 insertSelection(obj, selected, changed, flush)
1151     Sj3Object               obj;
1152     int                     selected;
1153     int                    *changed;
1154     int                    *flush;
1155 {
1156     Xsj3cBuf                buf = obj->sj3.sj3buf;
1157     int                     ret = 0;
1158 
1159     obj->sj3.selectionending = True;
1160     switch (obj->sj3.state) {
1161     case candidate_state:
1162         obj->sj3.curcand = selected;
1163         ret = Xsj3cSetCandidate(buf, selected, changed, flush);
1164         break;
1165     case symbol_state:
1166         obj->sj3.cursymbol = selected;
1167         ret = Xsj3cSetSymbol(buf, selected, changed, flush);
1168         break;
1169     case hinsi_state:
1170         obj->sj3.curhinsi = selected;
1171         ret = Xsj3cSetHinsi(buf, selected, changed, flush);
1172         break;
1173     }
1174     obj->sj3.selectionending = False;
1175 
1176     return ret;
1177 }
1178 
1179 static void
1180 allocCandlist(obj, n)
1181     Sj3Object               obj;
1182     int                     n;
1183 {
1184     ICString *p;
1185 
1186     if (n <= obj->sj3.candlistsize)
1187         return;
1188 
1189     if (obj->sj3.candlistsize == 0) {
1190         p = (ICString *)XtMalloc(n * sizeof(ICString));
1191     } else {
1192         p = (ICString *)XtRealloc((char *)obj->sj3.candlist,
1193                   n * sizeof(ICString));
1194     }
1195 
1196     obj->sj3.candlist = p;
1197     obj->sj3.candlistsize = n;
1198 }
1199 
1200 static void
1201 startRegistration(obj)
1202     Sj3Object   obj;
1203 {
1204     ICAuxControlArg         arg;
1205 
1206     arg.command = ICAuxStart;
1207     XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
1208                (XtPointer)&arg);
1209 }
1210 
1211 static void
1212 changeRegistration(obj)
1213     Sj3Object               obj;
1214 {
1215     ICAuxControlArg         arg;
1216 
1217     arg.command = ICAuxChange;
1218     XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
1219                (XtPointer)&arg);
1220 }
1221 
1222 static void
1223 endRegistration(obj)
1224     Sj3Object   obj;
1225 {
1226     Xsj3cBuf                buf = obj->sj3.sj3buf;
1227     ICAuxControlArg         arg;
1228 
1229     arg.command = ICAuxEnd;
1230     XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback,
1231                (XtPointer)&arg);
1232     Xsj3cEndDict(buf);
1233 }
1234 
1235 /*
1236  * keeping list of objects
1237  */
1238 typedef struct _oblist_ {
1239     Sj3Object               obj;
1240     struct _oblist_        *next;
1241 } ObjRec;
1242 
1243 static ObjRec *ObjList = NULL;
1244 
1245 static void
1246 addObject(obj)
1247     Sj3Object               obj;
1248 {
1249     ObjRec                 *objp = XtNew(ObjRec);
1250 
1251     objp->obj = obj;
1252     objp->next = ObjList;
1253     ObjList = objp;
1254 }
1255 
1256 static void
1257 deleteObject(obj)
1258     Sj3Object obj;
1259 {
1260     ObjRec                 *objp, *objp0;
1261 
1262     for (objp0 = NULL, objp = ObjList;
1263             objp != NULL;
1264             objp0 = objp, objp = objp->next) {
1265         if (objp->obj == obj) {
1266             if (objp0 == NULL) {
1267                 ObjList = objp->next;
1268             } else {
1269                 objp0->next = objp->next;
1270             }
1271             XtFree((char *)objp);
1272             return;
1273         }
1274     }
1275 }
1276 
1277 static void
1278 bell(obj)
1279     Sj3Object               obj;
1280 {
1281     XBell(XtDisplayOfObject((Widget)obj), 0);
1282 }
1283