//--------------------------------------------------------------------------------------
// サポート関数群
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "support.h"
#include "XB.h"
#include "code2code.h"
#include <stdio.h>		// fileno()
#include <sys/stat.h>	// fstat()
#include <math.h>
#import "rgbhsv.h"
#import "atod3.h"

//--------------------------------------------------------------------------------------

// fac[i]からr/g/b/alhaを取得する
// 個別rgbおよび合成rgb対応
int getRGBColorFromFac(FAC fac[],int i,int *r,int *g,int *b,int *alpha)
{
	*r=(int)fac[i++].dl.l[LL];
	if (fac[i].facType==VOID_PARAM) { // rしかないとき
		// 合成rgb値が指定されているとみなす
		splitRGB(*r,r,g,b,alpha);
	} else {
		// 個別指定；でもalphaは省略される可能性がある
		*g=(int)fac[i++].dl.l[LL];
		*b=(int)fac[i++].dl.l[LL];
		if (fac[i].facType!=VOID_PARAM) { // 引数が省略されていない時
			*alpha=(int)fac[i].dl.l[LL];
		} else {
			*alpha=255; // 省略時
		}
	}
	// 次の取得位置を返す
	i++;
	return (i);
}

//--------------------------------------------------------------------------------------

// 文字列を常にUTF8で得る
UByte *strWithUTF8no(UByte *str,int no)
{
	printFunc();
	nslog(@"fsjisInRun=%d,(no=%d)str=%s",fsjisInRun,no,str);
	if (fsjisInRun) {
		// 強制SHIFT-JISモード
		// SHIFT-JIS→UTF8変換して返す
		sjisToUtf8S(tmp3s[no],str);
		return (tmp3s[no]);
	}
	// UTF8モードの時は何もせずそのまま帰す
	return (str);
}

//--------------------------------------------------------------------------------------

// リターンするだけの関数
// 主に外部関数の初期化不要時に呼び出す
void returnOnly(void)
{
	// returnのみ
	DBG_printsn("returnOnly");
}

//--------------------------------------------------------------------------------------

// 680x0 rol.w相当
UWord rolw(UWord w,int cnt)
{
	#ifdef CORE_DEBUG2
	DBG_printf("w=$%04x<<%d",w,cnt);
	#endif
	#if 1
	LONG_WORD lw;
	lw.l=(ULong)w;
	lw.l<<=cnt;
	#ifdef CORE_DEBUG2
	DBG_printf("=$%04x\n",(lw.w[LW]|lw.w[HW]));
	#endif
	return (lw.w[LW]|lw.w[HW]);
	#else
	int bit15;
	while (cnt-->0) {
		bit15=(w&bit(15));
		w<<=1;
		w|=(bit15!=0);
	}
	return (w);
	#endif
}

//--------------------------------------------------------------------------------------

// 標準関数fgets()の代替関数
// 相違点
// (1)改行コードがCRのみでもいける
// (2)リターン値が読み込んだバイト数になっている(-1=EOF/エラー)
//+(3)改行コードがLFのみでもいける
// 改行コードは消す=X-BASICの仕様に合わせるため(V2.5)
// buff[max]必要;読み込み最大サイズはmax-1(V3.01)
// EOT($1a)でも終了する(V3.01)
int fgets2(UByte *buff,int max,FILE *fp)
{
	int c;
	int len=0;
	while ((c=fgetc(fp))>=0) {
		if (c==EOT) {
			// EOTが来た時
			c=-1; // エラーで返す(X-BASIC/68の仕様)
			break;
		}
		if (c==CR) {
			// CR+LFかどうか調べる
			c=fgetc(fp);
			if (c!=LF) {
				// LFでないときは戻す
				ungetc(c,fp);
			}
			break;
		}
		if (c==LF) { // LFのみのとき
			break;
		}
		*buff++=(UByte)c;
		if (++len>=max-1) break; // いっぱい(V3.01)
	}
	if (c<0) { // EOF(EOTではない)またはエラー
//		if (len==0) len=c; // １バイト目読み込みの時だったらエラーで返す
		len=c; // エラーで返す(X-BASIC/68の仕様)
	}
	*buff=EOS;
	return (len); // EOSを含まないバイト数
}

