#ifndef BREXCRUN_H
#define BREXCRUN_H
//========================================================================================
//
//	This source file is a component of the Bedrock Class Library
//
//	File:				BRExcRun.c
//	Release Version:	$ 1.0d1 $
//
//	Creation Date:		12/10/92
//	
//	This file derived from runtime.c
//		Creation Date:	 June 1, 1992
//
//	COPYRIGHT 1990-93 SYMANTEC CORPORATION. ALL RIGHTS RESERVED. UNPUBLISHED -- RIGHTS
//	RESERVED UNDER THE COPYRIGHT LAWS OF THE UNITED STATES. USE OF COPYRIGHT NOTICE IS
//	PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION OR DISCLOSURE.
//
//	THIS SOFTWARE Contains PROPRIETARY AND CONFIDENTIAL INFORMATION OF SYMANTEC
//	CORPORATION. USE, DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
//	EXPRESS WRITTEN PERMISSION OF SYMANTEC CORPORATION.
//
//	RESTRICTED RIGHTS LEGEND
//	Use, duplication, or disclosure by the Government is subject to restrictions as Set
//	forth in subparagraph (c)(l)(ii) of the Rights in Technical Data and Computer
//	Software clause at DFARS 252.227-7013. Symantec Corporation, 10201 Torre Avenue,
//	Cupertino, CA 95014.
//
//========================================================================================

#ifndef   BREXCEPT_H
#include "BRExcept.h"
#endif

#ifndef   BRDELSTA_H
#include "BRDelSta.h"
#endif

#ifndef   BREXCTAS_H
#include "BRExcTas.h"
#endif

#ifdef BR_DEBUG
#include <stdio.h>
#endif

class _BR_CTryBlockContext;
class __BR_CBedNewHelper;

//========================================================================================
//	Functions for "unexpected" and "terminate"
//
//		See ARM, Section 15.6
//========================================================================================

extern void terminate();
extern void unexpected();

extern PFV set_terminate(PFV);
extern PFV set_unexpected(PFV);

//========================================================================================
// CLASS _BR_CExceptionRuntime
//========================================================================================

class _BR_CExceptionRuntime
{
public:
    enum
    {
        kDefaultExceptionBufferSize = 128,
			// Exception buffer size in bytes.
			// This limits size of largest exception object that may be thrown
    };
	
	static void Initialize();
	static void Terminate();

	static void Throw(const _BR_CException & thrownException);
	static void ThrowSame();
	static void ThrowConstructor(_BR_CException & thrownException);
	static void ThrowSameConstructor();
	static void CaughtException(_BR_CException * caughtException);
	static void CaughtEverythingException();
	static void CaughtNoInstanceException();
	static void CaughtReferenceException();
	static void KeepThrowing();
	static void CatchCleanup();
	static void ResetExceptionBufferSize(size_t newSize);
    static PFV SetTerminate(PFV);
    static PFV SetUnexpected(PFV);
	
	static void SetExceptionBufferSize(size_t nNewSize);
	static size_t GetExceptionBufferSize();
	static void SetExceptionBuffer(void* pExceptionBuffer);
	static void* GetExceptionBuffer();
    static void SetCaughtException(_BR_CException * pCaughtException);
    static _BR_CException * GetCaughtException();
    static void SetThrownException(_BR_CException * pThrownException);
    static _BR_CException * GetThrownException();
	static void SetThrowing(short fIsThrowing);
	static short  IsThrowing();
	static void SetCurrentTerminate(PFV pfCurrentTerminate);
	static PFV GetCurrentTerminate();
	static void SetCurrentUnexpected(PFV pfCurrentUnexpected);
	static PFV GetCurrentUnexpected();
	
#ifdef BR_DEBUG
	static	_BR_CMetaClass *SetBreakOnThrow(_BR_CMetaClass *breakExceptionKind = NULL);
	static	_BR_CMetaClass *GetBreakOnThrow();
#endif

private:
    static void DeleteObjectsInContextAndJump(_BR_CTryBlockContext * BRTryBlo);
	static void PrimitiveThrow(const _BR_CException & thrownException);
	static void PrimitiveThrowSame();

};

//========================================================================================
// CLASS _BR_CExceptionRuntime INLINE Functions (Static Task Globals Versions)
//========================================================================================

#ifdef BR_STATIC_TASK_GLOBALS

inline void _BR_CExceptionRuntime::SetExceptionBufferSize(size_t newSize)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gExceptionBufferSize = newSize;
}

inline size_t _BR_CExceptionRuntime::GetExceptionBufferSize()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gExceptionBufferSize;
}

inline void _BR_CExceptionRuntime::SetExceptionBuffer(void* exceptionBuffer)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gExceptionBuffer = exceptionBuffer;
}

inline void* _BR_CExceptionRuntime::GetExceptionBuffer()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gExceptionBuffer;
}

