/*
 *	app.c
 *
 *	dSnrSeqS.exe - シナリオシーケンサシミュレータ
 *	Copyright (C) 2017-2018 Naoyuki Sawa
 *
 *	* Sun Nov 05 23:33:59 JST 2017 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Nov 07 23:58:59 JST 2017 Naoyuki Sawa
 *	- 一時フォルダの取得に、GetTempPath()を使うのをやめて、TMP,又は,TEMP環境変数を直接参照するように変更しました。
 *	  そうした理由は、GetTempPath()はWindowsフォルダを返す可能性が有るからです。
 *	  □参照資料:「Windows Dev Center - GetTempPath function」(https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx)
 *	  │Remarks
 *	  │The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:
 *	  │1. The path specified by the TMP environment variable.
 *	  │2. The path specified by the TEMP environment variable.
 *	  │3. The path specified by the USERPROFILE environment variable.
 *	  │4. The Windows directory.	←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←注目!!
 *	  なぜGetTempPath()がWindowsフォルダを返すような仕様になっているのか不明ですが、実際に試してみた所確かにこういう動作になっているようです。
 *	  具体的には、TMP,TEMP,USERPROFILE環境変数を未定義にしてGetTempPath()を実行すると、"C:\WINDOWS\"が返されました。
 *	  GetTempPath()を信用すると、Windowsフォルダ内に一時ファイル内にゴミファイルが増えてしまう恐れがあり、良くありません。
 *	  そこで、GetTempPath()を使うのをやめて、TMP,又は,TEMP環境変数を直接参照して、一時フォルダを取得する事にしました。
 *	  尚、USERPROFILE("C:\Users\ユーザー名\")も一時フォルダとして適切ではないと思うので、USERPROFILEも参照しない事にしました。
 *	  TMPもTEMPもUSERPROFILEも定義されていない場合は、カレントフォルダを使用する事にしました。
 *	* Thu Nov 09 23:57:54 JST 2017 Naoyuki Sawa
 *	- エラー処理を強化しました。
 *	  これまでは、エラー発生時に即、DIE()で終了していたのですが、Tclスクリプトのエラーが調査し辛い問題が有りました。
 *	  そこで、極力、Tclのエラーとして通知するように変更しました。
 *	  Tclスクリプト内でcatch命令を使って捕捉する事も出来ますし、捕捉しない場合でもこれまでよりも判り易いエラーメッセージを表示して終了します。
 *	* Tue Nov 14 23:59:59 JST 2017 Naoyuki Sawa
 *	- /clip/cliptcl.c モジュールを更新した事に伴い、当ツールもリビルドしました。
 *	  当ツールのソースは、変更していません。
 *	  詳細は、/clip/cliptcl.c モジュールの、同日のコメントを参照して下さい。
 *	* Thu Nov 16 23:42:50 JST 2017 Naoyuki Sawa
 *	- /clip/cliptcl.c モジュールを更新した事に伴い、当ツールもリビルドしました。
 *	  当ツールのソースは、変更していません。
 *	  詳細は、/clip/cliptcl.c モジュールの、同日のコメントを参照して下さい。
 *	* Sat Nov 18 23:37:58 JST 2017 Naoyuki Sawa
 *	- /clip/cliptcl.c モジュールを更新した事に伴い、当ツールもリビルドしました。
 *	  当ツールのソースは、変更していません。
 *	  詳細は、/clip/cliptcl.c モジュールの、同日のコメントを参照して下さい。
 *	* Sun Nov 19 22:01:55 JST 2017 Naoyuki Sawa
 *	- /clip/cliptcl.c モジュールを更新した事に伴い、当ツールもリビルドしました。
 *	  当ツールのソースは、変更していません。
 *	  詳細は、/clip/cliptcl.c モジュールの、同日のコメントを参照して下さい。
 *	* Tue Nov 21 23:59:59 JST 2017 Naoyuki Sawa
 *	- /clip/clipsnrs.c モジュールを更新した事に伴い、当ツールもリビルドしました。
 *	  当ツールのソースは、変更していません。
 *	  詳細は、/clip/clipsnrs.c モジュールの、同日のコメントを参照して下さい。
 *	* Sat Nov 25 23:56:03 JST 2017 Naoyuki Sawa
 *	- '-q'オプションを追加しました。
 *	* Sat Apr 07 23:59:59 JST 2018 Naoyuki Sawa
 *	- 'blob_read_ber'コマンドを追加しました。
 *	* Thu May 03 23:59:59 JST 2018 Naoyuki Sawa
 *	- Boehm GCを修正した事に伴い、当ツールもリビルドしました。
 *	  詳細は、/clip/tool/gc/README.TXTの'Wed May 02 23:59:59 JST 2018 Naoyuki Sawa'のコメントを参照して下さい。
 */
