diff Wnn/romkan/rk_main.c @ 0:bbc77ca4def5

initial import
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Thu, 13 Dec 2007 04:30:14 +0900
parents
children a7ccf412ba02
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wnn/romkan/rk_main.c	Thu Dec 13 04:30:14 2007 +0900
@@ -0,0 +1,1688 @@
+/*
+ *  $Id: rk_main.c,v 1.4 2005/04/10 15:26:38 aonoto 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
+ * Copyright FreeWnn Project 1999, 2000
+ *
+ * Maintainer:  FreeWnn Project   <freewnn@tomo.gr.jp>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/***********************************************************************
+                        rk_main.c
+                                                88. 6.10  改 正
+
+        ローマ字かな変換・その他、入力コードを変換するプログラム。
+        ASCIIコード使用を、前提としている。
+        このファイルは、変換のメインルーチン。
+***********************************************************************/
+
+#include "rk_header.h"
+#include "rk_extvars.h"
+#include "rk_fundecl.h"
+
+struct matchpair                /*    現在マッチされている変数の番号と、マッチした文字の
+                                   組を保持。 */
+{
+  int hennum;
+  letter ltrmch;
+};
+
+letter memory[SIZALL];          /* 変換対応表や、変数の変域などを入れる領域 */
+struct dat data[LINALL];        /* 対応表の一行ごとのデータへのポインタ */
+letter *hensudefhyo[VARTOT];    /* 変数ごとの変域データへのポインタ */
+struct matchpair henmatch[VARTOT];      /* 変数のマッチ状況をためておく */
+
+#ifdef KDSP
+#  ifdef MVUX
+letter displine[DSPLIN];        /* デバッグ用  表示の一行分を記憶 */
+#  endif
+#endif
+
+letter *curdis;
+int codein_len;
+letter *codeout, *remainkbf;
+letter ungetc_buf = EOLTTR;     /* romkan_ungetcが一文字退避しておくバッファ */
+letter unnext_buf = EOLTTR;     /* romkan_unnextが            〃             */
+
+letter (*keyin_method) ();      /* キーイン関数のアドレス */
+int (*bytcnt_method) ();        /* バイトカウント関数のアドレス */
+int (*kbytcnt_method) ();       /* キー入力解釈用バイトカウント関数のアドレス */
+char prv_modfnm[REALFN] = "\0"; /* モード表名(又はそのパス名)を保存 */
+            /* 初期設定がいい加減! */
+
+#define DISOUT ((flags & RK_NONISE) ? rk_output : disout)
+ /* フラグの値はromkan_init3()の中で設定され、そのRK_NONISEのビットの値の
+    標準は0。従ってDISOUTの標準値はdisout。これをrk_outputに変えると、偽コード
+    (除:LTREOF)を一切出さない(但し、キー入力があれば必ず何かを返すように
+    してある時に限り、EOLTTRをも返す)。 */
+
+char eofflg;                    /* romkan_next()からLTREOFが来たときに、romkan_henkan()内で1
+                                   にする。これの値が非0なら変換対応表の(error)を無視して、
+                                   本処理バッファ内の未確定コードも、強制的に変換させる。更に
+                                   LTREOFが来た時に特別にある出力を出すように指定されていれば
+                                   その処理も行う(但し、その処理は急ごしらえで不完全)。その
+                                   処理中はeofflgは2。 */
+
+letter evalbuf[2][2][OUTSIZ];
+char ebf_sw = 0;
+letter saishu_out[OUTSIZ];
+letter delchr, delchr2 = EOLTTR, nisedl;        /* DELのキャラクタは二個まで持てる */
+
+modetyp chgmod (), incmod (), decmod ();
+
+
+/* letterを返す関数の定義及び宣言(一部にはcharのものも混じっている) */
+
+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 は濁点を持つ文字を一まとめにしない。 */
+
+void BUGreport ();
+static void maeato_henkan (), add_at_eof (), rk_delete (), set_rubout (), mchevl (), codeout_chg (), ltrevlcpy ();
+int match ();
+static int p_eq (), hen_ikisrc (), henkan_ok (), rk_rst (), head_bytecount ();
+extern void readdata (), romkan_reset (), hank_setup (), to_hankata (), to_digit (), dakuadd (), handakuadd (), allchgmod ();
+extern int ltov ();
+
+static letter *
+ltrcpy (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  letter *org;
+
+  org = lp1;
+  while ((*lp1++ = *lp2++) != EOLTTR);
+  return (org);
+}
+
+#ifdef notuse
+letter *
+ltrncpy (lp1, lp2, n)           /* 末尾に'EOLTTR'をセット */
+     letter *lp1, *lp2;
+     int n;
+{
+  letter *org;
+
+  org = lp1;
+  for (; n; --n)
+    if (EOLTTR == (*lp1++ = *lp2++))
+      return (org);
+  *lp1 = EOLTTR;
+  return (org);
+}
+#endif
+
+ /** letterの列の末尾に一文字つなげる */
+static letter *
+ltr1cat (lp, l)
+     letter *lp, l;
+{
+  letter *org;
+
+  org = lp;
+  totail (lp);
+  *lp++ = l;
+  *lp = EOLTTR;
+  return (org);
+}
+
+ /** 文字列の末尾に一文字つなげる。ltr1catのchar版 */
+char *
+chrcat (s, c)
+     char *s, c;
+{
+  char *org;
+
+  org = s;
+  strtail (s);
+  *s++ = c;
+  *s = '\0';
+  return (org);
+}
+
+static letter *
+ltrcat (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  letter *org;
+
+  org = lp1;
+  totail (lp1);
+  ltrcpy (lp1, lp2);
+  return (org);
+}
+
+ /** letterの列lp2の各要素の最上位ビットを立ててから、lp1の後ろにつなげる。*/
+static letter *
+bitup_ltrcat (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  letter *org;
+
+  org = lp1;
+  totail (lp1);
+
+  while ((*lp1 = *lp2++) != EOLTTR)
+    *lp1++ |= HG1BIT;
+         /** lp2 の要素全ての最上位ビットを立てる。*lp2がNISEBP(rk_spclval.h
+             でdefine)などのときは最初から最上位が立ってるからよい */
+
+  return (org);
+}
+
+ /** ltrcatしたあと、結果の文字列の末尾にポインタをもっていく。*/
+letter *
+ltrgrow (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  totail (lp1);
+  while ((*lp1 = *lp2++) != EOLTTR)
+    lp1++;
+  return (lp1);
+}
+
+static int
+ltrlen (lp)
+     letter *lp;
+{
+  letter *org;
+
+  for (org = lp; *lp != EOLTTR; lp++);
+  return (lp - org);
+}
+
+ /**    letterの列の最後の文字へのポインタを返す。但し空文字列に対しては
+        そのまま返す。*/
+letter *
+ltrend (lp)
+     letter *lp;
+{
+  return ((*lp != EOLTTR) ? (lp + ltrlen (lp) - 1) : lp);
+}
+
+ /**    文字列の最後の文字へのポインタを返す。ltrend()のchar版。ltrend()と
+        同様、空文字列のときは特例がある。*/
+char *
+strend (s)
+     char *s;
+{
+  return (*s ? (s + strlen (s) - 1) : s);
+}
+
+int
+ltrcmp (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  for (; *lp1 == *lp2; lp1++, lp2++)
+    if (*lp1 == EOLTTR)
+      return (0);
+  return (*lp1 > *lp2 ? 1 : -1);
+}
+
+#ifdef notuse
+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));
+}
+
+letter *
+ltr_index (lp, l)
+     letter l, *lp;
+{
+  for (; *lp != EOLTTR; lp++)
+    if (*lp == l)
+      return (lp);
+  return (NULL);
+}
+#endif
+
+static letter *
+ltr_rindex (lp, l)
+     letter l, *lp;
+{
+  letter *lp2;
+
+  for (lp += ltrlen (lp2 = lp); lp2 != lp;)
+    if (*--lp == l)
+      return (lp);
+  return (NULL);
+}
+
+ /** 文字列の末尾一文字をカットする。*/
+letter *
+ltr1cut (lp)
+     letter *lp;
+{
+  int l;
+
+  if (0 == (l = ltrlen (lp)))
+    BUGreport (0);              /* Illegal POP */
+  *(lp + --l) = EOLTTR;
+  return (lp);
+}
+
+ /** letterの一文字を長さ1の文字列に変換する */
+static letter *
+ltr_to_ltrseq (lp, l)
+     letter *lp, l;
+{
+  *lp++ = l;
+  *lp-- = EOLTTR;
+  return (lp);
+}
+
+ /** charの列からletterを一つ取り出す。但し'\0'はEOLTTRに変える */
+/* *INDENT-OFF* */
+letter
+letterpick (lbfpptr)
+     uns_chr **lbfpptr;
+/* *INDENT-ON* */
+{
+  letter l = 0;
+  register int i;
+
+  for (i = (*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 (unnext_buf != EOLTTR)
+    return (in = unnext_buf, unnext_buf = EOLTTR, in);
+
+  if ((letter) EOF == (in = (*keyin_method) ()))
+    return (LTREOF);
+  c = (in &= 0xff);
+  n = (*kbytcnt_method) (&c);
+  for (i = 1; i < n; i++)
+    in = (in << 8) + ((*keyin_method) () & 0xff);
+  return (in);
+}
+
+ /*     letterの文字 l とcharの文字 c の比較。エンドマーク同士(letter列の
+    エンドマークはEOLTTR、char列のは'\0')も一致とみなす。 */
+#define ltrchreq(l, c) ((l) == ((c) != 0 ? (c) : EOLTTR))
+
+ /** letterの文字列とcharの文字列の比較 但し大小比較は符号なしとしてやる */
+int
+ltrstrcmp (l, s)
+     register letter *l;
+     register char *s;
+{
+  for (; ltrchreq (*l, *s); l++, s++)
+    if (*s == 0)
+      return (0);
+  return ((*l < (uns_chr) * s || *l == EOLTTR) ? -1 : 1);
+}
+
+ /** 最後にマッチした文字 つまりurabufの最後。urabufが空だとEOLTTRを返す */
+static letter
+lastmch ()
+{
+  return (*(ltrend (urabuf)));
+}
+
+/* end of 'letter' functions */
+
+
+#ifdef  OMAKE
+ /** お  ま  け
+        TVアニメのご案内(一部特撮を含む)。引数が非負整数の時はどれか一つ、
+        -1なら全てを出力し、それ以外なら何も出力しない。いずれの場合も、データ
+        の個数を返す。*/
+takeoka (i)
+     int i;
+{
+#define OPIMAX (numberof(opinion))
+
+  static char *opinion[] = {
+    "「魔法のアイドル パステルユーミ」は良い番組だ。by竹岡",
+    "「機動戦士ガンダムΖΖ」の地球編は良い番組だ。by服部",
+    "「魔法のスター マジカルエミ」は良い番組だ。by竹岡",
+    "(参考意見)「マジカルエミ〔蝉時雨〕」は良いアニメだ。by森島",
+    "「魔法の天使 クリィミーマミ」は良い番組だ。by竹岡",
+    "「サザエさん」は良い番組だ。by鈴木",
+    "「ムーミン」は良い番組だ。by鈴木",
+    "「マンガ大作戦」のロードランナーシリーズは良い番組だ。by新出",
+    "「スプーンおばさん」は良い番組だ。by鴨",
+    "「はじめ人間ギャートルズ」は良い番組だ。by富永",
+    "「宇宙の騎士テッカマン」は良い番組だ。by駒嵐",
+    "「妖怪人間ベム」は良い番組だ。by鴨",
+    "「アルプスの少女ハイジ」は良い番組だ。by富永",
+    "「ときめきトゥナイト」は良い番組だ。by駒嵐",
+    "「あしたのジョー」は良い番組だったね。by立木(ついき)",
+    "「きまぐれオレンジ・ロード」は良い番組だ。by三好・服部",
+    "「ゲッターロボ」(「ゲッターロボG」を含む)は良い番組だ。by新出",
+    "「テッちゃん」(「じゃりン子チエ」のこと)は良い番組だ。by松田",
+    "「チキチキマシン猛レース」は良い番組だ。by服部",
+    "「小公女セーラ」は良い番組だ。by森島",
+    "「秘密戦隊ゴレンジャー」は良い番組だ。by新出",
+    "(白黒時代の)「鉄人28号」は良い番組だ。by桜川"
+  };
+
+  if (i >= 0)
+    printf ("%s\n", opinion[i % OPIMAX]);
+  else if (i == -1)
+    for (i = 0; i < OPIMAX; i++)
+      printf ("%s\n", opinion[i]);
+  return (OPIMAX);
+}
+#endif /* OMAKE */
+
+
+ /** 変換バッファのクリア */
+void
+romkan_clear ()
+{
+#ifdef KDSP
+#  ifdef MVUX
+  *displine = EOLTTR;
+#  endif
+#endif
+  ungetc_buf = *keybuf = *urabuf = *disout = *rk_output = EOLTTR;
+  curdis = DISOUT;
+  lastoutlen = lastkbflen = 0;
+}
+
+ /**    表を読み込んで変換の初期設定をする。(part 1)*/
+int
+romkan_init (modhyo, delchr_, chmoutf, keyinfn, bytcntfn)
+     char *modhyo, chmoutf;
+     letter delchr_;
+letter (*keyinfn) ();
+     int (*bytcntfn) ();        /* 引数の詳細はromkan_init3を参照 */
+{
+  return (romkan_init2 (modhyo, delchr_, chmoutf, keyinfn, bytcntfn, 0, 0, 0));
+}
+
+#define ifflg(a, b) ((a) ? (b) : 0)
+
+ /**    表を読み込んで変換の初期設定をする。(part 2: キー入力に対し必ず何か
+        返すようにするか、キーバッファをクリアするかどうかなども指定可)*/
+int
+romkan_init2 (modhyo, delchr_, chmoutf, keyinfn, bytcntfn, keyackf, restartf, nonisecodf)
+     char *modhyo, chmoutf, keyackf, restartf, nonisecodf;
+     letter delchr_;
+letter (*keyinfn) ();
+     int (*bytcntfn) ();        /* 引数の詳細はromkan_init3を参照 */
+{
+  return (romkan_init3 (modhyo, delchr_, toNISE (delchr_), EOLTTR,
+                        keyinfn, bytcntfn, (int (*)()) NULL, restartf, ifflg (chmoutf, RK_CHMOUT) | ifflg (keyackf, RK_KEYACK) | ifflg (nonisecodf, RK_NONISE) | RK_DSPNIL));
+}
+
+ /**    表を読み込んで変換の初期設定をする。(part 3)*/
+int
+romkan_init3 (modhyo, delchr_, nisedl_, delchr2_, keyinfn, bytcntfn, kbytcntfn, restartf, flags_)
+     char *modhyo;              /* モード定義表の名又はそのパス名 */
+     letter delchr_;            /* DELとして使うコード */
+     letter nisedl_;            /* 偽DELとして使うコード */
+     letter delchr2_;           /* DELとして使うコードが二つある場合そのもう一方 */
+letter (*keyinfn) ();           /* キーイン関数 */
+     int (*bytcntfn) ();        /* バイトカウント関数 */
+     int (*kbytcntfn) ();       /* キーインの解釈用バイトカウント関数。NULL指定の時は
+                                   bytcntfnと同じものが使われる */
+     char restartf;
+ /*     rk_rst()内から呼ばれた時に立つフラグ。これが立つと、バッファをクリア
+    せずに済ます。この時はエラー検出時のメッセージも少し異なる */
+     int flags_;
+ /* 以下のフラグが利用可。これらはrk_spclval.hにて定義。
+    RK_CHMOUT:モードチェンジを知らせるコードを返すか?
+    RK_KEYACK:キーインに対し必ず何かを返すか
+    RK_DSPNIL:romkan_disp(off)modeのデフォルトを空文字列にするか
+    RK_NONISE:偽コードを出さないようにするか
+    RK_REDRAW:Wnn用特殊フラグ(redraw用のフラグを出すかどうか)
+    RK_SIMPLD:deleteの動作を単純にするか
+    RK_VERBOS:verboseモードで起こすか
+  */
+{
+  int errcod;                   /* 今の所1のみ */
+
+  /* 偽コードを出すかの設定はromkan_clearで使うので、フラグの設定を
+     先にやっておかないといけない。 */
+  if ((flags = flags_) & RK_VERBOS)
+    {
+      fprintf (stderr, "romkan_init invoked.\r\n");
+      fflush (stderr);
+    }
+
+#ifdef  OMAKE
+  if (modhyo == NULL)
+    takeoka (-1);               /* おまけ;通常は実行されない */
+#endif /* OMAKE */
+
+  keyin_method = keyinfn;
+  bytcnt_method = (bytcntfn == NULL ? head_bytecount : bytcntfn);
+  kbytcnt_method = (kbytcntfn == NULL ? bytcnt_method : kbytcntfn);
+  strcpy (prv_modfnm, modhyo);
+
+  delchr = delchr_;
+  nisedl = nisedl_;
+  delchr2 = delchr2_;
+ /**    実はDELのキャラクタを二個まで持てる。二個目:delchr2は、未設定の
+        とき(値がEOLTTR)は無視される。それ以外は、delchr2が入力されると
+        delchrが入力されたのと同じ振る舞いをする。*/
+
+  if ((errcod = setjmp (env0)) != 0)
+    {
+      fprintf (stderr, "romkan_init failed.");
+      if (!restartf)
+        {
+          romkan_reset ();
+          /*     fprintf(stderr,
+             "No conversion is currently performed."); */
+          fprintf (stderr, "\r\n");
+        }
+      else
+        {
+          fprintf (stderr, "Conversion method was unchanged.\r\n");
+        }
+    }
+  else
+    {
+      readdata (memory, data, hensudefhyo, modhyo);
+      if (!restartf)
+        {
+          romkan_clear ();
+          hank_setup ();
+        }
+    }
+
+  if (!errcod && (flags & RK_VERBOS))
+    {
+      fprintf (stderr, "romkan_init finished.\r\n");
+      fflush (stderr);
+    }
+  return (errcod);              /* 正常終了なら0 */
+}
+
+ /**    バイトカウント関数のデフォルト。sの指している所に入っているのが
+        何バイトコードかを返す。
+        romkan_nextに注意。そちらでは、バイトカウント関数の値は
+        引数の一文字目にのみ依存すると仮定している。*/
+static int
+head_bytecount (s)
+     uns_chr *s;
+{
+#ifdef IKIS
+  return ((*s <= 0xa0 || *s == 0xff) ? 1 : 2);
+#else
+  return (((*s <= 0xa0 && *s != HNKAK1) || *s == 0xff) ? 1 : 2);
+#endif
+}
+
+ /** 変換された文字を順次返す */
+/* *INDENT-OFF* */
+letter
+romkan_getc ()
+/* *INDENT-ON* */
+{
+  letter l;
+
+  /* ungetcされている場合は、それを取り出す。 */
+  if (ungetc_buf != EOLTTR)
+    return (l = ungetc_buf, ungetc_buf = EOLTTR, l);
+
+  while (*curdis == EOLTTR)
+    {
+      /* romkan_next()の値がLTREOFの時も、そのまま送れば良い。 */
+      curdis = romkan_henkan (romkan_next ());
+
+      /* keyackflgが非0なら、キーインがあれば必ず何か返す。その
+         ため、返すべきものがない時はEOLTTRを返すことにする。 */
+      if (flags & RK_KEYACK)
+        break;
+    }
+
+  if (EOLTTR != (l = *curdis))
+    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(*curdis != EOLTTR){p = curdis; curdis = nil; return(p);} */
+  /* ↑これではmae_inが無視される */
+  curdis = nil;
+
+  /* 前・後処理への入力は常にただ一文字 */
+  mae_out[0] = mae_out[1] = EOLTTR;
+
+  eofflg = rk_errstat = 0;
+  *rk_output = *disout = EOLTTR;
+
+  maeato_henkan (mae_in, mae_out, usemaehyo);
+  rk_input = *mae_out;
+
+  if (rk_input == LTREOF)
+    {
+      /* LTREOFが来た場合、(error)を無視し、本処理バッファの末尾迄
+         強制変換する。そのためにeofflgを1にする。その後、結果の
+         末尾に、LTREOFが来た時の特別コード(指定されていれば)と、
+         LTREOFをつなぐ。 */
+      eofflg = 1;
+      match ();
+
+      eofflg = 2;
+      add_at_eof ();            /* codeoutに、LTREOFが来た時出すコードが入る。 */
+      ltr1cat (codeout, LTREOF);
+
+      ltrcat (disout, codeout);
+      ltrcat (rk_output, codeout);
+    }
+  else if (rk_input == EOLTTR)
+    {
+      /* EOLTTRが来た場合も、上と同様の処理を行うが、LTREOFは
+         つながない。なお、これはromkan_getc()を呼んでいる時は
+         起こらない(romkan_next()がEOLTTRを返さないから)。 */
+      eofflg = 1;
+      match ();
+    }
+  else if (rk_input == delchr || rk_input == delchr2)
+    {
+      /* delchr2が未設定ならその値はEOLTTRなのでrk_inputと等しくない。 */
+      rk_delete (rk_input);
+    }
+  else
+    {
+      ltr1cat (keybuf, rk_input);
+      ltr1cat (disout, toNISE (rk_input));
+      match ();
+    }
+
+  if (!(flags & RK_CHMOUT))
+    {
+      /* chmoutflgが0の時は、CHMSIGを出さない。 */
+      for (p = DISOUT;; p++)
+        {
+          while (*p == CHMSIG)
+            ltrcpy (p, p + 1);
+          if (*p == EOLTTR)
+            break;
+        }
+    }
+
+  if ((flags & RK_REDRAW) && NULL != (p = ltr_rindex (disout, nisedl)))
+    {
+      for (p++; *p != EOLTTR || (ltr1cat (disout, REDRAW), 0); p++)
+        if (!isSPCL (*p))
+          break;
+    }
+  /* wnnのredrawのフラグが立っていて、disoutがnisedl以後特殊コードのみ
+     で終わっていたら、REDRAWを出して、Wnnに変換行のredrawをさせる。 */
+
+  return (DISOUT);
+}
+
+
+ /* デバッグ用関数 */
+#ifdef KDSP
+#  ifdef MVUX
+
+void
+pridbg2 (a, b, c)
+     char *a, *c;
+     letter *b;
+{
+  printf ("%s", a);
+  dump_fordbg (b);
+  printf ("%s", c);
+}
+
+int
+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);
+}
+
+void
+dump_fordbg (lp)
+     letter *lp;
+{
+  while (*lp != EOLTTR)
+    printf ("%x/", *lp++);
+}
+
+void
+print_fordbg (lp)
+     letter *lp;
+{
+  while (*lp != EOLTTR)
+    putletter (*lp++ & ~HG1BIT);
+}
+
+void
+print_ltrseq (lp)
+     letter *lp;
+{
+  while (*lp != EOLTTR)
+    print_ltr (*lp++ & ~HG1BIT);
+}
+
+void
+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)
+    {
+      *displine = *keybuf = *urabuf = EOLTTR;
+      lastoutlen = lastkbflen = 0;
+      putchar (l);
+    }
+  else if (l == delchr || l == nisedl)
+    {
+      if (*displine == EOLTTR)
+        putchar (BEEPCH);
+      else
+        {
+          disptail = ltrend (displine);
+          for (i = ltr_displen (*disptail); i; i--)
+            printf ("\031 \031");
+          *disptail = EOLTTR;
+        }
+    }
+  else
+    {
+      ltr1cat (displine, l);
+      putletter (l);
+    }
+}
+
+#  endif /* of #ifdef MVUX */
+#endif
+/* デバッグ用関数終わり */
+
+
+ /** DELが入力されたときの処理をする */
+static void
+rk_delete (input_del)
+     letter input_del;
+{
+  if (ltrlen (keybuf) > ((flags & RK_SIMPLD) ? 0 : lastkbflen))
+    {
+      ltr1cut (keybuf);
+      set_rubout (disout, 1, nisedl);
+    }
+  else
+    {
+      if (*urabuf != EOLTTR && !(flags & RK_SIMPLD))
+        {
+          ltr1cut (ltrcpy (keybuf, urabuf));
+          *urabuf = EOLTTR;
+
+          set_rubout (rk_output, lastoutlen, input_del);
+
+          set_rubout (disout, lastkbflen, nisedl);
+          bitup_ltrcat (ltrcat (disout, rk_output), keybuf);
+
+          lastkbflen = lastoutlen = 0;
+        }
+      else
+        {
+          set_rubout (disout, 1, input_del);
+          set_rubout (rk_output, 1, input_del);
+        }
+    }
+}
+
+ /**    letterの列 lp1 と lp2 のマッチを試みる。返値は、lp1がlp2の頭部と
+        一致の時 -1、lp1またはその頭部とlp2が一致のときは一致長(lp2が
+        空文字列の時を含む。この場合返値は0)、それ以外は -2。
+        lp2側に式が含まれていたら評価をする。lp1側には式を含んではだめ */
+static int
+prefixp (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  /* 1行マッチさせるごとに、まずmatch情報をクリアしてから。
+     つまり、henmatch[0] . ltrmch = EOLTTR; としておく。 */
+
+  register int mch_len = 0, d_len;
+
+  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 letter
+mchedsrc (num)
+     int num;
+{
+  struct matchpair *pairptr;
+
+  for (pairptr = henmatch; pairptr->ltrmch != EOLTTR; pairptr++)
+    {
+      if (num == pairptr->hennum)
+        return (pairptr->ltrmch);
+    }
+  return (BUGreport (8), 0);
+}
+
+ /**    num番目の変数が文字 l とマッチするか調べる。その変数がunboundだった
+        場合は l にbindする。マッチしたら(bindの時を含む)1、しないと0を返す */
+static int
+mchsrc (num, l)
+     int num;
+     letter l;
+{
+  struct matchpair *pairptr;
+
+  if (hen_ikisrc (num, l) == 0)
+    return (0);
+  for (pairptr = henmatch; 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 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 int
+p_eq (l1pp, l2pp)
+     register letter **l1pp, **l2pp;
+{
+  int num;
+  letter evlrsl[RSLMAX], *rslptr;
+  register int retval = -2;
+
+  /*  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に入れる */
+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++ = LWRMSK (*l1p++);
+          *l2p++ = 0;
+          break;                /* EOLではない */
+        case 5:
+          *l2p++ = CHMSIG;
+          *l2p++ = LWRMSK (*l1p++);
+          *l2p++ = 1;
+          break;
+        case 6:
+          *l2p++ = CHMSIG;
+          *l2p++ = XY2INT (2, LWRMSK (*l1p++));
+          *l2p++ = 1;
+          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 (!modesw[LWRMSK (*l1p++)].curmode)
+            *l2p++ = UNUSDC;
+          break;
+        case 21:
+          if (modesw[LWRMSK (*l1p++)].curmode)
+            *l2p++ = UNUSDC;
+          break;
+        case 22:
+          *l2p++ = REASIG;
+          break;
+        case 23:
+          *l2p++ = delchr;
+          break;
+        case 24:
+          *l2p++ = CHMSIG;
+          *l2p++ = XY2INT (1, 0);
+          /* これで「all」を表す */
+          *l2p++ = 0;
+          break;
+        case 25:
+          *l2p++ = CHMSIG;
+          *l2p++ = XY2INT (1, 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 (eofflg != 2 || *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++;
+          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 (modesw[modnum].curmode != *l1p++)
+              *l2p++ = UNUSDC;
+            break;
+          }
+        case 41:
+          {
+            letter modnum;
+
+            modnum = LWRMSK (*l1p++);
+            if (modesw[modnum].curmode == *l1p++)
+              *l2p++ = UNUSDC;
+            break;
+          }
+        case 42:
+          {
+            letter modnum;
+
+            modnum = LWRMSK (*l1p++);
+            if (modesw[modnum].curmode >= *l1p++)
+              *l2p++ = UNUSDC;
+            break;
+          }
+        case 43:
+          {
+            letter modnum;
+
+            modnum = LWRMSK (*l1p++);
+            if (modesw[modnum].curmode <= *l1p++)
+              *l2p++ = UNUSDC;
+            break;
+          }
+        case 44:
+          mchevl (&l1p, tmpevl);
+          *l2p++ = SENDCH;
+          *l2p++ = *tmpevl;
+          break;
+        default:                /* case 0及び上記以外 */ ;
+          BUGreport (7);
+        }
+    }
+
+  *l2p = EOLTTR;
+  *l1pp = l1p;
+}
+
+ /** num番目の変数の変域が文字 l を含むかどうかを返す */
+static int
+hen_ikisrc (num, l)
+     int num;
+     letter l;
+{
+  letter *defptr;
+
+  defptr = hyo_n[hyonum].hensudef[num];
+  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を返す */
+int
+match ()
+{
+  int henkanflg = 0, okcode = 0, chm_exist;
+  letter *p;
+  letter urabufcreate[KBFSIZ], orgkeybuf[KBFSIZ], kbftail[KBFSIZ];
+  letter *urabufjunbi, *outcutptr, *dis_end;
+
+  if (*keybuf == EOLTTR)
+    {
+      *urabuf = EOLTTR;
+      return (1);
+    }
+
+  ltrcpy (urabufjunbi = orgkeybuf, keybuf);
+  outcutptr = rk_output;
+
+  while ((okcode = henkan_ok ()) > 0)
+    {
+      henkanflg = 1;
+
+      codeout_chg ();
+      ltrcat (rk_output, codeout);
+
+      ltrcpy (kbftail, keybuf + codein_len);
+      ltrcat (ltrcpy (keybuf, remainkbf), kbftail);
+
+      if (okcode == 2)
+        {
+          ltrcpy (urabufjunbi = urabufcreate, keybuf);
+          totail (outcutptr);
+        }
+    }
+
+  if (okcode == 0)
+    {
+      ltr1cut (ltrcpy (keybuf, orgkeybuf));
+      ltr_to_ltrseq (disout, NISEBP);
+      *rk_output = EOLTTR;
+      return (0);
+    }
+  if (henkanflg)
+    {
+      ltrcpy (urabuf, urabufjunbi);
+
+      set_rubout (disout, ltrlen (orgkeybuf) - 1, nisedl);
+
+      dis_end = disout;
+      totail (dis_end);
+      ltrcpy (dis_end, rk_output);
+
+      /* モードチェンジを直ちに知らせるため CHMSIGを出力
+         (flags中のRK_CHMOUTが立ってないと、あとで一文字ずつに
+         分解する時点で、CHMSIGをカット)。
+         但し、rk_outputからは、CHMSIGを抜く。
+         また、CHMSIGは末尾に1回しか出力しない
+         (2回以上あっても、1回にまとめて、末尾に置く)。 */
+      for (chm_exist = 0, p = rk_output;; p++)
+        {
+          while (*p == CHMSIG)
+            {
+              chm_exist = 1;
+              if (ltrcpy (p, p + 1) < outcutptr)
+                outcutptr--;
+            }
+          if (*p == EOLTTR)
+            break;
+        }
+      if (chm_exist)
+        {
+          /* CHMSIGを1つにまとめたものをdis_endにつなげ直す。
+             このif文をカットすれば、CHMSIGのとりまとめはやらない */
+          ltr1cat (ltrcpy (dis_end, rk_output), CHMSIG);
+        }
+
+      bitup_ltrcat (disout, keybuf);
+      lastoutlen = ltrlen (outcutptr);
+      lastkbflen = ltrlen (keybuf);
+    }
+  return (1);
+}
+
+ /**    LTREOFが入ったときに、何か出すように指定されているか調べて、
+        codeoutをその結果の文字列(指定がなかったら当然空)にポイントする。
+        超急ごしらえで、特殊コード等は一切無視する。*/
+static void
+add_at_eof ()
+{
+  register struct dat *datptr;
+  register int i;
+  int hyoseq;
+  letter evlrsl[RSLMAX], *p;
+
+  for (hyoseq = 0; (hyonum = usehyo[hyoseq]) != -1; hyoseq++)
+    {
+      for (i = 0, datptr = hyo_n[hyonum].data; NULL != (p = datptr[i].code[0]); i++)
+        {
+          henmatch[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 (codeout = p = evalbuf[0][0], datptr[i].code[1]);
+          while (*p != EOLTTR)
+            {
+              if (isSPCL (*p))
+                ltrcpy (p, p + 1);
+              else
+                p++;
+            }
+          codeout_chg ();
+          return;
+
+        Pass:;
+        }
+    }
+  codeout = nil;
+}
+
+ /**    一回マッチを試みる。返値は、マッチして確定した場合1(モードチェンジが
+        混じっている場合は2)、マッチしたが未確定の時-1、マッチしなかったら0。
+        実行中は、変数 l に、それまでに一致した長さの最高記録を入れており、
+        より長く一致するものが見つかるごとに、これを更新する。lの値は、マッチ
+        していても0になることもある。p_eq() 及び prefixp() の注釈文を参照。*/
+static int
+henkan_ok ()
+{
+  register struct dat *datptr;
+  register int i, k;
+  int l, j, hyoseq;
+  char urabuf_clrf;             /* モードチェンジなどで、urabufをクリアする必要が
+                                   生じた場合はこれが立ち、その結果、henkan_ok()
+                                   が1を返すべきところで2を返す。それを見て、
+                                   match()がurabufなどの調整をする。 */
+  register letter *p;
+
+  if (*keybuf == EOLTTR)
+    return (-1);
+
+  for (l = -1, hyoseq = 0; (hyonum = usehyo[hyoseq]) != -1; hyoseq++)
+    {
+      for (i = 0, datptr = hyo_n[hyonum].data; NULL != (p = datptr[i].code[0]); i++)
+        {
+          henmatch[0].ltrmch = EOLTTR;
+          switch (k = prefixp (keybuf, p))
+            {
+            case -2:
+              break;
+            case -1:
+              if (eofflg != 0)
+                break;
+              /* eofflgが立っていたら、未確定の可能性は
+                 捨てる。 */
+
+              return (-1);
+            default:
+              if (k > l)
+                {
+                  ebf_sw = !ebf_sw;
+                  for (j = 1; j <= 2; j++)
+                    {
+                      ltrevlcpy (evalbuf[ebf_sw][j - 1], datptr[i].code[j]);
+                    }
+
+                  l = k;
+                }
+            }
+        }
+    }
+
+  if (l >= 0)
+    {
+      codein_len = l;
+      codeout = evalbuf[ebf_sw][0];
+      remainkbf = evalbuf[ebf_sw][1];
+
+      for (urabuf_clrf = 0, p = codeout; *p != EOLTTR;)
+        {
+          switch (*p)
+            {
+            case CHMSIG:
+              p++;
+              /* codeoutの1バイト目に関数のスイッチとモード番号、
+                 2バイト目にモードの新状態が入ってる */
+              switch (SHUBET (*p))
+                {
+                case 0:
+                  chgmod ((int) *p, (modetyp) * (p + 1));
+                  break;
+                case 1:
+                  allchgmod ((modetyp) * (p + 1));
+                  break;
+                case 2:
+                  incmod ((int) LWRMSK (*p), (modetyp) * (p + 1));
+                  break;
+                case 3:
+                  decmod ((int) LWRMSK (*p), (modetyp) * (p + 1));
+                  break;
+                }
+              ltrcpy (p, p + 2);
+              /* CHMSIGだけ残して1,2バイト目cut */
+
+              urabuf_clrf = 1;
+              break;
+            case URBFCL:
+              /* urabufのクリアを明示的に指定する */
+              urabuf_clrf = 1;
+              ltrcpy (p, p + 1);
+              break;
+            default:
+              p++;
+            }
+        }
+
+      if (*codeout == ERRCOD)
+        {
+          if (eofflg == 0)
+            {
+              rk_errstat = 1;
+              return (0);
+            }
+
+          /* (error)であって、しかもeofflgが立ってたら、keybuf
+             の末尾まで、そのまま出す。 */
+          codein_len = ltrlen (keybuf);
+          codeout = ltrcpy (evalbuf[ebf_sw][0], keybuf);
+          remainkbf = nil;
+          rk_errstat = 2;
+
+          return (1);
+        }
+      /* (error)は単独でしか書けないので、エラー検出はこれで十分。 */
+
+      if (*codeout == REASIG)
+        {
+          *codeout = (rk_rst () != 0 ? EOLTTR : CHMSIG);
+          /* 再readでエラったらモードチェンジの通知はしない */
+
+          urabuf_clrf = 1;
+        }
+      /* 表の再read。但し、これが起こったことを外に知らせるのはCHMSIGで
+         このコードそのものは外へ出ない。(restart)は、(error)同様、
+         単独でしか書けないので、検出はこれで十分。 */
+
+      return (urabuf_clrf ? 2 : 1);
+    }
+
+  /* 表に現れていないコードはそのまま返す */
+
+  codein_len = 1;
+  *(codeout = oneletter) = *keybuf;
+  remainkbf = nil;
+  return (1);
+}
+
+ /* rk_rst内で使うマクロ */
+#define taihi(X, Y, N) {for(i = 0; i < N; i++) X[i] = Y[i];}
+#define recov(X, Y, N) taihi(Y, X, N)
+
+ /**    表の動的再読み込みをする。現在の内部表現を全て退避し、前と同じ
+        ディレクトリ(に、現在のところ限定)から表を読み込む。もし、
+        読み込み中にエラーを検出すれば、もとの内部データを復活し非0を返す。*/
+static int
+rk_rst ()
+{
+  register int i;
+  int j;
+
+  letter memoryt[SIZALL];
+  struct dat datat[LINALL];
+  struct hyo hyo_nt[HYOMAX];
+  letter *hensudefhyot[VARTOT];
+  struct modestat modeswt[MODMAX];
+  char hyoshut[HYOMAX];
+  char *modmeibgnt[MODMAX], modmeimem_t[MODMEI];
+  char *dspnambgnt[DMDMAX], dspcod_t[DMDCHR];
+  int usemaehyot[HYOMAX], usehyot[HYOMAX], useatohyot[HYOMAX];
+  int naibu_t[NAIBMX];
+  char *dspmodt[2][2];
+
+  taihi (memoryt, memory, SIZALL);
+  taihi (datat, data, LINALL);
+  taihi (hyo_nt, hyo_n, HYOMAX);
+  taihi (hensudefhyot, hensudefhyo, VARTOT);
+  taihi (modeswt, modesw, MODMAX);
+  taihi (hyoshut, hyoshu, HYOMAX);
+  taihi (modmeibgnt, modmeibgn, MODMAX);
+  taihi (modmeimem_t, modmeimem_, MODMEI);
+  taihi (dspnambgnt, dspnambgn, DMDMAX);
+  taihi (dspcod_t, dspcod_, DMDCHR);
+  taihi (usemaehyot, usemaehyo, HYOMAX);
+  taihi (usehyot, usehyo, HYOMAX);
+  taihi (useatohyot, useatohyo, HYOMAX);
+  taihi (naibu_t, naibu_, NAIBMX);
+  for (i = 0; i < 2; i++)
+    for (j = 0; j < 2; j++)
+      dspmodt[i][j] = dspmod[i][j];
+
+  if (0 == romkan_init3 (prv_modfnm, delchr, nisedl, delchr2, keyin_method, bytcnt_method, kbytcnt_method, 1, flags & ~RK_VERBOS))
+    return (0);                 /* 正常終了 */
+
+  recov (memoryt, memory, SIZALL);
+  recov (datat, data, LINALL);
+  recov (hyo_nt, hyo_n, HYOMAX);
+  recov (hensudefhyot, hensudefhyo, VARTOT);
+  recov (modeswt, modesw, MODMAX);
+  recov (hyoshut, hyoshu, HYOMAX);
+  recov (modmeibgnt, modmeibgn, MODMAX);
+  recov (modmeimem_t, modmeimem_, MODMEI);
+  recov (dspnambgnt, dspnambgn, DMDMAX);
+  recov (dspcod_t, dspcod_, DMDCHR);
+  recov (usemaehyot, usemaehyo, HYOMAX);
+  recov (usehyot, usehyo, HYOMAX);
+  recov (useatohyot, useatohyo, HYOMAX);
+  recov (naibu_t, naibu_, NAIBMX);
+  for (i = 0; i < 2; i++)
+    for (j = 0; j < 2; j++)
+      dspmod[i][j] = dspmodt[i][j];
+  return (1);
+}
+
+ /** lp2から評価して得た文字列をlp1にコピー */
+static void
+ltrevlcpy (lp1, lp2)
+     letter *lp1, *lp2;
+{
+  while (*lp2 != EOLTTR)
+    {
+      mchevl (&lp2, lp1);
+      totail (lp1);
+    }
+  *lp1 = EOLTTR;
+}
+
+static void
+set_rubout (lp, n, del)
+ /** lpに 「del」n個の列をセットする。ここに del は 'delchr'か'nisedl' */
+     letter *lp, del;
+     int n;
+{
+  for (; n; n--)
+    *lp++ = del;
+  *lp = EOLTTR;
+}
+
+ /** これが実行されたらバグ。但し実行はそのまま続く */
+void
+BUGreport (n)
+     int n;
+{
+  fprintf (stderr, "\r\nromkan-Bug%d!!\r\n", n);
+}
+
+ /** 前処理(mae_in→mae_out)又は後処理(ato_in→ato_out)を行う。*/
+static void
+maeato_henkan (in, outp, m_a_hyo)
+     letter in;                 /* 入力の一文字 */
+     letter *outp;              /* 出力はここに入る */
+     int *m_a_hyo;              /* どの前・後処理表が選択されているかの情報 */
+{
+  struct dat *datptr;
+  int i, hyoseq;
+  letter *curdat;
+
+  if (isSPCL (in))
+    {
+      /* LTREOFやCHMSIGが来うるので、特殊コードはそのまま返すように
+         細工しておかないといけない。 */
+      ltr_to_ltrseq (outp, in);
+      return;
+    }
+
+  for (hyoseq = 0; (hyonum = m_a_hyo[hyoseq]) != -1; hyoseq++)
+    {
+      for (i = 0, datptr = hyo_n[hyonum].data; NULL != (curdat = datptr[i].code[0]); i++)
+        {
+          henmatch[0].ltrmch = EOLTTR;
+          if (!l_eq (curdat, in))
+            continue;
+
+          ltrevlcpy (outp, datptr[i].code[1]);
+          return;
+        }
+    }
+  ltr_to_ltrseq (outp, in);
+}
+
+ /** 後処理 */
+static void
+codeout_chg ()
+{
+  letter *saishu_outp;
+
+  *(saishu_outp = saishu_out) = EOLTTR;
+
+  for (; *codeout != EOLTTR; codeout++)
+    {
+      maeato_henkan (*codeout, saishu_outp, useatohyo);
+      totail (saishu_outp);
+    }
+
+  codeout = saishu_out;
+}
+
+ /** 一文字プッシュ・バック */
+/* *INDENT-OFF* */
+letter
+romkan_ungetc (l)
+     letter l;
+/* *INDENT-ON* */
+{
+  return (ungetc_buf = l);
+}
+
+ /** romkan_nextに対し一文字プッシュ・バック */
+/* *INDENT-OFF* */
+letter
+romkan_unnext (l)
+     letter l;
+/* *INDENT-ON* */
+{
+  return (unnext_buf = l);
+}
+
+ /**    deleteとして使うキャラクタの設定(偽deleteも)。これを実行後は
+        romkan_clearを実行しておかないと混乱のもとになります。*/
+/*      (廃止)
+void
+romkan_setdel(delchr_, nisedl_)
+letter  delchr_, nisedl_;
+{
+        delchr = delchr_;
+        nisedl = nisedl_;
+}
+*/