/*******************************************************************
 Copyright © 1995 - 1998, 3Com Corporation or its subsidiaries ("3Com").  
 All rights reserved.
   
 This software may be copied and used solely for developing products for 
 the Palm Computing platform and for archival and backup purposes.  Except 
 for the foregoing, no part of this software may be reproduced or transmitted 
 in any form or by any means or used to make any derivative work (such as 
 translation, transformation or adaptation) without express written consent 
 from 3Com.

 3Com reserves the right to revise this software and to make changes in content 
 from time to time without obligation on the part of 3Com to provide notification 
 of such revision or changes.  
 3COM MAKES NO REPRESENTATIONS OR WARRANTIES THAT THE SOFTWARE IS FREE OF ERRORS 
 OR THAT THE SOFTWARE IS SUITABLE FOR YOUR USE.  THE SOFTWARE IS PROVIDED ON AN 
 "AS IS" BASIS.  3COM MAKES NO WARRANTIES, TERMS OR CONDITIONS, EXPRESS OR IMPLIED, 
 EITHER IN FACT OR BY OPERATION OF LAW, STATUTORY OR OTHERWISE, INCLUDING WARRANTIES, 
 TERMS, OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND 
 SATISFACTORY QUALITY.

 TO THE FULL EXTENT ALLOWED BY LAW, 3COM ALSO EXCLUDES FOR ITSELF AND ITS SUPPLIERS 
 ANY LIABILITY, WHETHER BASED IN CONTRACT OR TORT (INCLUDING NEGLIGENCE), FOR 
 DIRECT, INCIDENTAL, CONSEQUENTIAL, INDIRECT, SPECIAL, OR PUNITIVE DAMAGES OF 
 ANY KIND, OR FOR LOSS OF REVENUE OR PROFITS, LOSS OF BUSINESS, LOSS OF INFORMATION 
 OR DATA, OR OTHER FINANCIAL LOSS ARISING OUT OF OR IN CONNECTION WITH THIS SOFTWARE, 
 EVEN IF 3COM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

 3Com, HotSync, Palm Computing, and Graffiti are registered trademarks, and 
 Palm III and Palm OS are trademarks of 3Com Corporation or its subsidiaries.

 IF THIS SOFTWARE IS PROVIDED ON A COMPACT DISK, THE OTHER SOFTWARE AND 
 DOCUMENTATION ON THE COMPACT DISK ARE SUBJECT TO THE LICENSE AGREEMENT 
 ACCOMPANYING THE COMPACT DISK.

 *-------------------------------------------------------------------
 * FileName:
 *		ErrorMgr.h
 *
 * Description:
 *		Include file for Error Management 
 *
 * History:
 *   	10/25/94  RM - Created by Ron Marianetti
 *
 *-----------------------------------------------------------------------
 *	Exception Handling
 *
 *		This unit implements an exception handling mechanism that is similar
 *		to "real" C++ Exceptions. Our Exceptions are untyped, and there
 *		must be one and only one Catch block for each Try block.
 *
 *	Try/Catch Syntax:
 *
 *		ErrTry {
 *			// Do something which may fail.
 *			// Call ErrThrow() to signal failure and force jump
 *			// to the following Catch block.
 *		}
 *
 *		ErrCatch(inErr) {
 *			// Recover or cleanup after a failure in the above Try block.
 *			// "inErr" is an ExceptionCode identifying the reason
 *			// for the failure.
 *			
 *			// You may call Throw() if you want to jump out to
 *			// the next Catch block.
 *
 *			// The code in this Catch block does not execute if
 *			// the above Try block completes without a Throw.
 *
 *		} ErrEndCatch
 *
 *		You must structure your code exactly as above. You can't have a
 *		ErrTry { } without a ErrCatch { } ErrEndCatch, or vice versa.
 *
 *
 *	ErrThrow
 *
 *		To signal failure, call ErrThrow() from within a Try block. The
 *		Throw can occur anywhere in the Try block, even within functions
 *		called from the Try block. A ErrThrow() will jump execution to the
 *		start of the nearest Catch block, even across function calls.
 *		Destructors for stack-based objects which go out of scope as
 *		a result of the ErrThrow() are called.
 *
 *		You can call ErrThrow() from within a Catch block to "rethrow"
 *		the exception to the next nearest Catch block.
 *
 *
 *	Exception Codes
 *
 *		An ExceptionCode is a 32-bit number. You will normally use
 *		Pilot error codes, which are 16-bit numbers. This allows
 *		plently of room for defining codes for your own kinds of errors.
 *
 *
 *	Limitations
 *
 *		Try/Catch and Throw are based on setjmp/longjmp. At the
 *		beginning of a Try block, setjmp saves the machine registers.
 *		Throw calls longjmp, which restores the registers and jumps
 *		to the beginning of the Catch block. Therefore, any changes
 *		in the Try block to variables stored in registers will not
 *		be retained when entering the Catch block. 
 *
 *		The solution is to declare variables that you want to use
 *		in both the Try and Catch blocks as "volatile". For example:
 *
 *		volatile long	x = 1;		// Declare volatile local variable
 *		ErrTry {
 *			x = 100;						// Set local variable in Try
 *			ErrThrow(-1);
 *		}
 *
 *		ErrCatch(inErr) {
 *			if (x > 1) {				// Use local variable in Catch 	
 *				SysBeep(1);
 *			}
 *		} ErrEndCatch
 *
 *
 *******************************************************************/

#ifndef __ERRORMGR_H__
#define __ERRORMGR_H__


// Include elementary types
#include <Common.h>					// Basic types
#include <SysTraps.h>				// Trap Numbers.