#include "app.h"
#define VERSION		"20180503"	//最終更新日
#include "app.h"
/****************************************************************************
 *	ローカル関数宣言
 ****************************************************************************/
static int SehErrMsg();
static void CheckArgc(int n);
static int GetInt(const char* s, int lo, int hi);
static int GetSnrTblNo(const char* pTableName);
static int GetTrigNo(const char* pTrigName);
static const char* GetFuncName(int iSnrFnc);
/*--------------------------------------------------------------------------*/
static int AddressList_CompareFunc(const void* pAddress, const char* pName);
static char* AddressList_Register(void* pAddress);
static void* AddressList_Lookup(char* pName);
static void AddressList_Unregister(void* pAddress);
/*--------------------------------------------------------------------------*/
static int fnSnrSeq(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs);
/*--------------------------------------------------------------------------*/
static int SnrSeq_NewCmd(Tcl_Interp* iPtr);
static int SnrSeq_InitCmd(Tcl_Interp* iPtr);
static int SnrSeq_FreeCmd(Tcl_Interp* iPtr);
static int SnrSeq_ExecCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_ExecCmd(Tcl_Interp* iPtr);
static int SnrSeq_ClrTblCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_SetTblCmd(Tcl_Interp* iPtr);
static int SnrSeq_SendTrigCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_SendTrigCmd(Tcl_Interp* iPtr);
static int SnrSeq_UnlockCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_UnlockCmd(Tcl_Interp* iPtr);
static int SnrSeq_StopCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_StopCmd(Tcl_Interp* iPtr);
static int SnrSeq_GetStatCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_GetStatCmd(Tcl_Interp* iPtr);
static int SnrSeqCh_SetTblNoCmd(Tcl_Interp* iPtr);
/*--------------------------------------------------------------------------*/
static int blob_reader_initCmd(Tcl_Interp* iPtr);
static int blob_read_bitCmd(Tcl_Interp* iPtr);
static int blob_read_byteCmd(Tcl_Interp* iPtr);
static int blob_read_halfCmd(Tcl_Interp* iPtr);
static int blob_read_exp10Cmd(Tcl_Interp* iPtr);
static int blob_read_wordCmd(Tcl_Interp* iPtr);
static int blob_read_berCmd(Tcl_Interp* iPtr);		//{{2018/04/07追加:'blob_read_ber'コマンドを追加しました。}}
static int blob_read_fp16Cmd(Tcl_Interp* iPtr);
static int blob_read_fp32Cmd(Tcl_Interp* iPtr);
static int blob_read_fp64Cmd(Tcl_Interp* iPtr);
static int blob_read_stringCmd(Tcl_Interp* iPtr);
static int blob_read_dataCmd(Tcl_Interp* iPtr);
static int blob_copy_dataCmd(Tcl_Interp* iPtr);
static int blob_reader_get_bitsCmd(Tcl_Interp* iPtr);	//フィールドアクセス用
static int blob_reader_get_posCmd(Tcl_Interp* iPtr);	//フィールドアクセス用
static int blob_reader_set_posCmd(Tcl_Interp* iPtr);	//フィールドアクセス用
/****************************************************************************
 *	main
 ****************************************************************************/
