/*
 * $Id: rk_main.c,v 2.5.2.1 2000/08/04 05:37:28 kaneda Exp $
 */
/*
WNN6 CLIENT LIBRARY--SOFTWARE LICENSE TERMS AND CONDITIONS


Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993

Preamble

These Wnn6 Client Library--Software License Terms and Conditions
 (the "License Agreement") shall state the conditions under which you are
 permitted to copy, distribute or modify the software which can be used
 to create Wnn6 Client Library (the "Wnn6 Client Library").  The License
 Agreement can be freely copied and distributed verbatim, however, you
 shall NOT add, delete or change anything on the License Agreement.

OMRON Corporation and OMRON Software Co., Ltd. (collectively referred to
 as "OMRON") jointly developed the Wnn6 Software (development code name
 is FI-Wnn), based on the Wnn Software.  Starting from November, 1st, 1998,
 OMRON publishes the source code of the Wnn6 Client Library, and OMRON
 permits anyone to copy, distribute or change the Wnn6 Client Library under
 the License Agreement.

Wnn6 Client Library is based on the original version of Wnn developed by
 Kyoto University Research Institute for Mathematical Sciences (KURIMS),
 OMRON Corporation and ASTEC Inc.

Article 1.  Definition.

"Source Code" means the embodiment of the computer code, readable and
 understandable by a programmer of ordinary skills.  It includes related
 source code level system documentation, comments and procedural code.

"Object File" means a file, in substantially binary form, which is directly
 executable by a computer after linking applicable files.

"Library" means a file, composed of several Object Files, which is directly
 executable by a computer after linking applicable files.

"Software" means a set of Source Code including information on its use.

"Wnn6 Client Library" the computer program, originally supplied by OMRON,
 which can be used to create Wnn6 Client Library.

"Executable Module" means a file, created after linking Object Files or
 Library, which is directly executable by a computer.

"User" means anyone who uses the Wnn6 Client Library under the License
 Agreement.

Article 2.  Copyright

2.1  OMRON Corporation and OMRON Software Co., Ltd. jointly own the Wnn6
 Client Library, including, without limitation, its copyright.

2.2  Following words followed by the above copyright notices appear
 in all supporting documentation of software based on Wnn6 Client Library:

  This software is based on the original version of Wnn6 Client Library
  developed by OMRON Corporation and OMRON Software Co., Ltd. and also based on
  the original version of Wnn developed by Kyoto University Research Institute
  for Mathematical Sciences (KURIMS), OMRON Corporation and ASTEC Inc.

Article 3.  Grant

3.1  A User is permitted to make and distribute verbatim copies of
 the Wnn6 Client Library, including verbatim of copies of the License
 Agreement, under the License Agreement.

3.2  A User is permitted to modify the Wnn6 Client Library to create
 Software ("Modified Software") under the License Agreement.  A User
 is also permitted to make or distribute copies of Modified Software,
 including verbatim copies of the License Agreement with the following
 information.  Upon modifying the Wnn6 Client Library, a User MUST insert
 comments--stating the name of the User, the reason for the modifications,
 the date of the modifications, additional terms and conditions on the
 part of the modifications if there is any, and potential risks of using
 the Modified Software if they are known--right after the end of the
 License Agreement (or the last comment, if comments are inserted already).

3.3  A User is permitted to create Library or Executable Modules by
 modifying the Wnn6 Client Library in whole or in part under the License
 Agreement.  A User is also permitted to make or distribute copies of
 Library or Executable Modules with verbatim copies of the License
 Agreement under the License Agreement.  Upon modifying the Wnn6 Client
 Library for creating Library or Executable Modules, except for porting
 a computer, a User MUST add a text file to a package of the Wnn6 Client
 Library, providing information on the name of the User, the reason for
 the modifications, the date of the modifications, additional terms and
 conditions on the part of the modifications if there is any, and potential
 risks associated with using the modified Wnn6 Client Library, Library or
 Executable Modules if they are known.

3.4  A User is permitted to incorporate the Wnn6 Client Library in whole
 or in part into another Software, although its license terms and
 conditions may be different from the License Agreement, if such
 incorporation or use associated with the incorporation does NOT violate
 the License Agreement.

Article 4. Warranty

THE WNN6 CLIENT LIBRARY IS PROVIDED BY OMRON ON AN "AS IS" BAISIS.
  OMRON EXPRESSLY DISLCIAMS ANY AND ALL WRRANTIES, EXPRESS OR IMPLIED,
 INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, IN CONNECTION WITH THE WNN6 CLIENT LIBRARY
 OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT LIBRARY.  IN NO EVENT
 SHALL OMRON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, PUNITIVE
 OR CONSEQUENTIAL DAMAGES OF ANY KIND WHATSOEVER IN CONNECTION WITH THE
 WNN6 CLIENT LIBRARY OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT
LIBRARY.

***************************************************************************
Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993
***************************************************************************

Comments on Modifications:
*/
/***********************************************************************
			rk_main.c
						88. 6.10  改 正
						93.10.19

	ローマ字かな変換・その他、入力コードを変換するプログラム。
	ASCIIコード使用を、前提としている。
	このファイルは、変換のメインルーチン。
***********************************************************************/
/*	Version 3.0
 */
