/*
 * $Id: rk_main.c,v 1.2 2001/06/14 18:16:09 ura Exp $
 */

/*
 * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
 * This file is part of FreeWnn.
 * 
 * Copyright Kyoto University Research Institute for Mathematical Sciences
 *                 1987, 1988, 1989, 1990, 1991, 1992
 * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
 * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
 *
 * Author: OMRON SOFTWARE Co., Ltd. <freewnn@rd.kyoto.omronsoft.co.jp>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU Emacs; see the file COPYING.  If not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Commentary:
 *
 * Change log:
 *
 * Last modified date: 8,Feb.1999
 *
 * Code:
 *
 */
/***********************************************************************
                        rk_main.c
                                                87.12. 3  改 正

        ローマ字かな変換・その他、入力コードを変換するプログラム。
        ASCIIコード使用を、前提としている。
        このファイルは、変換のメインルーチン。
***********************************************************************/
/*      Version 3.1     88/06/14        H.HASHIMOTO
 */
#ifndef OMRON_LIB
#include "rk_header.h"
#include "rk_extvars.h"
#ifdef  MULTI
#include "rk_multi.h"
#endif /*MULTI*/
#endif
#include "rext.h"
#ifdef  MULTI
#define DISOUT ((cur_rk->flags & RK_NONISE) ? cur_rk->rk_output : cur_rk->disout)
  /* フラグの値はromkan_init3()の中で設定され、そのRK_NONISEのビットの値の
     標準は0。従ってDISOUTの標準値はdisout。これをrk_outputに変えると、偽コード
     （除：LTREOF）を一切出さない（但し、キー入力があれば必ず何かを返すように
     してある時に限り、EOLTTRをも返す）。 */
#else /* !MULTI */
#ifdef KDSP
#       ifdef MVUX
  letter displine[DSPLIN];      /* デバッグ用  表示の一行分を記憶 */
#       endif
#endif

/* 88/06/02 V3.1 */
static letter nil[1] = { EOLTTR };
static letter *curdis;
static int codein_len;
static letter *codeout, *remainkbf;
static letter ungetc_buf = EOLTTR;      /* romkan_ungetcが一文字退避しておくバッファ */
static letter unnext_buf = EOLTTR;      /* romkan_unnextが            〃             */

static letter (*keyin_method) ();       /* キーイン関数のアドレス */
static int (*bytcnt_method) (); /* バイトカウント関数のアドレス */
static int (*kbytcnt_method) ();        /* キー入力解釈用バイトカウント関数のアドレス */

/* モード表名（又はそのパス名）を保存 *//* 初期設定がいい加減! */
static char prv_modfnm[REALFN] = "\0";

#define DISOUT ((flags & RK_NONISE) ? rk_output : disout)
 /* フラグの値はromkan_init3()の中で設定され、そのRK_NONISEのビットの値の
    標準は0。従ってDISOUTの標準値はdisout。これをrk_outputに変えると、偽コード
    （除：LTREOF）を一切出さない（但し、キー入力があれば必ず何かを返すように
    してある時に限り、EOLTTRをも返す）。 */

static                          /* V3.1 */
char eofflg;                    /* romkan_next()からLTREOFが来たときに、romkan_henkan()内で1
                                   にする。これの値が非0なら変換対応表の(error)を無視して、
                                   本処理バッファ内の未確定コードも、強制的に変換させる。更に
                                   LTREOFが来た時に特別にある出力を出すように指定されていれば
                                   その処理も行う（但し、その処理は急ごしらえで不完全）。その
                                   処理中はeofflgは2。 */

static letter evalbuf[2][2][OUTSIZ];
static letter delchr, delchr2 = EOLTTR, nisedl; /* DELのキャラクタは二個まで持てる */

/* 88/05/31 V3.1 */
static letter rk_input;         /* 入力。3バイトまでは変更なしに対応可 */
static letter disout[OUTSIZ];   /* 本処理からの出力のバッファ */
static letter rk_output[OUTSIZ];        /* 後処理からの出力（最終出力）のバッファ */
static letter keybuf[KBFSIZ], urabuf[KBFSIZ];   /* 本処理バッファとその退避領域 */
static int lastoutlen, lastkbflen;
static int hyonum;
#endif /* MULTI */

static void romkan_delete (), mchevl (), add_at_eof (), free_for_all_area (), ltrevlcpy (), set_rubout (), maeato_henkan (), codeout_chg ();

/* letterを返す関数の定義及び宣言（一部にはcharのものも混じっている） */

static int head_bytecount (), p_eq (), hen_ikisrc (), match (), henkan_ok (), romkan_restart ();
static letter mchedsrc ();
letter romkan_next (), romkan_unnext ();
letter romkan_getc (), romkan_ungetc (), *romkan_henkan ();
letter to_zenalpha (), to_zenhira (), to_zenkata ();
 /* to_zenhira;kata は濁点を持つ文字を一まとめにしない。 */

static letter *
ltrcpy (lp1, lp2)
     fast letter *lp1, *lp2;    /* V3.1 */
{
  fast letter *org;             /* V3.1 */

  org = lp1;
  while ((*lp1++ = *lp2++) != EOLTTR);
  return (org);
}

#ifdef nodef
static letter *
ltrncpy (lp1, lp2, n)           /* 末尾に'EOLTTR'をセット */
     letter *lp1, *lp2;
     int n;
{
  fast letter *org;

  org = lp1;
  for (; n; --n)
    if (EOLTTR == (*lp1++ = *lp2++))
      return (org);
  *lp1 = EOLTTR;
  return (org);
}
#endif

 /** letterの列の末尾に一文字つなげる */
static                          /* V3.1 */
letter *
ltr1cat (lp, l)
     fast letter *lp, l;        /* V3.1 */
{
  fast letter *org;             /* V3.1 */

  org = lp;
  totail (lp);
  *lp++ = l;
  *lp = EOLTTR;
  return (org);
}

 /** 文字列の末尾に一文字つなげる。ltr1catのchar版 */
#ifdef OMRON_LIB
static
#endif
char *
chrcat (s, c)
     fast char *s, c;           /* V3.1 */
{
  fast char *org;               /* V3.1 */

  org = s;
  strtail (s);
  *s++ = c;
  *s = '\0';
  return (org);
}

static letter *
ltrcat (lp1, lp2)
     fast letter *lp1, *lp2;    /* V3.1 */
{
  fast letter *org;             /* V3.1 */

  org = lp1;
  totail (lp1);
  ltrcpy (lp1, lp2);
  return (org);
}

 /** letterの列lp2の各要素の最上位ビットを立ててから、lp1の後ろにつなげる。*/
static                          /* V3.1 */
letter *
bitup_ltrcat (lp1, lp2)
     fast letter *lp1, *lp2;    /* V3.1 */
{
  fast letter *org;             /* V3.1 */

  org = lp1;
  totail (lp1);

  while ((*lp1 = *lp2++) != EOLTTR)
    *lp1++ |= HG1BIT;
         /** lp2 の要素全ての最上位ビットを立てる。*lp2がNISEBP(rk_spclval.h
             でdefine)などのときは最初から最上位が立ってるからよい */

  return (org);
}

 /** ltrcatしたあと、結果の文字列の末尾にポインタをもっていく。*/
#ifdef OMRON_LIB
static
#endif
letter *
ltrgrow (lp1, lp2)
     fast letter *lp1, *lp2;    /* V3.1 */
{
  totail (lp1);
  while ((*lp1 = *lp2++) != EOLTTR)
    lp1++;
  return (lp1);
}

int
ltrlen (lp)
     fast letter *lp;           /* V3.1 */
{
  fast letter *org;             /* V3.1 */

  for (org = lp; *lp != EOLTTR; lp++);
  return (lp - org);
}

 /**    letterの列の最後の文字へのポインタを返す。但し空文字列に対しては
        そのまま返す。*/
static letter *
ltrend (lp)
     fast letter *lp;           /* V3.1 */
{
  return ((*lp != EOLTTR) ? (lp + ltrlen (lp) - 1) : lp);
}

 /**    文字列の最後の文字へのポインタを返す。ltrend()のchar版。ltrend()と
        同様、空文字列のときは特例がある。*/
#ifdef OMRON_LIB
static
#endif
char *
strend (s)
     fast char *s;              /* V3.1 */
{
  return (*s ? (s + strlen (s) - 1) : s);
}

int
ltrcmp (lp1, lp2)
     fast letter *lp1, *lp2;    /* V3.1 */
{
  for (; *lp1 == *lp2; lp1++, lp2++)
    if (*lp1 == EOLTTR)
      return (0);
  return (*lp1 > *lp2 ? 1 : -1);
}

