/*-----------------------------------------------------------------------*
 * filename - except.c
 *
 * function(s)
 *      _setexc         - install RTL exception handler
 *      _unsetexc       - remove RTL exception handler
 *      _SetUserHandler - install user exception handler
 *-----------------------------------------------------------------------*/

/*
 *      C/C++ Run Time Library - Version 6.0
 *
 *      Copyright (c) 1991, 1993 by Borland International
 *      All Rights Reserved.
 *
 */

#ifdef __OS2__
#include <os2bc.h>
#else
#define INCL_USER
#include <ntbc.h>
#endif

#include <_defs.h>
#include <_io.h>

/*----------------------------------------------------------------------
 * _ExcRegPtr contains the address of an exception registration
 * record in the startup code's local stack area.
 */
extern PEXCEPTIONREGISTRATIONRECORD  _ExcRegPtr;

/*----------------------------------------------------------------------
 * The following flag is set to 1 by initstk.c if stack checking
 * is enabled.
 */
int _stkchk = 0;

/*----------------------------------------------------------------------
 * A pointer to the current exception handler.  If signal() is not
 * used, it points to a handler that always returns XCPT_CONTINUE_SEARCH.
 * If signal() is called, signal() sets it to point to its own exception
 * handler.
 */
ERR _HandlerPtr, _UserHandlerPtr;


/*----------------------------------------------------------------------
 * The default RTL exception handler
 */
ULONG __EHCC _DefHandler(PEXCEPTIONREPORTRECORD p,
                         struct _EXCEPTIONREGISTRATIONRECORD *q,
                         PCONTEXTRECORD r,
                         PVOID s);

/*---------------------------------------------------------------------*

Name            DefHandler - default Exception handler

Usage           ULONG __EHCC DefHandler(
                             PEXCEPTIONREPORTRECORD p,
                             PEXCEPTIONREGISTRATIONRECORD q,
                             PCONTEXTRECORD r,
                             PVOID s);

Description     This function is called indirectly by the RTL's internal
                exception handler if signal() is not used.  Its parameters
                are the normal exception handling parameters.
                The function performs no action except to return a code
                indicating that the exception was not handled.

Return value    The function returns XCPT_CONTINUE_SEARCH.

*---------------------------------------------------------------------*/

#pragma argsused

static ULONG __EHCC DefHandler(PEXCEPTIONREPORTRECORD p,
							   PEXCEPTIONREGISTRATIONRECORD q,
							   PCONTEXTRECORD r,
							   PVOID s)
{
	return (XCPT_CONTINUE_SEARCH);
}


/*---------------------------------------------------------------------*

Name            ExcHandler - RTL internal exception handler

Usage           static ULONG __EHCC ExcHandler(
                             PEXCEPTIONREPORTRECORD p,
                             PEXCEPTIONREGISTRATIONRECORD q,
                             PCONTEXTRECORD r,
                             PVOID s);

Description     This function is the sole exception handler for the RTL.
                It merely calls the exception handler pointed to
                by _UserHandlerPtr.  If _UserHandlerPtr cannot handle
                the exception, the exception handler pointed by
                _HandlerPtr is called.  Normally, both _UserHandler and
                _HandlerPtr point to DefHandler, the default handler.
                The user program can modify _UserHandlerPtr by calling
                _SetUserHandler. If signal() is used, _HandlerPtr will be
                modified to point to signal()'s own exception handler.

Return value    This function returns the value returned
                by the function pointed to by _UserHandlerPtr (if it
                returns XCPT_CONTINUE_EXCECUTION), or the value
                returned by _HandlerPtr.

*---------------------------------------------------------------------*/

#pragma warn -cln       /* XCPT_ constants are long */

static ULONG __EHCC ExcHandler(PEXCEPTIONREPORTRECORD p,
							   PEXCEPTIONREGISTRATIONRECORD q,
							   PCONTEXTRECORD r,
							   PVOID s)
{
	if (p->ExceptionNum == XCPT_UNABLE_TO_GROW_STACK && _stkchk != 0)
		_ErrorExit("Stack Overflow!");
	if (_UserHandlerPtr)
		if ((*_UserHandlerPtr)(p, q, r, s) == XCPT_CONTINUE_EXECUTION)
			return (XCPT_CONTINUE_EXECUTION);
	if (_HandlerPtr)
		if ((*_HandlerPtr)(p, q, r, s) == XCPT_CONTINUE_EXECUTION)
			return (XCPT_CONTINUE_EXECUTION);
		else
			return _DefHandler(p, q, r, s);
}

#pragma warn .cln