#include "rk_multi.h"
#include "rk_fundecl.h"


struct	matchpair /*	現在マッチされている変数の番号と、マッチした文字の
			組を保持。*/
{
	int	hennum;
	letter	ltrmch;
};

letter	memory[SIZALL]; /* 変換対応表や、変数の変域などを入れる領域 */
struct	dat	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 	*romkan_henkan_body();
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_body(), 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の一文字を長さ１の文字列に変換する */
static
letter	*ltr_to_ltrseq(lp, l)
letter	*lp, l;
{
	*lp++ = l;
	*lp-- = EOLTTR;
	return(lp);
}

 /** charの列からletterを一つ取り出す。但し'\0'はEOLTTRに変える */
letter
letterpick(lbfpptr, cur_rk)
uns_chr **lbfpptr;
ARGS *cur_rk;
{
	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
	にて定義）に変える。*/
letter
romkan_next_body(cur_rk)
ARGS *cur_rk;
{
	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
romkan_next()
{
    ARGS *cur_rk = NULL;

    letter x;
    LockMutex(&(cur_rk->rk_lock));
    x = romkan_next_body(cur_rk);
    UnlockMutex(&(cur_rk->rk_lock));
    return x;
}

 /*	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(cur_rk)
ARGS *cur_rk;
{
	return(*(ltrend(urabuf)));
}

/* end of 'letter' functions */


#ifdef	OMAKE
 /** お	 ま  け
	ＴＶアニメのご案内（一部特撮を含む）。引数が非負整数の時はどれか一つ、
	-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三好・服部",
	"「ゲッターロボ」（「ゲッターロボＧ」を含む）は良い番組だ。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_body(cur_rk)
ARGS *cur_rk;
{
#ifdef KDSP
#  ifdef MVUX
	*displine = EOLTTR;
#  endif
#endif
	ungetc_buf = *keybuf = *urabuf = *disout = *rk_output = EOLTTR;
	curdis = DISOUT;
	lastoutlen = lastkbflen = 0;
}

void
romkan_clear()
{
    ARGS *cur_rk = NULL;

    LockMutex(&(cur_rk->rk_lock));
    romkan_clear_body(cur_rk);
    UnlockMutex(&(cur_rk->rk_lock));
}

 /**	表を読み込んで変換の初期設定をする。（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のみ */
	ARGS 	*cur_rk;

	DoOnce( &once, _InitMutexs );
	LockMutex(&open_lock);
	cur_rk = NULL;

	 /* 偽コードを出すかの設定は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_body(cur_rk);
		 /*	fprintf(stderr,
			      "No conversion is currently performed."); */
			fprintf(stderr, "\r\n");
		} else {
			fprintf(stderr,
				"Conversion method was unchanged.\r\n");
		}
	} else {
		readdata(memory, dat_data, hensudefhyo, modhyo, cur_rk);
		if(!restartf){
			romkan_clear_body(cur_rk);
			hank_setup();
		}
	}

	if(!errcod && (flags & RK_VERBOS)){
		fprintf(stderr, "romkan_init finished.\r\n");
		fflush(stderr);
	}

	UnlockMutex(&open_lock);
	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
}

 /** 変換された文字を順次返す */