#ifdef nodef
int
ltrncmp (lp1, lp2, n)
     letter *lp1, *lp2;
     int n;
{
  for (; n && *lp1 == *lp2; n--, lp1++, lp2++)
    if (*lp1 == EOLTTR)
      return (0);
  return (n == 0 ? 0 : (*lp1 > *lp2 ? 1 : -1));
}

/* 88/06/14 V3.1 */
/******************************************************************************/
#ifndef OMRON
letter *
ltr_index (lp, l)
     letter l, *lp;
{
  for (; *lp != EOLTTR; lp++)
    if (*lp == l)
      return (lp);
  return (NULL);
}
#endif
/******************************************************************************/
#endif

static                          /* V3.1 */
letter *
ltr_rindex (lp, l)
     fast letter l, *lp;        /* V3.1 */
{
  fast letter *lp2;             /* V3.1 */

  for (lp += ltrlen (lp2 = lp); lp2 != lp;)
    if (*--lp == l)
      return (lp);
  return (NULL);
}

 /** 文字列の末尾一文字をカットする。*/
/*static V3.1 */
letter *
ltr1cut (lp)
     fast letter *lp;           /* V3.1 */
{
  fast int l;                   /* V3.1 */

  if (0 == (l = ltrlen (lp)))
    BUGreport (0);              /* Illegal POP */
  *(lp + --l) = EOLTTR;
  return (lp);
}

 /** letterの一文字を長さ１の文字列に変換する */
static                          /* V3.1 */
letter *
ltr_to_ltrseq (lp, l)
     letter *lp, l;
{
  *lp++ = l;
  *lp-- = EOLTTR;
  return (lp);
}

 /** charの列からletterを一つ取り出す。但し'\0'はEOLTTRに変える */
#ifdef OMRON_LIB
static
#endif
  letter
letterpick (lbfpptr)
     fast uns_chr **lbfpptr;
{
  fast letter l = 0;
  fast int i;                   /* V3.1 */

  for (i = (*(cur_rk_table->bytcnt_method)) (*lbfpptr); i; i--)
    l = (l << 8) + *(*lbfpptr)++;
  return (l == 0 ? EOLTTR : l);
}

 /**    入力されたコードを文字単位にまとめる。但しEOFはLTREOF（rk_spclval.h
        にて定義）に変える。*/
/* *INDENT-OFF* */
letter
romkan_next ()
/* *INDENT-ON* */
{
  letter in;
  int i, n;
  uns_chr c;

  /* unnextされている場合は、それを取り出す。 */
  if (cur_rk->unnext_buf != EOLTTR)
    return (in = cur_rk->unnext_buf, cur_rk->unnext_buf = EOLTTR, in);

  if ((letter) EOF == (in = (*(cur_rk_table->keyin_method)) ()))
    return (LTREOF);
  c = (in &= 0xff);
  n = (*(cur_rk_table->kbytcnt_method)) (&c);
  for (i = 1; i < n; i++)
    in = (in << 8) + ((*(cur_rk_table->keyin_method)) () & 0xff);
  return (in);
}

 /*     letterの文字 l とcharの文字 c の比較。エンドマーク同士（letter列の
    エンドマークはEOLTTR、char列のは'\0'）も一致とみなす。 */
#define ltrchreq(l, c) ((l) == (c) && (c) != 0 || (l) == EOLTTR && (c) == 0)

 /** letterの文字列とcharの文字列の比較 但し大小比較は符号なしとしてやる */
#ifdef OMRON_LIB
static
#endif
  int
ltrstrcmp (l, s)
     fast letter *l;            /* V3.1 */
     fast char *s;              /* V3.1 */
{
  for (; ltrchreq (*l, *s); l++, s++)
    if (*s == 0)
      return (0);
  return (1);
/*
        return((*l < (uns_chr)*s || *l == EOLTTR)? -1 : 1);
*/
}

 /** 最後にマッチした文字 つまりurabufの最後。urabufが空だとEOLTTRを返す */
static                          /* V3.1 */
  letter
lastmch ()
{
  return (*(ltrend (cur_rk->urabuf)));
}

/* end of 'letter' functions */


 /** 変換バッファのクリア */
 /* 注意！ romkan_clear()を呼ぶ時は、必ずその前に、cur_rkをセットすること */
void
romkan_clear ()
{
#ifdef KDSP
#       ifdef MVUX
  *displine = EOLTTR;
#       endif
#endif
  cur_rk->ungetc_buf = *(cur_rk->keybuf) = *(cur_rk->urabuf) = *(cur_rk->disout) = *(cur_rk->rk_output) = EOLTTR;
  cur_rk->curdis = DISOUT;
  cur_rk->lastoutlen = cur_rk->lastkbflen = 0;
}

 /**    WnnV4.0マルチクライアント用のRomkan構造体を初期化する **/
Romkan *
rk_buf_init ()
{
  register Romkan *p;
  register int i;

  if ((p = (Romkan *) malloc (sizeof (Romkan))) == NULL)
    {
      return (NULL);
    }
  malloc_for_henmatch (&(p->rk_henmatch), cur_rk_table->rk_hensuudef.count);
  malloc_for_modesw (&(p->rk_modesw), cur_rk_table->rk_modesw.max);
  p->rk_modesw.max = cur_rk_table->rk_modesw.max;
  p->rk_modesw.count = cur_rk_table->rk_modesw.count;
  for (i = 0; i < cur_rk_table->rk_modesw.max; i++)
    {
      p->rk_modesw.point[i] = cur_rk_table->rk_modesw.point[i];
    }
  malloc_for_usehyo (&(p->rk_usehyo), cur_rk_table->rk_usehyo.size);
  p->rk_usehyo.size = cur_rk_table->rk_usehyo.size;
  for (i = 0; i < (cur_rk_table->rk_usehyo.size + 1); i++)
    {
      p->rk_usehyo.usemaehyo[i] = cur_rk_table->rk_usehyo.usemaehyo[i];
      p->rk_usehyo.usehyo[i] = cur_rk_table->rk_usehyo.usehyo[i];
      p->rk_usehyo.useatohyo[i] = cur_rk_table->rk_usehyo.useatohyo[i];
    }
  p->rk_errstat = NULL;
  p->flags = 0;
  p->nil[0] = EOLTTR;
  p->ungetc_buf = EOLTTR;
  p->unnext_buf = EOLTTR;
  p->delchr2 = EOLTTR;
  p->ebf_sw = NULL;
  p->oneletter[0] = p->oneletter[1] = EOLTTR;
  p->keybuf[0] = p->urabuf[0] = p->disout[0] = p->rk_output[0] = EOLTTR;
  p->rk_table = (RomkanTable *) NULL;
  return (p);
}

RomkanTable *
rk_table_buf_init ()
{
  RomkanTable *p;
  if ((p = (RomkanTable *) malloc (sizeof (RomkanTable))) == NULL)
    {
      return (NULL);
    }
  p->flags = 0;
  p->rk_usehyo.size = -1;
  p->prv_modfnm[0] = NULL;
  return (p);
}


void
rk_close (p)
     Romkan *p;
{
/*free_for_all_area(); *//* V3.1 */
  free_for_modesw (&(p->rk_modesw));
  free_for_henmatch (&(p->rk_henmatch));
  free_for_usehyo (&(p->rk_usehyo));
  free (p);
}

 /**    表を読み込んで変換の初期設定をする。（part 3）*/
 /* WnnV4.0マルチクライアントの場合
    romkan_init3は、Romkan構造体へのポインタを返します。
    その後、romkanをする場合は、グローバル変数cur_rkに
    そのポインタを入れなければならない。 
    但し、romkan_init3()は、内部で一時的にcur_rkをセットし、
    returnする時に元の値に戻します。 */

#ifdef nodef
/* 88/06/13 V3.1 */
 /** 変換表のクリア */
static                          /* V3.1 */
  void
romkan_reset ()
{
  if (cur_rk_table->rk_modenaibu.org != NULL)
    {
      cur_rk_table->rk_modenaibu.org[0] = 0;    /* Terminator */
    }
  choosehyo ();
  romkan_clear ();
}
#endif


RomkanTable *
romkan_table_init (p, modhyo, keyinfn, bytcntfn, kbytcntfn, flags_)
     RomkanTable *p;
     fast char *modhyo;         /* モード定義表の名又はそのパス名 */
