//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	外部関数：標準関数
//
//--------------------------------------------------------------------------------------
// 外部関数の構造を持っている

#include "fdef.h"
#include "XBfunc.h"
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>	// rand()/srand()/random()/srandom()
#import "libs.h"

#include "support.h"
#include "code2code.h"
#import "malloc2.h"
#import "make_base.h"
#import "atod3.h"

//---------------------------------------------------------------------------------------------
// 共通ワーク

static UByte *tempBuff;		// 文字列作成領域
static const UByte nullStr[]={0};	// 空文字列

//---------------------------------------------------------------------------------------------
// 関数実体
//---------------------------------------------------------------------------------------------

// この外部関数のバージョンを返す
static RET_FUNC _F_version(SWord numFAC,FAC fac[])
{
	printFunc();
	fac[0].dl.cp[LL]=VERSION_XBFUNC;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// エラーの時はリターン値を!=0
// "UTF8"は、たぶんそのままUTF8文字列でも使える物
//---------------------------------------------------------------------------------------------
// 文字列関数
//---------------------------------------------------------------------------------------------

// strの中にて最初にcharの見つかった位置を返す。
// 先頭=0,見つからなかった=-1
// Cの同名関数とはリターン値が違う
// ASCII専用
static RET_FUNC _F_strchr(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str=fac[0].dl.bp[LL];
	UByte ch  =(UByte)fac[1].dl.l[LL];
	int len=0;
	UByte c;
	while ((c=*str++)!=EOS) {
		len++; // 先に+1、後で-1する
		if (c==ch) break;
	}
	if (c==EOS) len=0; // 見つからなかったとき；後で-1される
	// fac[]に入れて返す
	fac[0].dl.l[LL]=len-1; // 見つからなかった時は-1を返す
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// 文字列2中のどれか1文字が文字列1中に最初に出てきた位置を返す
// 先頭=0,見つからなかった時は文字列1の長さを返す
// 文字列2=NULLのときも文字列1の長さを返す
// 文字列1がNULLの時は0を返す
// 文字列2をASCIIコード範囲に収める限り"UTF8"
static RET_FUNC _F_strcspn(SWord numFAC,FAC fac[])
{
	printFunc();
	char *str1=fac[0].dl.cp[LL];
	char *str2=fac[1].dl.cp[LL];
	size_t sz=strcspn(str1,str2);
	// fac[]に入れて返す
	fac[0].dl.l[LL]=(ULong)sz;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// 文字列2中に含まれない文字が文字列1中に最初に出てきた位置を返す
// 先頭=0,見つからなかった時は文字列1の長さを返す
// 文字列1/2=NULLのときは0を返す
// 文字列2をASCIIコード範囲に収める限り"UTF8"
static RET_FUNC _F_strspn(SWord numFAC,FAC fac[])
{
	printFunc();
	char *str1=fac[0].dl.cp[LL];
	char *str2=fac[1].dl.cp[LL];
	size_t sz=strspn(str1,str2);
	// fac[]に入れて返す
	fac[0].dl.l[LL]=(ULong)sz;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//----------------------------------------------------------------------
// 以下の関数は文字列長が変わらないのでチェックなし

// 英大文字を小文字化する
// "UTF8"
static RET_FUNC _F_strlwr(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	UByte c;
	while ((c=*str1)!=0) {
		if (c>='A' && c<='Z') {
			*str1=(c+('a'-'A'));
		}
		str1++;
	}
	// リターン値は.bpで変化なし
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}


// 英大文字を大文字化する
// "UTF8"
static RET_FUNC _F_strupr(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	UByte c;
	while ((c=*str1)!=0) {
		if (c>='a' && c<='z') {
			*str1=(c-('a'-'A'));
		}
		str1++;
	}
	// リターン値は.bpで変化なし
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// 文字列の全ての文字をcにする
// ASCII専用
static RET_FUNC _F_strset(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=   fac[0].dl.bp[LL];
	UByte c=(UByte)fac[1].dl.l[LL];
	while (*str1!=0) {
		*str1++=c;
	}
	// リターン値は.bpで変化なし
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// 文字列のバイト並びを逆転する
// ASCII専用
static RET_FUNC _F_strrev(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	//
	// lenのとき
	// i=0～len/2
	// str1[i] ←→ str1[len-1-i]
	size_t len=bstrlen(str1); // size_t
	if (len>=2) {
		int i;
		for (i=0;i<len/2;i++) {
			UByte c=str1[i];
			str1[i]=str1[len-1-i];
			str1[len-1-i]=c;
		}
	}
	// リターン値は.bpで変化なし
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// 文字列の先頭n文字をcに変換する
// ASCII専用
static RET_FUNC _F_strnset(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte   *str1=		 fac[0].dl.bp[LL];
	UByte	    c=(UByte)fac[1].dl.l[LL];
	int	      len=(int)	 fac[2].dl.l[LL];
	while (len-->0) {
		if (*str1==EOS) break;
		*str1++=c;
	}
	// リターン値は.bpで変化なし
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// 文字列中で文字cが最後に見つかった位置を返す。
// 先頭=0,全く見つからない時は=-1
// ASCII専用
static RET_FUNC _F_strrchr(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=	   fac[0].dl.bp[LL];
	UByte     c=(UByte)fac[1].dl.l[LL];
	// EOSまで飛ばすと同時に長さを求める
	int len=0;
	while (*str1!=EOS) {
		len++;
		str1++;
	}
	// str1==EOSの位置
	// 後ろから前に探す
	while (--len>=0) {
		if (*--str1==c) break;
	}
	// fac[]に入れて返す
	fac[0].dl.l[LL]=len;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// str2に含まれるどれか1文字を区切り文字として、見付かれば先頭からその位置までの文字列を返す=文字列からトークンを取り出す
// 最初の呼び出し時はstr1の先頭に連続する、str2に含まれる文字があっても無視する。
// 続いてstr1を""にして実行すると、次にstr2に含まれる文字が見かるところまでの文字列を返す。
// str2に含まれる文字が見つからなくなると、""を返す。
// str2==""のときはstr1をそのまま返す。
// 文字列2をASCIIコード範囲に収める限り"UTF8"
static RET_FUNC _F_strtok(SWord numFAC,FAC fac[])
{
	printFunc();
	
	UByte *str1=fac[0].dl.bp[LL];
	if (str1[0]==EOS) str1=NULL; // 引数としてNULLは与えられないから
	UByte *str2=fac[1].dl.bp[LL];
	DBG_printf2("str1=%p,str2=%p\n",str1,str2);
	//
	// http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/strtok.3.html
	static UByte *saveptr;
	str1=(UByte *)strtok_r((char *)str1, (const char *)str2, (char **)&saveptr);
	if (str1==NULL) {
		str1=(UByte *)nullStr; // NULLの代わりに空文字列を返す
	}
	fac[0].dl.bp[LL]=str1;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// 文字コード判別関数
//---------------------------------------------------------------------------------------------
// "UTF8"

static RET_FUNC _F_isalnum(SWord numFAC,FAC fac[])
{
	int c=(int)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isalnum(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isalpha(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isalpha(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isascii(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isascii(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_iscntrl(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(iscntrl(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isdigit(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isdigit(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isgraph(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isgraph(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_islower(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(islower(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isprint(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isprint(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_ispunct(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(ispunct(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isspace(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isspace(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isupper(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isupper(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_isxdigit(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(isxdigit(c)? BASIC_YES:BASIC_NO);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//----------------------------------------------------------------------
// "UTF8"

static RET_FUNC _F_tolower(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=tolower(c);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_toupper(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=toupper(c);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_toascii(SWord numFAC,FAC fac[])
{
	int c=(UByte)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=toascii(c);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// ASCII文字列の先頭1文字のコードを返す
// ASCII専用
static RET_FUNC _F_asc(SWord numFAC,FAC fac[])
{
	UByte *str1=fac[0].dl.bp[LL];
	fac[0].dl.l[LL]=(int)*str1;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// 文字列のバイト数を返す(バイト数なので文字コードに関係しない)
static RET_FUNC _F_len(SWord numFAC,FAC fac[])
{
	UByte *str1=fac[0].dl.bp[LL];
	fac[0].dl.l[LL]=(ULong)bstrlen(str1); // size_t
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// 文字列操作関数
//---------------------------------------------------------------------------------------------

// 文字列str1中から文字列str2を探して左から何文字目にあるかを返す
RET_FUNC _F_instr(SWord numFAC,FAC fac[])
{
	printFunc();
	int i=(int)fac[0].dl.l[LL];
	UByte *str1=fac[1].dl.bp[LL];
	UByte *str2=fac[2].dl.bp[LL];
	//
	fac[0].dl.l[LL]=0; // とりあえず見つからないの印
	if (i>0 && *str1!=EOS && *str2!=EOS) {
		int len2=(int)bstrlen(str2);
		for (;i<(int)bstrlen(str1)-len2;i++) {
			if (memcmp((char *)&str1[i],(char *)str2,len2)==0) {
				// 見つかった
				fac[0].dl.l[LL]=i+1; // 位置は1～だから
				break;
			}
		}
	}
	//
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//--------
// 以下の関数ではできる文字列長は必ず元の文字列以下になるので長さチェックはしない

// ASCIIコード専用
// pos=0～len(str1)-1 : BASICの引数とは違うので注意
static UByte *mid(UByte *str1,int pos,int ln)
{
	if (ln<0) ln=operationStatus.sz_str-1; // 文字列長最大＝残り全部(EOSを含まない長さ)
	DBG_printf3("str=%s,pos=%d,ln=%d\n",str1,pos,ln);
	int i=0;
	if (pos>=0) {
		int len=(int)bstrlen(str1); // size_t
		if (pos<len) {
			str1+=pos;
			while (ln-->0) {
				if ((tempBuff[i++]=*str1++)==EOS) break;
			}
		} // pos>=lenのときはNULL
	} // pos<=0の時はNULLを返す
	tempBuff[i]=EOS;
	return (tempBuff);
}

static RET_FUNC _F_midS(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	int i1=(int)fac[1].dl.l[LL];
	int i2=(int)fac[2].dl.l[LL];
	//
	fac[0].dl.bp[LL]=mid(str1,i1-1,i2);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_leftS(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	int i1=(int)fac[1].dl.l[LL];
	//
	fac[0].dl.bp[LL]=mid(str1,0,i1);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_rightS(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	int i1     =(int)fac[1].dl.l[LL];
	//
	fac[0].dl.bp[LL]=mid(str1,(int)bstrlen(str1)-i1,i1);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//--------

static RET_FUNC _F_chrS(SWord numFAC,FAC fac[])
{
	printFunc();
	ULong c=fac[0].dl.l[LL];
	DBG_printf1("c=$%04x\n",(int)c);
	UByte *bp;
	if (fsjisInRun) {
		bp=storeSjis(tempBuff,c);
	} else {
		bp=storeUtf8(tempBuff,c);
	}
	*bp=EOS;
	if (bstrlen(tempBuff)>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	fac[0].dl.bp[LL]=tempBuff;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_binS(SWord numFAC,FAC fac[])
{
	printFunc();
	unsigned int i=(unsigned int)fac[0].dl.l[LL];
	//
	int p=make_base(i,tempBuff,2);
	if (bstrlen(tempBuff)>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	//
	fac[0].dl.bp[LL]=&tempBuff[p];
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_octS(SWord numFAC,FAC fac[])
{
	printFunc();
	unsigned int i=(unsigned int)fac[0].dl.l[LL];
	//
	int p=make_base(i,tempBuff,8);
	if (bstrlen(tempBuff)>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	//
	fac[0].dl.bp[LL]=&tempBuff[p];
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_hexS(SWord numFAC,FAC fac[])
{
	printFunc();
	unsigned int i=(unsigned int)fac[0].dl.l[LL];
	//
	int p=make_base(i,tempBuff,16);
	if (bstrlen(tempBuff)>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	//
	fac[0].dl.bp[LL]=&tempBuff[p];
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static void string(int i,UByte c)
{
	int j;
	for (j=0;j<i;j++) {
		tempBuff[j]=c;
	}
	tempBuff[j]=EOS;
}

// 文字コード事実上関係なし
static RET_FUNC _F_spaceS(SWord numFAC,FAC fac[])
{
	printFunc();
	int i=(int)fac[0].dl.l[LL]; // i<=0のときはNULLになる
	if (i>=operationStatus.sz_str-1) { // operationStatus.sz_strはEOSを含むサイズだから
		i=operationStatus.sz_str-1;
	}
	//
	string(i,' ');
	//
	fac[0].dl.bp[LL]=tempBuff;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// 文字列sの先頭1バイトを指定個数並べた文字列を作る
// ASCII(相当)専用
static RET_FUNC _F_stringS(SWord numFAC,FAC fac[])
{
	printFunc();
	int i=(int)fac[0].dl.l[LL]; // i<=0のときはNULLになる
	if (i>=operationStatus.sz_str-1) { // operationStatus.sz_strはEOSを含むサイズだから
		i=operationStatus.sz_str-1;
	}
	UByte *str1=fac[1].dl.bp[LL];
	string(i,*str1); // 1文字目
	//
	fac[0].dl.bp[LL]=tempBuff;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// バイト列で左右反転文字列を作る(文字列長は変わらない)
// ASCII(相当)専用
static RET_FUNC _F_mirrorS(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	//
	int i=0;
	size_t p=bstrlen(str1); // str1[p]=0
	while (p>0) {
		--p;
		tempBuff[i++]=str1[p];
	}
	tempBuff[i]=EOS;
	//
	fac[0].dl.bp[LL]=tempBuff;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// 数値←→文字列変換関数
//---------------------------------------------------------------------------------------------
// "UTF8"

// float型のデータを文字列に変換
static RET_FUNC _F_strS(SWord numFAC,FAC fac[])
{
	printFunc();
	double f=fac[0].dl.d;
	makeNormalFloatString(tempBuff,f);
	int i=0;
	if (f>=0) { // v3.5で修正
		if (tempBuff[0]==' ') i++;
	}
	fac[0].dl.bp[LL]=&tempBuff[i];
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// 文字列を浮動小数値に変換して返す
// &B、&H/0x、&O形式の整数文字列も変換できる
static RET_FUNC _F_atof(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	fac[0].dl.d=atod3(str1,NULL,NULL); // 正常変換できなくてもそのまま通す
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_itoa(SWord numFAC,FAC fac[])
{
	printFunc();
	int i=(int)fac[0].dl.l[LL];
	sprintf((char *)tempBuff,"%d",i);
	if (bstrlen(tempBuff)>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	fac[0].dl.bp[LL]=tempBuff;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_atoi(SWord numFAC,FAC fac[])
{
	printFunc();
	UByte *str1=fac[0].dl.bp[LL];
	double d;
	d=atod3(str1,NULL,NULL); // &?による進数指定を可能にするため、いったんatod3()で読ませる / 正常変換できなくてもそのまま通す
	fac[0].dl.l[LL]=(int)d;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_ecvt(SWord numFAC,FAC fac[])
{
	printFunc();
	double f=fac[0].dl.d;		// 数値
	int    i=(int)fac[1].dl.l[LL];	// 文字列の小数点以下の桁数を指定する
	int *ip1=fac[2].dl.ip[LL];	// 
	int *ip2=fac[3].dl.ip[LL];	// 符号(1=負数)
	fac[0].dl.cp[LL]=ecvt(f,i,ip1,ip2); // ecvt()は内部静的領域を使う
	// ecvt()はLIBCではすでに廃止対象なので、リンクができなくなったらX68-LIBCをリンクするか、廃止するしかない。
	if (bstrlen(fac[0].dl.cp[LL])>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_fcvt(SWord numFAC,FAC fac[])
{
	printFunc();
	double f=fac[0].dl.d;		// 数値
	int    i=(int)fac[1].dl.l[LL];	// 文字列の桁数を指定する
	int *ip1=fac[2].dl.ip[LL];	// 
	int *ip2=fac[3].dl.ip[LL];	// 符号(1=負数)
	fac[0].dl.cp[LL]=fcvt(f,i,ip1,ip2); // fcvt()は内部静的領域を使う
	// fcvt()はLIBCではすでに廃止対象なので、リンクができなくなったらX68-LIBCをリンクするか、廃止するしかない。
	if (bstrlen(fac[0].dl.cp[LL])>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_gcvt(SWord numFAC,FAC fac[])
{
	printFunc();
	double f=fac[0].dl.d;
	int    i=(int)fac[1].dl.l[LL];
	fac[0].dl.cp[LL]=gcvt(f,i,(char *)tempBuff);
	if (bstrlen(tempBuff)>=operationStatus.sz_str) {
		setExternalFuncErrmes("変換結果文字列が最大長を超えます","The conversion result string exceeds the maximum length.");
		return (RET_FUNC_ERR);
	}
	// gcvt()はLIBCではすでに廃止対象なので、リンクができなくなったらX68-LIBCをリンクするか、廃止するしかない。
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// 数値関数
//---------------------------------------------------------------------------------------------
// "UTF8"(というか、文字コード関係なし)

static RET_FUNC _F_abs(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"f=%.15f/abs(f)=%.15f",f,fabs(f));
	fac[0].dl.d=fabs(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_iabs(SWord numFAC,FAC fac[])
// iOS
{
	int i=(int)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(i<0? -i:i);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// iOS
static RET_FUNC _F_inc(SWord numFAC,FAC fac[])
{
	int *ip=fac[0].dl.ip[LL];
	int i=*ip;
	*ip=++i;
	fac[0].dl.l[LL]=i;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// iOS
static RET_FUNC _F_dec(SWord numFAC,FAC fac[])
{
	int *ip=fac[0].dl.ip[LL];
	int i=*ip;
	*ip=--i;
	fac[0].dl.l[LL]=i;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// 浮動小数fの小数点以下を切り捨てた値を返す
static RET_FUNC _F_fix(SWord numFAC,FAC fac[])
{
	double f1=fac[0].dl.d;
	double f2;
	double f=modf(f1,&f2); // f=小数部 , f2=整数部
	//
	fac[0].dl.d=(f1-f); // 小数部を引くことで整数部を得る
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// 浮動小数fの小数部を返す
// iOS
static RET_FUNC _F_modf(SWord numFAC,FAC fac[])
{
	double f1=fac[0].dl.d;
	double f2;
	fac[0].dl.d=modf(f1,&f2); // f=小数部 , f2=整数部
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_int(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	fac[0].dl.d=floor(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_sgn(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	DBG_printf1("_F_sgn\nfloat=%f\n",f);
	fac[0].dl.d=(f<0? -1.0:(f==0.0? 0.0:1.0));
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// iOS
static RET_FUNC _F_isgn(SWord numFAC,FAC fac[])
{
	int i=(int)fac[0].dl.l[LL];
	fac[0].dl.l[LL]=(i<0? -1:(i==0? 0:1));
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_sqr(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	if (f<0) {
		// エラー処理
		setExternalFuncErrmes(	"√に負数は使えません",
								"Negative number is not available to sqr().");
		return (RET_FUNC_ERR);
	}
	fac[0].dl.d=sqrt(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_pow(SWord numFAC,FAC fac[])
{
	double x=fac[0].dl.d;
	double y=fac[1].dl.d;

	// pow(x,y)
	// x=0 and y<0 error
	if (x==0 && y<0) {
		// エラー処理
		setExternalFuncErrmes(	"x=0かつy<0では使えません",
								"Can't use pow() with x=0 and y<0.");
		return (RET_FUNC_ERR);
	}
	if (x<0) {
		// x<0 and y!=整数 error
		double sei;
		if (modf(y,&sei)!=0) {
			// エラー処理
			setExternalFuncErrmes(	"x<0かつyが整数でない場合は使えません",
									"Can't use pow() with x<0 and y is not integer.");
			return (RET_FUNC_ERR);
		}
	}

	fac[0].dl.d=pow(x,y);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}


// iOS
static RET_FUNC _F_int6880(SWord numFAC,FAC fac[])
{
	LONG_WORD lb;
	lb.l=fac[0].dl.l[LL];
	//  68:H[0:1:2:3]L
	// ARM:H[3:2:1:0]L	86も同じ
	UByte b;
	b=lb.b[0]; lb.b[0]=lb.b[3]; lb.b[3]=b;
	b=lb.b[2]; lb.b[2]=lb.b[1]; lb.b[1]=b;
	//
	fac[0].dl.l[LL]=lb.l;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// iOS
static RET_FUNC _F_float6880(SWord numFAC,FAC fac[])
{
	LONG_WORD lbh; lbh.l=fac[0].dl.l[HW];
	LONG_WORD lbl; lbl.l=fac[0].dl.l[LW];
	
	//  68:H[0:1:2:3]L
	// ARM:H[3:2:1:0]L	86も同じ
	UByte b;
	b=lbh.b[0]; lbh.b[0]=lbh.b[3]; lbh.b[3]=b;
	b=lbh.b[2]; lbh.b[2]=lbh.b[1]; lbh.b[1]=b;
	b=lbl.b[0]; lbl.b[0]=lbl.b[3]; lbl.b[3]=b;
	b=lbl.b[2]; lbl.b[2]=lbl.b[1]; lbl.b[1]=b;
	//
	fac[0].dl.l[HW]=lbl.l;
	fac[0].dl.l[LW]=lbh.l;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//----------------------------------------------------------------------
// 対数

// 自然対数
static RET_FUNC _F_log(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	if (f<=0) {
		// エラー処理
		setExternalFuncErrmes(	"logにx<=0は使えません",
								"Zero or negative number is not available to log().");
		return (RET_FUNC_ERR);
	}
	fac[0].dl.d=log(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// 常用対数
static RET_FUNC _F_log10(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	if (f<=0) {
		// エラー処理
		setExternalFuncErrmes(	"log10にx<=0は使えません",
								"Zero or negative number is not available to log10().");
		return (RET_FUNC_ERR);
	}
	fac[0].dl.d=log10(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_exp(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	fac[0].dl.d=exp(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//----------------------------------------------------------------------
// 三角関数

static RET_FUNC _F_pi(SWord numFAC,FAC fac[])
{
	double f=1.0;
	if (fac[0].facType!=VOID_PARAM) { // 引数が省略されていない時
		f=fac[0].dl.d;
	}
	fac[0].dl.d=M_PI*f;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}


static RET_FUNC _F_sin(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"sin:f=%.15f,sin(f)=%.15e",f,sin(f));
	fac[0].dl.d=sin(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_cos(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	fac[0].dl.d=cos(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_tan(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"tan:f=%.15f,tan(f)=%.15e",f,tan(f));
	fac[0].dl.d=tan(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_atan(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	fac[0].dl.d=atan(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_asin(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"asin:f=%.15f,asin(f)=%.15e",f,asin(f));
	fac[0].dl.d=asin(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_acos(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"acos:f=%.15f,acos(f)=%.15e",f,acos(f));
	fac[0].dl.d=acos(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// atan()は元からある
// 以下iOS

static RET_FUNC _F_sinh(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"sinh=%.15f,sinh(f)=%.15e",f,sinh(f));
	fac[0].dl.d=sinh(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_cosh(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"cosh=%.15f,cosh(f)=%.15e",f,cosh(f));
	fac[0].dl.d=cosh(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_tanh(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"tanh=%.15f,tanh(f)=%.15e",f,tanh(f));
	fac[0].dl.d=tanh(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_asinh(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"asinh=%.15f,asinh(f)=%.15e",f,asinh(f));
	fac[0].dl.d=asinh(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_acosh(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"acosh=%.15f,acosh(f)=%.15e",f,acosh(f));
	fac[0].dl.d=acosh(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

static RET_FUNC _F_atanh(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"atanh=%.15f,atanh(f)=%.15e",f,atanh(f));
	fac[0].dl.d=atanh(f);
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// V2.1
static RET_FUNC _F_isnan(SWord numFAC,FAC fac[])
{
	double f=fac[0].dl.d;
	nslog(@"isnan:%f : isnan()=%d",f,isnan(f));
	fac[0].dl.l[LL]=c2basicYESNO(isnan(f));
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

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

// int rand([type;int])
// 0～2147483647の整数疑似乱数を発生する
// type : NO/省略 rand() , YES=random()
static RET_FUNC _F_rand(SWord numFAC,FAC fac[])
{
	int type=NO;
	if (fac[0].facType!=VOID_PARAM) { // 引数が省略されていない時
		type=basic2cYESNO(fac[0].dl.l[LL]);
	}
//	nslog(@"type=%d",type);
	fac[0].dl.l[LL]=(type? (int)random():rand()); // 整数乱数
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// float rnd([type;int])
// 0以上1未満の実数型乱数を返す
// type : NO/省略 rand() , YES=random()
static RET_FUNC _F_rnd(SWord numFAC,FAC fac[])
{
	int type=NO;
	if (fac[0].facType!=VOID_PARAM) { // 引数が省略されていない時
		type=basic2cYESNO(fac[0].dl.l[LL]);
	}
//	nslog(@"type=%d",type);
	double d=(type? (double)random():(double)rand());
	nslog(@"RAND_MAX=%d",RAND_MAX);
	d/=(double)(RAND_MAX);	// 32bitではLONG_MAXで良いが、64bitでは大きすぎるのでダメ。INT_MAXを使っていたが、LIBCの仕様書によるとRAND_MAXのほうが正しいらしい
	fac[0].dl.d=d; // 実数乱数
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// srand(seed;int)/randomize(seed;int)
//  seed = 0～2147483647
//	X68では-32768〜32767だった
static RET_FUNC _F_srand(SWord numFAC,FAC fac[])
{
	unsigned int seed=(int)fac[0].dl.l[LL];
	nslog(@"seed=%d",seed);
	srand(seed); 	// rand()の初期化
	srandom(seed);	// random()の初期化
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// ファイル名操作関数
//---------------------------------------------------------------------------------------------

// str lastPathComponent(path;str)
// iOS拡張 : UTF8
static RET_FUNC _F_lastPathComponent(SWord numFAC,FAC fac[])
{
	printFunc();
	char *cp=fac[0].dl.cp[LL];
	if (*cp==0) {
		nslog(@"このファイル名からは取り出しようがない");
		tempBuff[0]=0; // EOSのみ
	} else {
		NSString *fileext=[@(cp) lastPathComponent];
		if (bstrlen(nsStringTocString(fileext))>=operationStatus.sz_str) {
			setExternalFuncErrmes("ファイル名が文字列が最大長を超えます","The file name exceeds the maximum length.");
			return (RET_FUNC_ERR);
		}
		strcpy((char *)tempBuff,nsStringTocString(fileext));
	}
	fac[0].dl.bp[LL]=tempBuff;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// str pathExtension(path;str)
// iOS拡張 : UTF8
static RET_FUNC _F_pathExtension(SWord numFAC,FAC fac[])
{
	printFunc();
	char *cp=fac[0].dl.cp[LL];
	if (*cp==0) {
		nslog(@"このパス名からは取り出しようがない");
		tempBuff[0]=0; // EOSのみ
	} else {
		NSString *ext=[@(cp) pathExtension];
		if (bstrlen(nsStringTocString(ext))>=operationStatus.sz_str) {
			setExternalFuncErrmes("パス名が文字列が最大長を超えます","The path name exceeds the maximum length.");
			return (RET_FUNC_ERR);
		}
		strcpy((char *)tempBuff,nsStringTocString(ext));
	}
	fac[0].dl.bp[LL]=tempBuff;

	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// インフォメーションテーブル (5.2.1章)
//---------------------------------------------------------------------------------------------

// 関数名テーブル(トークンテーブル)
static const char *standardTokens[]={
	// ここでは引数の個数順にしているが、別にそうする必要はない
	// 0引数(+リターン値)
	"rand",
	"rnd",

	// 1引数(+リターン値)
	"pi",
	"abs",
	"fix",
	"modf",		// 追加
	"int",
	"sgn",
	"sin",
	"cos",
	"tan",
	"atan",
	"log",		// log e 自然対数
	"exp",
	"sqr",
	"val",
	"atof",
	"srand",
	"randomize",	// v2.4
	"itoa",
	"itoa$",	// 文字列変換なので$のも用意しておく
	"str$",
	"bin$",
	"chr$",
	"hex$",
	"oct$",
	"space$",
	"mirror$",
	"strlwr",
	"strupr",
	"strrev",
	"atoi",
	"asc",
	"len",		// =strlen
	"strlen",
	"isalnum",
	"isalpha",
	"isascii",
	"iscntrl",
	"isdigit",
	"isgraph",
	"islower",
	"isprint",
	"ispunct",
	"isspace",
	"isupper",
	"isxdigit",
	"tolower",
	"toupper",
	"toascii",

	// 2引数(+リターン値)
	"pow",
	"gcvt",
	"left$",
	"right$",
	"string$",
	"strtok",
	"strset",
	"strchr",
	"strrchr",
	"strcspn",
	"strspn",

	// 3引数(+リターン値)
	"mid$",
	"strnset",
	"instr",

	// 4引数(+リターン値)
	"ecvt",
	"fcvt",
	
	// iOS版追加
	"iabs"	,
	"isgn"	,
	"inc"	,
	"dec"	,
	"lastPathComponent",
	"pathExtension",
	// PC-1450からの追加
	"log10"	,	// log 10	常用対数
	"asin"	,	// arcsin
	"acos"	,	// arccos
	"sinh"	,	// 双曲線(Hyperbolic)
	"cosh"	,	// 双曲線
	"tanh"	,	// 双曲線
	"asinh"	,	// arc Hyperbolic
	"acosh"	,
	"atanh"	,
	// ↑ここまで
	"isnan"	,
	"int6880",
	"float6880",
	
	// バージョン
	"versionXBfunc$",
	// end of table
	NULL,
};

// 実行アドレステーブル
static FUNC_EXEC standardFuncExec[]={
	// Cの標準関数名と重複させないよう_F_を付ける
	{_F_rand	},
	{_F_rnd	},

	// 1引数(+リターン値)
	{_F_pi		},
	{_F_abs		},
	{_F_fix		},
	{_F_modf	},	// 追加
	{_F_int		},
	{_F_sgn		},
	{_F_sin		},
	{_F_cos		},
	{_F_tan		},
	{_F_atan	},
	{_F_log		},
	{_F_exp		},
	{_F_sqr		},
	{_F_atof	},	// val()
	{_F_atof	},
	{_F_srand	},
	{_F_srand	},	// randomize()	V2.4
	{_F_itoa	},
	{_F_itoa	},	// itoa$()
	{_F_strS	},
	{_F_binS	},
	{_F_chrS	},
	{_F_hexS	},
	{_F_octS	},
	{_F_spaceS	},
	{_F_mirrorS	},
	{_F_strlwr	},
	{_F_strupr	},
	{_F_strrev	},
	{_F_atoi	},
	{_F_asc		},
	{_F_len		},
	{_F_len		},
	{_F_isalnum	},
	{_F_isalpha	},
	{_F_isascii	},
	{_F_iscntrl	},
	{_F_isdigit	},
	{_F_isgraph	},
	{_F_islower	},
	{_F_isprint	},
	{_F_ispunct	},
	{_F_isspace	},
	{_F_isupper	},
	{_F_isxdigit},
	{_F_tolower	},
	{_F_toupper	},
	{_F_toascii	},

	// 2引数(+リターン値)
	{_F_pow		},
	{_F_gcvt	},
	{_F_leftS	},
	{_F_rightS	},
	{_F_stringS	},
	{_F_strtok	},
	{_F_strset	},
	{_F_strchr	},
	{_F_strrchr	},
	{_F_strcspn	},
	{_F_strspn	},

	// 3引数(+リターン値)
	{_F_midS	},
	{_F_strnset	},
	{_F_instr	},

	// 4引数(+リターン値)
	{_F_ecvt	},
	{_F_fcvt	},

	// iOS版追加
	{_F_iabs	},
	{_F_isgn	},
	{_F_inc		},
	{_F_dec		},
	{_F_lastPathComponent},
	{_F_pathExtension},
	//
	{_F_log10	},	// log 10	常用対数
	{_F_asin	},	// arcsin
	{_F_acos	},	// arccos
	{_F_sinh	},	// 双曲線(Hyperbolic)
	{_F_cosh	},	// 双曲線
	{_F_tanh	},	// 双曲線
	{_F_asinh	},	// arc Hyperbolic
	{_F_acosh	},
	{_F_atanh	},
	//
	{_F_isnan	},
	{_F_int6880	},
	{_F_float6880},
	
	// バージョン
	{_F_version},
	// end of table
	{NULL},
};

//------------------------------
// パラメーターテーブル
// (1)種類別定義
// 1関数の引数は最大MAX_PARAM個

//------------------------------
// float 返り値
static const uwPARAMTYPE p_pi[]={
	FLOAT_OMT,
	FLOAT_RET,
};

static const uwPARAMTYPE p_pow[]={
	FLOAT_VAL,
	FLOAT_VAL,
	FLOAT_RET,
};

static const uwPARAMTYPE p_modf[]={
	FLOAT_VAL,
	FLOAT_RET,
};

static const uwPARAMTYPE p_abs[]={
	FLOAT_VAL,
	FLOAT_RET,
};
// 同じ引数の物は#define定義しておく
#define	p_fix	p_abs
#define	p_sgn	p_abs
#define	p_sin	p_abs
#define	p_cos	p_abs
#define	p_tan	p_abs
#define	p_atan	p_abs
#define	p_log	p_abs
#define	p_exp	p_abs
#define	p_sqr	p_abs
#define	p_int	p_abs
#define	p_log10	p_abs
#define	p_sinh	p_abs
#define	p_cosh	p_abs
#define	p_tanh	p_abs
#define	p_asin	p_abs
#define	p_acos	p_abs
#define	p_asinh	p_abs
#define	p_acosh	p_abs
#define	p_atanh	p_abs

static const uwPARAMTYPE p_rnd[]={
	INT_OMT,
	FLOAT_RET,
};

static const uwPARAMTYPE p_atof[]={
	STR_VAL,
	FLOAT_RET,
};
#define	p_val	p_atof

//------------------------------
// int 返り値

static const uwPARAMTYPE p_rand[]={
	INT_OMT,
	INT_RET,
};

static const uwPARAMTYPE p_instr[]={
	INT_VAL,
	STR_VAL,
	STR_VAL,
	INT_RET,
};

static const uwPARAMTYPE p_strcspn[]={
	STR_VAL,
	STR_VAL,
	INT_RET,
};
#define	p_strspn	p_strcspn

static const uwPARAMTYPE p_asc[]={
	STR_VAL,
	INT_RET,
};
#define	p_len	p_asc
#define	p_atoi	p_asc

static const uwPARAMTYPE p_strchr[]={
	STR_VAL,
	CHAR_VAL,
	INT_RET,
};
#define	p_strrchr	p_strchr

static const uwPARAMTYPE p_isalnum[]={
	INT_VAL,
	INT_RET,
};
#define	p_isalpha	p_isalnum
#define	p_isascii	p_isalnum
#define	p_iscntrl	p_isalnum
#define	p_isdigit	p_isalnum
#define	p_isgraph	p_isalnum
#define	p_islower	p_isalnum
#define	p_isprint	p_isalnum
#define	p_ispunct	p_isalnum
#define	p_isspace	p_isalnum
#define	p_isupper	p_isalnum
#define	p_isxdigit	p_isalnum
#define	p_tolower	p_isalnum
#define	p_toupper	p_isalnum
#define p_toascii	p_isalnum

static const uwPARAMTYPE p_iabs[]={
	INT_VAL,
	INT_RET,
};
#define	p_isgn	p_iabs

static const uwPARAMTYPE p_inc[]={
	INT_VP,
	INT_RET,
};
#define	p_dec	p_inc

static const uwPARAMTYPE p_isnan[]={
	FLOAT_VAL,
	INT_RET,
};

static const uwPARAMTYPE p_int6880[]={
	INT_VAL,
	INT_RET,
};

static const uwPARAMTYPE p_float6880[]={
	FLOAT_VAL,
	FLOAT_RET,
};

//------------------------------
// str 返り値

static const uwPARAMTYPE p_leftS[]={
	STR_VAL,
	INT_VAL,
	STR_RET,
};
#define	p_rightS	p_leftS

static const uwPARAMTYPE p_binS[]={
	INT_VAL,
	STR_RET,
};
#define	p_octS		p_binS
#define	p_hexS		p_binS
#define	p_spaceS	p_binS
#define	p_itoa		p_binS
#define	p_itoaS		p_itoa

static const uwPARAMTYPE p_midS[]={
	STR_VAL,
	INT_VAL,
	INT_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_gcvt[]={
	FLOAT_VAL,
	INT_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_strnset[]={
	STR_VP,
	CHAR_VAL,
	INT_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_ecvt[]={
	FLOAT_VAL,
	INT_VAL,
	INT_VP,
	INT_VP,
	STR_RET,
};
#define	p_fcvt	p_ecvt

static const uwPARAMTYPE p_strS[]={
	FLOAT_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_strtok[]={
	STR_VAL,
	STR_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_stringS[]={
	INT_VAL,
	STR_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_mirrorS[]={
	STR_VAL,
	STR_RET,
};
#define p_lastPathComponent	p_mirrorS
#define p_pathExtension		p_mirrorS

static const uwPARAMTYPE p_strlwr[]={
	STR_VP,
	STR_RET,
};
#define	p_strupr	p_strlwr
#define	p_strrev	p_strlwr

static const uwPARAMTYPE p_strset[]={
	STR_VP,
	CHAR_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_chrS[]={
	INT_VAL,
	STR_RET,
};

static const uwPARAMTYPE p_srand[]={
	INT_VAL,
	VOID_RET,
};
#define p_randomize	p_srand

static const uwPARAMTYPE p_version[]={
	STR_RET,
};

//------------------------------
// パラメーターテーブル
// (2)関数別定義

const
uwPARAMTYPE *standardParams[]={
	p_rand		,
	p_rnd		,

	// 1引数(+リターン値)
	p_pi		,
	p_abs		,
	p_fix		,
	p_modf		,	// 追加
	p_int		,
	p_sgn		,
	p_sin		,
	p_cos		,
	p_tan		,
	p_atan		,
	p_log		,
	p_exp		,
	p_sqr		,
	p_val		,
	p_atof		,
	p_srand		,
	p_randomize	,	// randomize V2.4
	p_itoa		,
	p_itoaS		,
	p_strS		,
	p_binS		,
	p_chrS		,
	p_hexS		,
	p_octS		,
	p_spaceS	,
	p_mirrorS	,
	p_strlwr	,
	p_strupr	,
	p_strrev	,
	p_atoi		,
	p_asc		,
	p_len		,
	p_len		,
	p_isalnum	,
	p_isalpha	,
	p_isascii	,
	p_iscntrl	,
	p_isdigit	,
	p_isgraph	,
	p_islower	,
	p_isprint	,
	p_ispunct	,
	p_isspace	,
	p_isupper	,
	p_isxdigit	,
	p_tolower	,
	p_toupper	,
	p_toascii	,

	// 2引数(+リターン値)
	p_pow		,
	p_gcvt		,
	p_leftS		,
	p_rightS	,
	p_stringS	,
	p_strtok	,
	p_strset	,
	p_strchr	,
	p_strrchr	,
	p_strcspn	,
	p_strspn	,

	// 3引数(+リターン値)
	p_midS		,
	p_strnset	,
	p_instr		,

	// 4引数(+リターン値)
	p_ecvt		,
	p_fcvt		,
	
	// iOS版追加
	p_iabs		,
	p_isgn		,
	p_inc		,
	p_dec		,
	p_lastPathComponent,
	p_pathExtension,
	//
	p_log10		,	// log 10	常用対数
	p_asin		,	// arcsin
	p_acos		,	// arccos
	p_sinh		,	// 双曲線(Hyperbolic)
	p_cosh		,	// 双曲線
	p_tanh		,	// 双曲線
	p_asinh		,	// arc Hyperbolic
	p_acosh		,
	p_atanh		,
	//
	p_isnan		,
	p_int6880	,
	p_float6880	,
	
	// バージョン
	p_version	,
	// end of table
	NULL,
};

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

// この中の関数の初期化処理
static void _Finit(void)
{
	printFunc();
	nslog(@"Finit");

	// 本来operationStatus.sz_strだけ確保すれば良さそうに思えるが、
	// 文字列変換の途中には最大3倍になる可能性があるため、*3確保する。
	// (ASC->UTF8変換で、UTF8は１文字３バイトがありえるから)
	// 変換結果のバイト数がoperationStatus.sz_strを超えるときは、改めてエラーを出す
	int sz=operationStatus.sz_str*3;
	if (sz<256) sz=256; // 数字の文字列化にも使うので、一定サイズ以下にはしない。
	nslog(@"%@:%s",@(__FILE__),__FUNCTION__);
	tempBuff=malloc2(sz);
	if (tempBuff==NULL) {
		// エラーが発生したときはerrorNoにエラーコードを入れて返す
		// 規定コードに該当する物がないときはERR_IN_EXTERNAL_FUNCTIONにする
		errorNo=ERR_NO_WORKAREA; // メモリー不足
	}
}

static void _Frun(void)
{
	printFunc();
}

static void _Fend(void)
{
	printFunc();
}

// この中の関数の終了処理
static void _Fexit(void)
{
	printFunc();
	free2(tempBuff);
}

static void _Fbreak(void)
{
	printFunc();
	nslog(@"Fbreak");
}

// インフォメーションテーブル
const
INFORMATION_TABLE	InfoStandardFuncs={
	#ifdef FUNC_DEBUG
	"Standard functions",	//"標準関数群",
	#endif
	_Finit,		// Finit
	_Frun,		// Frun
	_Fend,		// Fend
	_Fexit,		// Fexit
	_Fbreak,	// Fbreak
	NULL,		// FctrlD;未使用
	NULL,		// 予約1
	NULL,		// 予約2
	//
	standardTokens,
	standardParams,
	standardFuncExec
};

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