#if EMULATION_LEVEL != EMULATION_NONE
#include <setjmp.h>
#endif

/************************************************************
 * Macros for Showing Errors
 *
 ********************************************************************/


//------------------------------------------------------------
// Full Error Checking
//------------------------------------------------------------
#if ERROR_CHECK_LEVEL == ERROR_CHECK_FULL

#define ErrFatalDisplay(msg) \
	ErrDisplayFileLineMsg(__FILE__, __LINE__, msg)

#define ErrFatalDisplayIf(condition, msg) \
	{if (condition) ErrDisplayFileLineMsg(__FILE__, __LINE__, msg);}

#define ErrNonFatalDisplayIf(condition, msg) \
	{if (condition) ErrDisplayFileLineMsg(__FILE__, __LINE__, msg);}

#define ErrNonFatalDisplay(msg) \
	ErrDisplayFileLineMsg(__FILE__, __LINE__, msg)
	
#define ErrDisplay(msg) \
		ErrDisplayFileLineMsg(__FILE__, __LINE__, msg)




//------------------------------------------------------------
// Fatal  Error Checking Only
//------------------------------------------------------------
#elif ERROR_CHECK_LEVEL == ERROR_CHECK_PARTIAL

#define ErrFatalDisplay(msg) \
	ErrDisplayFileLineMsg(__FILE__, __LINE__, msg)

#define ErrFatalDisplayIf(condition, msg) \
	{if (condition) ErrDisplayFileLineMsg(__FILE__, __LINE__, msg);}

#define ErrNonFatalDisplayIf(condition, msg) 

#define ErrNonFatalDisplay(msg) 
	
#define ErrDisplay(msg) \
		ErrDisplayFileLineMsg(__FILE__, __LINE__, msg)



//------------------------------------------------------------
// No  Error Checking  
//------------------------------------------------------------
#elif ERROR_CHECK_LEVEL == ERROR_CHECK_NONE

#define ErrFatalDisplay(msg) 

#define ErrFatalDisplayIf(condition, msg) 

#define ErrNonFatalDisplayIf(condition, msg) 

#define ErrNonFatalDisplay(msg) 

#define ErrDisplay(msg)  


//------------------------------------------------------------
// Not Defined...
//------------------------------------------------------------
#else
#error	ERROR: the compiler define 'ERROR_CHECK_LEVEL' must be defined!

#endif // ERROR_CHECK_LEVEL



				
/********************************************************************
 * Try / Catch / Throw support
 *
 * ---------------------------------------------------------------------
 * Exception Handler structure
 *  
 *	An ErrExceptionType object is created for each ErrTry & ErrCatch block.
 *	At any point in the program, there is a linked list of
 *	ErrExceptionType objects. GErrFirstException points to the
 *	most recently entered block. A ErrExceptionType blocks stores
 *	information about the state of the machine (register values)
 *	at the start of the Try block
 ********************************************************************/
	
#if EMULATION_LEVEL != EMULATION_NONE
	#define	ErrJumpBuf	jmp_buf
#else
	typedef long* ErrJumpBuf[12];			// D3-D7,PC,A2-A7
#endif
	
// Structure used to store Try state.
typedef struct ErrExceptionType {
	struct ErrExceptionType*	nextP;	// next exception type
	ErrJumpBuf						state;	// setjmp/longjmp storage
	Long								err;		// Error code
	} ErrExceptionType;
typedef ErrExceptionType* ErrExceptionPtr;


// Try & Catch macros
#define	ErrTry																\
	{																				\
		ErrExceptionType	_TryObject;										\
		_TryObject.err = 0;													\
		_TryObject.nextP = (ErrExceptionPtr)*ErrExceptionList();	\
		*ErrExceptionList() = (Ptr)&_TryObject;						\
		if (ErrSetJump(_TryObject.state) == 0) {

		
// NOTE: All variables referenced in and after the ErrCatch must 
// be declared volatile.  Here's how for variables and pointers:
// volatile Word					oldMode;
//	ShlDBHdrTablePtr volatile hdrTabP = nil;
// If you have many local variables after the ErrCatch you may
// opt to put the ErrTry and ErrCatch in a separate enclosing function.
#define	ErrCatch(theErr)												\
			*ErrExceptionList() = (Ptr)_TryObject.nextP;			\
			} 																	\
		else {																\
			Long	theErr = _TryObject.err;							\
			*ErrExceptionList() = (Ptr)_TryObject.nextP;
			
			
#define	ErrEndCatch														\
			}																	\
	}



/********************************************************************
 * Error Manager Routines
 ********************************************************************/
#ifdef __cplusplus
extern "C" {
#endif

#if EMULATION_LEVEL != EMULATION_NONE
	#define	ErrSetJump(buf)			setjmp(buf)
	#define	ErrLongJump(buf,res) 	longjmp(buf,res)

#else
	Int	ErrSetJump(ErrJumpBuf buf)
								SYS_TRAP(sysTrapErrSetJump);
								
	void	ErrLongJump(ErrJumpBuf buf, Int result)
								SYS_TRAP(sysTrapErrLongJump);
#endif
						
Ptr*	ErrExceptionList(void)
							SYS_TRAP(sysTrapErrExceptionList);	
							
void  ErrThrow(Long err) 
							SYS_TRAP(sysTrapErrThrow);

void	ErrDisplayFileLineMsg(const Char * const filename, UInt lineNo, 
			const Char * const msg)
							SYS_TRAP(sysTrapErrDisplayFileLineMsg);

#ifdef __cplusplus 
}
#endif




#endif // __ERRORMGR_H__




