Mercurial > kinput2.yaz
diff lib/Ruby.c @ 16:598fcbe482b5
imported patch 19_kinput2-v3.1-ruby.patch
| author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
|---|---|
| date | Mon, 08 Mar 2010 20:38:17 +0900 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/Ruby.c Mon Mar 08 20:38:17 2010 +0900 @@ -0,0 +1,947 @@ +/* + * 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 NEC Corporation, Tokyo, Japan. + * + * 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 NEC Corporation + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. NEC + * Corporation makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Author: Akira Kon, NEC Corporation. (kon@d1.bs2.mt.nec.co.jp) + */ + +/* Copyright 2003 Hiroyuki Komatsu <komatsu@taiyaki.org> (Ruby.c) */ + +/* 直さなければならないところ + + ・Destroy が呼ばれないので CloseUIContext できない。 + ・モード領域の大きさ。(これは他のファイルだろうな) + + */ + +#ifndef lint +static char *rcsid = "$Id: Ruby.c,v 1.2 2003/06/10 02:11:23 komatsu Exp $"; +#endif + +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xmu/Atoms.h> +#define XK_KATAKANA +#include <X11/keysym.h> +#if XtSpecificationRelease > 4 +#include <X11/Xfuncs.h> +#endif + +#include "RubyP.h" +#include "DebugPrint.h" + +#define wchar_t wchar + +#include "ruby-c.h" + +static XtResource resources[] = { +#define offset(field) XtOffset(RubyObject, ruby.field) + { XtNrubyhost, XtCRubyhost, XtRString, sizeof(String), + offset(rubyhost), XtRString, NULL }, + { XtNrubyfile, XtCRubyfile, XtRString, sizeof(String), + offset(rubyfile), XtRString, NULL }, + { XtNsendReturnByString, XtCSendReturnByString, + XtRBoolean, sizeof(Boolean), + offset(sendReturnByString), XtRBoolean, False }, +#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 int GetTriggerKeys(); +static int PreeditString(); +static int StatusString(); + +static void convend(); + +#if 1 /* KC_SETLISTCALLBACK */ +static void openSelection(); +#define SELECTION_SET 0 /* SelectionStart をしても良いと言う情報を設定する */ +#define SELECTION_DO 1 /* 実際に SelectionStart を開始する */ +#else /* !KC_SETLISTCALLBACK */ +#define openSelection(x, y, z) +#endif /* !KC_SETLISTCALLBACK */ + +static ICString *GetAuxSegments(); + +RubyClassRec rubyClassRec = { + { /* object fields */ + /* superclass */ (WidgetClass) &inputConvClassRec, + /* class_name */ "Ruby", + /* widget_size */ sizeof(RubyRec), + /* 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 */ GetTriggerKeys, + /* num_trigger_keys */ 0, + /* trigger_keys */ NULL, + /* GetPreeditString */ PreeditString, + /* GetStatusString */ StatusString, + /* NoMoreObjects */ False, + }, + { /* ruby fields */ + /* foo */ 0, + } +}; + +WidgetClass rubyObjectClass = (WidgetClass)&rubyClassRec; + +static void fix(); + +static ICString *SymbolList; +static int NumSymbols; + +static void addObject(); +static void deleteObject(); + +static Display *displaybell = (Display *)0; + +static void rubyEUCtoICString(); +static void rubyEUCArraytoICStringArray(); +static void rubySelectionEvent(); +static void rubySelectionDisplay(); +static void rubyDialogDisplay(); +static void rubyDisplayPreEdit(); + +typedef struct { + ICString *array; + int length; +} ICStringArray; + +static ICString *ruby_tmp_seg; +static ICStringArray *ruby_cand_list; + +static void +ClassInitialize() +{ + ruby_init(); + + ruby_tmp_seg = XtMalloc(sizeof(ICString)); + ruby_tmp_seg->nchars = 0; + ruby_tmp_seg->nbytes = 0; + ruby_cand_list = XtMalloc(sizeof(ICStringArray)); + ruby_cand_list->length = 0; + + ruby_eval("$LOAD_PATH.concat(eval(`ruby -e 'p $LOAD_PATH'`))"); + ruby_eval("$LOAD_PATH.uniq!"); + + if (ruby_eval("ENV['KINPUT2_RUBY']") != Qnil) { + ruby_eval("require ENV['KINPUT2_RUBY']"); + } else { + ruby_eval("require 'kinput2_default'"); + } + if (ruby_eval("global_variables.member?('$kanjiConv')") == Qfalse) { + fprintf(stderr, "Abort: KanjiConv was not initialized.\n"); + exit (-1); + } + ruby_eval("kanjiConv = $kanjiConv"); + TRACE(("RubyObjectClass initialized\n")); +} + +static int +InputEvent(w, event) +Widget w; +XEvent *event; +{ + RubyObject obj = (RubyObject)w; + char key_buf[200]; + KeySym keysym; + int len, nbytes, functionalChar; + + /* KeyPress以外は捨てる */ + if (event->type != KeyPress /*&& event->type != KeyRelease*/) return 0; + + /* 取りあえず文字に直してしまう */ + key_buf[0] = '\0'; + key_buf[1] = '\0'; + key_buf[2] = '\0'; + nbytes = XLookupString(event, key_buf, 20, &keysym, NULL); + + if (keysym == XK_space && (event->xkey.state & ShiftMask)) { + convend(obj); + return 0; + } + + /* ベルを鳴らすディスプレイの設定 */ + displaybell = XtDisplayOfObject((Widget)obj); + + /* かな漢字変換する */ + { + VALUE pass; + printf ("key_buf: `%d'\n", key_buf[0]); + printf ("strlen(key_buf): `%d'\n", strlen(key_buf)); + printf ("nbytes: `%d'\n", nbytes); + pass = ruby_evalf ("kanjiConv.inputEvent(%d, %d, %d)", + key_buf[0], (int)keysym, (int)(event->xkey.state)); + printf ("Input: done\n"); + + rubyDisplayPreEdit(obj); + + return NUM2INT(pass); /* 1: pass the key / 0: trap the key */ + } +} + + +static void +rubyDialogDisplay(obj) +RubyObject obj; +{ + ICAuxControlArg arg; + + /* I'm not sure about Aux. */ + if (ruby_eval("kanjiConv.dialog.visible") == Qfalse) { + if (ruby_eval("kanjiConv.dialog.call_open") == Qtrue && + ruby_eval ("kanjiConv.dialog.text.length > 0") == Qtrue) { + printf ("Dialog: open\n"); + arg.command = ICAuxStart; + XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback, + (XtPointer)&arg); + ruby_eval("kanjiConv.dialog.open_end"); + } + } else { /* value_dialog_visible == true */ + if (ruby_eval("kanjiConv.dialog.call_close") == Qtrue) { + printf ("Dialog: close\n"); + arg.command = ICAuxEnd; + XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback, + (XtPointer)&arg); + ruby_eval("kanjiConv.dialog.close_end"); + printf ("Dialog: close...done\n"); + } else { + arg.command = ICAuxChange; + XtCallCallbackList((Widget)obj, obj->inputConv.auxcallback, + (XtPointer)&arg); + } + } +} + +static void +rubySelectionEvent(obj) +RubyObject obj; +{ + /*** Right ***/ + if (ruby_eval("kanjiConv.selection.call_right") == Qtrue) { + moveSelection(obj, ICMoveRight); + ruby_eval("kanjiConv.selection.right_end"); + } + + /*** Left ***/ + if (ruby_eval("kanjiConv.selection.call_left") == Qtrue) { + moveSelection(obj, ICMoveLeft); + ruby_eval("kanjiConv.selection.left_end"); + } + + /*** Down ***/ + if (ruby_eval("kanjiConv.selection.call_down") == Qtrue) { + moveSelection(obj, ICMoveDown); + ruby_eval("kanjiConv.selection.down_end"); + } + + /*** Up ***/ + if (ruby_eval("kanjiConv.selection.call_up") == Qtrue) { + moveSelection(obj, ICMoveUp); + ruby_eval("kanjiConv.selection.up_end"); + } + + /*** Beginning Line ***/ + if (ruby_eval("kanjiConv.selection.call_line_beginning") == Qtrue) { + moveSelection(obj, ICMoveLeftMost); + ruby_eval("kanjiConv.selection.line_beginning_end"); + } + + /*** End Line ***/ + if (ruby_eval("kanjiConv.selection.call_line_end") == Qtrue) { + moveSelection(obj, ICMoveRightMost); + ruby_eval("kanjiConv.selection.line_end_end"); + } + + /*** Get Index ***/ + { + ICSelectionControlArg arg; + arg.command = ICSelectionGet; + arg.u.current_item = -1; + + XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback, + (XtPointer)&arg); + + if (arg.u.current_item >= 0) { + ruby_evalf ("kanjiConv.set_cand_index (%d)", arg.u.current_item); + } + } +} + +static void +moveSelection(obj, dir) +RubyObject obj; +int dir; +{ + ICSelectionControlArg arg; + + arg.command = ICSelectionMove; + arg.u.dir = dir; + XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback, + (XtPointer)&arg); +} + +static void +rubySelectionDisplay(obj) +RubyObject obj; +{ + ICSelectionControlArg arg; + + if (ruby_eval("kanjiConv.selection.call_open") == Qtrue) { + printf ("Selection: open\n"); + 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 = 0; /* INDEX of ITEM */ + XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback, + (XtPointer)&arg); + + ruby_eval("kanjiConv.selection.open_end"); + } else if (ruby_eval("kanjiConv.selection.call_close") == Qtrue) { + printf ("Selection: close\n"); + arg.command = ICSelectionEnd; + arg.u.current_item = -1; + XtCallCallbackList((Widget)obj, obj->inputConv.selectioncallback, + (XtPointer)&arg); + ruby_eval("kanjiConv.selection.close_end"); + } +} + + +static void +rubyDisplayPreEdit(obj) +RubyObject obj; +{ + Widget w = (Widget)obj; + + if (ruby_eval("kanjiConv.call_fix") == Qtrue) { + fix(obj); + } + + /* 入力モードをチェックする */ +/* #if 0 */ +/* if (ks->info & KanjiModeInfo) { */ +/* printf("modechangecallback\n"); */ + XtCallCallbackList(w, obj->inputConv.modechangecallback, + (XtPointer)NULL); +/* } */ +/* #endif */ + + rubyDialogDisplay(obj); + rubySelectionEvent(obj); + rubySelectionDisplay(obj); + + XtCallCallbackList(w, obj->inputConv.textchangecallback, + (XtPointer)NULL); +} + + + + +static ICString * +GetMode(w) +Widget w; +{ + rubyEUCtoICString (ruby_eval ("kanjiConv.modeline"), ruby_tmp_seg); + ruby_tmp_seg->attr = ICAttrNormalString; + return ruby_tmp_seg; +} + +static int +CursorPos(w, nsegp, ncharp) +Widget w; +Cardinal *nsegp; +Cardinal *ncharp; +{ + /* + return value : =0 corsor ON / =1 OFF + nseg: >0 segment index / =0 no segment + nchar: number of chars; 'テs' == 2 + */ + *ncharp = NUM2INT(ruby_eval("kanjiConv.input.cursor")); + *nsegp = 0; + +/* printf ("CursorPos: nseg=%d, nchar=%d\n", (int)*nsegp, (int)*ncharp); */ + + return (*ncharp == 0) ? 1: 0; +} + +static int +NumSegments(w) +Widget w; +{ + int num; + printf ("NumSegments\n"); + num = NUM2INT(ruby_eval("kanjiConv.segment_length")); +/* printf ("NumSegments: num=%d\n", num); */ + return num; +} + +static ICString * +GetSegment(w, n) +Widget w; +Cardinal n; +{ + RubyObject obj = (RubyObject)w; + static ICString seg; + + printf("GetSegment\n"); + + rubyEUCtoICString (ruby_evalf ("kanjiConv.segment_word(%d)", n), + ruby_tmp_seg); + if (ruby_evalf("kanjiConv.segment_status(%d) == :highlight", n) == Qtrue) { + ruby_tmp_seg->attr = ICAttrConverted | ICAttrCurrentSegment; + } else { + ruby_tmp_seg->attr = ICAttrNotConverted; + } + /* ICAttrConverted | ICAttrCurrentSegment : Inversion. */ + /* |= ICAttrChanged : Non-Underline. */ + return ruby_tmp_seg; +} + +/* ARGSUSED */ +static int +CompareSegment(w, seg1, seg2, n) +Widget w; +ICString *seg1; +ICString *seg2; +Cardinal *n; +{ + wchar *p, *q; + int len, nsame; + int result = 0; + + printf("CompareSegment\n"); + + if (seg1->attr != seg2->attr) result |= ICAttrChanged; + + len = seg1->nchars > seg2->nchars ? seg2->nchars : seg1->nchars; + nsame = 0; + p = (wchar *)seg1->data; + q = (wchar *)seg2->data; + while (nsame < len && *p++ == *q++) nsame++; + + if (nsame != len || len != seg1->nchars || len != seg2->nchars) + result |= ICStringChanged; + + if (n) *n = nsame; + + return result; +} + +static ICString * +GetItemList(w, n) +Widget w; +Cardinal *n; +{ + RubyObject obj = (RubyObject)w; + + printf("GetItemList\n"); + rubyEUCArraytoICStringArray(ruby_eval("kanjiConv.cand_list"), + ruby_cand_list); + *n = ruby_cand_list->length; + return ruby_cand_list->array; +} + +static int +SelectItem(w, n) +Widget w; +int n; +{ + + RubyObject obj = (RubyObject)w; + printf ("selectItem\n"); + ruby_evalf("kanjiConv.selection_fix (%d)", n); + /* FIXME: Create new fix function in the feature. */ + fix (obj); + XtCallCallbackList(w, obj->inputConv.textchangecallback, + (XtPointer)NULL); + return 0; +} + +static int +ConvertedString(w, encoding, format, length, string) +Widget w; +Atom *encoding; +int *format; +int *length; +XtPointer *string; +{ + RubyObject obj = (RubyObject)w; + wchar *wbuf, *wp; + int len, wlen; + extern int convJWStoCT(); + + /* メモリの解放は自動的に行われる. str を直接書き換えてはいけない. */ + unsigned char *str = STR2CSTR(ruby_eval("kanjiConv.value_fixed")); + + printf("ConvertedString\n"); + + wbuf = XtMalloc((strlen(str) + 1) * sizeof(wchar)); + euc2wcs(str, strlen(str), wbuf); + wlen = wstrlen(wbuf); + + /* + * Ruby オブジェクトは COMPOUND_TEXT エンコーディングしかサポートしない + * COMPOUND_TEXT に変換する + */ + *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject((Widget)obj)); + *format = 8; + + /* COMPOUND_TEXT は \r が送れないので \n に変換しておく */ + 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(wbuf); + + return 0; +} + +static int +ClearConversion(w) +Widget w; +{ + ruby_eval ("kanjiConv.clear"); + return 0; +} + +static ICString * +GetAuxSegments(w, n, ns, nc) +Widget w; +Cardinal *n, *ns, *nc; +{ + /* I'm not sure about this function's purpose. */ + /* n => ngseg ; number of segments (1 <= n <= 3). */ + /* ns => nseg ; index of reversed segment (0 or 1). */ + /* nc => nchar ; length of current segment??? */ + printf ("GetAuxSegments\n"); + + if ((ruby_eval ("kanjiConv.dialog.visible") == Qtrue || + ruby_eval ("kanjiConv.dialog.call_open") == Qtrue) && + ruby_eval ("kanjiConv.dialog.text.length > 0") == Qtrue) { + if (n) { + *n = 1; + } + + if (ns) { + *ns = 0; + } + + rubyEUCtoICString (ruby_eval ("kanjiConv.dialog.text"), + ruby_tmp_seg); + ruby_tmp_seg->attr = ICAttrConverted; + + if (nc) { + *nc = ruby_tmp_seg->nchars; + } + + return ruby_tmp_seg; + } else { + if (n) { + *n = 0; + } + if (ns) { + *ns = 0; + } + if (nc) { + *nc = 0; + } + return NULL; + } +} + +/* ARGSUSED */ +static void +Initialize(req, new, args, num_args) +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + RubyObject obj = (RubyObject)new; + + obj->ruby.selectionending = False; + obj->ruby.textchanged = False; + obj->ruby.symbollist = SymbolList; + obj->ruby.numsymbols = NumSymbols; + obj->ruby.cursymbol = 0; + obj->ruby.candlist = NULL; + obj->ruby.candlistsize = 0; + obj->ruby.numcand = 0; + obj->ruby.lastTextLengthIsZero = False; + + addObject(obj); +} + +static int +bell() +{ + if (displaybell) { + XBell(displaybell, 0); + } + return 0; +} + +static int nRubyContexts = 0; + +static void +Destroy(w) +Widget w; +{ + RubyObject obj = (RubyObject)w; + wchar buf[512]; + int i; + + if (obj->ruby.candlist) { + for (i = 0 ; i < obj->ruby.candlistsize ; i++) { + if ((obj->ruby.candlist + i)->data) { + XtFree((obj->ruby.candlist + i)->data); + } + } + + XtFree((char *)obj->ruby.candlist); + } + + /* Ruby 用終了処理をここに書く */ + + deleteObject(obj); +} + +static Boolean +SetValues(cur, req, wid, args, num_args) +Widget cur; +Widget req; +Widget wid; +ArgList args; +Cardinal *num_args; +/* ARGSUSED */ +{ + RubyObject old = (RubyObject)cur; + RubyObject new = (RubyObject)wid; + + return False; +} + +static void +fix(obj) +RubyObject obj; +{ + /* 確定の処理 */ + XtCallCallbackList((Widget)obj, obj->inputConv.fixcallback, + (XtPointer)NULL); + ruby_eval("kanjiConv.fix_end"); +} + +static void +convend(obj) +RubyObject obj; +{ + XtCallCallbackList((Widget)obj, obj->inputConv.endcallback, + (XtPointer)NULL); + ruby_eval("kanjiConv.reset"); +} + +/* + * keeping list of objects + */ +typedef struct _oblist_ { + RubyObject obj; + struct _oblist_ *next; +} ObjRec; + +static ObjRec *ObjList = NULL; + +static void +addObject(obj) +RubyObject obj; +{ + ObjRec *objp = XtNew(ObjRec); + + objp->obj = obj; + objp->next = ObjList; + ObjList = objp; +} + +static void +deleteObject(obj) +RubyObject 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; + } + } +} + +/* ARGSUSED */ +static int +GetTriggerKeys(w, keys_return) +Widget w; +ICTriggerKey **keys_return; +{ + /* 何をする関数なのか不明 (komatsu) */ + + *keys_return = NULL; + return 0; +} + +/* ARGSUSED */ + + +/* + * int ICGetPreeditString(Widget object, int segn, int offset, + * Atom *encoding, int *format, + * int *length, XtPointer *string) + * 変換途中の segn 番目の セグメントの offset 文字からのテキストを + * string に返す + * encoding には、テキストのエンコーディングを指定しておく + * ただしこれは単なるリクエストであって、変換オブジェクトは + * 別のエンコーディングで返してもよい + * encoding には実際のエンコーディングが返される + * 変換オブジェクトは少なくとも COMPOUND_TEXT エンコーディングは + * サポートしなくてはならない + * format には 8/16/32 のいずれか、length は string のエレメント数が + * それぞれ返される + * テキストの領域は malloc されているのでこの関数を呼んだ側で + * free しなければならない + * 変換テキストがない時やエラーの場合には -1、そうでなければ 0 が + * 関数の値として返される + */ +/* まだ, 未検討 (komatsu) */ +static int +PreeditString(w, segn, offset, encoding, format, length, string) +Widget w; +int segn; +int offset; +Atom *encoding; +int *format; +int *length; +XtPointer *string; +{ + RubyObject obj = (RubyObject)w; + + return -1; +} + +/* 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(); + + printf("StatusString\n"); + + seg = GetMode(w); + if (seg == NULL) { + *length = *nchars = 0; + return -1; + } + + wlen = seg->nchars; + if (wlen <= 0) { + *length = *nchars = 0; + return -1; + } + + /* + * data に入っている変換テキストは null ターミネートされていないかも + * しれないので、まずコピーして null ターミネートする + */ + wbuf = (wchar *)XtMalloc((wlen + 1) * sizeof(wchar)); + (void)bcopy(seg->data, (char *)wbuf, sizeof(wchar) * wlen); + wbuf[wlen] = 0; + + /* + * Ruby オブジェクトは COMPOUND_TEXT エンコーディングしかサポートしない + * COMPOUND_TEXT に変換する + */ + *encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w)); + *format = 8; + + /* COMPOUND_TEXT は \r が送れないので \n に変換しておく */ + 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 を free しておく */ + XtFree((char *)wbuf); + + return 0; +} + +/*** +ic_str->nbytes が 0 の場合 ic_str->data は自動的に確保 (XtMalloc) される. + 0 以外の場合 ic_str->data は (XtRealloc) される. + */ +static void +rubyEUCtoICString(ruby_str, ic_str) +VALUE ruby_str; +ICString *ic_str; +{ + unsigned char *euc_str; + int euc_len; + wchar *wc_str; + +/* printf("String_Len: %d\n", RSTRING(ruby_str)->len); */ + + euc_str = STR2CSTR(ruby_str); + euc_len = strlen(euc_str); + + if (ic_str->nbytes == 0) { + wc_str = (wchar *)XtMalloc((euc_len + 1) * sizeof(wchar)); + } else { + wc_str = (wchar *)XtRealloc(ic_str->data, (euc_len + 1) * sizeof(wchar)); + } + euc2wcs(euc_str, euc_len, wc_str); + + ic_str->data = (char *)wc_str; + ic_str->nchars = wstrlen(wc_str); + ic_str->nbytes = (euc_len + 1) * sizeof(wchar); + ic_str->attr = ICAttrNotConverted; +} + +static void +rubyEUCArraytoICStringArray(ruby_str_ary, ic_str_ary) +VALUE ruby_str_ary; +ICStringArray *ic_str_ary; +{ + VALUE ruby_str; + int i, array_length; + ICString ic_str; + + array_length = RARRAY(ruby_str_ary)->len; + if ((ic_str_ary->length) < array_length) { + ic_str_ary->array = (ICString *)XtRealloc((char *)ic_str_ary->array, + array_length * sizeof(ICString)); + for (i = ic_str_ary->length; i < array_length; i++) { +/* ic_str_ary->array[i] = (ICString *)XtMalloc(1 * sizeof(ICString)); */ + ic_str_ary->array[i].nbytes = 0; + } + } + ic_str_ary->length = array_length; + +/* printf("array_length: %d\n", array_length); */ + + for (i = 0; i < array_length; i++) { + rubyEUCtoICString(rb_ary_entry(ruby_str_ary, i), &(ic_str_ary->array[i])); + } +}