//--------------------------------------------------------------------------------------

// 通常表示用の浮動小数点数値文字列をtmpに作る
// 現在str$()/print floatで利用中
int makeNormalFloatString(UByte *tmp,double d)
{
	nslog(@"makeNormalFloatString:d=%.15f/%e",d,d);
	/* X-BASIC/68(ぺけ-BASICも同じ)の仕様
	 数字桁数は常に14桁
	 	符号、小数点は含まず
	 	0.??になる時はその0も含まず
	 0.0??になる時は整数1桁.E-0*表記になる
	 	ただし、-004以下になる時は桁数が1桁づつ減る〜これは再現実装しない
	 
	 Cのdoubleの有効桁数は15桁らしい( http://www.cc.kyoto-su.ac.jp/~yamada/programming/float.html )
	*/
	if (isnan(d)) { // 演算不可なとき (Not a Number)
		strcpy((char*)tmp,STR_NaN);
		return (LEN_NaN); // EOSの位置
	}
	// 演算可能なとき

	// 数値を文字列するに際して、必要な表示桁数を予め得ておく
	// 整数桁数を得る
	// -xxxx.123456789012345
	UByte tmp1[330]; // E+-308までなので余裕を持って
	UByte *p=tmp1;
	double dd=fabs(d); // 絶対値
	sprintf((char *)p,"%."MAX_PRINT_KETAS"f",dd); // %fだけだと表示桁数は6桁
	nslog(@"%s\n",p);
	//
	UWord formatFlag=USING_BPLUS2; // 標準は前に正なら空白、負なら'-'をつける
	int shousuu=MAX_PRINT_KETA-1; // 1桁を整数に割り付けるため(仮)
	if (*p=='0') {
		// 数字先頭が0の時は0のみまたは0.xxx
		printf("0.〜 : ");
		if (dd==0.0) {
			// 0だけは特別処理
			shousuu=0;
			nslog(@"0の特別処理\n");
		} else {
			if (dd<0.1) {
				formatFlag|=USING_SISUU; // 0.1未満の時は指数表示にする(必ず整数1桁になる)
				nslog(@"整数1桁、小数%d桁\n",shousuu);
			} else {
				shousuu=MAX_PRINT_KETA; // 0.1〜なので、全ての桁を小数に割り当てる
				nslog(@"整数0桁、小数%d桁\n",shousuu);
			}
		}
	} else {
		// 整数桁があるとき
		nslog(@"整数桁あり\n");
		
		// x.123456789012345なので、必ず小数点はある
		int len=0;
		while (*p!='.') {
			p++;
			len++;
		}
		// 全体の桁をMAX_PRINT_KETAにするため、整数桁の分を小数桁数から減らす
		nslog(@"整数桁=%d/",len);
		shousuu-=len;
		nslog(@"小数桁=%d\n",shousuu);
		if (shousuu<0) {
			// ただし、整数だけでMAX_PRINT_KETA桁を超えてしまう時はE表示に変える
			nslog(@"整数だけで%d桁を超えてしまうのでE表示に変える:整数=1桁,小数=%d桁",MAX_PRINT_KETA,shousuu);
			shousuu=MAX_PRINT_KETA-1; // 整数桁に1桁使うので、小数はMAX_PRINT_KETA-1
			formatFlag|=USING_SISUU;
		}
	}
	
	// 数値の文字列化はここで行う
	nslog(@"d=%f/shousuu=%d",d,shousuu);
	int len=makeFloatString(d,1,shousuu,tmp1,tmp,formatFlag);
	nslog(@"tmp1=%s/tmp=%s/len=%d",tmp1,tmp,len);
	// 0 -> " 0"					len=2
	// 1 -> " 1.000000000000000"	len>2
	if (len>1+1) {
		// 後ろから連続する'0'を取り除く
		// Eが付く場合はその前
		// これでX-BASICと同じになる
		UByte *ep=NULL;
		if (tmp[len-5]=='E') {
			// E付きの時
			len-=5;
			ep=&tmp[len]; // Eの位置
			nslog(@"E付き:%s\n",ep);
		}
		len--; // EOSまたはEの1つ前から
		while (tmp[len]=='0') len--;
		if    (tmp[len]=='.') len--; // 小数点も消す
		// tmp[len]=小数点以下で0でない桁または整数第1位
		len++;
		if (ep!=NULL) {
			nslog(@"E以降をコピー:%p←%p\n",&tmp[len],ep);
			strcpy((char *)&tmp[len],(char *)ep);
			len+=5; // E+000
		} else {
			nslog(@"EOSを入れる\n");
			tmp[len]=EOS; // その後ろにEOSを入れる
		}
	} // len=2の時：実際には" 0"のときは何もしない
	return (len); // EOSの位置を返す
}

