1/* Copyright 1992 NEC Corporation, Tokyo, Japan.
2 *
3 * Permission to use, copy, modify, distribute and sell this software
4 * and its documentation for any purpose is hereby granted without
5 * fee, provided that the above copyright notice appear in all copies
6 * and that both that copyright notice and this permission notice
7 * appear in supporting documentation, and that the name of NEC
8 * Corporation not be used in advertising or publicity pertaining to
9 * distribution of the software without specific, written prior
10 * permission.  NEC Corporation makes no representations about the
11 * suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * NEC CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
16 * NO EVENT SHALL NEC CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19 * OTHER TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23/************************************************************************/
24/* THIS SOURCE CODE IS MODIFIED FOR TKO BY T.MURAI 1997
25/************************************************************************/
26
27
28#if !defined(lint) && !defined(__CODECENTER__)
29static char rcs_id[] = "$Id: chikuji.c 14875 2005-11-12 21:25:31Z bonefish $";
30#endif
31
32#include	"canna.h"
33#include "RK.h"
34#include "RKintern.h"
35
36#ifdef MEASURE_TIME
37#include	<sys/types.h>
38#ifdef WIN
39#include	<sys/timeb.h>
40#else
41/* If you compile with Visual C++, then please comment out the next line. */
42#include <sys/times.h>
43#endif
44#endif /* MEASURE_TIME */
45
46
47static int restoreChikujiYomi(uiContext d, int old);
48static int doesSupportChikuji(void);
49static int chikujiSubstYomi(uiContext d);
50static int chikuji_restore_yomi(uiContext d);
51static int chikuji_subst_yomi(uiContext d);
52static int ChikujiTanExtend(uiContext d);
53static int ChikujiTanShrink(uiContext d);
54static int ChikujiYomiDeletePrevious(uiContext d);
55static int ChikujiHenkan(uiContext d);
56static int generalNaive(uiContext d, int (*fn )(...));
57static int ChikujiHenkanNaive(uiContext d);
58static int ChikujiHenkanOrNothing(uiContext d);
59static int ChikujiMuhenkan(uiContext d);
60
61extern int yomiInfoLevel, nKouhoBunsetsu, KeepCursorPosition;
62extern int defaultContext;
63extern KanjiModeRec tankouho_mode, cy_mode, cb_mode;
64extern void makeYomiReturnStruct (uiContext);
65extern int RkwGetServerVersion (int *, int *);
66extern int RkwGetProtocolVersion (int *, int *);
67
68int forceRomajiFlushYomi (uiContext);
69void moveToChikujiTanMode (uiContext);
70void moveToChikujiYomiMode (uiContext);
71
72
73inline void
74clearHenkanContent(yomiContext yc)
75{
76  yc->allkouho = 0;
77  yc->kouhoCount = yc->curIkouho = 0;
78  return;
79}
80
81void
82clearHenkanContext(yomiContext yc)
83{
84  if (yc->context >= 0) {
85    RkwCloseContext(yc->context);
86    yc->context = -1;
87  }
88  yc->nbunsetsu = yc->curbun = 0;
89  clearHenkanContent(yc);
90  return;
91}
92
93extern int NothingChanged (uiContext);
94
95/*
96  restoreChikujiYomi
97
98  ��������:
99    d   : uiContext
100    old : ��������������������
101
102  ����������������:
103   (1) ��������������������������������������������������������������������������������������������
104   (2) ��������������������RkwRemoveBun ����������������
105   (3) ����������������������������������������
106   (4) ����������������������������������������������������������������
107 */
108
109static int
110restoreChikujiYomi(uiContext d, int old)
111{
112  yomiContext yc = (yomiContext)d->modec;
113  WCHAR_T *s = d->buffer_return, *e = s + d->n_buffer;
114  RkStat stat;
115  int len, i, j, yomilen, ll = 0, m = 0, n = 0, recalc = 0;
116
117  d->nbytes = 0;
118  yomilen = yc->kEndp - yc->cStartp;
119  if (yc->nbunsetsu) {
120    yc->status |= CHIKUJI_ON_BUNSETSU;
121    if (yc->nbunsetsu > old) {
122      recalc = 1;
123    }
124    if (nKouhoBunsetsu) {
125      (void)cutOffLeftSide(d, yc, nKouhoBunsetsu - yc->nbunsetsu);
126      if (nKouhoBunsetsu < yc->nbunsetsu) {
127	n = yc->nbunsetsu - nKouhoBunsetsu;
128	if (n > old) {
129	  n = old; /* ���������������������������������������������������������������������������������������������������� */
130	}
131      }
132    }
133    if (n > 0) { /* �������������������������������� */
134
135      recalc = 1;
136      for (i = 0 ; i < n ; i++) {
137	if (RkwGoTo(yc->context, i) < 0 ||
138	    (len = RkwGetKanji(yc->context, s, (int)(e - s))) < 0 ||
139	    RkwGetStat(yc->context, &stat) == -1) {
140	  return -1;
141	}
142	s += len;
143
144	ll += stat.ylen;
145	m += stat.klen;
146      }
147      d->nbytes = s - d->buffer_return;
148      if (s < e) {
149	*s++ = (WCHAR_T)'\0';
150      }
151
152      if (RkwRemoveBun(yc->context, cannaconf.Gakushu ? 1 : 0) == -1) {
153	return -1;
154      }
155
156      /* �������������������������������������������� */
157      kPos2rPos(yc, 0, ll, (int *)0, &j);
158
159      if (yomiInfoLevel > 0) {
160	d->kanji_status_return->info |= KanjiYomiInfo;
161	len = xString(yc->kana_buffer, ll, s, e);
162	s += len;
163	if (s < e) {
164	  *s++ = (WCHAR_T)'\0';
165	}
166	if (yomiInfoLevel > 1) {
167	  len = xString(yc->romaji_buffer, j, s, e);
168	  s += len;
169	}
170	if (s < e) {
171	  *s++ = (WCHAR_T)'\0';
172	}
173      }
174
175      removeKana(d, yc, ll, j);
176
177      yc->nbunsetsu -= n;
178    }
179    if (RkwGoTo(yc->context, yc->nbunsetsu - 1) == -1)
180      return(-1);
181    yc->curbun = yc->nbunsetsu - 1;
182    if (old < yc->curbun) { /* ������������������������������������������������ */
183      yc->curbun = old;
184    }
185  }
186
187  if (recalc) {
188    yomilen = RkwGetLastYomi(yc->context, d->genbuf, ROMEBUFSIZE);
189    if (yomilen == -1) {
190      return -1;
191    }
192    if (yomilen < yc->kEndp) { /* ������������������������ */
193      kPos2rPos(yc, 0, yc->kEndp - yomilen, (int *)0, &j);
194      yc->cStartp = yc->kEndp - yomilen;
195      yc->cRStartp = j;
196    }
197    yc->ys = yc->ye = yc->kEndp;
198  }
199
200  if (yc->nbunsetsu) {
201    moveToChikujiTanMode(d);
202  }
203  return(0);
204}
205
206static int
207doesSupportChikuji(void)
208{
209  int a, b;
210
211  if (defaultContext == -1) {
212    if (KanjiInit() < 0 || defaultContext == -1) {
213      jrKanjiError = KanjiInitError();
214      return(-1);
215    }
216  }
217  RkwGetProtocolVersion(&a, &b);
218  return(a > 1);
219}
220
221#ifndef NO_EXTEND_MENU
222int
223chikujiInit(uiContext d)
224{
225  int chikuji_f;
226  yomiContext yc = (yomiContext)d->modec;
227
228  if (yc->generalFlags & CANNA_YOMI_CHGMODE_INHIBITTED) {
229    return NothingChangedWithBeep(d);
230  }
231
232  d->status = 0;
233  killmenu(d);
234
235  chikuji_f = doesSupportChikuji();
236
237  if (ToggleChikuji(d, 1) == -1) {
238    if(!chikuji_f)
239      jrKanjiError = "\245\265\241\274\245\320\244\254\303\340\274\241\274\253"
240	"\306\260\312\321\264\271\244\362\245\265\245\335\241\274\245\310"
241	"\244\267\244\306\244\244\244\336\244\273\244\363";
242                     /* ������������������������������������������������������������������������������������ */
243    else
244      jrKanjiError = "\303\340\274\241\274\253\306\260\312\321\264\271\244\313"
245	"\300\332\302\330\244\250\244\353\244\263\244\310\244\254\244\307"
246	"\244\255\244\336\244\273\244\363";
247                     /* ���������������������������������������������������������������������������� */
248    makeGLineMessageFromString(d, jrKanjiError);
249    currentModeInfo(d);
250    return(-1);
251  }
252  else {
253    if(!chikuji_f)
254      makeGLineMessageFromString(d, "\245\265\241\274\245\320\244\254\303\340"
255	"\274\241\274\253\306\260\312\321\264\271\244\362\245\265\245\335"
256	"\241\274\245\310\244\267\244\306\244\244\244\336\244\273\244\363");
257                /* ������������������������������������������������������������������������������������ */
258    else
259      makeGLineMessageFromString(d, "\303\340\274\241\274\253\306\260\312\321"
260	"\264\271\244\313\300\332\302\330\244\250\244\336\244\267\244\277");
261                /* ���������������������������������������������������� */
262    currentModeInfo(d);
263    return 0;
264  }
265}
266#endif /* not NO_EXTEND_MENU */
267
268static int
269chikujiSubstYomi(uiContext d)
270{
271  yomiContext yc = (yomiContext)d->modec;
272  int n = yc->nbunsetsu, ret;
273
274  if (yc->context == -1) { /* ������������������������������������������������������������ */
275    if (confirmContext(d, yc) < 0) {
276      return -1;
277    }
278    if (!doesSupportChikuji()) {
279      jrKanjiError = "\245\265\241\274\245\320\244\254\303\340\274\241\274\253"
280	"\306\260\312\321\264\271\244\362\245\265\245\335\241\274\245\310"
281	"\244\267\244\306\244\244\244\336\244\273\244\363";
282                     /* ������������������������������������������������������������������������������������ */
283      abandonContext(d, yc);
284      return(-1);
285    }
286    if (RkwBgnBun(yc->context, (WCHAR_T *)0, 1,
287                    RK_XFER << RK_XFERBITS | RK_KFER) == NG) {
288    substError:
289      jrKanjiError = "\303\340\274\241\274\253\306\260\312\321\264\271\244\313"
290	"\274\272\307\324\244\267\244\336\244\267\244\277";
291                     /* ���������������������������������������������������� */
292      /* ������������������������������������������������������������ */
293      if (TanMuhenkan(d) == -1) {
294	return -2;
295      }
296      return(-1);
297    }
298  }
299  yc->nbunsetsu = RkwSubstYomi(yc->context,
300			       yc->ys - yc->cStartp, yc->ye - yc->cStartp,
301			       yc->kana_buffer + yc->ys, yc->kEndp - yc->ys);
302  yc->ys = yc->ye = yc->kEndp;
303  if (yc->nbunsetsu < 0 || (ret = restoreChikujiYomi(d, n)) < 0) {
304    goto substError;
305  }
306  return(ret);
307}
308
309int
310ChikujiSubstYomi(uiContext d)
311{
312  yomiContext yc = (yomiContext)d->modec;
313
314  if ((yc->ys == yc->ye && yc->kEndp == yc->ye)
315      || yc->kEndp != yc->kCurs
316      || !(yc->kAttr[yc->kEndp - 1] & HENKANSUMI)) {
317    /* ������������������������������������������������
318       ��������������������������������������������������������
319       ���������������������������������������������������������������������������������������������������������������� */
320    return 0; /* ������������������������ */
321  }
322  return chikujiSubstYomi(d);
323}
324
325int
326ChikujiTanDeletePrevious(uiContext d)
327{
328  yomiContext yc = (yomiContext)d->modec;
329  int i, j, l = 0, flg = 0;
330  RkStat stat;
331
332  if (yc->cRStartp < yc->rEndp) { /* ���������������������������������������� */
333    flg = 1;
334  }
335  d->nbytes = 0;
336
337  /* ������������������������������������������������������������������������ */
338  if (forceRomajiFlushYomi(d)) {
339    return d->nbytes;
340  }
341  if (RkwSubstYomi(yc->context, 0, yc->ye - yc->cStartp,
342                                    (WCHAR_T *)0, 0) == NG) {
343    /* �������������������������������������������������������������������������������� */
344    (void)makeRkError(d, "\306\311\244\337\244\313\314\341\244\271\244\263"
345	"\244\310\244\254\244\307\244\255\244\336\244\273\244\363");
346                         /* ���������������������������������������������������� */
347    (void)TanMuhenkan(d); /* ������������������������ */
348    return 0;
349  }
350  yc->ys = yc->ye = yc->cStartp;
351  for (i = yc->nbunsetsu - 1 ; i >= yc->curbun ; i--) {
352    /* ������������������������������������������������������������������������������������ */
353    if (RkwGoTo(yc->context, i) == NG
354	|| RkwGetStat(yc->context, &stat) == NG
355	|| RkwStoreYomi(yc->context, (WCHAR_T *)0, 0) == NG) {
356      (void)makeRkError(d, "\306\311\244\337\244\313\314\341\244\271\244\263"
357	"\244\310\244\254\244\307\244\255\244\336\244\273\244\363");
358                           /* ���������������������������������������������������� */
359      TanMuhenkan(d); /* ���������������������������� */
360      return 0;
361    }
362    l += stat.ylen;
363  }
364  yc->nbunsetsu = yc->curbun;
365  if (l) {
366    i = j = 0;
367    do {
368      ++i;
369      if (yc->kAttr[yc->cStartp - i] & SENTOU) {
370	for (j++ ;
371	     j < yc->cRStartp && !(yc->rAttr[yc->cRStartp - j] & SENTOU) ;) {
372	  j++;
373	}
374      }
375    } while (i < l);
376    yc->cStartp = (i < yc->cStartp) ? yc->cStartp - i : 0;
377    yc->cRStartp = (j < yc->cRStartp) ? yc->cRStartp - j : 0;
378  }
379  if (KeepCursorPosition && yc->kCurs != yc->kEndp) {
380    yc->kRStartp = yc->kCurs = yc->cStartp;
381    yc->rStartp = yc->rCurs = yc->cRStartp;
382  }
383  else {
384    yc->kRStartp = yc->kCurs = yc->kEndp;
385    yc->rStartp = yc->rCurs = yc->rEndp;
386  }
387  yc->ys = yc->ye = yc->cStartp;
388  clearHenkanContent(yc);
389  if (yc->curbun) {
390    yc->curbun--;
391  }
392  yc->status |= CHIKUJI_OVERWRAP;
393  moveToChikujiYomiMode(d);
394  makeKanjiStatusReturn(d, yc);
395  if (flg && cannaconf.chikujiRealBackspace && !KeepCursorPosition) {
396    d->more.todo = 1;
397    d->more.ch = 0;
398    d->more.fnum = CANNA_FN_DeletePrevious;
399    /* ������������������������������������������������������������ */
400  }
401  return 0;
402}
403
404/*
405  chikuji_restore_yomi
406
407    cStartp, cRStartp ��������������������
408 */
409
410static int
411chikuji_restore_yomi(uiContext d)
412{
413  yomiContext yc = (yomiContext)d->modec;
414  int l, j;
415
416  if ((l = RkwGetLastYomi(yc->context, d->genbuf, ROMEBUFSIZE)) == -1) {
417    return makeRkError(d, "\314\244\267\350\312\270\300\341\244\362\274\350"
418	"\244\352\275\320\244\273\244\336\244\273\244\363\244\307\244\267"
419	"\244\277");
420                          /* ������������������������������������������������������������ */
421  }
422  if (l != yc->kEndp - yc->cStartp) { /* �������������������� */
423    kPos2rPos(yc, 0, yc->kEndp - l, (int *)0, &j);
424    yc->cStartp = yc->kEndp - l;
425    yc->cRStartp = j;
426  }
427
428  yc->ys = yc->ye = yc->cStartp;
429  return 0;
430}
431
432static int
433chikuji_subst_yomi(uiContext d)
434{
435  yomiContext yc = (yomiContext)d->modec;
436  int l, n = yc->nbunsetsu;
437
438  /* ������������������������������������ */
439  l = RkwSubstYomi(yc->context, yc->ys - yc->cStartp, yc->ye - yc->cStartp,
440		   yc->kana_buffer + yc->ys, yc->kEndp - yc->ys);
441  yc->ys = yc->ye = yc->kEndp;
442  if (l == -1) {
443    jrKanjiError = "\312\321\264\271\244\313\274\272\307\324\244\267\244\336"
444	"\244\267\244\277";
445                   /* ������������������������������������ */
446    (void)TanMuhenkan(d);
447    return -1;
448  }
449  yc->nbunsetsu = l;
450  if (l > n) {
451    yc->curbun = n; /* ������������������������������������ */
452  }
453  return chikuji_restore_yomi(d);
454}
455
456
457static int
458ChikujiTanExtend(uiContext d)
459{
460  yomiContext yc = (yomiContext)d->modec;
461  int i;
462
463  d->nbytes = 0;
464  yc->kouhoCount = 0;
465
466  if (yc->ys < yc->kEndp || yc->ye != yc->kEndp) {
467    i = yc->curbun; /* ���������������� */
468    if (chikuji_subst_yomi(d) == -1) {
469      makeGLineMessageFromString(d, jrKanjiError);
470      return TanMuhenkan(d);
471    }
472    if (RkwGoTo(yc->context, i) == -1) {
473      (void)makeRkError(d, "\312\270\300\341\244\316\260\334\306\260\244\313"
474	"\274\272\307\324\244\267\244\336\244\267\244\277");
475                           /* ������������������������������������������������ */
476      return TanMuhenkan(d);
477    }
478    yc->curbun = i;
479  }
480  if ((yc->nbunsetsu = RkwEnlarge(yc->context)) <= 0) {
481    (void)makeRkError(d, "\312\270\300\341\244\316\263\310\302\347\244\313"
482	"\274\272\307\324\244\267\244\336\244\267\244\277");
483                         /* ������������������������������������������������ */
484    return TanMuhenkan(d);
485  }
486  if (chikuji_restore_yomi(d) == NG) {
487    return TanMuhenkan(d);
488  }
489  yc->status |= CHIKUJI_OVERWRAP;
490  makeKanjiStatusReturn(d, yc);
491  return d->nbytes;
492}
493
494
495static int
496ChikujiTanShrink(uiContext d)
497{
498  yomiContext yc = (yomiContext)d->modec;
499  RkStat stat;
500  int i;
501
502  d->nbytes = 0;
503  yc->kouhoCount = 0;
504  if (yc->ys < yc->kEndp || yc->ye != yc->kEndp) {
505    i = yc->curbun;
506    if (chikuji_subst_yomi(d) == -1) {
507      makeGLineMessageFromString(d, jrKanjiError);
508      return TanMuhenkan(d);
509    }
510    if (RkwGoTo(yc->context, i) == -1) {
511      (void)makeRkError(d, "\312\270\300\341\244\316\275\314\276\256\244\313"
512	"\274\272\307\324\244\267\244\336\244\267\244\277");
513                           /* ������������������������������������������������ */
514      return TanMuhenkan(d);
515    }
516    yc->curbun = i;
517  }
518
519  if (RkwGetStat(yc->context, &stat) < 0 || stat.ylen == 1) {
520    /* ���������������������������������������������������������������������������� */
521    return NothingForGLine(d);
522  }
523  yc->nbunsetsu = RkwShorten(yc->context);
524  if (yc->nbunsetsu <= 0) { /* 0 �������������������������������������������� */
525    (void)makeRkError(d, "\312\270\300\341\244\316\275\314\276\256\244\313"
526	"\274\272\307\324\244\267\244\336\244\267\244\277");
527                         /* ������������������������������������������������ */
528    return TanMuhenkan(d);
529  }
530  if (chikuji_restore_yomi(d) == NG) {
531    return TanMuhenkan(d);
532  }
533  yc->status |= CHIKUJI_OVERWRAP;
534  makeKanjiStatusReturn(d, yc);
535  return d->nbytes;
536}
537
538
539static int
540ChikujiYomiDeletePrevious(uiContext d)
541{
542  yomiContext yc = (yomiContext)d->modec;
543  RkStat stat;
544  int i, j, l = 0;
545
546  d->nbytes = 0;
547  if (!(yc->cStartp < yc->kCurs)) { /* ���������������������������� */
548    if (!yc->nbunsetsu) { /* �������������������� */
549      return NothingChanged(d);
550    }
551    else {
552      if (RkwSubstYomi(yc->context, 0, yc->ye - yc->cStartp,
553                                        (WCHAR_T *)0, 0) == NG) {
554	(void)makeRkError(d, "\306\311\244\337\244\313\314\341\244\271\244\263"
555	"\244\310\244\254\244\307\244\255\244\336\244\273\244\363");
556                             /* ���������������������������������������������������� */
557	(void)TanMuhenkan(d);
558	return 0;
559      }
560      yc->ys = yc->ye = yc->cStartp;
561      yc->curbun = yc->nbunsetsu - 1; /* �������������������������������� */
562      for (i = yc->nbunsetsu - 1; i >= yc->curbun; i--) {
563	if (RkwGoTo(yc->context, i) == NG ||
564	    RkwGetStat(yc->context, &stat) == NG ||
565	    RkwStoreYomi(yc->context, (WCHAR_T *)0, 0) == NG) {
566	  return makeRkError(d, "\306\311\244\337\244\313\314\341\244\271"
567	"\244\263\244\310\244\254\244\307\244\255\244\336\244\273\244\363");
568                                /* ���������������������������������������������������� */
569	}
570	l += stat.ylen;
571	yc->nbunsetsu--;
572      }
573      i = j = 0;
574      do {
575	++i;
576	if (yc->kAttr[yc->cStartp - i] & SENTOU) {
577	  for (j++ ;
578	       j < yc->cRStartp && !(yc->rAttr[yc->cRStartp - j] & SENTOU) ;) {
579	    j++;
580	  }
581	}
582      } while (i < l);
583      yc->kCurs = yc->kRStartp = yc->cStartp;
584      yc->rCurs = yc->rStartp = yc->cRStartp;
585      yc->cStartp = (i < yc->cStartp) ? yc->cStartp - i : 0;
586      yc->cRStartp = (j < yc->cRStartp) ? yc->cRStartp - j : 0;
587      yc->ys = yc->ye = yc->cStartp;
588      clearHenkanContent(yc);
589      if (yc->curbun) {
590	yc->curbun--;
591      }
592
593      makeKanjiStatusReturn(d, yc);
594      return 0;
595    }
596  }
597  if (yc->kCurs - 1 < yc->ys) {
598    yc->ys = yc->kCurs - 1;
599  }
600  if (yc->ys < 0) {
601    yc->ys = 0;
602  }
603  KanaDeletePrevious(d);
604  yc->status |= CHIKUJI_OVERWRAP;
605  if (yc->kCurs <= yc->cStartp && yc->kEndp <= yc->cStartp && yc->nbunsetsu) {
606    /* �������������������������������������������������������� */
607    if (RkwGoTo(yc->context, yc->nbunsetsu - 1) == -1) {
608      return makeRkError(d, "\312\270\300\341\244\316\260\334\306\260\244\313"
609	"\274\272\307\324\244\267\244\336\244\267\244\277");
610                            /* ������������������������������������������������ */
611    }
612    yc->kouhoCount = 0;
613    yc->curbun = yc->nbunsetsu - 1;
614    moveToChikujiTanMode(d);
615    makeKanjiStatusReturn(d, yc);
616  }
617  else {
618    moveToChikujiYomiMode(d);
619    makeYomiReturnStruct(d);
620    if (yc->kEndp <= yc->cStartp && !yc->nbunsetsu) {
621      /* �������������������� */
622      d->current_mode = yc->curMode = yc->myEmptyMode;
623      d->kanji_status_return->info |= KanjiEmptyInfo;
624    }
625  }
626  return 0;
627}
628
629
630static int
631ChikujiHenkan(uiContext d)
632{
633  yomiContext yc = (yomiContext)d->modec;
634  int n, tmp, idx;
635
636  if (!yc->nbunsetsu && yc->rEndp == /* yc->cRStartp(== 0) + */ 1 &&
637      (yc->kAttr[0] & SUPKEY) &&
638      (idx = findSup(yc->romaji_buffer[0]))) {
639    return selectKeysup(d, yc, idx - 1);
640  }
641  if (!doesSupportChikuji()) {
642    jrKanjiError = "\245\265\241\274\245\320\244\254\303\340\274\241\274\253"
643	"\306\260\312\321\264\271\244\362\245\265\245\335\241\274\245\310"
644	"\244\267\244\306\244\244\244\336\244\273\244\363";
645                   /* ������������������������������������������������������������������������������������ */
646    makeGLineMessageFromString(d, jrKanjiError);
647    makeKanjiStatusReturn(d, yc);
648    d->nbytes = 0;
649    return 0;
650  }
651  if (yc->status & CHIKUJI_ON_BUNSETSU) {
652    tmp = yc->curbun;
653  }
654  else {
655    tmp = yc->nbunsetsu;
656  }
657  d->nbytes = 0;
658  if (yc->kCurs < yc->ys) {
659    yc->ys = yc->kCurs;
660  }
661  if (forceRomajiFlushYomi(d)) {
662    return d->nbytes;
663  }
664
665  if (containUnconvertedKey(yc)) {
666    if (yc->cmark < yc->cStartp) {
667      yc->cmark = yc->cStartp;
668    }
669    YomiMark(d);
670    yc->ys = yc->pmark;
671    if (forceRomajiFlushYomi(d)) {
672      return d->nbytes;
673    }
674  }
675
676  yc->kRStartp = yc->kCurs = yc->kEndp;
677  yc->rStartp  = yc->rCurs = yc->rEndp;
678
679  if (yc->cStartp < yc->kEndp) { /* ������������������������ */
680    yc->kCurs = yc->kEndp;
681    if (chikujiSubstYomi(d) < 0) {
682      makeGLineMessageFromString(d, jrKanjiError);
683      TanMuhenkan(d);
684      return 0;
685    }
686    n = RkwFlushYomi(yc->context);
687    if (n == -1) {
688      (void)makeRkError(d, "\312\321\264\271\244\313\274\272\307\324\244\267"
689	"\244\336\244\267\244\277");
690                           /* ������������������������������������ */
691      (void)TanMuhenkan(d);
692      return 0;
693    }
694    yc->cStartp = yc->kEndp;
695    yc->cRStartp = yc->rEndp;
696    yc->kouhoCount = 1;
697    yc->status |= CHIKUJI_ON_BUNSETSU;
698    if (n > yc->nbunsetsu) {
699      yc->curbun = yc->nbunsetsu;
700      yc->nbunsetsu = n;
701    }
702  }
703  if (RkwGoTo(yc->context, tmp) == -1) {
704    makeRkError(d, "\303\340\274\241\312\321\264\271\244\313\274\272\307\324"
705	"\244\267\244\336\244\267\244\277");
706                   /* �������������������������������������������� */
707    return 0;
708  }
709  yc->curbun = tmp;
710  yc->ys = yc->ye = yc->cStartp;
711  d->current_mode = yc->curMode = &tankouho_mode;
712  yc->minorMode = CANNA_MODE_TankouhoMode;
713  if (cannaconf.kouho_threshold > 0 &&
714      yc->kouhoCount >= cannaconf.kouho_threshold) {
715    return tanKouhoIchiran(d, 0);
716  }
717  currentModeInfo(d);
718  makeKanjiStatusReturn(d, yc);
719  return d->nbytes;
720}
721
722void
723moveToChikujiTanMode(uiContext d)
724{
725  yomiContext yc = (yomiContext)d->modec;
726
727  yc->status |= CHIKUJI_ON_BUNSETSU;
728  yc->minorMode = CANNA_MODE_ChikujiTanMode;
729  d->current_mode = yc->curMode = &cb_mode;
730  currentModeInfo(d);
731}
732
733void
734moveToChikujiYomiMode(uiContext d)
735{
736  yomiContext yc = (yomiContext)d->modec;
737
738  yc->status &= ~CHIKUJI_ON_BUNSETSU;
739  d->current_mode = yc->curMode = &cy_mode;
740  EmptyBaseModeInfo(d, yc);
741}
742
743static int
744generalNaive(uiContext d, int (*fn )(...))
745{
746  if ((((yomiContext)d->modec)->generalFlags) &
747      (CANNA_YOMI_HANKAKU | CANNA_YOMI_ROMAJI | CANNA_YOMI_BASE_HANKAKU)) {
748    return (*fn)(d);
749  }
750  else {
751    return ChikujiHenkan(d);
752  }
753}
754
755static int
756ChikujiHenkanNaive(uiContext d)
757{
758  return generalNaive(d, (int(*)(...))YomiInsert);
759}
760
761
762static int
763ChikujiHenkanOrNothing(uiContext d)
764{
765  return generalNaive(d, (int(*)(...))NothingChanged);
766}
767
768
769static int
770ChikujiMuhenkan(uiContext d)
771{
772  yomiContext yc = (yomiContext)d->modec;
773
774  if (yc->nbunsetsu) {
775    return TanMuhenkan(d);
776  }
777  else if (yc->left || yc->right) {
778    removeCurrentBunsetsu(d, (tanContext)yc);
779    yc = (yomiContext)d->modec;
780  }
781  else {
782    RomajiClearYomi(d);
783    d->current_mode = yc->curMode = yc->myEmptyMode;
784    d->kanji_status_return->info |= KanjiEmptyInfo;
785  }
786  makeKanjiStatusReturn(d, yc);
787  return 0;
788}
789
790#include "chikujimap.h"
791