letter (*keyinfn) ();
     fast int (*bytcntfn) ();
     fast int (*kbytcntfn) ();
     fast int flags_;
{
  int errcod;                   /* 今の所1のみ */
  fast RomkanTable *tmp_cur_rk_table;
  fast RomkanTable *rk_table_buf;

  tmp_cur_rk_table = cur_rk_table;
  if (p == NULL)
    {
      if ((rk_table_buf = (RomkanTable *) rk_table_buf_init ()) == NULL)
        {
          return (NULL);
        }
    }
  else
    {
      rk_table_buf = p;
    }
  cur_rk_table = rk_table_buf;
  cur_rk_table->keyin_method = keyinfn;
  cur_rk_table->bytcnt_method = (bytcntfn == NULL ? head_bytecount : bytcntfn);
  cur_rk_table->kbytcnt_method = (kbytcntfn == NULL ? cur_rk_table->bytcnt_method : kbytcntfn);
  /* 88/05/30/ V3.1 */
  if (modhyo == NULL)
    modhyo = "";
  strcpy (cur_rk_table->prv_modfnm, modhyo);    /* V3.1 */
  if ((errcod = setjmp (cur_rk_table->env0)) != 0)
    {
      /* 88/06/13 V3.1 */
      free_for_all_area ();     /* V3.1 */
      fprintf (stderr, "romkan_init failed.");
    }
  else
    {
      readdata (modhyo);        /* 88/06/08 V3.1 */
    }
  cur_rk_table = tmp_cur_rk_table;
  if (!errcod)
    {
      return (rk_table_buf);
    }
  else
    {
      free (rk_table_buf);
      return (NULL);
    }
}


 /**    表を読み込んで変換の初期設定をする。（part 3）*/

Romkan *
romkan_init3 (delchr_, nisedl_, delchr2_, flags_)
     letter delchr_;            /* DELとして使うコード */
     letter nisedl_;            /* 偽DELとして使うコード */
     letter delchr2_;           /* DELとして使うコードが二つある場合そのもう一方 */
     int flags_;
 /* 以下のフラグが利用可。これらはrk_spclval.hにて定義。
    RK_CHMOUT:モードチェンジを知らせるコードを返すか？
    RK_KEYACK:キーインに対し必ず何かを返すか
    RK_NONISE:偽コードを出さないようにするか
    RK_REDRAW:Wnn用特殊フラグ（redraw用のフラグを出すかどうか）
    RK_SIMPLD:deleteの動作を単純にするか
  */
{
  Romkan *tmp_cur_rk;
  Romkan *rk_buf;

  tmp_cur_rk = cur_rk;

  if (setjmp (cur_rk_table->env0) != 0)
    {
      return (NULL);
    }

  if ((rk_buf = (Romkan *) rk_buf_init ()) == NULL)
    {
      return (NULL);
    }
  cur_rk = rk_buf;
  /* 偽コードを出すかの設定はromkan_clearで使うので、フラグの設定を
     先にやっておかないといけない。 */
  cur_rk->flags = flags_;
  cur_rk->curdis = DISOUT;
  cur_rk->delchr = delchr_;
  cur_rk->nisedl = nisedl_;
  cur_rk->delchr2 = delchr2_;
 /**    実はDELのキャラクタを二個まで持てる。二個目：delchr2は、未設定の
        とき（値がEOLTTR）は無視される。それ以外は、delchr2が入力されると
        delchrが入力されたのと同じ振る舞いをする。*/

  choosehyo ();
  cur_rk = tmp_cur_rk;
  return (rk_buf);
}

#define ifflg(a, b) ((a) ? (b) : 0)

 /**    表を読み込んで変換の初期設定をする。（part 2: キー入力に対し必ず何か
        返すようにするか、キーバッファをクリアするかどうかなども指定可）*/

Romkan *
romkan_init2 (delchr_, chmoutf, keyinfn, bytcntfn, keyackf, restartf, nonisecodf)
     char chmoutf, keyackf, restartf, nonisecodf;
     letter delchr_;
letter (*keyinfn) ();
     int (*bytcntfn) ();        /* 引数の詳細はromkan_init3を参照 */
{
  return (romkan_init3 (delchr_, toNISE (delchr_), EOLTTR, keyinfn, bytcntfn, (int (*)()) NULL, ifflg (chmoutf, RK_CHMOUT) | ifflg (keyackf, RK_KEYACK) | ifflg (nonisecodf, RK_NONISE)));
}

 /**    表を読み込んで変換の初期設定をする。（part 1）*/
Romkan *
romkan_init (delchr_, chmoutf, keyinfn, bytcntfn)
     char chmoutf;
     letter delchr_;
letter (*keyinfn) ();
     int (*bytcntfn) ();        /* 引数の詳細はromkan_init3を参照 */
{
  return (romkan_init2 (delchr_, chmoutf, keyinfn, bytcntfn, 0, 0, 0));
}


 /**    バイトカウント関数のデフォルト。sの指している所に入っているのが
        何バイトコードかを返す。
        romkan_nextに注意。そちらでは、バイトカウント関数の値は
        引数の一文字目にのみ依存すると仮定している。*/
static                          /* V3.1 */
  int
head_bytecount (s)
     fast uns_chr *s;
{
  fast uns_chr c = *s;
#ifdef IKIS
  return ((c <= 0xa0 || c == 0xff) ? 1 : 2);
#else
  if (c == SS2)
    return (2);
  if (c == SS3)
    return (3);
  if (c <= 0xa0)
    return (1);
  else
    return (2);
#endif
}

 /** 変換された文字を順次返す */
/* *INDENT-OFF* */
letter
romkan_getc ()
/* *INDENT-ON* */
{
  fast letter l;                /* V3.1 */

  /* ungetcされている場合は、それを取り出す。 */
  if (cur_rk->ungetc_buf != EOLTTR)
    return (l = cur_rk->ungetc_buf, cur_rk->ungetc_buf = EOLTTR, l);

  while (*(cur_rk->curdis) == EOLTTR)
    {
      /* romkan_next()の値がLTREOFの時も、そのまま送れば良い。 */
      cur_rk->curdis = romkan_henkan (romkan_next ());

      /* keyackflgが非0なら、キーインがあれば必ず何か返す。その
         ため、返すべきものがない時はEOLTTRを返すことにする。 */
      if (cur_rk->flags & RK_KEYACK)
        break;
    }

  if (EOLTTR != (l = *(cur_rk->curdis)))
    cur_rk->curdis++;
  return (l);
  /* 偽物の文字なら、HG1BITが立っている。 */
  /* 特別なコード(例えば偽のBEEPとしてNISEBP)を返すときがある。それらは
     rk_spclval.hに定義されている。 */
}

 /**    romkan_getcの下位関数として、入力を一文字受け取って
        変換結果の文字列を出力する。*/
letter *
romkan_henkan (mae_in)
     letter mae_in;
{
  letter mae_out[2], *p;

  /* if(*(cur_rk->curdis) != EOLTTR){p = cur_rk->curdis; cur_rk->curdis = cur_rk->nil; return(p);} */
  /* ↑これではmae_inが無視される */
  cur_rk->curdis = cur_rk->nil;

  /* 前・後処理への入力は常にただ一文字 */
  mae_out[0] = mae_out[1] = EOLTTR;

  cur_rk->eofflg = cur_rk->rk_errstat = 0;
  *(cur_rk->rk_output) = *(cur_rk->disout) = EOLTTR;

  maeato_henkan (mae_in, mae_out, cur_rk->rk_usehyo.usemaehyo);
  cur_rk->rk_input = *mae_out;

  if (cur_rk->rk_input == LTREOF)
    {
      /* LTREOFが来た場合、(error)を無視し、本処理バッファの末尾迄
         強制変換する。そのためにeofflgを1にする。その後、結果の
         末尾に、LTREOFが来た時の特別コード（指定されていれば）と、
         LTREOFをつなぐ。 */
      cur_rk->eofflg = 1;
      match ();

      cur_rk->eofflg = 2;
      add_at_eof ();            /* codeoutに、LTREOFが来た時出すコードが入る。 */
      ltr1cat (cur_rk->codeout, LTREOF);

      ltrcat (cur_rk->disout, cur_rk->codeout);
      ltrcat (cur_rk->rk_output, cur_rk->codeout);
    }
  else if (cur_rk->rk_input == EOLTTR)
    {
      /* EOLTTRが来た場合も、上と同様の処理を行うが、LTREOFは
         つながない。なお、これはromkan_getc()を呼んでいる時は
         起こらない（romkan_next()がEOLTTRを返さないから）。 */
      cur_rk->eofflg = 1;
      match ();
    }
  else if (cur_rk->rk_input == cur_rk->delchr || cur_rk->rk_input == cur_rk->delchr2)
    {
      /* delchr2が未設定ならその値はEOLTTRなのでrk_inputと等しくない。 */
      romkan_delete (cur_rk->rk_input); /* V3.1 */
    }
  else
    {
      ltr1cat (cur_rk->keybuf, cur_rk->rk_input);
      ltr1cat (cur_rk->disout, toNISE (cur_rk->rk_input));
      match ();
    }

  if (!(cur_rk->flags & RK_CHMOUT))
    {
      /* chmoutflgが0の時は、CHMSIGを出さない。 */
      for (p = DISOUT;; p++)
        {
          while (*p == CHMSIG)
            ltrcpy (p, p + 1);
          if (*p == EOLTTR)
            break;
        }
    }

  if ((cur_rk->flags & RK_REDRAW) && NULL != (p = ltr_rindex (cur_rk->disout, cur_rk->nisedl)))
    {
      for (p++; *p != EOLTTR || (ltr1cat (cur_rk->disout, REDRAW), 0); p++)
        if (!isSPCL (*p))
          break;
    }
  /* wnnのredrawのフラグが立っていて、disoutがnisedl以後特殊コードのみ
     で終わっていたら、REDRAWを出して、Wnnに変換行のredrawをさせる。 */

  return (DISOUT);
}