letter
romkan_getc_body(cur_rk)
ARGS *cur_rk;
{
	letter	l;

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

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

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

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

letter
romkan_getc()
{
    letter x;
    ARGS *cur_rk = NULL;

    LockMutex(&(cur_rk->rk_lock));
    x = romkan_getc_body(cur_rk);
    UnlockMutex(&(cur_rk->rk_lock));
    return x;
}

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

	/* 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, cur_rk);
	rk_input = *mae_out;

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

		eofflg = 2;
		add_at_eof(cur_rk); /* 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(cur_rk);
	} else if(rk_input == delchr || rk_input == delchr2){
	    /* delchr2が未設定ならその値はEOLTTRなのでrk_inputと等しくない。*/
		rk_delete(rk_input, cur_rk);
	} else {
		ltr1cat(keybuf, rk_input);
		ltr1cat(disout, toNISE(rk_input));
		match(cur_rk);
	}

	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をさせる。*/

	x = DISOUT;
	return x;
}

letter *
romkan_henkan(mae_in)
letter  mae_in;
{
    letter *x;
    ARGS *cur_rk = NULL;

    LockMutex(&(cur_rk->rk_lock));
    x = romkan_henkan_body(mae_in, cur_rk);
    UnlockMutex(&(cur_rk->rk_lock));
    return x;
}


 /* デバッグ用関数 */
#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, cur_rk)
letter	*lp;
ARGS *cur_rk;
{
	while(*lp != EOLTTR) print_ltr(*lp++ & ~HG1BIT, cur_rk);
}