int main(int argc, char* argv[]) {
	int exitCode = EXIT_SUCCESS;
#ifdef  _DEBUG
	remove("syslog.out");			//毎回ログを削除する事にした。
    #ifndef USE_JOB_DEBUG
	openlog(NULL, LOG_PERROR, LOG_USER);	//デバッグビルドでは、システムログを標準エラーにも出力する。ただし、デバッグジョブを使用する場合は、デバッグジョブのcurses表示と衝突しないよう、標準エラーには出力しない。
    #endif//USE_JOB_DEBUG
#else //_DEBUG
	setlogmask(LOG_UPTO(LOG_INFO));		//リリースビルドでは、LOG_DEBUGを抑制する。
#endif//_DEBUG
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
//	putenv("GC_LOG_FILE=CON");//ログ出力先を指定する。
//	GC_set_find_leak(1);//メモリリーク検出を開始する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
#ifdef  __CLIP_SEH_H__
	SEH_init();
#endif//__CLIP_SEH_H__
	app_init(argc, argv);
	exitCode = app_main(argc, argv);
	app_exit();
#if     (defined(GC_H) && !defined(USE_BISON_FLEX))
//	CHECK_LEAKS();//メモリリークを検出する。
#endif//(defined(GC_H) && !defined(USE_BISON_FLEX))
	return exitCode;
}
/****************************************************************************
 *	usage
 ****************************************************************************/
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dSnrSeqS.exe - シナリオシーケンサシミュレータ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2017-2018 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "OPTIONS:\n");
	fprintf(stderr, "  -q  進捗表示を抑制します。\n");
	fprintf(stderr, "  -h  使い方を表示します。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  ①dSnrSeqS.exe シナリオファイル.bin ドライバファイル.tcl [引数 ...]\n");
	fprintf(stderr, "    'シナリオファイル.bin'を読み込み、ドライバファイル.tclで実行します。\n");
	fprintf(stderr, "  ②dSnrSeqS.exe シナリオファイル.txt ドライバファイル.tcl [引数 ...]\n");
	fprintf(stderr, "    'シナリオファイル.txt'を変換し、'シナリオファイル.bin'を生成します。\n");
	fprintf(stderr, "    'シナリオファイル.bin'を読み込み、ドライバファイル.tclで実行します。\n");
	fprintf(stderr, "  ※シナリオファイルの拡張子が'.bin'以外ならば全て、②の動作となります。\n");
	exit(EXIT_FAILURE);
}
/****************************************************************************
 *	
 ****************************************************************************/