/*---------------------------------------------------------------------*

Name            _setexc - install RTL exception handler

Usage           void _setexc(PEXCEPTIONREGISTRATIONRECORD p);

Prototype in    none

Related
functions usage void _unsetexc(PEXCEPTIONREGISTRATIONRECORD p);

Description     This function installs the current thread's exception
                handler.  This must be done before starting the
                thread's main code.  The exception registration
                record is filled in by this function, and must
                be passed to _unsetexc before the thread terminates.
                The record must be located in the caller's local
                stack area, and the caller must be the outermost
                function of the thread; this ensures that the
                record will not disappear while the thread is
                running.

Return value    None.

*---------------------------------------------------------------------*/

void _setexc(PEXCEPTIONREGISTRATIONRECORD p)
{
    p->prev_structure = NULL;
    p->ExceptionHandler = ExcHandler;
    _SetExceptionHandler(p);
}

/*---------------------------------------------------------------------*

Name            _unsetexc - remove RTL exception handler

Usage           void _unsetexc(PEXCEPTIONREGISTRATIONRECORD p);

Prototype in    none

Related
functions usage void _setexc(PEXCEPTIONREGISTRATIONRECORD p);

Description     This function removes the current thread's exception
                handler.  This must be done prior to terminating
                the thread.  The exception registration record must
                have been filled in by an earlier call to _setexc.

Return value    None.

*---------------------------------------------------------------------*/

void _unsetexc(PEXCEPTIONREGISTRATIONRECORD p)
{
    _UnsetExceptionHandler(p);    /* un-set exception handler */
}


/*---------------------------------------------------------------------*

Name            _SetUserHandler - install user exception handler

Usage           void _SetUserHandler(ERR handler);

Prototype in    none

Related
functions usage void _unsetuserhandler(void);

Description     This function installs a user's exception handler.
                It does this by simply setting the global variable
                _UserHandlerPtr to point to the function specified
                by handler.

                When an exception occurs, the RTL's exception
                handler will call the user's handler. If the
                user's handler returns XCPT_CONTINUE_SEARCH,
                the RTL will attempt to handle the exception itself,
                possibly by generating a signal.  Otherwise the RTL
                will assume that the user's handler took care of the
                exception and will perform no other processing.

                This function returns the address of the previous
                exception handler.  If you wish to "chain" exceptions,
                you should save this address.  When your exception
                handler encounters an exception it cannot handle,
                it should call the previous handler and return the
                previous handler's return value.

                If you do not need to chain exceptions, you can ignore
                the return value of _SetUserHandler.  In this case,
                when your exception handler encounters an exception it
                cannot handle, it should return XCPT_CONTINUE_SEARCH.

                There are two ways to remove an exception handler. You
                can call _SetUserHandler with the address of the previous
                handler; this will allow correct exception chaining.
                Or you can call _unsethandler, which will remove
                all exception handlers, thereby "breaking" the chain.

Return value    The address of the previous exception handling function.

*---------------------------------------------------------------------*/

ERR _RTLENTRY _EXPFUNC _SetUserHandler(ERR handler)
{
    ERR oldhandler;

    oldhandler = _UserHandlerPtr;
    _UserHandlerPtr = handler;
    return oldhandler;
}

/*---------------------------------------------------------------------*

Name            _unsetuserhandler - remove user exception handler

Usage           void _unsetuserhandler(void);

Prototype in    none

Related
functions usage void _SetUserHandler(ERR handler);

Description     This function removes a user's exception handler
                that had been previously installed with _SetUserHandler.
                This is done by simply setting the global variable
                _UserHandlerPtr to point to a default exception
                handler that does nothing.

Return value    None.

*---------------------------------------------------------------------*/

void _RTLENTRY _EXPFUNC _unsetuserhandler(void)
{
    _UserHandlerPtr = DefHandler;   /* use default handler again */
}

void _init_except(void)
{
#pragma startup _init_except 0
    
    _HandlerPtr = DefHandler;       /* point to default signal handler */
    _UserHandlerPtr = DefHandler;   /* point to default user handler */
}


void _exit_except(void)
{
#pragma exit _exit_except 0

    if (_ExcRegPtr)
        _unsetexc(_ExcRegPtr);          /* un-set exception handler */
}

/* Called in startup to supply default handler */
void _InitDefaultHander(void)
{
    /* Register the exception handler using an exception registration
     * record that is in the local stack area of the startup code.
     * If a function like signal() were to set up its own exception handler,
     * the record would get corrupted as soon as the function returned,
     * because it would be in a stack frame that was no longer valid.
     */
    if (_ExcRegPtr)
        _setexc(_ExcRegPtr);
}