/******************************************************************************/
 /* デバッグ用関数 */
#ifdef  KDSP
#       ifdef   MVUX

pridbg2 (a, b, c)
     char *a, *c;
     letter *b;
{
  printf ("%s", a);
  dump_fordbg (b);
  printf ("%s", c);
}

ltr_displen (l)
     letter l;
{
  while (l >= 256)
    l >>= 8;

  if (l == 0)
    return (0);
  if (l < ' ')
    return (0);
  if (168 <= l && l <= 170)
    return (1);
  return (l > 160 ? 2 : 1);
}

dump_fordbg (lp)
     letter *lp;
{
  while (*lp != EOLTTR)
    printf ("%x/", *lp++);
}

print_fordbg (lp)
     letter *lp;
{
  while (*lp != EOLTTR)
    putletter (*lp++ & ~HG1BIT);
}

print_ltrseq (lp)
     letter *lp;
{
  while (*lp != EOLTTR)
    print_ltr (*lp++ & ~HG1BIT);
}

print_ltr (l)
     letter l;
{
  letter *disptail;
  int i;

  if (!isSPCL (l))
    l &= ~HG1BIT;

  if (l == CHMSIG)
#ifdef CHMDSP
    printf ("...mode=%s\n", romkan_dispmode ())
#endif
      ;
  else
#define BEEPCH  '\007'
#define NEWLIN  '\n'
  if (l == BEEPCH || l == NISEBP)
    putchar (BEEPCH);
  else if (l == NEWLIN)
    {
      *(cur_rk->displine) = *(cur_rk->keybuf) = *(cur_rk->urabuf) = EOLTTR;
      cur_rk->lastoutlen = cur_rk->lastkbflen = 0;
      putchar (l);
    }
  else if (l == cur_rk->delchr || l == cur_rk->nisedl)
    {
      if (*(cur_rk->displine) == EOLTTR)
        putchar (BEEPCH);
      else
        {
          disptail = ltrend (cur_rk->displine);
          for (i = ltr_displen (*disptail); i; i--)
            printf ("\031 \031");
          *disptail = EOLTTR;
        }
    }
  else
    {
      ltr1cat (cur_rk->displine, l);
      putletter (l);
    }
}

#       endif /* of #ifdef MVUX */
#endif
/* デバッグ用関数終わり */


/* 88/06/10 V3.1 */
 /** DELが入力されたときの処理をする */
static                          /* V3.1 */
  void
romkan_delete (input_del)
     letter input_del;
{
  if (ltrlen (cur_rk->keybuf) > ((cur_rk->flags & RK_SIMPLD) ? 0 : cur_rk->lastkbflen))
    {
      ltr1cut (cur_rk->keybuf);
      set_rubout (cur_rk->disout, 1, cur_rk->nisedl);
    }
  else
    {
      if (*(cur_rk->urabuf) != EOLTTR && !(cur_rk->flags & RK_SIMPLD))
        {
          ltr1cut (ltrcpy (cur_rk->keybuf, cur_rk->urabuf));
          *(cur_rk->urabuf) = EOLTTR;

          set_rubout (cur_rk->rk_output, cur_rk->lastoutlen, input_del);

          set_rubout (cur_rk->disout, cur_rk->lastkbflen, cur_rk->nisedl);
          bitup_ltrcat (ltrcat (cur_rk->disout, cur_rk->rk_output), cur_rk->keybuf);

          cur_rk->lastkbflen = cur_rk->lastoutlen = 0;
        }
      else
        {
          set_rubout (cur_rk->disout, 1, input_del);
          set_rubout (cur_rk->rk_output, 1, input_del);
        }
    }
}

 /**    letterの列 lp1 と lp2 のマッチを試みる。返値は、lp1がlp2の頭部と
        一致の時 -1、lp1またはその頭部とlp2が一致のときは一致長（lp2が
        空文字列の時を含む。この場合返値は0）、それ以外は -2。
        lp2側に式が含まれていたら評価をする。lp1側には式を含んではだめ */
static                          /* V3.1 */
  int
prefixp (lp1, lp2)
     letter *lp1, *lp2;
{
  /* 1行マッチさせるごとに、まずmatch情報をクリアしてから。
     つまり、rk_henmatch.point[0].ltrmch = EOLTTR; としておく。 */

  fast int mch_len = 0, d_len;  /* V3.1 */

  for (;;)
    {
      if (*lp2 == EOLTTR)
        return (mch_len);
      if (*lp1 == EOLTTR)
        return (-1);
      if ((d_len = p_eq (&lp2, &lp1)) < 0)
        return (d_len);
      mch_len += d_len;
    }
}

 /** num番目の変数が既にある文字とマッチしていると仮定して、その文字を返す */
static                          /* V3.1 */
  letter
mchedsrc (num)
     fast int num;              /* V3.1 */
{
  fast matchpair *pairptr;      /* V3.1 */

  if (cur_rk->rk_henmatch.size <= 0)
    return (0);
  for (pairptr = cur_rk->rk_henmatch.point; pairptr->ltrmch != EOLTTR; pairptr++)
    {
      if (num == pairptr->hennum)
        return (pairptr->ltrmch);
    }
  return (BUGreport (8), 0);
}

 /**    num番目の変数が文字 l とマッチするか調べる。その変数がunboundだった
        場合は l にbindする。マッチしたら(bindの時を含む)1、しないと0を返す */
static                          /* V3.1 */
  int
mchsrc (num, l)
     fast int num;              /* V3.1 */
     fast letter l;             /* V3.1 */
{
  fast matchpair *pairptr;      /* V3.1 */

  if (hen_ikisrc (num, l) == 0)
    return (0);
  if (cur_rk->rk_henmatch.size <= 0)
    return (0);
  for (pairptr = cur_rk->rk_henmatch.point; pairptr->ltrmch != EOLTTR; pairptr++)
    {
      if (num == pairptr->hennum)
        return (pairptr->ltrmch == l);
    }

  pairptr->ltrmch = l;
  pairptr->hennum = num;
  (++pairptr)->ltrmch = EOLTTR;
  return (1);
}

 /**    l1pから一単位を取って評価し、文字l2と一致するかどうかを返す。評価した
        結果が一文字にならなかったら、当然一致しない。*/
static                          /* V3.1 */
  int
l_eq (l1p, l2)
     letter *l1p, l2;
{
  letter evlrsl[RSLMAX];

  switch (SHUBET (*l1p))
    {
    case 0:
      return (*l1p == l2);
    case 1:
      return (mchsrc ((int) LWRMSK (*l1p), l2));
    case 2:
      mchevl (&l1p, evlrsl);
      return (evlrsl[0] == l2 && evlrsl[1] == EOLTTR);
    default:
      return (BUGreport (1), 0);
    }
}

 /**    prefixp内で使用  但し引数の順序は逆、すなわち式が含まれうるのはl1pp側
        のみ。l1ppから一単位ぶん取って評価したものとl2ppのマッチを試みる。それ
        がl2ppまたはその頭部とマッチすれば一致長を返し（l1ppの評価結果が空文字
        列の時を含む。この場合返値は0）、逆にl1ppの評価結果の頭部とl2ppがマッ
        チした時は -1を返す。マッチが失敗したら返値は -2。*/
static                          /* V3.1 */
  int