//--------------------------------------------------------------------------------------

//#define PR_DEBUG

// 指定整数桁.小数桁を持つ小数点文字列を作成する
// DBG_printfの%d.%dでは整数位桁数を指定できないのでややこしい処理をしている
// 2つの作業用ワークを必要とする
// 結果はtmp2に入る
// formatFlag : USING_BPLUS/USING_BPLUS2/USING_YEN/USING_ASTA/USING_ZERO/USING_APLUS/USING_AMINUS/USING_SISUUのみ処理する
// 現在using / makeNormalFloatStringから利用中
// リターン値 : strlen(tmp2)
int makeFloatString(double d,int seisuu,int shousuu,UByte *tmp,UByte *tmp2,UWord formatFlag)
{
	DBG_Func();
	nslog(@"%s",__FUNCTION__);
	nslog(@"%.15f : 整数%d桁,小数%d桁(補正前) : フォーマット指定=$%04x\n",d,seisuu,shousuu,formatFlag);
	// 整数桁はそれを超えるときはその分をすべて表示する。だから、桁あわせでなく単に表示したいときはseisuu=1で良い
	
	if (isnan(d)) { // 演算不可なとき (Not a Number)
		strcpy((char*)tmp2,STR_NaN);
	} else { // 演算可能なとき
		UByte *bp,*bp2,c,sp=' ';
		if (formatFlag&USING_ZERO) sp='0';
		if (formatFlag&USING_ASTA) sp='*'; // こっちの方が優先
		int e=0; // =0は警告回避のため

		// 指数形式で表現するかどうか
		if (formatFlag&USING_SISUU) {
			nslog(@"指数表現処理");
			// (1)桁指定文字列を作る;指数表現では整数1桁が必ず入る
			// (1-1)seisuu>0 && d>=1.0 : 123.45  → 1.2345E+002
			// (1-2)seisuu>0 && d< 1.0 : 0.12345 → 1.2345E-002
			if (seisuu <0) seisuu =0; // 念のため
			if (shousuu<0) shousuu=0; // 念のため
			int sketa;
			if (seisuu==0) { // 整数桁が0の時；特別
				sketa=0;
			} else {
				sketa=seisuu-1;
				if (!(formatFlag&(USING_AMINUS|USING_APLUS))) { // 後ろに符号を入れないとき
					sketa--; // 前に常に符号分が入る
				}
			}
			sprintf((char *)tmp2,"%%.%dE",shousuu+sketa);
			nslog(@"小数桁指定文字列:%s",tmp2);
			
			// (2)指数表現文字列化する
			sprintf((char *)tmp,(char *)tmp2,d);
			nslog(@"数値文字列:%s",tmp);
			
			// (3)指数を取り出す
			// E+0 E+00 E-000のパターンがある
			// 文字列最後2~4桁：±000	符号もあるので注意
			bp=(UByte *)strchr((char *)tmp,'E'); // Eのある位置を探す
			e=atoi((char *)bp+1); // Eの直後から
			nslog(@"指数=E%d",e);
			
			// (4)指数部を消して数値化する
			*bp=EOS;
			d=atod3(tmp,NULL,NULL);
			if (seisuu>=2) {
				// 整数部へ移動
				int i=sketa;
				while (i-->0) d*=10;
				e-=sketa; // 整数部へ移動した分減らす
			} else {
				if (seisuu==0) {
					// 小数部への移動
					d/=10;
					e++; // 小数部へ移動した分増やす
				}
				// seisuu=1のときは元のままなので何もしなくてよい
			}
			nslog(@"指数補正後 %"MAX_PRINT_KETAS"f : 整数%d桁.小数%d桁\n",d,seisuu,shousuu);
			// 以下同じ
		}
		
		/* ぺけ-BASICとX-BASIC/68で動作が異なる上に統一的な動作が見いだせないので、ここでは以下の通りで統一する。
			formatFlagに符号表示指定がない場合
				整数桁指定には符号分1桁を含む。従って、数字は1桁少なくなる。
			formatFlagに符号表示指定がある場合
				整数桁指定には符号分は含まない＝符号は符号指定に任せる。従って、数字は指定通りになる。
			後ろ符号指定がある場合は前には符号が入らない
			
			￥￥	数値の直前に￥を付加する
				前+があるときは、￥の前に表示する	+￥
				負数の時も同様					-￥
				￥￥分2桁が整数表示桁数に追加される
				
			英語モードの時は$$にする
		*/

		enum {
			PLUS=0,	// 負号なし
			BMINUS,	// 前に負号
			AMINUS,	// 後ろに負号
		};
		int fsign=PLUS;
		
		// 特殊なバグ発生への対処のため、一旦文字列化する
		// %f(.15%でも同じ)での表示は1.0なのに、内部表現が0.9999...のとき、sei=0,shou=0.999....となってしまい、以下で正しい処理されない
		// 1.0の内部表現には1.0000...も存在し、こちらは問題ない

		double sei;
		double shou;
		sprintf((char*)tmp,"%.15f",d); // 文字列化と有効表示桁への桁上げ
//		printf("文字列化=%s",tmp);
		int i=0;
		if (tmp[i]=='-') { // 負号がある
			i++;
			fsign=BMINUS;
			if (formatFlag&(USING_AMINUS|USING_APLUS)) fsign=AMINUS; // 後ろで符号をつけるとき
			printf("(負号あり)");
		}
//		printf("\n");
		// 一旦、整数+小数の全体を数値化する。これを小数に入れておく
#ifdef PR_DEBUG
		d=
#endif
		shou=atod3(&tmp[i], NULL,NULL); // 負号は消えている
		// 小数点を探す
		int j=i;
		while (c=tmp[j],c!='.' && c!=EOS) j++;
		if (c=='.') tmp[j]=EOS; // 小数があるときはそこで分離する
		sei=atod3(&tmp[i], NULL,NULL);
		// shouには整数部も含んでいるので、整数分を引くことで小数のみ取り出す
		shou-=sei;
#ifdef PR_DEBUG	// dのため
		printf("再合成数値=%.15f = %.15f + %.15f\n",d,sei,shou);
#endif
		//
		char sign_C='+';
		int fbplus=(formatFlag&(USING_BPLUS|USING_BPLUS2)); // 前に強制的に符号をつけるかどうか
		if (formatFlag&USING_BPLUS2) sign_C=' ';
#ifdef PR_DEBUG	// dのため
		nslog(@"%.15f(fsign=%d) : 整数%d桁,小数%d桁(補正後)",d,fsign,seisuu,shousuu);
#endif
		nslog(@"fbplus=%d",fbplus);
		//
		// shousuu=0のとき、整数桁への四捨五入を行う
		// ここだけは%fでは行なってくれないので
		if (shousuu==0) {
			if (shou>=0.5) {
				printf("shousuu=0 のとき、整数桁への四捨五入を行う:%f\n",shou);
				sei=sei+1.0;
				shou=0; // 念のため
			}
		}
		
		// 整数部を文字列化する
		bp=tmp2;
		*bp=EOS;
		if (seisuu>0) {
			nslog(@"整数桁あり:%d",seisuu);
			char *fmt="%.0f";
			if (formatFlag&USING_YEN) {
				fmt=(operationStatus.fenglish? "$%.0f":"\\%.0f");	// ￥￥は2つで1つの￥(本当は半角文字)。それはCの仕様
			}
			sprintf((char *)tmp,fmt,sei); // 小数以下は作らせない
			nslog(@"整数桁:%s(補正前)",tmp);
			int len=seisuu-(int)bstrlen(tmp);
			if (fbplus||fsign==BMINUS) len--; // 符号も入れるため
			while (len-->0) *bp++=sp; // 桁が足りないときは前にスペースを入れる
			if (fbplus) {
				nslog(@"前に符号あり");
				UByte sc=(fsign==BMINUS? '-':sign_C); // 入れる符号文字
				if (formatFlag&USING_ZERO) {
					// +%%のときは一番前に符号を入れる
					//   |=bp(tmp2)
					// 00+??という状態
					// +00??と入れ替える
					// |bp2
					// ||bp1=bp
					// 0+
					// +0
					UByte *bp2=bp-1,*bp1=bp;
					while (bp2>=tmp2) {
						*bp1=*bp2;
						bp1--;
						bp2--;
					}
					tmp2[0]=sc;
					bp++;
				} else {
					*bp++=sc;
				}
				fsign=PLUS; // BPLUS優先だから
			} else {
				nslog(@"前に符号なし");
				if (fsign==BMINUS) *bp++='-'; // 後ろで表示指定がないならここで入れる
			}
			bp2=tmp;
			while ((c=*bp2++)!=EOS) {
				if (c=='.') break; // 小数点が出てきても終了
				*bp++=c;
			}
			*bp=EOS;
			nslog(@"整数桁:%s(補正後)",tmp2);
		} else { 
			// 整数桁指定が0のとき
			nslog(@"整数桁なし");
			// 符号だけ処理する
			if (fbplus) {
				nslog(@"前に符号あり");
				*bp++=(fsign==BMINUS? '-':sign_C);
				fsign=PLUS; // BPLUS優先だから
			} else {
				nslog(@"前に符号なし");
				if (fsign==BMINUS) *bp++='-'; // 後ろで表示指定がないならここで入れる
			}
			if (formatFlag&USING_YEN) *bp++=(operationStatus.fenglish? '$':'\\');
			*bp=EOS;
			nslog(@"整数桁(なし):%s(補正後)",tmp2);
		}
		// tmp2に整数桁の文字列ができる
		
		// 小数部を文字列化する
		if (shousuu>0) {
			sprintf((char *)tmp,"%%.%df",shousuu); // 桁指定文字列を作る
			nslog(@"小数桁指定文字列:%s",tmp);
			sprintf((char *)bp,(char *)tmp,shou);
			nslog(@"小数桁:%s",bp);
			//				    |=bp
			// このままでは"整数0.小数点以下"となるため、0を消す
			bp2=bp+1;
			while ((*bp++=*bp2++)!=EOS);
			bp--; // EOS位置に戻す
		}
		nslog(@"後符号付け前全桁文字列:%s",tmp2);

		if (formatFlag&USING_SISUU) {
			// 指数表現だったときは、指数部を戻す
			if (e>=0) {
				sprintf((char *)bp,"E+%03d",e);
			} else {
				sprintf((char *)bp,"E-%03d",-e);
			}
			nslog(@"指数変更後数値:%s",tmp2);
			bp+=5; // 指数部文字数;これが指数指定^*5の桁数
		}
		
		if (formatFlag&(USING_AMINUS|USING_APLUS)) {
			if (fsign==AMINUS) {
				// 負数の場合"-"を最後尾に付加する
				*bp++='-';
			} else {
				// 正数の場合"+"または" "を最後尾に付加する
				*bp++=(formatFlag&USING_APLUS? '+':' ');
			}
		}
		*bp=EOS;
	}
	nslog(@"全桁文字列:%s\n",tmp2);
	return ((int)bstrlen(tmp2));
}