void
print_ltr(l, cur_rk)
letter	l;
ARGS *cur_rk;
{
	letter	*disptail;
	int	i;

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

	if(l == CHMSIG)
#ifdef CHMDSP
                printf("...mode=%s\n",romkan_dispmode_body(cur_rk))
#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, cur_rk)
letter	input_del;
ARGS *cur_rk;
{
	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, cur_rk)
letter	*lp1, *lp2;
ARGS *cur_rk;
{
	/* 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, cur_rk)) < 0) return(d_len);
		mch_len += d_len;
	}
}

 /** num番目の変数が既にある文字とマッチしていると仮定して、その文字を返す */
static letter
mchedsrc(num, cur_rk)
int	num;
ARGS *cur_rk;
{
	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, cur_rk)
int	num;
letter	l;
ARGS *cur_rk;
{
	struct	matchpair	*pairptr;

	if(hen_ikisrc(num, l, cur_rk) == 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, cur_rk)
letter	*l1p, l2;
ARGS *cur_rk;
{
	letter	evlrsl[RSLMAX];

	switch(SHUBET(*l1p)){
		case 0: return(*l1p == l2);
		case 1: return(mchsrc((int)LWRMSK(*l1p), l2, cur_rk));
		case 2:
			mchevl(&l1p, evlrsl, cur_rk);
			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, cur_rk)
register letter **l1pp, **l2pp;
ARGS *cur_rk;
{
	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)++, cur_rk) ? 1 : -2);
				break;
			case 2: /* 式と文字 */
				mchevl(l1pp, rslptr = evlrsl, cur_rk);
				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, cur_rk)
letter	**l1pp, *l2p;
ARGS *cur_rk;
{
	letter	*l1p, tmpevl[RSLMAX];

	l1p = *l1pp;

	switch(SHUBET(*l1p)){
		case 0: *l2p++ = *l1p++; break;
		case 1: *l2p++ = mchedsrc((int)LWRMSK(*l1p++), cur_rk); break;
		case 2:	 /* toupper, tolower, error, … */
			switch(LWRMSK(*l1p++)){
				case 2: mchevl(&l1p, tmpevl, cur_rk);
					*l2p++ = to_upper(*tmpevl);
					break;
				case 3: mchevl(&l1p, tmpevl, cur_rk);
					*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, cur_rk);
					*l2p++ = to_updown(*tmpevl);
					break;
				case 8:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p++ = to_zenalpha(*tmpevl, cur_rk);
					break;
				case 9:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p++ = to_hira(*tmpevl);
					break;
				case 10:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p++ = to_kata(*tmpevl);
					break;
				case 11:
					mchevl(&l1p, tmpevl, cur_rk);
					to_hankata(*tmpevl, &l2p);
					break; /* 特殊 */
				case 12:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p++ = to_zenhira(*tmpevl, cur_rk);
					break;
				case 13:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p++ = to_zenkata(*tmpevl, cur_rk);
					break;
				case 14:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p += *tmpevl;
					LWRCUT(*l2p++);
					break;
				case 15:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p -= *tmpevl;
					LWRCUT(*l2p++);
					break;
				case 16:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p *= *tmpevl;
					LWRCUT(*l2p++);
					break;
				case 17:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					if(! *tmpevl) *l2p = LTRHUG;
					 else *l2p /= *tmpevl;
					LWRCUT(*l2p++);
					break;
				case 18:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					if(! *tmpevl) *l2p = LTRHUG;
					 else *l2p %= *tmpevl;
					LWRCUT(*l2p++);
					break;
				 /* 19〜21・30は、条件を満たすと空文字列、
				    そうでないとUNUSDCを文字列として返す。*/
				case 19:
					mchevl(&l1p, tmpevl, cur_rk);
					if(lastmch(cur_rk) != *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, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p &= *tmpevl;
					LWRCUT(*l2p++);
					break;
				case 27:
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p = *tmpevl;
					mchevl(&l1p, tmpevl, cur_rk);
					*l2p |= *tmpevl;
					LWRCUT(*l2p++);
					break;
				case 28:
					mchevl(&l1p, tmpevl, cur_rk);
					*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, cur_rk);
						code = *tmpevl;
						mchevl(&l1p, tmpevl, cur_rk);
						if((basenum = *tmpevl) <= 1 ||
						   BASEMX < basenum)
							basenum = 10;
						to_digit(code, basenum, &l2p);
					}
					break;
				case 32:
					mchevl(&l1p, tmpevl, cur_rk);
					dakuadd(*tmpevl, &l2p);
					break; /* 特殊 */
				case 33:
					mchevl(&l1p, tmpevl, cur_rk);
					handakuadd(*tmpevl, &l2p);
					break; /* 特殊 */
				case 34:
					mchevl(&l1p, tmpevl, cur_rk);
					*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, cur_rk);
					*l2p++ = SENDCH;
					*l2p++ = *tmpevl;
					break;
				default:/* case 0及び上記以外 */;
					BUGreport(7);
			}
	}

	*l2p = EOLTTR;
	*l1pp = l1p;
}

 /** num番目の変数の変域が文字 l を含むかどうかを返す */
static int
hen_ikisrc(num, l, cur_rk)
int	num;
letter	l;
ARGS *cur_rk;
{
	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(cur_rk)
ARGS *cur_rk;
{
	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(cur_rk)) > 0){
		henkanflg = 1;

		codeout_chg(cur_rk);
		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は末尾に１回しか出力しない
		    （２回以上あっても、１回にまとめて、末尾に置く）。*/
		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を１つにまとめたものを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(cur_rk)
ARGS *cur_rk;
{
	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, cur_rk);
						if(*evlrsl != EOLTTR)
							goto Pass;
					 /* 入力コード部に、評価すると
					    空文字列になるものが、他にはない
					    ことが前提。*/
				}
			}

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