p_eq (l1pp, l2pp)
     fast letter **l1pp, **l2pp;        /* V3.1 */
{
  int num;
  letter evlrsl[RSLMAX], *rslptr;
  fast int retval = -2;         /* V3.1 */

  /*  l2pp側には式を含まない筈 */
  if (!is_HON (**l2pp))
    {
      /*  if(is_HON(**l1pp)) retval = p_eq(l2pp, l1pp); else  */
      BUGreport (9);
    }
  else
    {
      switch (SHUBET (**l1pp))
        {
        case 0:         /* 文字同士 */
          retval = (*(*l1pp)++ == *(*l2pp)++ ? 1 : -2);
          break;
        case 1:         /* 変数と文字 */
          num = LWRMSK (*(*l1pp)++);
          retval = (mchsrc (num, *(*l2pp)++) ? 1 : -2);
          break;
        case 2:         /* 式と文字 */
          mchevl (l1pp, rslptr = evlrsl);
          for (retval = 0; *rslptr != EOLTTR; retval++)
            {
              if (**l2pp == EOLTTR)
                {
                  retval = -1;
                  break;
                }
              else if (*rslptr++ != *(*l2pp)++)
                {
                  retval = -2;
                  break;
                }
            }
          break;
        default:
          BUGreport (2);
        }
    }

  return (retval);
}

 /** l1pから一単位評価してl2pに入れる */
#ifdef  MULTI


#define XY2INT(X, Y) (((X) << 24) | (Y))        /* これが１回しかYを評価しないことに
                                                   依存して書いてある箇所がある  注意！ */

 /** l1pから一単位評価してl2pに入れる */
static void
mchevl (l1pp, l2p)
     letter **l1pp, *l2p;
{
  letter *l1p, tmpevl[RSLMAX];

  l1p = *l1pp;

  switch (SHUBET (*l1p))
    {
    case 0:
      *l2p++ = *l1p++;
      break;
    case 1:
      *l2p++ = mchedsrc ((int) LWRMSK (*l1p++));
      break;
    case 2:                     /* toupper, tolower, error, … */
      switch (LWRMSK (*l1p++))
        {
        case 2:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_upper (*tmpevl);
          break;
        case 3:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_lower (*tmpevl);
          break;
        case 4:
          *l2p++ = CHMSIG;
          *l2p++ = *l1p++;
          *l2p++ = 0;
          break;                /* EOLではない */
        case 5:
          *l2p++ = CHMSIG;
          *l2p++ = *l1p++;
          *l2p++ = 1;
          break;
        case 6:
          *l2p++ = CHMSIG;
          *l2p++ = *l1p++;
          *l2p++ = 2;
          break;
        case 7:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_updown (*tmpevl);
          break;
        case 8:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_zenalpha (*tmpevl);
          break;
        case 9:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_hira (*tmpevl);
          break;
        case 10:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_kata (*tmpevl);
          break;
        case 11:
          mchevl (&l1p, tmpevl);
          to_hankata (*tmpevl, &l2p);
          break;                /* 特殊 */
        case 12:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_zenhira (*tmpevl);
          break;
        case 13:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_zenkata (*tmpevl);
          break;
        case 14:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p += *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 15:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p -= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 16:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p *= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 17:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          if (!*tmpevl)
            *l2p = LTRHUG;
          else
            *l2p /= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 18:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          if (!*tmpevl)
            *l2p = LTRHUG;
          else
            *l2p %= *tmpevl;
          LWRCUT (*l2p++);
          break;
          /* 19〜21・30は、条件を満たすと空文字列、
             そうでないとUNUSDCを文字列として返す。 */
        case 19:
          mchevl (&l1p, tmpevl);
          if (lastmch () != *tmpevl)
            *l2p++ = UNUSDC;
          break;
        case 20:
          if (!(cur_rk->rk_modesw.point)[LWRMSK (*l1p++)])
            *l2p++ = UNUSDC;
          break;
        case 21:
          if (cur_rk->rk_modesw.point[LWRMSK (*l1p++)])
            *l2p++ = UNUSDC;
          break;
        case 22:
          *l2p++ = REASIG;
          break;
        case 23:
          *l2p++ = cur_rk->delchr;
          break;
        case 24:
          *l2p++ = CHMSIG;
          *l2p++ = 0;           /* これで「all」を表す */
          *l2p++ = 0;
          break;
        case 25:
          *l2p++ = CHMSIG;
          *l2p++ = 0;
          *l2p++ = 1;
          break;
        case 26:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p &= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 27:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p |= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 28:
          mchevl (&l1p, tmpevl);
          *l2p = ~(*tmpevl);
          LWRCUT (*l2p++);
          break;
        case 29:
          *l2p++ = URBFCL;
          break;
        case 30:
          if (cur_rk->eofflg != 2 || *(cur_rk->keybuf) != EOLTTR)
            *l2p++ = UNUSDC;
          break;
        case 31:
          {
            letter code, basenum;

            mchevl (&l1p, tmpevl);
            code = *tmpevl;
            mchevl (&l1p, tmpevl);
            if ((basenum = *tmpevl) <= 1 || BASEMX < basenum)
              basenum = 10;
            to_digit (code, basenum, &l2p);
          }
          break;
        case 32:
          mchevl (&l1p, tmpevl);
          dakuadd (*tmpevl, &l2p);
          break;                /* 特殊 */
        case 33:
          mchevl (&l1p, tmpevl);
          handakuadd (*tmpevl, &l2p);
          break;                /* 特殊 */
        case 34:
          mchevl (&l1p, tmpevl);
          *l2p++ = ltov (*tmpevl);
          break;
        case 35:
          *l2p++ = ERRCOD;
          break;
          /* case 36: omitted */
        case 37:
          *l2p++ = CHMSIG;
/*
                                        *l2p++ = LWRMSK(*l1p++);
*/
          *l2p++ = *l1p++;
          *l2p++ = *l1p++;
          break;
        case 38:
          *l2p++ = CHMSIG;
          *l2p++ = XY2INT (2, LWRMSK (*l1p++));
          *l2p++ = *l1p++;
          break;
        case 39:
          *l2p++ = CHMSIG;
          *l2p++ = XY2INT (3, LWRMSK (*l1p++));
          *l2p++ = *l1p++;
          break;
        case 40:
          {
            letter modnum;

            modnum = LWRMSK (*l1p++);
            if (cur_rk->rk_modesw.point[modnum] != *l1p++)
              *l2p++ = UNUSDC;
            break;
          }
        case 41:
          {
            letter modnum;

            modnum = LWRMSK (*l1p++);
            if (cur_rk->rk_modesw.point[modnum] == *l1p++)
              *l2p++ = UNUSDC;
            break;
          }
        case 42:
          {
            letter modnum;

            modnum = LWRMSK (*l1p++);
            if (cur_rk->rk_modesw.point[modnum] >= *l1p++)
              *l2p++ = UNUSDC;
            break;
          }
        case 43:
          {
            letter modnum;

            modnum = LWRMSK (*l1p++);
            if (cur_rk->rk_modesw.point[modnum] <= *l1p++)
              *l2p++ = UNUSDC;
            break;
          }
        case 44:
          mchevl (&l1p, tmpevl);
          *l2p++ = SENDCH;
          *l2p++ = *tmpevl;
          break;
        default:                /* case 0及び上記以外 */ ;
          BUGreport (7);
        }
    }

  *l2p = EOLTTR;
  *l1pp = l1p;
}
#else /*!MULTI */
static                          /* V3.1 */
mchevl (l1pp, l2p)
     letter **l1pp, *l2p;
{
  letter *l1p, tmpevl[RSLMAX];

  l1p = *l1pp;

  switch (SHUBET (*l1p))
    {
    case 0:
      *l2p++ = *l1p++;
      break;
    case 1:
      *l2p++ = mchedsrc ((int) LWRMSK (*l1p++));
      break;
    case 2:                     /* toupper, tolower, error, … */
      switch (LWRMSK (*l1p++))
        {
        case 1:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_upper (*tmpevl);
          break;
        case 2:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_lower (*tmpevl);
          break;
        case 3:
          *l2p++ = ERRCOD;
          break;
        case 4:
          *l2p++ = CHMSIG;
          *l2p++ = *l1p++;
          *l2p++ = 0;
          break;                /* EOLではない */
        case 5:
          *l2p++ = CHMSIG;
          *l2p++ = *l1p++;
          *l2p++ = 1;
          break;
        case 6:
          *l2p++ = CHMSIG;
          *l2p++ = *l1p++;
          *l2p++ = 2;
          break;
        case 7:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_updown (*tmpevl);
          break;
        case 8:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_zenalpha (*tmpevl);
          break;
        case 9:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_hira (*tmpevl);
          break;
        case 10:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_kata (*tmpevl);
          break;
        case 11:
          mchevl (&l1p, tmpevl);
          to_hankata (*tmpevl, &l2p);
          break;                /* 特殊 */
        case 12:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_zenhira (*tmpevl);
          break;
        case 13:
          mchevl (&l1p, tmpevl);
          *l2p++ = to_zenkata (*tmpevl);
          break;
        case 14:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p += *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 15:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p -= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 16:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p *= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 17:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          if (!*tmpevl)
            *l2p = LTRHUG;
          else
            *l2p /= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 18:
          mchevl (&l1p, tmpevl);
          *l2p++ = ltov (*tmpevl);
          break;
          /* 19〜21・30は、条件を満たすと空文字列、
             そうでないとUNUSDCを文字列として返す。 */
        case 19:
          mchevl (&l1p, tmpevl);
          if (lastmch () != *tmpevl)
            *l2p++ = UNUSDC;
          break;
        case 20:
          if (!(cur_rk->rk_modesw.point)[LWRMSK (*l1p++)])
            *l2p++ = UNUSDC;
          break;
        case 21:
          if (cur_rk->rk_modesw.point[LWRMSK (*l1p++)])
            *l2p++ = UNUSDC;
          break;
        case 22:
          *l2p++ = REASIG;
          break;
        case 23:
          *l2p++ = cur_rk->delchr;
          break;
        case 24:
          *l2p++ = CHMSIG;
          *l2p++ = 0;           /* これで「all」を表す */
          *l2p++ = 0;
          break;
        case 25:
          *l2p++ = CHMSIG;
          *l2p++ = 0;
          *l2p++ = 1;
          break;
        case 26:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p &= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 27:
          mchevl (&l1p, tmpevl);
          *l2p = *tmpevl;
          mchevl (&l1p, tmpevl);
          *l2p |= *tmpevl;
          LWRCUT (*l2p++);
          break;
        case 28:
          mchevl (&l1p, tmpevl);
          *l2p = ~(*tmpevl);
          LWRCUT (*l2p++);
          break;
        case 29:
          *l2p++ = URBFCL;
          break;
        case 30:
          if (cur_rk->eofflg != 2 || *(cur_rk->keybuf) != EOLTTR)
            *l2p++ = UNUSDC;
          break;
        case 31:
          {
            letter code, basenum;

            mchevl (&l1p, tmpevl);
            code = *tmpevl;
            mchevl (&l1p, tmpevl);
            if ((basenum = *tmpevl) <= 1 || BASEMX < basenum)
              basenum = 10;
            to_digit (code, basenum, &l2p);
          }
          break;
        case 32:
          mchevl (&l1p, tmpevl);
          dakuadd (*tmpevl, &l2p);
          break;                /* 特殊 */
        case 33:
          mchevl (&l1p, tmpevl);
          handakuadd (*tmpevl, &l2p);
          break;                /* 特殊 */
        default:                /* case 0及び上記以降 */ ;
          BUGreport (7);
        }
    }

  *l2p = EOLTTR;
  *l1pp = l1p;
}
#endif /*!MULTI */

 /** num番目の変数の変域が文字 l を含むかどうかを返す */