//--------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------

// どんなポインタもバイト単位で加算する
// リターン値は型キャストすること
void *pointerAdd(void *p,size_t size)
{
	// この関数の引数にする際に型キャストが行われるのでこれでいける
	// void * = char *
	return (p+size);
}

//--------------------------------------------------------------------------------------

// adrs1〜adrs2のオフセットを計算する
psize_t calcAdrsOffset(void *adrs1,void *adrs2)
{
	return (size_t)adrs1-(size_t)adrs2;
}

//--------------------------------------------------------------------------------------

// オフセットaddress書き込み .p単位
// wp=飛び先アドレス , adrs=現在アドレス
uwCODE *writeOfstAdrs(uwCODE *wp,uwCODE *adrs)
{
	DBG_Func();
//	nslog(@"wp=%p,adrs=%p",wp,adrs);
	
	psize_t p1=(psize_t)wp;
	psize_t p2=(psize_t)adrs;
	p2-=p1; // 書き込み位置からの相対位置に変換する
	DBG_printf3("*wp:%p<-相対:%d($%x)\n",wp,(int)p2,(int)p2);
	mmemcpy(wp, &p2, sizeof(psize_t));

	return (wp+withWord(SZ_VOIDP));	// 次のアドレスを返す
}

//--------------------------------------------------------------------------------------
// 中間コードの書き込み
//--------------------------------------------------------------------------------------

