/*
 *	clipseh.c
 *
 *	構造化例外処理 (Structured Exception Handling)
 *
 *	* Fri Jul 03 01:00:00 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Fri Jul 03 21:00:32 JST 2015 Naoyuki Sawa
 *	- clipseh.cに「使用例」を追記しました。
 */
#include "clip.h"
/****************************************************************************
 *	グローバル変数
 ****************************************************************************/
jmp_buf* SEH_root;
/****************************************************************************
 *	使用例
 ****************************************************************************/
#if 0
/*--------------------------------------------------------------------------*/
//最小限の書き方の例。
//最小限過ぎてあまり意味がありません。(例外ブロックを書かないのと同じだから。)
static void Sample1() {
	SEH_init();
	printf("<1>\n");
	SEH_try {
		printf("<2>\n");
	} SEH_end
	printf("<3>\n");
}
//↓↓↓展開結果↓↓↓
static void Sample1() {
	{ jmp_buf __SEH_node__;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(SEH_code) { die("Uncaught exception: 0x%08X", SEH_code); } }
	printf("<1>\n");
	{ jmp_buf __SEH_node__, * const __SEH_save__ = SEH_root;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(!SEH_code) {
		printf("<2>\n");
	    SEH_root = __SEH_save__;				←←←例外が発生しなかった場合に例外フレームを巻き戻す処理
	  } else {
	    SEH_root = __SEH_save__;				←←←例外が捕捉されなかった場合に例外フレームを巻き戻す処理
	    SEH_throw(SEH_code);				←←←捕捉されなかった例外を上位の例外フレームへ再投入する処理
	} }
	printf("<3>\n");
}
/*--------------------------------------------------------------------------*/
//基本的な例。
const char AppException1[1];
const char AppException2[1];
static void Sample2() {
	SEH_init();
	printf("<1>\n");
	SEH_try {
		printf("<2>\n");
		SEH_throw(AppException2);			←←←例外コードには、'0'以外の任意の値を指定できます。アプリケーション全体で一意とするために、変数アドレスを例外コードとするのが良いです。
	} SEH_catch(AppException1) {
		printf("<3>\n");
	} SEH_catch(AppException2) {
		printf("<4>\n");
	} SEH_catch_all {
		printf("<5> 0x%08X\n", SEH_code);		←←←例外処理ブロックの中では、発生した例外コードを'SEH_code'で参照出来る。
	} SEH_end
	printf("<6>\n");
}
//↓↓↓展開結果↓↓↓
static void Sample2() {
	{ jmp_buf __SEH_node__;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(SEH_code) { die("Uncaught exception: 0x%08X", SEH_code); } }
	printf("<1>\n");
	{ jmp_buf __SEH_node__, * const __SEH_save__ = SEH_root;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(!SEH_code) {
		printf("<2>\n");
		longjmp((*SEH_root), (int)(AppException2));
	  SEH_root = __SEH_save__;				←←←例外が発生しなかった場合に例外フレームを巻き戻す処理
	} else if(SEH_code == (int)(AppException1)) {
	  SEH_root = __SEH_save__;				←←←例外を捕捉した場合に例外フレームを巻き戻す処理
		printf("<3>\n");
	  SEH_root = __SEH_save__;				←←←無駄処理となるが動作上問題は無い。
	} else if(SEH_code == (int)(AppException2)) {
	  SEH_root = __SEH_save__;				←←←例外を捕捉した場合に例外フレームを巻き戻す処理
		printf("<4>\n");
	  SEH_root = __SEH_save__;				←←←無駄処理となるが動作上問題は無い。
	} else if(SEH_code == (int)(SEH_code)) {
	  SEH_root = __SEH_save__;				←←←例外を捕捉した場合に例外フレームを巻き戻す処理
		printf("<5> 0x%08X\n", SEH_code);
	    SEH_root = __SEH_save__;				←←←無駄処理となるが動作上問題は無い。
	  } else {
	    SEH_root = __SEH_save__;				←←←例外が捕捉されなかった場合に例外フレームを巻き戻す処理
	    longjmp((*SEH_root), (int)(SEH_code));		←←←捕捉されなかった例外を上位の例外フレームへ再投入する処理
	} }
	printf("<6>\n");
}
/*--------------------------------------------------------------------------*/
//例外処理ブロックの中からreturnで抜ける例。
const char AppException1[1];
const char AppException2[1];
int Sample3() {
	SEH_init();
	printf("<1>\n");
	SEH_try {
		printf("<2>\n");
		if(now & 1) { SEH_return 1; }			←←←tryブロックの中から「return」で例外ブロックを抜けてはいけない。代りに「SEH_return」を使って下さい。「SEH_return;」「SEH_return 戻り値;」のどちらにも使用可能です。
								　　　「SEH_return」をifブロックに入れる場合は'{〜}'で囲って下さい。「if(now & 1) SEH_return 1;」と書いてはいけません。
								　　　tryブロックの中から「goto」「break」「continue」等で例外ブロックを抜ける事も禁止です。これらは必要なケースが少ないと思ったので、代替手段は用意しない事にしました。
	} SEH_catch(AppException1) {
		printf("<3>\n");
		return 2;					←←←catchブロックの中では、「return」でも「SEH_return」でも構いません。
	} SEH_catch(AppException2) {
		printf("<4>\n");
		SEH_return 3;					←←←catchブロックの中では、「return」でも「SEH_return」でも構いません。
	} SEH_end
	printf("<6>\n");
	return 0;
}
//↓↓↓展開結果↓↓↓
static void Sample1() {
	{ jmp_buf __SEH_node__;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(SEH_code) { die("Uncaught exception: 0x%08X", SEH_code); } }
	printf("<1>\n");
	{ jmp_buf __SEH_node__, * const __SEH_save__ = SEH_root;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(!SEH_code) {
		printf("<2>\n");
		if(now & 1) { SEH_root = __SEH_save__; return 1; }
	  SEH_root = __SEH_save__;
	} else if(SEH_code == (int)(AppException1)) {
	  SEH_root = __SEH_save__;
		printf("<3>\n");
		return 2;
	  SEH_root = __SEH_save__;
	} else if(SEH_code == (int)(AppException2)) {
	  SEH_root = __SEH_save__;
		printf("<4>\n");
		SEH_root = __SEH_save__; return 3;		←←←「SEH_root = __SEH_save__;」は無駄処理となるが動作上問題は無い。
	    SEH_root = __SEH_save__;
	  } else {
	    SEH_root = __SEH_save__;
	    SEH_throw(SEH_code);
	} }
	printf("<5>\n");
	return 0;
}
/*--------------------------------------------------------------------------*/
//catchブロックの中から例外を再投入する例。
const char AppException1[1];
const char AppException2[1];
static void Sample2() {
	SEH_init();
	printf("<1>\n");
	SEH_try {
		printf("<2>\n");
		SEH_throw(AppException1);
	} SEH_catch(AppException1) {
		printf("<3>\n");
		SEH_throw(AppException2);			←←←catchブロックの中から、上位の例外フレームへ別の例外を投入出来ます。
	} SEH_catch(AppException2) {
		printf("<4>\n");
		SEH_throw_last;					←←←catchブロックの中から、上位の例外フレームへ同じ例外を投入出来ます。
	} SEH_end
	printf("<6>\n");
}
//↓↓↓展開結果↓↓↓
static void Sample2() {
	{ jmp_buf __SEH_node__;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(SEH_code) { die("Uncaught exception: 0x%08X", SEH_code); } }
	printf("<1>\n");
	{ jmp_buf __SEH_node__, * const __SEH_save__ = SEH_root;
	  const int SEH_code = setjmp(*(SEH_root = &__SEH_node__));
	  if(!SEH_code) {
		printf("<2>\n");
		longjmp((*SEH_root), (int)(AppException1));
	  SEH_root = __SEH_save__;
	} else if(SEH_code == (int)(AppException1)) {
	  SEH_root = __SEH_save__;
		printf("<3>\n");
		longjmp((*SEH_root), (int)(AppException2));	←←←catchブロックの中から、上位の例外フレームへ別の例外を投入する処理
	  SEH_root = __SEH_save__;
	} else if(SEH_code == (int)(AppException2)) {
	  SEH_root = __SEH_save__;
		printf("<4>\n");
		longjmp((*SEH_root), (int)(SEH_code));		←←←catchブロックの中から、上位の例外フレームへ同じ例外を投入する処理
	    SEH_root = __SEH_save__;
	  } else {
	    SEH_root = __SEH_save__;
	    longjmp((*SEH_root), (int)(SEH_code));
	} }
	printf("<5>\n");
}
/*--------------------------------------------------------------------------*/
#endif