static                          /* V3.1 */
  int
hen_ikisrc (num, l)
     int num;
     letter l;
{
  fast letter *defptr;          /* V3.1 */

  defptr = cur_rk_table->rk_hyo.point[cur_rk->hyonum].hensudef[num];    /* V3.1 */
  if (*defptr == VARRNG)
    {
      for (defptr++; *defptr != EOLTTR;)
        if (*defptr++ <= l && l <= *defptr++)
          return (1);
      return (0);
    }

  for (; *defptr != EOLTTR; defptr++)
    {
      if (l == *defptr)
        return (1);
    }
  return (0);
}

 /**    変換のメインルーチン。本処理を行うが、ついでに後処理もやっている。
        ちなみに前処理は、romkan_getcの下位関数romkan_henkanの中で、
        この関数を呼ぶ前にやっている。
        この関数は、romkan_nextから一文字来る度に呼ばれる。呼び出された直後は
        outputは空文字列、disoutには入力コード一文字が入っている。
        この関数で得られる文字の列が、romkan_henkanに渡り、
        romkan_getcは、それを文字ごとに分解して返す。
        (error)でエラーが引き起こされた場合は0を返し、正常終了時は1を返す */
static                          /* V3.1 */
  int
match ()
{
  int henkanflg = 0, okcode = 0, chm_exist;
  letter *q;                    /* V3.1 */
  letter urabufcreate[KBFSIZ], orgkeybuf[KBFSIZ];
  letter *urabufjunbi, *outcutptr, *dis_end;
  /* 88/03/01/ V3.1 */
  letter nokoribuf[KBFSIZ];

  if (*(cur_rk->keybuf) == EOLTTR)
    {
      *(cur_rk->urabuf) = EOLTTR;
      return (1);
    }

  ltrcpy (urabufjunbi = orgkeybuf, cur_rk->keybuf);
  outcutptr = cur_rk->rk_output;

  while ((okcode = henkan_ok ()) > 0)
    {
      henkanflg = 1;

      codeout_chg ();
      ltrcat (cur_rk->rk_output, cur_rk->codeout);
      /* 88/03/01/ V3.1 */
      /*
         p = keybuf + codein_len;

         ltrcat(ltrcpy(keybuf, remainkbf), p);
       */
      ltrcpy (nokoribuf, cur_rk->keybuf + cur_rk->codein_len);
      ltrcat (ltrcpy (cur_rk->keybuf, cur_rk->remainkbf), nokoribuf);

      if (okcode == 2)
        {
          ltrcpy (urabufjunbi = urabufcreate, cur_rk->keybuf);
          totail (outcutptr);
        }
    }

  if (okcode == 0)
    {
      ltr1cut (ltrcpy (cur_rk->keybuf, orgkeybuf));
      ltr_to_ltrseq (cur_rk->disout, NISEBP);
      *(cur_rk->rk_output) = EOLTTR;
      return (0);
    }
  if (henkanflg)
    {
      ltrcpy (cur_rk->urabuf, urabufjunbi);

      set_rubout (cur_rk->disout, ltrlen (orgkeybuf) - 1, cur_rk->nisedl);

      dis_end = cur_rk->disout;
      totail (dis_end);
      ltrcpy (dis_end, cur_rk->rk_output);

      /* モードチェンジを直ちに知らせるため CHMSIGを出力
         （romkan_chmack(1)をやってないと、あとで一文字ずつに
         分解する時点で、CHMSIGをカット）。
         但し、rk_outputからは、CHMSIGを抜く。
         また、CHMSIGは末尾に１回しか出力しない
         （２回以上あっても、１回にまとめて、末尾に置く）。 */
      for (chm_exist = 0, q = cur_rk->rk_output;; q++)
        {
          while (*q == CHMSIG)
            {
              chm_exist = 1;
              if (ltrcpy (q, q + 1) < outcutptr)
                outcutptr--;
            }
          if (*q == EOLTTR)
            break;
        }
      if (chm_exist)
        {
          /* CHMSIGを１つにまとめたものをdis_endにつなげ直す。
             このif文をカットすれば、CHMSIGのとりまとめはやらない */
          ltr1cat (ltrcpy (dis_end, cur_rk->rk_output), CHMSIG);
        }

      bitup_ltrcat (cur_rk->disout, cur_rk->keybuf);
      cur_rk->lastoutlen = ltrlen (outcutptr);
      cur_rk->lastkbflen = ltrlen (cur_rk->keybuf);
    }
  return (1);
}

 /**    LTREOFが入ったときに、何か出すように指定されているか調べて、
        codeoutをその結果の文字列（指定がなかったら当然空）にポイントする。
        超急ごしらえで、特殊コード等は一切無視する。*/
static                          /* V3.1 */
  void
