/******************************************************************************
 **	Filename:	danerror.c
 **	Purpose:	Routines for managing error trapping
 **	Author:		Dan Johnson
 **	History:	3/17/89, DSJ, Created.
 **
 **	(c) Copyright Hewlett-Packard Company, 1988.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 ******************************************************************************/
/**----------------------------------------------------------------------------
          Include Files and Type Defines
----------------------------------------------------------------------------**/
#include "general.h"
#include "danerror.h"
#include "callcpp.h"
#include "globaloc.h"
#ifdef __UNIX__
#include "assert.h"
#endif

#include <stdio.h>
#include <setjmp.h>

#define MAXTRAPDEPTH    100

#define ERRORTRAPDEPTH    1000

/**----------------------------------------------------------------------------
        Global Data Definitions and Declarations
----------------------------------------------------------------------------**/
static jmp_buf ErrorTrapStack[MAXTRAPDEPTH];
static VOID_PROC ProcTrapStack[MAXTRAPDEPTH];
static INT32 CurrentTrapDepth = 0;

/**----------------------------------------------------------------------------
              Public Code
----------------------------------------------------------------------------**/
/*---------------------------------------------------------------------------*/
void ReleaseErrorTrap() {
/*
 **	Parameters:
 **		None
 **	Globals:
 **		CurrentTrapDepth	number of traps on the stack
 **	Operation:
 **		This routine removes the current error trap from the
 **		error trap stack, thus returning control to the previous
 **		error trap.  If the error trap stack is empty, nothing is
 **		done.
 **	Return:
 **		None
 **	Exceptions:
 **		None
 **	History:
 **		4/3/89, DSJ, Created.
 */
  if (CurrentTrapDepth > 0) {
    CurrentTrapDepth--;
  }
}                                /* ReleaseErrorTrap */


/*---------------------------------------------------------------------------*/
void DoError(int Error, const char *Message) {
/*
 **	Parameters:
 **		Error	error number which is to be trapped
 **		Message	pointer to a string to be printed as an error message
 **	Globals:
 **		ErrorTrapStack		stack of error traps
 **		CurrentTrapDepth	number of traps on the stack
 **	Operation:
 **		This routine prints the specified error message to stderr.
 **		It then jumps to the current error trap.  If the error trap
 **		stack is empty, the calling program is terminated with a
 **		fatal error message.
 **	Return:
 **		None - this routine does not return.
 **	Exceptions:
 **		Empty error trap stack terminates the calling program.
 **	History:
 **		4/3/89, DSJ, Created.
 */
  if (Message != NULL) {
    cprintf ("\nError: %s!\n", Message);
  }

  if (CurrentTrapDepth <= 0) {
    cprintf ("\nFatal error: No error trap defined!\n");

    /* SPC 20/4/94
       There used to be a call to abort() here. I've changed it to call into the
       C++ error code to generate a meaningful status code
     */
    signal_termination_handler(Error);
  }

  if (ProcTrapStack[CurrentTrapDepth - 1] != DO_NOTHING)
    (*ProcTrapStack[CurrentTrapDepth - 1]) ();

  longjmp (ErrorTrapStack[CurrentTrapDepth - 1], 1);
}                                /* DoError */


/**----------------------------------------------------------------------------
              Private Code
----------------------------------------------------------------------------**/
/*---------------------------------------------------------------------------*/
jmp_buf &PushErrorTrap(VOID_PROC Procedure) {
/*
 **	Parameters:
 **		Procedure		trap procedure to execute
 **	Globals:
 **		ErrorTrapStack		stack of error traps
 **		CurrentTrapDepth	number of traps on the stack
 **	Operation:
 **		This routine pushes a new error trap onto the top of
 **		the error trap stack.  This new error trap can then be
 **		used in a call to setjmp.  This trap is then in effect
 **		until ReleaseErrorTrap is called.  WARNING: a procedure
 **		that calls PushErrorTrap should never exit before calling
 **		ReleaseErrorTrap.
 **	Return:
 **		Pointer to a new error trap buffer
 **	Exceptions:
 **		Traps an error if the error trap stack is already full
 **	History:
 **		3/17/89, DSJ, Created.
 **		9/12/90, DSJ, Added trap procedure parameter.
 */
  if (CurrentTrapDepth >= MAXTRAPDEPTH)
    DoError (ERRORTRAPDEPTH, "Error trap depth exceeded");
  ProcTrapStack[CurrentTrapDepth] = Procedure;
  return ErrorTrapStack[CurrentTrapDepth++];

}                                /* PushErrorTrap */