//#define	DISP_OFST
#ifdef DISP_OFST
// 相対アドレス表示の時
#define	iAdrs		calcAdrsOffset(internalCode.bp,internalCodeTop)
#define	wpAdrs(wp)	calcAdrsOffset(wp,internalCodeTop)
#else
// 絶対アドレス表示の時
#define	iAdrs		(internalCode.l)
#define	wpAdrs(wp)	((ULong)(wp))
#endif

// #defineで定義すると、code内容によっては2重参照になるので関数化


// .w用
void storeInternalCode(uwCODE code)
{
#ifdef DISP_OFST
	DBG_printf("internalCode.wp=%p",internalCode.wp); _f();
#endif
	DBG_printf("[$%08lx<-$%04x.w]\n",iAdrs,code); _f();
	
	*internalCode.wp++=code;
}

// .w用;オフセット位置指定可能
// ofstは.w単位
// ポインタは移動しない
void storeInternalCodeWithOffsetN(uwCODE code,int ofst)
{
	DBG_printf("[%p+%d",internalCode.wp,ofst);

	uwCODE *wp=internalCode.wp+ofst;

	DBG_printf("=%p<-$%04x.w]\n",wp,code); _f();
	
	*wp=code;
}

// .l用
void storeInternalCodeL(ULong ldata)
{
#ifdef DISP_OFST
	DBG_printf("internalCode.lp=%p",internalCode.lp); _f();
#endif
	DBG_printf("[$%08x<-$%08x.l]\n",(int)iAdrs,(int)ldata); _f();
	
#if AARM>=2
	storeLongToPointer(internalCode.lp, ldata);
#else
	*internalCode.lp=ldata;
#endif
	internalCode.lp++;
}