add_at_eof ()
{
  fast dat *datptr;             /* V3.1 */
  fast int i;                   /* V3.1 */
  fast int hyoseq;              /* V3.1 */
  letter *p;
  letter evlrsl[RSLMAX];

  /* 88/06/14 V3.1 */
  for (hyoseq = 0; cur_rk_table->rk_hyo.point != NULL && (cur_rk->hyonum = cur_rk->rk_usehyo.usehyo[hyoseq]) != -1; hyoseq++)
    {
      for (i = 0, datptr = cur_rk_table->rk_hyo.point[cur_rk->hyonum].data; (p = datptr[i].code[0]) != NULL; i++)
        {
          if (cur_rk->rk_henmatch.size > 0)
            {
              cur_rk->rk_henmatch.point[0].ltrmch = EOLTTR;
            }
          while (*p != EOLTTR)
            {
              switch (SHUBET (*p))
                {
                case 0: /* 文字 */
                case 1: /* 変数 */
                  /* これらがある場合は、NULLとは
                     マッチし得ない。 */
                  goto Pass;
                case 2: /* 式 */
                  mchevl (&p, evlrsl);
                  if (*evlrsl != EOLTTR)
                    goto Pass;
                  /* 入力コード部に、評価すると
                     空文字列になるものが、他にはない
                     ことが前提。 */
                }
            }

          ltrevlcpy (cur_rk->codeout = p = cur_rk->evalbuf[0][0], datptr[i].code[1]);
          while (*p != EOLTTR)
            {
              if (isSPCL (*p))
                ltrcpy (p, p + 1);
              else
                p++;
            }
          codeout_chg ();
          return;

        Pass:;
        }
    }
  cur_rk->codeout = cur_rk->nil;
}

/* 88/06/02 V3.1 */
 /**    num番目のモードをチェンジし、変換表を選択し直す。引数 mod の値が0なら
        モードをoff、1ならon、2なら切り替える。旧modの値（0か1）を返す。*/
static int
chgmod (num, mod)
     int num, mod;
{
  fast int oldmod;              /* V3.1 */

  oldmod = cur_rk->rk_modesw.point[num];
  cur_rk->rk_modesw.point[num] = (mod != 2 ? mod : !oldmod);
  choosehyo ();
  return (oldmod);
}

 /** 全モードを、modが1ならon、0ならoffに切り換える。2ならswitchする。*/
static void
allchgmod (mod)
     int mod;
{
  fast int i;                   /* V3.1 */

  /* 88/06/07 V3.1 */
  for (i = 0; i < cur_rk->rk_modesw.count; i++)
    cur_rk->rk_modesw.point[i] = (mod != 2 ? mod : !(cur_rk->rk_modesw.point[i]));
  choosehyo ();
}

 /**    一回マッチを試みる。返値は、マッチして確定した場合1（モードチェンジが
        混じっている場合は2）、マッチしたが未確定の時-1、マッチしなかったら0。
        実行中は、変数 l に、それまでに一致した長さの最高記録を入れており、
        より長く一致するものが見つかるごとに、これを更新する。lの値は、マッチ
        していても0になることもある。p_eq() 及び prefixp() の注釈文を参照。*/
static                          /* V3.1 */
  int
henkan_ok ()
{
  fast dat *datptr;             /* V3.1 */
  fast int i, k;                /* V3.1 */
  fast int l, j, hyoseq;        /* V3.1 */
  char urabuf_clrf;             /* モードチェンジなどで、urabufをクリアする必要が
                                   生じた場合はこれが立ち、その結果、henkan_ok()
                                   が1を返すべきところで2を返す。それを見て、
                                   match()がurabufなどの調整をする。 */
  fast letter *p;               /* V3.1 */
#ifndef MULTI
  static char ebf_sw = 0;       /* V3.1 */
  static letter oneletter[2] = { EOLTTR, EOLTTR };      /* V3.1 */
#endif /*!MULTI */

  if (*(cur_rk->keybuf) == EOLTTR)
    return (-1);

  /* 88/06/14 V3.1 */
  for (l = -1, hyoseq = 0; cur_rk_table->rk_hyo.point != NULL && cur_rk->rk_usehyo.usehyo != NULL && (cur_rk->hyonum = cur_rk->rk_usehyo.usehyo[hyoseq]) != -1; hyoseq++)
    {
      for (i = 0, datptr = cur_rk_table->rk_hyo.point[cur_rk->hyonum].data; (p = datptr[i].code[0]) != NULL; i++)
        {
          if (cur_rk->rk_henmatch.size > 0)
            {
              cur_rk->rk_henmatch.point[0].ltrmch = EOLTTR;
            }
          switch (k = prefixp (cur_rk->keybuf, p))
            {
            case -2:
              break;
            case -1:
              if (cur_rk->eofflg != 0)
                break;
              /* eofflgが立っていたら、未確定の可能性は
                 捨てる。 */

              return (-1);
            default:
              if (k > l)
                {
                  cur_rk->ebf_sw = !cur_rk->ebf_sw;
                  for (j = 1; j <= 2; j++)
                    {
                      ltrevlcpy (cur_rk->evalbuf[cur_rk->ebf_sw][j - 1], datptr[i].code[j]);
                    }

                  l = k;
                }
            }
        }
    }

  if (l >= 0)
    {
      cur_rk->codein_len = l;
      cur_rk->codeout = cur_rk->evalbuf[cur_rk->ebf_sw][0];
      cur_rk->remainkbf = cur_rk->evalbuf[cur_rk->ebf_sw][1];

      for (urabuf_clrf = 0, p = cur_rk->codeout; *p != EOLTTR; p++)
        {
          switch (*p)
            {
            case CHMSIG:
              /* codeoutの1,2バイト目に
                 モード番号とスイッチが入ってる */
              if (*(p + 1) == 0)
                allchgmod ((int) *(p + 2));
              else
                chgmod ((int) LWRMSK (*(p + 1)), (int) *(p + 2));
              ltrcpy (p + 1, p + 3);
              /* CHMSIGだけ残して1,2バイト目cut */

              urabuf_clrf = 1;
              break;
            case URBFCL:
              /* urabufのクリアを明示的に指定する */
              urabuf_clrf = 1;
              ltrcpy (p, p + 1);
              p--;              /* 一文字前にずれるため、
                                   for文の p++ を相殺して、
                                   同じ地点をもう一度見る。 */
              break;
            }
        }

      if (*(cur_rk->codeout) == ERRCOD)
        {
          if (cur_rk->eofflg == 0)
            {
              cur_rk->rk_errstat = 1;
              return (0);
            }

          /* (error)であって、しかもeofflgが立ってたら、keybuf
             の末尾まで、そのまま出す。 */
          cur_rk->codein_len = ltrlen (cur_rk->keybuf);
          cur_rk->codeout = ltrcpy (cur_rk->evalbuf[cur_rk->ebf_sw][0], cur_rk->keybuf);
          cur_rk->remainkbf = cur_rk->nil;
          cur_rk->rk_errstat = 2;

          return (1);
        }
      /* (error)は単独でしか書けないので、エラー検出はこれで十分。 */

      if (*(cur_rk->codeout) == REASIG)
        {
          *(cur_rk->codeout) = (romkan_restart () != 0 ? EOLTTR : CHMSIG);
          /* 再readでエラったらモードチェンジの通知はしない */

          urabuf_clrf = 1;
        }
      /* 表の再read。但し、これが起こったことを外に知らせるのはCHMSIGで
         このコードそのものは外へ出ない。(restart)は、(error)同様、
         単独でしか書けないので、検出はこれで十分。 */

      return (urabuf_clrf ? 2 : 1);
    }

  /* 表に現れていないコードはそのまま返す */

  cur_rk->codein_len = 1;
  *(cur_rk->codeout = cur_rk->oneletter) = *(cur_rk->keybuf);
  cur_rk->remainkbf = cur_rk->nil;
  return (1);
}

static void
free_for_all_area ()
{
  fast int i;

  free_for_modetable_struct (&(cur_rk_table->rk_defmode));
  free_for_modetable_struct (&(cur_rk_table->rk_taiouhyo));
  free_for_modetable_struct (&(cur_rk_table->rk_path));
  free_for_modebuf (&(cur_rk_table->rk_modebuf));
  free_for_hyobuf (&(cur_rk_table->rk_hyobuf));
  free_for_heniki (&(cur_rk_table->rk_heniki));
  free_for_hensuu (&(cur_rk_table->rk_hensuu));

  free_for_modetable_struct (&(cur_rk_table->rk_dspmode));
  /* free_for_modesw(&(cur_rk_table->rk_modesw)); */
  free_for_modenaibu (&(cur_rk_table->rk_modenaibu));
  for (i = 0; i < cur_rk_table->rk_hyo.size; i++)
    {
      free_for_hyo_area (&(cur_rk_table->rk_hyo), i);
    }
  free_for_hyo (&(cur_rk_table->rk_hyo));
  /* free_for_usehyo(&(cur_rk_table->rk_usehyo)); */
  free_for_hensuudef (&(cur_rk_table->rk_hensuudef));
  /* free_for_henmatch(&(cur_rk_table->rk_henmatch)); */
}

/* 88/06/10 V3.1 */
 /* romkan_restart内で使うマクロ */