inline void _BR_CExceptionRuntime::SetCaughtException(_BR_CException* caughtException)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gCaughtException = caughtException;
}

inline _BR_CException* _BR_CExceptionRuntime::GetCaughtException()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gCaughtException;
}

inline void _BR_CExceptionRuntime::SetThrownException(_BR_CException* thrownException)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gThrownException = thrownException;
}

inline _BR_CException* _BR_CExceptionRuntime::GetThrownException()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gThrownException;
}

inline void _BR_CExceptionRuntime::SetThrowing(short isThrowing)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gIsThrowing = isThrowing;
}

inline short _BR_CExceptionRuntime::IsThrowing()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gIsThrowing;
}

inline void _BR_CExceptionRuntime::SetCurrentTerminate(PFV pfCurrentTerminate)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gCurrentTerminate = pfCurrentTerminate;
}

inline PFV _BR_CExceptionRuntime::GetCurrentTerminate()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gCurrentTerminate;
}

inline void _BR_CExceptionRuntime::SetCurrentUnexpected(PFV pfCurrentUnexpected)
{
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gCurrentUnexpected = pfCurrentUnexpected;
}

inline PFV _BR_CExceptionRuntime::GetCurrentUnexpected()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gCurrentUnexpected;
}

#ifdef BR_DEBUG
inline _BR_CMetaClass *_BR_CExceptionRuntime::SetBreakOnThrow(_BR_CMetaClass *breakExceptionKind)
{
	_BR_CMetaClass *previous = BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gBreakExceptionKind;
	BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gBreakExceptionKind = breakExceptionKind;
	return previous;
}
#endif

#ifdef BR_DEBUG
inline _BR_CMetaClass *_BR_CExceptionRuntime::GetBreakOnThrow()
{
	return BR_CExceptionTaskGlobals::gExceptionTaskGlobals.
					gBedExceptionGlobals.gBreakExceptionKind;
}
#endif

#endif

//========================================================================================
// CLASS _BR_CExceptionRuntime INLINE Functions (Dynamic Task Globals Versions)
//========================================================================================

#ifndef BR_STATIC_TASK_GLOBALS

inline void _BR_CExceptionRuntime::SetExceptionBufferSize(size_t nNewSize)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gExceptionBufferSize = nNewSize;
}

inline size_t _BR_CExceptionRuntime::GetExceptionBufferSize()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gExceptionBufferSize;
}

inline void _BR_CExceptionRuntime::SetExceptionBuffer(void* pExceptionBuffer)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gExceptionBuffer = pExceptionBuffer;
}

inline void* _BR_CExceptionRuntime::GetExceptionBuffer()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gExceptionBuffer;
}

inline void _BR_CExceptionRuntime::SetCaughtException(_BR_CException* pCaughtException)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gCaughtException = pCaughtException;
}

inline _BR_CException* _BR_CExceptionRuntime::GetCaughtException()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gCaughtException;
}

inline void _BR_CExceptionRuntime::SetThrownException(_BR_CException* pThrownException)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gThrownException = pThrownException;
}

inline _BR_CException* _BR_CExceptionRuntime::GetThrownException()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gThrownException;
}

inline void _BR_CExceptionRuntime::SetThrowing(short isThrowing)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gIsThrowing = isThrowing;
}

inline short _BR_CExceptionRuntime::IsThrowing()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gIsThrowing;
}

inline void _BR_CExceptionRuntime::SetCurrentTerminate(PFV pfCurrentTerminate)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gCurrentTerminate = pfCurrentTerminate;
}

inline PFV _BR_CExceptionRuntime::GetCurrentTerminate()
{
	return PFV(BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gCurrentTerminate);
}

inline void _BR_CExceptionRuntime::SetCurrentUnexpected(PFV pfCurrentUnexpected)
{
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gCurrentUnexpected = pfCurrentUnexpected;
}

inline PFV _BR_CExceptionRuntime::GetCurrentUnexpected()
{
	return PFV(BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gCurrentUnexpected);
}

#ifdef BR_DEBUG
inline _BR_CMetaClass *_BR_CExceptionRuntime::SetBreakOnThrow(_BR_CMetaClass *breakExceptionKind)
{
	_BR_CMetaClass *previous = BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gBreakExceptionKind;
	BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gBreakExceptionKind = breakExceptionKind;
	return previous;
}
#endif

#ifdef BR_DEBUG
inline _BR_CMetaClass *_BR_CExceptionRuntime::GetBreakOnThrow()
{
	return BR_CExceptionTaskGlobals::GetTaskGlobals()->
					gBedExceptionGlobals.gBreakExceptionKind;
}
#endif

#endif

//========================================================================================
// CLASS _BR_CExceptionRuntime INLINE Functions (Platform-independent Versions)
//========================================================================================

inline void _BR_CExceptionRuntime::CatchCleanup()
{
	SetCaughtException(NULL);
	SetThrownException(NULL);
}

#endif