// .b用
void storeInternalCodeB(UByte c)
{
	// アドレス=内容
#ifdef DISP_OFST
	DBG_printf("internalCode.bp=%p",internalCode.bp); _f();
#endif
	DBG_printf("[$%08lx<-$%02x.b]\n",iAdrs,c); _f();
	
	*internalCode.bp++=c;
}


// .vp用
void storeInternalCodeP(void *p)
{
#ifdef DISP_OFST
	DBG_printf("internalCode.vp=%p",internalCode.vp); _f();
#endif
	DBG_printf("[$%08lx<-%p]\n",iAdrs,p); _f();
	
#if AARM>=2
	storeVoidPointerToPointer(internalCode.vp, &p);
#else
	*internalCode.vp=p;
#endif
	internalCode.vp++;
}

//--------------------------------------------------------------------------------------
// コード読み出し
//--------------------------------------------------------------------------------------

// .w;ポインター移動なし
uwCODE	_readInternalCodeN(void)
{
#ifdef DISP_OFST
	DBG_printf("internalCode.wp=%p",internalCode.wp); _f();
#endif
	DBG_printf("[$%08lx",iAdrs);
	
	uwCODE code=*internalCode.wp;
	
	DBG_printf(" → $%04x.w]\n",code); _f();
	
	// 中間コード出力付き
	fputCodeW(code);

	return (code);
}

