/*
 * Exception Handling test
 *
 * Copyright (c) 2000
 *    Issei Suzuki <issei@issei.org>   All rights reserved.
 *
 * $Id$
 */

#include "except.h"
#include <stdio.h>

#ifndef __GNUC__
# define __FUNCTION__ ""
#endif

#define	DBG(str) \
	fprintf(stderr,"%-8s %10s %-8s #%d\n", str, "", __FUNCTION__, except_nestlevel())

#define	DBG_E() DBG("enter")

#define	DBG_L() DBG("leave")

#define DBG_CATCH(err) \
	fprintf(stderr, "catch    (%-8s) %-8s #%d\n", err,  __FUNCTION__, except_nestlevel())

enum exerr {
	EX_NONE, EX_IOERR, EX_MISC
};

static void
f1(void)
{
	DBG_E();
	TRY {
		fprintf(stderr, "throw    (%-8s) %-8s #%d\n",
			"EX_IOERR", __FUNCTION__, except_nestlevel());
		THROW(EX_IOERR, "EX_IOERR");
	}
	CATCH (EX_IOERR) {
		DBG_CATCH("EX_IOERR");
	}
	END_TRY;
	DBG_L();
}

static void
g2(void)
{
	DBG_E();
	fprintf(stderr, "throw    (%-8s) %-8s #%d\n",
		"EX_IOERR", __FUNCTION__, except_nestlevel());
	THROW(EX_IOERR, "EX_IOERR");
	DBG_L();
}

static void
g1(void)
{
	DBG_E();
	g2();
	DBG_L();
}

static void
h2(void)
{
	DBG_E();
	fprintf(stderr, "throw    (%-8s) %-8s #%d\n",
		"EX_IOERR", __FUNCTION__, except_nestlevel());
	THROW(EX_IOERR, "EX_IOERR");
	DBG_L();
}


static void
h1(void)
{
	DBG_E();
	TRY {
		h2();
	}
	CATCH (EX_IOERR) {
		DBG_CATCH("EX_IOERR");
		fprintf(stderr, "throw    (%-8s) %-8s #%d\n",
		    "PASSUP", __FUNCTION__, except_nestlevel());
		THROW_PASSUP();
	}
	END_TRY;
	DBG_L();
}


void
ex_handler(void)
{
	fprintf(stderr, "handler  (%8d) %-8s #%d\n",
		except_type(), __FUNCTION__, except_nestlevel());
}

int
main(void)
{
	DBG_E();

	except_handler_regist(ex_handler);
	/*
	 * Throw EX_IOERR in f1() and catch it in f1()
	 *
	 *  enter            f1       #1
	 *  throw (EX_IOERR) f1       #2
	 *  catch (EX_IOERR) f1       #2
	 *  leave            f1       #1
	 */
	TRY {
		f1();
	}
	CATCH_ALL {
		DBG_CATCH("ALL");
	}
	END_TRY;
	
	/*
	 * Throw EX_IOERR in g2 and catch it in main()
	 *
	 *  enter            g1       #1
	 *  enter            g2       #1
	 *  throw (EX_IOERR) g2       #1
	 *  catch (ALL     ) main     #1
	 */
	TRY {
		g1();
	}
	CATCH_ALL {
		DBG_CATCH("ALL");
	}
	END_TRY;
		    
	/*
	 * Throw EX_IOERR in h2 and catch it in h1.
	 * h1 re-throw the exception and catch it in main()
	 *
	 *  enter            h1       #1
	 *  enter            h2       #2
	 *  throw (EX_IOERR) h2       #2
	 *  catch (EX_IOERR) h1       #2
	 *  catch (ALL     ) main     #1
	 */
	TRY {
		h1();
	}
	CATCH_ALL {
		DBG_CATCH("ALL");
	}
	END_TRY;

	/*
	 * Throw EX_IOERR in main and noone catch it.  Exception
	 * handler is called, and it terminates the program.
	 *
	 *  throw    (EX_IOERR) main     #1
	 *  handler  (       1) ex_handler #1
	 *  except : [try.c line# 170] failed to handle exception.
	 */
	TRY {
		fprintf(stderr, "throw    (%-8s) %-8s #%d\n",
			"EX_IOERR", __FUNCTION__, except_nestlevel());
		THROW(EX_IOERR, "EX_IOERR");
	}
	END_TRY;

	DBG_L();

	return 0;
}