#define taihi(X, Y) {(X) = (Y);}
#define clear(X, N) {memset((char *)(&(X)), 0, (N));}
#define recov(X, Y) taihi((Y), (X))

 /**    表の動的再読み込みをする。現在の内部表現を全て退避し、前と同じ
        ディレクトリ（に、現在のところ限定）から表を読み込む。もし、
        読み込み中にエラーを検出すれば、もとの内部データを復活し非0を返す。*/
static                          /* V3.1 */
  int
romkan_restart ()
{
  fast int i /*, j */ ;         /* V3.1 */
  RomkanTable *rk_t = cur_rk_table;

  modenaibutable rk_modenaibu_sv;
  modeswtable rk_modesw_sv;
  modetable rk_dspmode_sv;
  hyotable rk_hyo_sv;
  /* usehyotable  rk_usehyo_sv; */
  hensuudeftable rk_hensuudef_sv;
  /* matchtable   rk_henmatch_sv; */

  /* char *dspmod_sv[2][2]; */

  /* 待避 */
  taihi (rk_modenaibu_sv, rk_t->rk_modenaibu);
  taihi (rk_modesw_sv, rk_t->rk_modesw);
  taihi (rk_dspmode_sv, rk_t->rk_dspmode);
  taihi (rk_hyo_sv, rk_t->rk_hyo);
  /* taihi(rk_usehyo_sv,          rk_t->rk_usehyo); */
  taihi (rk_hensuudef_sv, rk_t->rk_hensuudef);
  /* taihi(rk_henmatch_sv,                rk_t->rk_henmatch);

     for(i = 0; i < 2; i++)
     for(j = 0; j < 2; j++)  dspmod_sv[i][j] = rk_t->dspmod[i][j];
   */

  /* 消去 */
  clear (rk_t->rk_modenaibu, sizeof (modenaibutable));
  clear (rk_t->rk_modesw, sizeof (modeswtable));
  clear (rk_t->rk_dspmode, sizeof (modetable));
  clear (rk_t->rk_hyo, sizeof (hyotable));
  /* clear(rk_t->rk_usehyo,               sizeof(usehyotable)); */
  clear (rk_t->rk_hensuudef, sizeof (hensuudeftable));
  /* clear(rk_t->rk_henmatch,             sizeof(matchtable)); */

  if (NULL != romkan_table_init (rk_t, rk_t->prv_modfnm, rk_t->keyin_method, rk_t->bytcnt_method, rk_t->kbytcnt_method, rk_t->flags))
    {
      /* 正常終了 */
      /* 88/06/10 V3.1 */
      /* 不要領域の削除 */
      free_for_modenaibu (&rk_modenaibu_sv);
      free_for_modesw (&rk_modesw_sv);
      free_for_modetable_struct (&rk_dspmode_sv);
      for (i = 0; i < rk_hyo_sv.size; i++)
        {
          free_for_hyo_area (&rk_hyo_sv, i);
        }
      free_for_hyo (&rk_hyo_sv);
      /* free_for_usehyo(&rk_usehyo_sv); */
      free_for_hensuudef (&rk_hensuudef_sv);
      /* free_for_henmatch(&rk_henmatch_sv); */

      return (0);
    }

  /* 異常終了 */
  /* 88/06/10 V3.1 */
  /* 不要領域の削除 */
  free_for_modenaibu (&(rk_t->rk_modenaibu));
  free_for_modesw (&(rk_t->rk_modesw));
  free_for_modetable_struct (&(rk_t->rk_dspmode));
  for (i = 0; i < rk_t->rk_hyo.size; i++)
    {
      free_for_hyo_area (&(rk_t->rk_hyo), i);
    }
  free_for_hyo (&(rk_t->rk_hyo));
  /* free_for_usehyo(&(rk_t->rk_usehyo)); */
  free_for_hensuudef (&(rk_t->rk_hensuudef));
  /* free_for_henmatch(&(rk_t->rk_henmatch)); */

  /* 復帰 */
  recov (rk_modenaibu_sv, rk_t->rk_modenaibu);
  recov (rk_modesw_sv, rk_t->rk_modesw);
  recov (rk_dspmode_sv, rk_t->rk_dspmode);
  recov (rk_hyo_sv, rk_t->rk_hyo);
  /* recov(rk_usehyo_sv,          rk_t->rk_usehyo); */
  recov (rk_hensuudef_sv, rk_t->rk_hensuudef);
  /* recov(rk_henmatch_sv,                rk_t->rk_henmatch);

     for(i = 0; i < 2; i++)
     for(j = 0; j < 2; j++)  rk_t->dspmod[i][j] = dspmod_sv[i][j];
   */
  return (1);
}

 /** lp2から評価して得た文字列をlp1にコピー */
static                          /* V3.1 */
  void
ltrevlcpy (lp1, lp2)
     letter *lp1, *lp2;
{
  while (*lp2 != EOLTTR)
    {
      mchevl (&lp2, lp1);
      totail (lp1);
    }
  *lp1 = EOLTTR;
}

static                          /* V3.1 */
  void
set_rubout (lp, n, del)
 /** lpに 「del」n個の列をセットする。ここに del は 'delchr'か'nisedl' */
     fast letter *lp, del;      /* V3.1 */
     fast int n;                /* V3.1 */
{
  for (; n; n--)
    *lp++ = del;
  *lp = EOLTTR;
}

 /** これが実行されたらバグ。但し実行はそのまま続く */
#ifdef OMRON_LIB
static
#endif
  void
BUGreport (n)
     int n;
{
  fprintf (stderr, "\r\nromkan-Bug%d!!\r\n", n);
}

 /** 前処理(mae_in→mae_out)又は後処理(ato_in→ato_out)を行う。*/
static                          /* V3.1 */
  void
maeato_henkan (in, outp, m_a_hyo)
     letter in;                 /* 入力の一文字 */
     letter *outp;              /* 出力はここに入る */
     int *m_a_hyo;              /* どの前・後処理表が選択されているかの情報 */
{
  fast dat *datptr;             /* V3.1 */
  fast int i, hyoseq;           /* V3.1 */
  fast letter *curdat;          /* V3.1 */

  if (isSPCL (in))
    {
      /* LTREOFやCHMSIGが来うるので、特殊コードはそのまま返すように
         細工しておかないといけない。 */
      ltr_to_ltrseq (outp, in);
      return;
    }

  /* 88/06/14 V3.1 */
  for (hyoseq = 0; m_a_hyo != NULL && (cur_rk->hyonum = m_a_hyo[hyoseq]) != -1; hyoseq++)
    {
      for (i = 0, datptr = cur_rk_table->rk_hyo.point[cur_rk->hyonum].data; NULL != (curdat = datptr[i].code[0]); i++)
        {
          if (cur_rk->rk_henmatch.size > 0)
            {
              cur_rk->rk_henmatch.point[0].ltrmch = EOLTTR;
            }
          if (!l_eq (curdat, in))
            continue;

          ltrevlcpy (outp, datptr[i].code[1]);
          return;
        }
    }
  ltr_to_ltrseq (outp, in);
}

 /** 後処理 */
static                          /* V3.1 */
  void
codeout_chg ()
{
  fast letter *saishu_outp;     /* V3.1 */
  letter saishu_out[OUTSIZ];    /* V3.1 */

  *(saishu_outp = saishu_out) = EOLTTR;

  for (; *(cur_rk->codeout) != EOLTTR; cur_rk->codeout++)
    {
      maeato_henkan (*(cur_rk->codeout), saishu_outp, cur_rk->rk_usehyo.useatohyo);
      totail (saishu_outp);
    }

  cur_rk->codeout = saishu_out;
}

 /** 一文字プッシュ・バック */
/* *INDENT-OFF* */
letter
romkan_ungetc (l)
     letter l;
/* *INDENT-ON* */
{
  return (cur_rk->ungetc_buf = l);
}

 /** romkan_nextに対し一文字プッシュ・バック */
/* *INDENT-OFF* */
letter
romkan_unnext (l)
     letter l;
/* *INDENT-ON* */
{
  return (cur_rk->unnext_buf = l);
}

/* 88/06/02 V3.1 */
/******************************************************************************/
#ifndef OMRON
 /**    deleteとして使うキャラクタの設定（偽deleteも）。これを実行後は
        romkan_clearを実行しておかないと混乱のもとになります。（廃止予定）*/
void
romkan_setdel (delchr_, nisedl_)
     letter delchr_, nisedl_;
{
  cur_rk->delchr = delchr_;
  cur_rk->nisedl = nisedl_;
}
#endif
/******************************************************************************/
