/*
 *	app.c
 *
 *	tclwin.exe - 独自実装のTclインタプリタ
 *	Copyright (C) 2014-2018 Naoyuki Sawa
 *
 *	* Sun Oct 26 19:32:00 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	* Fri Nov 03 23:05:28 JST 2017 Naoyuki Sawa
 *	- /clip/test.win/を元にしたプロジェクトに移行しました。
 *	  当ツールの動作には変更有りません。
 *	* 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 モジュールの、同日のコメントを参照して下さい。
 *	* Wed Apr 04 23:59:59 JST 2018 Naoyuki Sawa
 *	- /clip/cliptcl.c モジュールを更新した事に伴い、当ツールもリビルドしました。
 *	  当ツールのソースは、変更していません。
 *	  詳細は、/clip/cliptcl.c モジュールの、同日のコメントを参照して下さい。
 *	* 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 srandCmd(Tcl_Interp* iPtr);
static int randCmd(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;
}
/****************************************************************************
 *	
 ****************************************************************************/
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, "srand", srandCmd, NULL);
		Tcl_CreateCommand(iPtr, "rand",  randCmd,  NULL);
//}}必要に応じて、ここでアプリケーション特有のTcl_CreateCommand()を行ってください。
	}
//}}アプリケーション特有の処理
}
/*--------------------------------------------------------------------------*/
void app_exit() {
//{{アプリケーション特有の処理
	{
		//※TODO:
	}
//}}アプリケーション特有の処理
}
/*--------------------------------------------------------------------------*/
int app_main(int argc, char* argv[]) {
	FILE* fp = stdin;
	int retCode, i;
	//□tclsh ?fileName arg ...?
	//│argc  argで指定された引数の数(もし引数がなければ0)が入っています。引数にはスクリプトファイル名は含まれません。
	//│argv  argで指定された引数を順に並べたTclのリストが入っています。もしargで引数が指定されなかった時には空文字列になります。
	//│argv0 もしfileName引数が指定されていればそれが入ります。そうでなければtclshが起動された時のコマンド名が入ります。
	//argv0に、実行ファイル名を設定する。
	Tcl_SetVar(iPtr, "argv0", *argv++);		//argvを次へ進める。
	//最初の引数が有り、'-'でなければ…
	if(*argv && strcmp(*argv, "-")) {
		fp = fopen(*argv, "r");			//Tclスクリプトファイルを開く。
		if(!fp) { error(EXIT_FAILURE, errno, "### %sが開けません｡", *argv); }
		//argv0に、Tclスクリプトファイル名を設定する。
		Tcl_SetVar(iPtr, "argv0", *argv);	//Tclスクリプトファイル名を、argv(0)にも設定するので、argvを次へ進めません。
	}
	//argv()配列を設定する。
	for(i = 0; *argv; i++, argv++) {
		Tcl_SetVar(iPtr, strdup_printf("argv(%d)", i), *argv);
	}
	//argcを設定する。
	Tcl_SetVar(iPtr, "argc", strdup_printf("%d", i));
	//Tclスクリプトを実行する。
	retCode = Tcl_EvalStream(iPtr, fp);
	//本来はTcl_EvalFile()が適切に処理するが、シェルの場合は非インタラクティブでもエラーを表示したいので、以下の処理を行う。
	if(retCode && !isatty(fileno(fp))) {	//エラー発生,かつ,非インタラクティブ(=Tcl_EvalFile()がエラーを表示しない)ならば…
		fprintf(stderr, "Error");
		if(retCode != TCL_ERROR) { fprintf(stderr, " %d", retCode); }
		if(*iPtr->result) { fprintf(stderr, ": %s", iPtr->result); }
		fprintf(stderr, "\n");
#ifdef  _DEBUG
		//Visual Studio 6.0のIDEでデバッグ実行した場合、プログラム終了後にすぐDOS窓が閉じてしまうので、結果を見るためにキー入力待ちをすることにした。
		_cputs("何かキーを押すと終了します。");
		_getch();
#endif//_DEBUG
	}
	return retCode;
}
/****************************************************************************
 *	
 ****************************************************************************/
//srand seed
static int srandCmd(Tcl_Interp* iPtr) {
	int seed;
	switch(iPtr->argc) {
	case 1:
		seed = time(NULL);
		break;
	case 2:
		seed = atoi(iPtr->argv[1]);
		break;
	default:
		iPtr->result = "wrong # args";
		return TCL_ERROR;
	}
	srand(seed);
	return TCL_OK;
}
/*--------------------------------------------------------------------------*/
//rand
static int randCmd(Tcl_Interp* iPtr) {
	iPtr->result = strdup_printf("%d", rand());
	return TCL_OK;
}