void app_init(int argc, char* argv[]) {
//{{アプリケーション特有の処理
	{
#if 0
		seed = GetTickCount();
		srand(seed);
		srand48(seed);
		WELL_init(&well, seed);
#endif
		//Tclインタプリタを作成する。
		iPtr = Tcl_CreateInterp();
//{{必要に応じて、ここでアプリケーション特有のTcl_CreateCommand()を行ってください。
		Tcl_CreateCommand(iPtr	,"SnrSeq_New"		,SnrSeq_NewCmd		,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_Init"		,SnrSeq_InitCmd		,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_Free"		,SnrSeq_FreeCmd		,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_Exec"		,SnrSeq_ExecCmd		,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_Exec"	,SnrSeqCh_ExecCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_ClrTbl"	,SnrSeq_ClrTblCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_SetTbl"	,SnrSeqCh_SetTblCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_SendTrig"	,SnrSeq_SendTrigCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_SendTrig"	,SnrSeqCh_SendTrigCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_Unlock"	,SnrSeq_UnlockCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_Unlock"	,SnrSeqCh_UnlockCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_Stop"		,SnrSeq_StopCmd		,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_Stop"	,SnrSeqCh_StopCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeq_GetStat"	,SnrSeq_GetStatCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_GetStat"	,SnrSeqCh_GetStatCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"SnrSeqCh_SetTblNo"	,SnrSeqCh_SetTblNoCmd	,NULL);
		/*--------------------------------------------------------------------------*/
		Tcl_CreateCommand(iPtr	,"blob_reader_init"	,blob_reader_initCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_bit"	,blob_read_bitCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_byte"	,blob_read_byteCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_half"	,blob_read_halfCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_exp10"	,blob_read_exp10Cmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_word"	,blob_read_wordCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_ber"	,blob_read_berCmd	,NULL);	//{{2018/04/07追加:'blob_read_ber'コマンドを追加しました。}}
		Tcl_CreateCommand(iPtr	,"blob_read_fp16"	,blob_read_fp16Cmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_fp32"	,blob_read_fp32Cmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_fp64"	,blob_read_fp64Cmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_string"	,blob_read_stringCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_read_data"	,blob_read_dataCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_copy_data"	,blob_copy_dataCmd	,NULL);
		Tcl_CreateCommand(iPtr	,"blob_reader_get_bits"	,blob_reader_get_bitsCmd,NULL);	//フィールドアクセス用
		Tcl_CreateCommand(iPtr	,"blob_reader_get_pos"	,blob_reader_get_posCmd	,NULL);	//フィールドアクセス用
		Tcl_CreateCommand(iPtr	,"blob_reader_set_pos"	,blob_reader_set_posCmd	,NULL);	//フィールドアクセス用
//}}必要に応じて、ここでアプリケーション特有のTcl_CreateCommand()を行ってください。
	}
//}}アプリケーション特有の処理
}
/*--------------------------------------------------------------------------*/
void app_exit() {
//{{アプリケーション特有の処理
	{
		//※TODO:
	}
//}}アプリケーション特有の処理
}
/*--------------------------------------------------------------------------*/
int app_main(int argc, char* argv[]) {
	int retCode;
	int opt_q = 0;
	{
		int opt;
		opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
		while((opt = getopt(argc, argv, "eqh")) != -1) {	//コマンドラインオプションを処理する。
			switch(opt) {
			case 'q':
				opt_q = 1;
				break;
			case 'h':
			default:
				usage();
			}
		}
		if((optind + 1/*snrFname*/ + 1/*tclFname*/) > argc) { usage(); }
	}
	{
		char* snrFname = argv[optind++];
		{
			char fname[_MAX_FNAME], ext[_MAX_EXT];
			splitpath(snrFname, NULL, NULL, fname, ext);
			if(strcasecmp(ext, ".bin")) {
//{{2017/11/07変更:一時フォルダの取得に、GetTempPath()を使うのをやめて、TMP,又は,TEMP環境変数を直接参照するように変更しました。
//				char dir[_MAX_DIR], *binFname;
//				if(!GetTempPath(sizeof dir, dir)) { DIE(); }
//↓2017/11/07変更:一時フォルダの取得に、GetTempPath()を使うのをやめて、TMP,又は,TEMP環境変数を直接参照するように変更しました。
				char *dir, *binFname;
				dir = getenv("TMP");
				if(!dir) { dir = getenv("TEMP"); }
			//不要	if(!dir) { dir = "."; }	//dir==NULLでもカレントフォルダと同じ意味になるのでこの処理は不要です。
//}}2017/11/07変更:一時フォルダの取得に、GetTempPath()を使うのをやめて、TMP,又は,TEMP環境変数を直接参照するように変更しました。
				binFname = strdup_makepath(NULL, dir, fname, ".bin");
				{
					GString* cmdLine = g_string_new("dSnrSeqC.exe");
					if(opt_q) { g_string_append_printf(cmdLine, " -q"); }	//dSnrSeqS.exeに対して'-q'オプションが指定されていたら、dSnrSeqC.exeに対しても'-q'オプションを指定してメッセージを抑制する。
					g_string_append_printf(cmdLine, " -len");
					g_string_append_printf(cmdLine, " -o\"%s\"", binFname);
					g_string_append_printf(cmdLine, " \"%s\"", snrFname);
					g_string_append_printf(cmdLine, " >NUL");
					if(!opt_q) { fprintf(stderr, "%s\n", cmdLine->str); }	//dSnrSeqS.exeに対して'-q'オプションが指定されていなければ、dSnrSeqC.exeを起動するコマンドラインを表示する。(判り易さのため)
					retCode = system(cmdLine->str);
					if(retCode) { error(retCode, 0, "%s (%s)", "compile error", snrFname); }
				}
				snrFname = binFname;
			}
		}
		{
			struct stat st;
			FILE* fp = fopen(snrFname, "rb");
			if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。", snrFname); }
			if(fstat(fileno(fp), &st)) { DIE(); }
			if(!(TBL_SnrTblNo = malloc(st.st_size))) { DIE(); }
			if((int)fread(TBL_SnrTblNo, 1, st.st_size, fp) != (int)st.st_size) { DIE(); }	//fread()の戻り値はunsigned型，st.st_sizeは(なぜか)signed型なので、そのまま比較すると警告が出る。警告を抑制するには片方をキャストするだけでも良いが、判り易さのために両方をキャストして比較する事にした。
			fclose(fp);
		}
	}
	{
		char* tclFname = argv[optind++];
		//□tclsh ?fileName arg ...?
		//│argc  argで指定された引数の数(もし引数がなければ0)が入っています。引数にはスクリプトファイル名は含まれません。
		//│argv  argで指定された引数を順に並べたTclのリストが入っています。もしargで引数が指定されなかった時には空文字列になります。
		//│argv0 もしfileName引数が指定されていればそれが入ります。そうでなければtclshが起動された時のコマンド名が入ります。
		if(!Tcl_SetVar(iPtr, "argv0", tclFname)) { DIE(); }
		if(!Tcl_SetVar(iPtr, "argv", strjoinv(" ", &argv[optind]))) { DIE(); }
		if(!Tcl_SetVar(iPtr, "argc", strdup_printf("%d", argc - optind))) { DIE(); }
		retCode = Tcl_EvalFile(iPtr, tclFname);
		if(retCode) { error(retCode, 0, "%s", iPtr->result); }
	}
	return retCode;
}
/****************************************************************************
 *	
 ****************************************************************************/
//Tclのコマンド関数の、SEH_catchブロック内からのみ、呼び出し可能です。
static int SehErrMsg() {
//{{cliptcl.cTcl_Merge()より
	char *s = strdup(""), *t, **argv = iPtr->argv;
	while((t = *argv++)) {
//{{cliptcl.cのTcl_Escape()より
		//要素をエスケープする。
		t = strescape(t, " $;[]{}");	//文字列をエスケープする。
		if(!*t) { t = strdup("\\0"); }	//空文字列であった場合は、明示的な空要素を示す"\0"に変換する。	//"\0"の代りに"{}"でも構いません。どちらにしても動作するはずです。
//}}cliptcl.cのTcl_Escape()より
//{{cliptcl.cのTcl_AppendElement()より
		//元の文字列が空文字列でなければ、元の文字列とエスケープした要素を、空白文字を挟んで連結する。
		//元の文字列が空文字列ならば、エスケープした要素をそのまま返す。先頭に、空白文字は付与しない。
		s = *s ? strjoin(" ", s, t, NULL) : t;
//}}cliptcl.cのTcl_AppendElement()より
	}
//}}cliptcl.cTcl_Merge()より
	iPtr->result = strdup_printf("%s:%d: %s: \"%s\""/*error_at_lineに合わせた*/,
	                             SEH_info.file ? basename((char*)SEH_info.file) : "",	//設定されているはずだが念のため。
	                             SEH_info.line,
	                             SEH_info.msg ? SEH_info.msg : "",
	                             s);
	return TCL_ERROR;
}
/*--------------------------------------------------------------------------*/
//Tclのコマンド関数の、SEH_tryブロック内からのみ、呼び出し可能です。
static void CheckArgc(int n) {
	if(iPtr->argc != n) {
		SEH_throw_msg(AppException, strdup_printf("expected %d args but got %d", n, iPtr->argc));
	}
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static int GetInt(const char* s, int lo, int hi) {
	char* p = (char*)s;
//{{cliptcl.cのTcl_GetInt()より
	int i = strtol(p, &p, 0);		//数値を取得する。
	while(*p && isspace(*p)) { p++; }	//数値の後の空白を読み飛ばす。
	if((p == s) || *p) {			//空文字列が指定されたか,又は,数値の後に空白以外が有ればエラー。
		SEH_throw_msg(AppException, strdup_printf("expected integer but got \"%s\"", s));
	}
//}}cliptcl.cのTcl_GetInt()より
	if(i < lo) { SEH_throw_msg(AppException, strdup_printf("expected not below %d but got %d", lo, i)); }
	if(i > hi) { SEH_throw_msg(AppException, strdup_printf("expected not above %d but got %d", hi, i)); }
	return i;
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static int GetSnrTblNo(const char* pTableName) {	//pTableNameは、テーブル名("SnrTblNo_..."),又は,テーブル番号("1"～SnrTblNo_Max)で指定して下さい。
	int iSnrTblNo;
	//"SnrTblNo_..."ならば、テーブル名と見なす。
	if(str_has_prefix(pTableName, "SnrTblNo_")) {
		iSnrTblNo = SnrSeq_TryGetTableNo(TBL_SnrTblNo, pTableName + 9);
		if(iSnrTblNo == -1) {
			SEH_throw_msg(AppException, strdup_printf("unknown table name \"%s\"", pTableName));
		}
	//"SnrTblNo_..."以外ならば、テーブル番号と見なす。
	} else {
		iSnrTblNo = GetInt(pTableName, 1, (TBL_SnrTblNo[0]/*nSnrTblNo*/ - 1)/*SnrTblNo_Max*/);
	}
	return iSnrTblNo;
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static int GetTrigNo(const char* pTrigName) {	//pTrigNameは、トリガ名("SnrTrg_..."),又は,トリガ番号("0"～"255")で指定して下さい。
	int iSnrTrg;
	//"SnrTrg_..."ならば、トリガ名と見なす。
	if(str_has_prefix(pTrigName, "SnrTrg_")) {
		iSnrTrg = SnrSeq_TryGetTrigNo(TBL_SnrTblNo, pTrigName + 7/*"SnrTrg_"*/);
		if(iSnrTrg == -1) {
			SEH_throw_msg(AppException, strdup_printf("unknown trigger name \"%s\"", pTrigName));
		}
	//"SnrTrg_..."以外ならば、トリガ番号と見なす。
	} else {
		iSnrTrg = GetInt(pTrigName, SnrTrg_set, SnrTrg_clr);
	}
	return iSnrTrg;
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static const char* GetFuncName(int iSnrFnc) {
	const char* pFuncName = SnrSeq_TryGetFuncName(TBL_SnrTblNo, iSnrFnc);
	if(!pFuncName) {
		SEH_throw_msg(AppException, strdup_printf("unknown function number %d", iSnrFnc));
	}
	return strconcat("SnrFnc_", pFuncName, NULL);
}
/****************************************************************************
 *	
 ****************************************************************************/
static int AddressList_CompareFunc(const void* pAddress, const char* pName) {
	return strcmp(strdup_printf("%p", pAddress), pName);	//アドレス値をキーとすることにした。一意なsearchIdを作成する目的でありアドレス値として解釈することは無い。
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static char* AddressList_Register(void* pAddress) {
	char* pName = strdup_printf("%p", pAddress);		//アドレス値をキーとすることにした。一意なsearchIdを作成する目的でありアドレス値として解釈することは無い。
	GSList* pLink = g_slist_find_custom(pAddressList, pName, AddressList_CompareFunc);
	if(pLink) { SEH_throw_msg(AppException, strdup_printf("AddressList_Register failed \"%s\"", pName)); }	//二重登録は不可。おそらく当ツールのバグです。スクリプトエラーでは発生し得ないはずです。
	pAddressList = g_slist_append(pAddressList, pAddress);
	return pName;
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static void* AddressList_Lookup(char* pName) {
	GSList* pLink = g_slist_find_custom(pAddressList, pName, AddressList_CompareFunc);
	if(!pLink) { SEH_throw_msg(AppException, strdup_printf("AddressList_Lookup failed \"%s\"", pName)); }	//登録されていない。当ツールのバグ,又は,スクリプトエラーによっても発生し得ます。
	return pLink->data;
}
/*--------------------------------------------------------------------------*/
//SEH_tryブロック内からのみ、呼び出し可能です。
static void AddressList_Unregister(void* pAddress) {
	char* pName = strdup_printf("%p", pAddress);		//アドレス値をキーとすることにした。一意なsearchIdを作成する目的でありアドレス値として解釈することは無い。
	GSList* pLink = g_slist_find_custom(pAddressList, pName, AddressList_CompareFunc);
	if(!pLink) { SEH_throw_msg(AppException, strdup_printf("AddressList_Unregister failed \"%s\"", pName)); }	//登録されていない。当ツールのバグ,又は,スクリプトエラーによっても発生し得ます。
	pAddressList = g_slist_delete_link(pAddressList, pLink);
}
/****************************************************************************
 *	
 ****************************************************************************/
static int fnSnrSeq(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs) {
	int result = 0;
	SEH_try {
		char* pFunc = g_dataset_get_data(pSnrSeq, "pFunc");
		if(!pFunc) { DIE(); }	//登録されていない。もしここで停止したら当ツールのバグです。
		if(Tcl_EvalString(iPtr, strdup_printf("apply {%s} %s %d %s %s",
		                  pFunc,
		                  strdup_printf("%p", pSnrSeq),	//アドレス値をキーとすることにした。一意なsearchIdを作成する目的でありアドレス値として解釈することは無い。
		                  iCh,
		                  GetFuncName(iSnrFnc),
		                  AddressList_Register(pArgs)))) {
			//↓ここで例外を投入して下でまとめて処理する事も可能ではあるが、既にiPtr->resultのメッセージに例外箇所が含まれている可能性が高く二重に表示されて見辛くなる。それを防ぐために直接終了する事にした。
			error(EXIT_FAILURE, 0, "%s", iPtr->result);	//インタプリタのエラーメッセージ(iPtr->result)を表示して終了する。fnSnrSeq()はTclのコマンド関数ではないのでTCL_ERRORを返して継続する事は出来ない。
		}
		AddressList_Unregister(pArgs);
		result = GetInt(iPtr->result, INT_MIN, INT_MAX);
	} SEH_catch(AppException) {
		error(EXIT_FAILURE, 0, "%s:%d: %s"/*error_at_lineに合わせた*/,	//例外のエラーメッセージ(SEH_info.msg)を表示して終了する。fnSnrSeq()はTclのコマンド関数ではないのでTCL_ERRORを返して継続する事は出来ない。
		      SEH_info.file ? basename((char*)SEH_info.file) : "",	//設定されているはずだが念のため。
		      SEH_info.line,
		      SEH_info.msg ? SEH_info.msg : "");
	} SEH_end
	return result;
}
/****************************************************************************
 *	
 ****************************************************************************/
//SnrSeq_New pFunc nCh nCtx	//pFuncはlambdaExpr形式で指定して下さい。
static int SnrSeq_NewCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(4);
		{
			ST_SnrSeq* pSnrSeq = SnrSeq_New(fnSnrSeq,
				GetInt(iPtr->argv[2], 0, 255),
				GetInt(iPtr->argv[3], 0, 255));
			iPtr->result = AddressList_Register(pSnrSeq);
			g_dataset_set_data(pSnrSeq, "pFunc", iPtr->argv[1]);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_Init pSnrSeq pFunc nCh nCtx
static int SnrSeq_InitCmd(Tcl_Interp* iPtr) {
	SEH_try {
		SEH_throw_msg(AppException, "not implemented");	//未対応
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_Free pSnrSeq
static int SnrSeq_FreeCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			AddressList_Unregister(pSnrSeq);
			g_dataset_destroy(pSnrSeq);
			SnrSeq_Free(pSnrSeq);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_Exec pSnrSeq
static int SnrSeq_ExecCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeq_Exec(pSnrSeq);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_Exec pSnrSeq iCh
static int SnrSeqCh_ExecCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(3);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeqCh_Exec(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_ClrTbl pSnrSeq
static int SnrSeq_ClrTblCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeq_ClrTbl(pSnrSeq);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_SetTbl pSnrSeq iCh pSnrTbl	//pSnrTblは"NULL"のみ対応。それ以外はSnrSeqCh_SetTblNoを使用して下さい。
static int SnrSeqCh_SetTblCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(4);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			if(strcmp(iPtr->argv[3], "NULL")) {
				SEH_throw_msg(AppException, strdup_printf("expected \"NULL\" but got \"%s\"", iPtr->argv[3]));
			}
			SnrSeqCh_SetTbl(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1),
				NULL);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_SendTrig pSnrSeq iTrig
static int SnrSeq_SendTrigCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(3);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeq_SendTrig(pSnrSeq,
				GetTrigNo(iPtr->argv[2]));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_SendTrig pSnrSeq iCh iTrig
static int SnrSeqCh_SendTrigCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(4);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeqCh_SendTrig(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1),
				GetTrigNo(iPtr->argv[3]));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_Unlock pSnrSeq
static int SnrSeq_UnlockCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeq_Unlock(pSnrSeq);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_Unlock pSnrSeq iCh
static int SnrSeqCh_UnlockCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(3);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeqCh_Unlock(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_Stop pSnrSeq
static int SnrSeq_StopCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeq_Stop(pSnrSeq);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_Stop pSnrSeq iCh
static int SnrSeqCh_StopCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(3);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			SnrSeqCh_Stop(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeq_GetStat pSnrSeq
static int SnrSeq_GetStatCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			iPtr->result = strdup_printf("%d", SnrSeq_GetStat(pSnrSeq));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_GetStat pSnrSeq iCh
static int SnrSeqCh_GetStatCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(3);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			iPtr->result = strdup_printf("%d", SnrSeqCh_GetStat(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1)));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//SnrSeqCh_SetTblNo pSnrSeq iCh pSnrSeqBin iSnrTblNo	//pSnrSeqBinは"TBL_SnrTblNo"固定。
static int SnrSeqCh_SetTblNoCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(5);
		{
			ST_SnrSeq* pSnrSeq = AddressList_Lookup(iPtr->argv[1]);
			if(strcmp(iPtr->argv[3], "TBL_SnrTblNo")) {
				SEH_throw_msg(AppException, strdup_printf("expected \"TBL_SnrTblNo\" but got \"%s\"", iPtr->argv[3]));
			}
			SnrSeqCh_SetTblNo(pSnrSeq,
				GetInt(iPtr->argv[2], 0, pSnrSeq->nCh - 1),
				TBL_SnrTblNo,
				GetSnrTblNo(iPtr->argv[4]));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/****************************************************************************
 *	
 ****************************************************************************/
//blob_reader_init reader data size
static int blob_reader_initCmd(Tcl_Interp* iPtr) {
	SEH_try {
		SEH_throw_msg(AppException, "not implemented");	//未対応
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_bit reader
static int blob_read_bitCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(reader->pos/*8N+0～7*/ >= reader->bits/*8N*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%d", blob_read_bit(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_byte reader
static int blob_read_byteCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 1/*byte*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%d", blob_read_byte(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_half reader
static int blob_read_halfCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 2/*half*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%d", blob_read_half(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_exp10 reader
static int blob_read_exp10Cmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 2/*exp10*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%d", blob_read_exp10(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_word reader
static int blob_read_wordCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 4/*word*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%d", blob_read_word(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//{{2018/04/07追加:'blob_read_ber'コマンドを追加しました。
//blob_read_ber reader
static int blob_read_berCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			{
				int n = (reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8;				//残りバイト数を求める。
				unsigned char* s = (unsigned char*)reader->data + ((reader->pos/*8N+0～7*/ + 7) / 8);	//BER圧縮整数の先頭アドレスを求める。
				int t;
				if(n < BER_Decode(s, &t)) { SEH_throw_msg(AppException, "end of args"); }		//残りバイト数がBER圧縮整数のバイト数未満ならばエラー。
			}
			iPtr->result = strdup_printf("%d", blob_read_ber(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
//}}2018/04/07追加:'blob_read_ber'コマンドを追加しました。
/*--------------------------------------------------------------------------*/
//blob_read_fp16 reader
static int blob_read_fp16Cmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 2/*fp16*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%g", blob_read_fp16(reader));
//{{cliptcl.cのTcl_ExprMakeString()より
			//Tcl6.7準拠の実装では「set x [expr 1.0]」が「1」となりそれ以降整数演算されてしまう問題がある。対策として以下の処理をTcl7.0のTcl_PrintDouble()からバックポートして修正した。
			if(!strchr(iPtr->result, '.') && !strchr(iPtr->result, 'e')) { iPtr->result = strconcat(iPtr->result, ".0", NULL); }
//}}cliptcl.cのTcl_ExprMakeString()より
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_fp32 reader
static int blob_read_fp32Cmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 4/*fp32*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%g", blob_read_fp32(reader));
//{{cliptcl.cのTcl_ExprMakeString()より
			//Tcl6.7準拠の実装では「set x [expr 1.0]」が「1」となりそれ以降整数演算されてしまう問題がある。対策として以下の処理をTcl7.0のTcl_PrintDouble()からバックポートして修正した。
			if(!strchr(iPtr->result, '.') && !strchr(iPtr->result, 'e')) { iPtr->result = strconcat(iPtr->result, ".0", NULL); }
//}}cliptcl.cのTcl_ExprMakeString()より
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_fp64 reader
static int blob_read_fp64Cmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			if(((reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8) < 8/*fp64*/) { SEH_throw_msg(AppException, "end of args"); }
			iPtr->result = strdup_printf("%g", blob_read_fp64(reader));
//{{cliptcl.cのTcl_ExprMakeString()より
			//Tcl6.7準拠の実装では「set x [expr 1.0]」が「1」となりそれ以降整数演算されてしまう問題がある。対策として以下の処理をTcl7.0のTcl_PrintDouble()からバックポートして修正した。
			if(!strchr(iPtr->result, '.') && !strchr(iPtr->result, 'e')) { iPtr->result = strconcat(iPtr->result, ".0", NULL); }
//}}cliptcl.cのTcl_ExprMakeString()より
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_string reader
static int blob_read_stringCmd(Tcl_Interp* iPtr) {
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			{
				int n = (reader->bits/*8N*/ - reader->pos/*8N+0～7*/) / 8;			//残りバイト数を求める。
				char* s = (char*)reader->data + ((reader->pos/*8N+0～7*/ + 7) / 8);		//文字列の先頭アドレスを求める。
				if(n <= (int)strnlen(s, n)) { SEH_throw_msg(AppException, "end of args"); }	//残りバイト数が文字数以下ならばエラー。同じでも不可。終端のヌル文字を含めると超過するから。
			}
			iPtr->result = strdup_printf("%s", blob_read_string(reader));
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_read_data reader size
static int blob_read_dataCmd(Tcl_Interp* iPtr) {
	SEH_try {
		SEH_throw_msg(AppException, "not implemented");	//未対応
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_copy_data reader p size
static int blob_copy_dataCmd(Tcl_Interp* iPtr) {
	SEH_try {
		SEH_throw_msg(AppException, "not implemented");	//未対応
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_reader_get_bits reader
static int blob_reader_get_bitsCmd(Tcl_Interp* iPtr) {	//フィールドアクセス用
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			iPtr->result = strdup_printf("%d", reader->bits);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_reader_get_pos reader
static int blob_reader_get_posCmd(Tcl_Interp* iPtr) {	//フィールドアクセス用
	SEH_try {
		CheckArgc(2);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			iPtr->result = strdup_printf("%d", reader->pos);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//blob_reader_set_pos reader pos
static int blob_reader_set_posCmd(Tcl_Interp* iPtr) {	//フィールドアクセス用
	SEH_try {
		CheckArgc(3);
		{
			struct blob_reader* reader = AddressList_Lookup(iPtr->argv[1]);
			reader->pos = GetInt(iPtr->argv[2], 0, reader->bits);
		}
	} SEH_catch(AppException) {
		return SehErrMsg();
	} SEH_end
	return TCL_OK;
}