// .w;ポインター移動あり
uwCODE	_readInternalCode(void)
{
	uwCODE code=_readInternalCodeN();
	internalCode.wp++;
	return (code);
}


// .l;ポインター移動なし
ULong	_readInternalCodeLN(void)
{
#ifdef DISP_OFST
	DBG_printf("internalCode.lp=%p",internalCode.lp); _f();
#endif
	DBG_printf("[$%08lx",iAdrs);
	
	ULong code=readLong(internalCode.lp);
	
	DBG_printf(" → $%08x.l]\n",(int)code); _f();
	
	// 中間コード出力付き
	fputCodeL(code);

	return (code);
}

// .l;ポインター移動あり
ULong	_readInternalCodeL(void)
{
	ULong code=_readInternalCodeLN();
	internalCode.lp++;
	return (code);
}


// .vp;ポインター移動なし
psize_t	_readInternalCodePN(void)
{
#ifdef DISP_OFST
	DBG_printf("internalCode.vp=%p",internalCode.vp); _f();
#endif
	DBG_printf("[$%08lx",iAdrs);
	
	psize_t ofst;
#if AARM>=2
	storeVoidPointerToPointer(&ofst,internalCode.vp);
#else
	ofst=*internalCode.vp;
#endif
	
	DBG_printf(" → $%zx]\n",ofst); _f();
	
	// 中間コード出力付き
	// 面倒なので省略

	return (ofst);
}


// 相対アドレス読みだして絶対アドレスに変換する
void readInternalAbsoluteAdrs(void)
{
	DBG_Func();
	DBG_printf1("internalCode=%p+",internalCode.wp);
	psize_t	ofst=readInternalCodePN();	// 相対アドレスを得る
	DBG_printf2("%zd($%zx)=",ofst,ofst);
	internalCode.bp+=ofst;
	DBG_printf1("%p\n",internalCode.wp);
}

//--------------------------------------------------------------------------------------
// デバッグ用
//--------------------------------------------------------------------------------------

#ifdef CORE_DEBUG

void DBG_printCode(uwCODE code)
{
//	DBG_printf("code=$%04x(%d)\n",code,code);	// 演算子は16進数、ステートメントは10進数で見た方がわかりやすい
	DBG_printf("code=$%04x\n",code);
	fflush(stdout);
}

void DBG_printName(UByte *name,swStrLEN len)
{
	DBG_printf("名前:");
	int i;
	for (i=0;i<len;i++) {
		int c=*name++;
		if (c>=' ') {
			switch (c) {
				case MULTI_STATEMENT3:
					c='{'; // 内部処理用マルチステートメント
					break;
				case MULTI_STATEMENT2:
					c=' '; // 内部処理用マルチステートメント
					break;
			}
			printf("%c",c);
//			fputc(c,stdout);
		} else {
			if (c==EOS) break;
			DBG_printf("<%02x>",c); // 制御コード時
		}
	}
	DBG_printf(" (長さ=%d)\n",i); // lenまたはEOSまでの長さ
	fflush(stdout);
}
#endif	// CORE_DEBUG

#if COMPILE_MODE!=2 // Distributionの時は外す
// デバッグ用；ただしDistribution時以外常時有効なので注意
void DBGprintName(UByte *name,swStrLEN len)
{
	printf("名前:");
	int i;
	for (i=0;i<len;i++) {
		int c=*name++;
		if (c>=' ') {
			switch (c) {
				case MULTI_STATEMENT3:
					c='{'; // 内部処理用マルチステートメント
					break;
				case MULTI_STATEMENT2:
					c=' '; // 内部処理用マルチステートメント
					break;
			}
			printf("%c",c);
//			fputc(c,stdout);
		} else {
			if (c==EOS) break;
			printf("<%02x>",c); // 制御コード時
		}
	}
	printf(" (長さ=%d)\n",i); // lenまたはEOSまでの長さ
	fflush(stdout);
}
#endif