Pass:			;
		}
	}
	codeout = nil;
}

 /**	一回マッチを試みる。返値は、マッチして確定した場合1（モードチェンジが
	混じっている場合は2）、マッチしたが未確定の時-1、マッチしなかったら0。
	実行中は、変数 l に、それまでに一致した長さの最高記録を入れており、
	より長く一致するものが見つかるごとに、これを更新する。lの値は、マッチ
	していても0になることもある。p_eq() 及び prefixp() の注釈文を参照。*/
static int
henkan_ok(cur_rk)
ARGS *cur_rk;
{
	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, cur_rk)){
			    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[(int)ebf_sw][j-1],
					 datptr[i] . code[j], cur_rk);
				    }
				    l = k;
				}
			}
		}
	}

	if(l >= 0){
		codein_len = l;
		codeout = evalbuf[(int)ebf_sw][0];
		remainkbf = evalbuf[(int)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), cur_rk);
							break;
						case 1:
							allchgmod((modetyp)
								    *(p + 1), cur_rk);
							break;
						case 2:
							incmod((int)LWRMSK(*p)
							  ,(modetyp)*(p + 1), cur_rk);
							break;
						case 3:
							decmod((int)LWRMSK(*p)
							  ,(modetyp)*(p + 1), cur_rk);
							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[(int)ebf_sw][0], keybuf);
			remainkbf = nil;
			rk_errstat = 2;

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

		if(*codeout == REASIG){
			*codeout = (rk_rst(cur_rk) != 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) {for(i = 0; i < N; i++) Y[i] = X[i];}

 /**	表の動的再読み込みをする。現在の内部表現を全て退避し、前と同じ
	ディレクトリ（に、現在のところ限定）から表を読み込む。もし、
	読み込み中にエラーを検出すれば、もとの内部データを復活し非0を返す。*/
static int
rk_rst(cur_rk)
ARGS *cur_rk;
{
	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,		dat_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,		dat_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, cur_rk)
letter	*lp1, *lp2;
ARGS *cur_rk;
{
	while(*lp2 != EOLTTR){
		mchevl(&lp2, lp1, cur_rk);
		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, cur_rk)
letter	in;		/* 入力の一文字 */
letter	*outp;		/* 出力はここに入る */
int	*m_a_hyo;	/* どの前・後処理表が選択されているかの情報 */
ARGS *cur_rk;
{
	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, cur_rk)) continue;

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

 /** 後処理 */
static void
codeout_chg(cur_rk)
ARGS *cur_rk;
{
	letter	*saishu_outp;

	*(saishu_outp = saishu_out) = EOLTTR;

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

	codeout = saishu_out;
}

 /** 一文字プッシュ・バック */
letter
romkan_ungetc_body(l, cur_rk)
letter	l;
ARGS *cur_rk;
{
	ungetc_buf = l;
	return l;
}

letter
romkan_ungetc(l)
letter  l;
{
    letter x;
    ARGS *cur_rk = NULL;

    LockMutex(&(cur_rk->rk_lock));
    x = romkan_ungetc_body(l, cur_rk);
    UnlockMutex(&(cur_rk->rk_lock));
    return x;
}

 /** romkan_nextに対し一文字プッシュ・バック */
letter
romkan_unnext_body(l, cur_rk)
letter	l;
ARGS *cur_rk;
{
        unnext_buf = l;
	return l;
}

letter
romkan_unnext(l)
letter  l;
{
    letter x;
    ARGS *cur_rk = NULL;

    LockMutex(&(cur_rk->rk_lock));
    x = romkan_unnext_body(l, cur_rk);
    UnlockMutex(&(cur_rk->rk_lock));
    return x;
}

 /**	deleteとして使うキャラクタの設定（偽deleteも）。これを実行後は
	romkan_clearを実行しておかないと混乱のもとになります。*/
/*	（廃止）
void
romkan_setdel(delchr_, nisedl_)
letter	delchr_, nisedl_;
{
        LockMutex(&(cur_rk->rk_lock));
	delchr = delchr_;
	nisedl = nisedl_;
	UnlockMutex(&(cur_rk->rk_lock));
}
*/