#ifdef CORE_DEBUG

// ネスト内の全ダンプ
void DBG_dumpNest(void)
{
	DBG_printf("--ネスト内の全ダンプ--\n");
	NEST_WORK *now	 =nest_work;
//	DBG_printf("now =%p\n",now);
	UWord *wp=(UWord *)nestWorkHontai;
//	DBG_printf("top =%p\n",wp);
//	DBG_printf("next=%p\n",now->next);
	DBG_printf("-----------top\n");
	for (;wp<(UWord *)now->next;wp++) {
		if (wp==(UWord *)now) DBG_printf("-----------now\n");
		DBG_printf("%p=$%04x\n",wp,*wp);
	}
	DBG_printf("-----------now → next\n");
	_f();
}

//-----------------------------------------------
// ダンプ系

// ファイルにメモリ内容を落とす
// mode="w"/"a"
void DBG_dump2(char *fname,void *top,int size,char *mode)
{
	FILE *fp;
	fp=fopen(fname,mode);
	if (fp==NULL) {
		DBG_printf("file not make:%s\n",fname);
		return;
	}
	fwrite(top,size,1,fp);
	fclose(fp);
}

void DBG_dumpNames(void)
{
	char *fname="Variables";
	FILE *fp;
	fp=fopen(fname,"a");
	if (fp==NULL) {
		DBG_printf("file not make:%s\n",fname);
		return;
	}
	fputs("-----------------------------------------------\n",fp);
	int i;
	for (i=0;i<nameBufferCnt;i++) {
		UByte *buffer=nameBufferList[i]; // 先頭アドレス
		int size=ADD_NAME_BUFFER;
		if (i==nameBufferCnt-1) size=ADD_NAME_BUFFER-nameLeftSize; // 最終ブロックだけは一部だけ
		fwrite(buffer,size,1,fp);
	}
	fputs("\n",fp);
	fclose(fp);
}

#endif

//--------------------------------------------------------------------------------------

#if defined(INTERNAL_TRACE)||defined(DEBUG)
// 手抜きで86モードでしか動かない

FILE *infp=NULL;

void openFputCode(char *mes)
{
	nslog(@"%s",mes);
#ifdef INTERNAL_TRACE
	infp=fopen("/test/codeTrace"VERSION_CORE".txt","w");
	if (infp==NULL) {
		nslog(@"ファイルが作れません");
		exit(1);
	}
	fputs(mes,infp);
#endif
}

void closeFputCode(void)
{
#ifdef INTERNAL_TRACE
	fclose(infp);
#endif
}

void fputCodeW(uwCODE wp)
{
#ifdef INTERNAL_TRACE
	if (infp!=NULL) fprintf(infp,"$%04x\n",wp);
#endif
}

void fputCodeL(ULong lp)
{
#ifdef INTERNAL_TRACE
	if (infp!=NULL) fprintf(infp,"$%08x\n",(int)lp);
#endif
}

void fputFileLine(char *file,int line)
{
#ifdef INTERNAL_TRACE
	if (infp!=NULL) {
		char c;
		int i=(int)strlen(file);
		do {
			c=file[--i];
		} while (i>0 && c!='/');
		if (c=='/') i++;
		fprintf(infp,"%s(%d)\t",&file[i],line);
	}
#endif
}

// ファイル出力のみ
void fnslog2(char *str)
{
#ifdef INTERNAL_TRACE
	if (infp!=NULL) fprintf(infp,"%s\n",str);
#endif
}

// ファイル出力＋nslog
void fnslog(char *str)
{
	fnslog2(str);
//	nslog("%s",str);
	printf("%s\n",str);
}

FILE *getinfp(void)
{
#ifdef INTERNAL_TRACE
	return (infp);
#else
	return NULL;
#endif
}

#endif

//--------------------------------------------------------------------------------------
