/* rlerrors.c ********************************************************************************
* rlerrors.c -- RingLib error handling routines.
*
* Mark Showalter & Neil Heather, PDS Ring-Moon Systems Node, March 1998
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ringlib.h"
#include "fortran.h"
/********************
* Type definitions *
********************/
#define RL_ERROR_ID_LEN 31 /* max length of an error id, excluding null */
typedef struct RL_ERRORNODE_STRUCT {
struct RL_ERRORNODE_STRUCT *next;
RL_CHAR id[RL_ERROR_ID_LEN+1];
RL_INT4 type;
} RL_ERRORNODE;
/********************
* Static variables *
********************/
#define ERROR_TYPE_LIST 32
#define ERROR_TYPE_MASK 31
static RL_ERRORNODE RL_TypeInfo[ERROR_TYPE_LIST] = {
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0},
{NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}, {NULL, "", 0}};
static RL_ERRORNODE RL_LastError = {NULL, "", 0};
static RL_ERRORNODE RL_TempNode = {NULL, "", 0};
static FILE *errfile = NULL;
/********************************
* Internal function prototypes *
********************************/
static RL_ERRORNODE *ZRL_FindNode RL_PROTO((RL_CHAR *error_id,
RL_ERRORNODE *top));
static RL_ERRORNODE *ZRL_MakeNode RL_PROTO((RL_CHAR *error_id,
RL_ERRORNODE *top));
static RL_ERRORNODE *ZRL_UnlinkNode RL_PROTO((RL_CHAR *error_id,
RL_ERRORNODE *top));
static RL_INT4 ZRL_Hash RL_PROTO((RL_CHAR *error_id));
/*
********************************************************************************
* EXPORTED ROUTINES
********************************************************************************
*$ Component_name:
* RL_RaiseError (rlerrors.c)
*$ Abstract:
* This routine raises an error in the manner specified by the error type.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* void RL_RaiseError(error_id, message)
* RL_CHAR *error_id;
* RL_CHAR *message;
*$ Inputs:
* error_id string identifying the error category.
* message specific message relating to this particular error.
*$ Outputs:
* none
*$ Returns:
* none
*$ Detailed_description:
* This routine raises an error in the manner specified by the error type.
* The error may or may not print a message and it may or may not be
* recorded. The default action is for the error message to be printed on
* the stream specified by errfile and for the program to abort.
*
* The behavior depends on the value of the error_type parameter associated
* with the error code. Options are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* RL_ABORT is the default behavior. These constants are defined in the
* include file ringlib.h.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* Depending on the error type, an error may be pushed onto the top of the
* stack, a message may be printed, and the program may abort.
*$ Examples:
* This snippet of code raises a "DIV_BY_ZERO" error before the program
* attempts to divide by zero.
*
* if (x == 0.) {
* RL_RaiseError("DIV_BY_ZERO",
* "You're attempting to divide by x when x is zero!");
* y = 0.;
* }
* else {
* y = 1. / x;
* }
*$ Error_handling:
* No error conditions are raised. If out of critical memory, the program
* prints a fatal error message and aborts.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
void RL_RaiseError(error_id, message)
RL_CHAR *error_id;
RL_CHAR *message;
{
RL_ERRORNODE *node;
RL_INT4 type;
RL_BOOL qprint, qrecord, qabort;
RL_CHAR *info;
/* Search error-type tree for matching node */
node = ZRL_FindNode(error_id, RL_TypeInfo + ZRL_Hash(error_id));
/* Determine error type */
if (node == NULL) type = RL_ABORT; /* the default */
else type = node->type;
/* Decide what to do */
switch (type) {
case RL_IGNORE:
qprint = FALSE; qrecord = FALSE; qabort = FALSE;
break;
case RL_INFORM:
qprint = TRUE; qrecord = FALSE; qabort = FALSE;
break;
case RL_RECORD:
qprint = FALSE; qrecord = TRUE; qabort = FALSE;
break;
case RL_SIGNAL:
qprint = TRUE; qrecord = TRUE; qabort = FALSE;
break;
case RL_ABORT:
default:
qprint = TRUE; qrecord = FALSE; qabort = TRUE;
break;
}
/* Record error condition if necessary */
if (qrecord) {
ZRL_MakeNode(error_id, &RL_LastError);
}
/* Print message if necessary */
if (qprint) {
if (qabort) info = "fatal";
else if (qrecord) info = "error";
else info = "warning";
if (errfile == NULL)
fprintf(stderr, "%s (%s): %s\n", error_id, info, message);
else
fprintf(errfile, "%s (%s): %s\n", error_id, info, message);
}
/* Abort program if necessary */
if (qabort) {
exit(1);
}
}
/*
********************************************************************************
*$ Component_name:
* RL_PipeErrors (rlerrors.c)
*$ Abstract:
* This routine changes the file into which error messages are placed. By
* default, error messages are displayed on the "stderr" stream.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* void RL_PipeErrors(filename)
* RL_CHAR *filename;
*$ Inputs:
* filename file where error messages are to be recorded. Use blank
* or NULL to direct messages back to "stderr".
*$ Outputs:
* none
*$ Returns:
* none
*$ Detailed_description:
* This routine changes the file into which error messages are placed. By
* default, error messages are displayed on the "stderr" stream.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* A file is opened if necessary.
*$ Examples:
* This sends future error messages to file "errors.lis":
* RL_PipeErrors("errors.lis");
* This redirects future error messages to the terminal:
* RL_PipeErrors(NULL);
* or
* RL_PipeErrors("");
*$ Error_handling:
* RingLib error handling is in effect. Conditions raised:
* RL_OPEN_FAILURE if file could not be opened for writing; in
* this case stderr is used for this and future
* messages.
*$ Limitations:
* none
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
void RL_PipeErrors(filename)
RL_CHAR *filename;
{
/* Close current error file if necessary */
if (errfile != NULL) {
fclose(errfile);
errfile = NULL;
}
/* Open new error file if necessary */
if (filename == NULL || filename[0] == '\0') {
errfile = NULL;
} else {
errfile = fopen(filename, "w+t");
if (errfile == NULL) {
RL_RaiseError("RL_OPEN_FAILURE", "unable to open error file");
}
}
}
/*
********************************************************************************
*$ Component_name:
* RL_TestError (rlerrors.c)
*$ Abstract:
* This routine tests for the presence of an error on the top of the error
* stack and returns a pointer to the error_id string. It does not modify
* the error stack.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_CHAR *RL_TestError(void)
*$ Inputs:
* none
*$ Outputs:
* none
*$ Returns:
* pointer (read-only) to a string containing the error id, or NULL if no
* error condition has been raised.
*$ Detailed_description:
* This routine tests for the presence of an error on the top of the error
* stack and returns a pointer to the error_id string. If it does not find
* an error, it returns a NULL. It does not modify the error stack.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose you call a routine Math() that might raise errors "DIV_BY_ZERO"
* or "SQRT_NEGATIVE". You wish to print your own error message if either
* of these errors occurred, and then to remove them from the error stack.
*
* RL_SetErrorType("DIV_BY_ZERO", RL_RECORD);
* RL_SetErrorType("SQRT_NEGATIVE", RL_RECORD);
* Math();
* if (RL_TestError() != NULL) {
* printf("Error %s occurred!\n", RL_ClearError());
* }
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_CHAR *RL_TestError()
{
if (RL_LastError.next == NULL) /* stack is empty */
return NULL;
else
return (RL_LastError.next->id);
}
/*
********************************************************************************
*$ Component_name:
* RL_ClearError (rlerrors.c)
*$ Abstract:
* This routine removes the most recent error from the top of the error
* stack and returns a pointer to the error_id string.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_CHAR *RL_ClearError(void)
*$ Inputs:
* none
*$ Outputs:
* none
*$ Returns:
* pointer (read-only) to a string containing the error id, or NULL if no
* error condition has been raised.
*$ Detailed_description:
* This routine removes the most recent error from the top of the error
* stack and returns a pointer to the error_id string. If it does not find
* an error, it returns a NULL.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* The first error is removed from the stack and freed.
*$ Examples:
* Suppose you call a routine Math() that might raise errors "DIV_BY_ZERO"
* or "SQRT_NEGATIVE". You wish to print your own error message if either
* of these errors occurred, and then to remove them from the error stack.
*
* RL_SetErrorType("DIV_BY_ZERO", RL_RECORD);
* RL_SetErrorType("SQRT_NEGATIVE", RL_RECORD);
* Math();
* if (RL_TestError() != NULL) {
* printf("Error %s occurred!\n", RL_ClearError());
* }
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_CHAR *RL_ClearError()
{
RL_ERRORNODE *top;
/* If stack is empty, return NULL */
if (RL_LastError.next == NULL) return NULL;
/* Otherwise pop stack and return error id */
top = RL_LastError.next; /* save top pointer */
RL_TempNode = *top; /* copy top node */
RL_LastError.next = RL_LastError.next->next; /* unlink */
XRL_Free(top); /* free */
return RL_TempNode.id; /* return id pointer */
}
/*
********************************************************************************
*$ Component_name:
* RL_TestError1 (rlerrors.c)
*$ Abstract:
* This routine tests for the presence of a particular error on the error
* stack. If returns TRUE if it is found and FALSE otherwise.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_BOOL RL_TestError1(error_id)
* RL_CHAR *error_id;
*$ Inputs:
* error_id pointer to a string containing the error id.
*$ Outputs:
* none
*$ Returns:
* TRUE if the error was found on the stack; FALSE otherwise.
*$ Detailed_description:
* This routine tests for the presence of a particular error on the error
* stack. If returns TRUE if it is found and FALSE otherwise. It does not
* modify the error stack.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose you call a routine Math() that might raise error "DIV_BY_ZERO".
* You wish to print your own error message if this occurs, and then leave
* it on the error stack for another routine to check.
*
* RL_SetErrorType("DIV_BY_ZERO", RL_RECORD);
* Math();
* if (RL_TestError1("DIV_BY_ZERO")) {
* printf("You tried to divide by zero!\n");
* }
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_BOOL RL_TestError1(error_id)
RL_CHAR *error_id;
{
RL_ERRORNODE *node;
node = ZRL_FindNode(error_id, &RL_LastError);
if (node == NULL) return FALSE;
else return TRUE;
}
/*
********************************************************************************
*$ Component_name:
* RL_ClearError1 (rlerrors.c)
*$ Abstract:
* This routine removes a particular error from the error stack. It
* returns TRUE if the error was found and FALSE otherwise.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_BOOL RL_ClearError1(error_id)
* RL_CHAR *error_id;
*$ Inputs:
* error_id pointer to a string containing the error id.
*$ Outputs:
* none
*$ Returns:
* TRUE if the error was found; FALSE otherwise.
*$ Detailed_description:
* This routine removes a particular error from the error stack. It
* returns TRUE if the error was found and FALSE otherwise.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* An error may be removed from the stack and freed.
*$ Examples:
* Suppose you call a routine Math() that might raise error "DIV_BY_ZERO".
* You wish to print your own error message if this occurs, and then
* remove it from the error stack.
*
* RL_SetErrorType("DIV_BY_ZERO", RL_RECORD);
* Math();
* if (RL_ClearError1("DIV_BY_ZERO")) {
* printf("You tried to divide by zero!\n");
* }
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_BOOL RL_ClearError1(error_id)
RL_CHAR *error_id;
{
RL_ERRORNODE *node;
/* Find the desired node and unlink it from the stack */
node = ZRL_UnlinkNode(error_id, &RL_LastError);
/* If the node was not found, return FALSE */
if (node == NULL) return FALSE;
/* Otherwise, free it and return TRUE */
XRL_Free(node);
return TRUE;
}
/*
********************************************************************************
*$ Component_name:
* RL_SetErrorType (rlerrors.c)
*$ Abstract:
* This routine sets the type for a particular error. It also returns the
* current value of the error type.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_INT4 RL_SetErrorType(error_id, error_type)
* RL_CHAR *error_id;
* RL_INT4 error_type;
*$ Inputs:
* error_id string identifying the error id.
* error_type value indicating how the error is to be handled.
* Options are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* These constants are defined in the include file
* ringlib.h.
*$ Outputs:
* none
*$ Returns:
* the previous error_type for this error_id.
*$ Detailed_description:
* This routine sets the type for a particular error. It also returns the
* current value of the error type.
*
* The error type controls what happens when RL_RaiseError() is called.
* Error type values are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* RL_ABORT is the default behavior. These constants are defined in the
* include file ringlib.h.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* Depending on the error type, an error may be removed from the stack and
* freed.
*$ Examples:
* Suppose you wish to change temporarily the method a program uses to
* handle DIV_BY_ZERO errors to RL_RECORD, and then to restore it to the
* previous method when you're done.
*
* RL_INT4 old_type;
*
* old_type = RL_SetErrorType("DIV_BY_ZERO", RL_RECORD);
* ... (DIV_BY_ZERO is now set to record)
* RL_SetErrorType("DIV_BY_ZERO", old_type);
* ... (previous type of DIV_BY_ZERO is restored)
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_INT4 RL_SetErrorType(error_id, error_type)
RL_CHAR *error_id;
RL_INT4 error_type;
{
RL_ERRORNODE *node;
RL_INT4 save_type;
/* On ABORT, free node */
if (error_type == RL_ABORT) {
node = ZRL_UnlinkNode(error_id, RL_TypeInfo + ZRL_Hash(error_id));
if (node == NULL) {
save_type = RL_ABORT;
} else {
save_type = node->type;
XRL_Free((RL_VOID *) node);
}
/* Otherwise, modify node */
} else {
node = ZRL_MakeNode(error_id, RL_TypeInfo + ZRL_Hash(error_id));
save_type = node->type;
node->type = error_type;
}
return save_type;
}
/*
********************************************************************************
*$ Component_name:
* RL_GetErrorType (rlerrors.c)
*$ Abstract:
* This routine returns the error type for a particular error id.
*$ Keywords:
* RINGLIB, ERRORS
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_INT4 RL_GetErrorType(error_id)
* RL_CHAR *error_id;
*$ Inputs:
* error_id string identifying the error id.
*$ Outputs:
* none
*$ Returns:
* the error type for the given error id.
*$ Detailed_description:
* This routine returns the error type for a particular error id.
*
* The error type controls what happens when RL_RaiseError() is called.
* Error type values are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* RL_ABORT is the default behavior. These constants are defined in the
* include file ringlib.h.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose you call a routine Math() that might raise error "DIV_BY_ZERO".
* Without changing the type of this error permanently, you wish to make
* sure a message is printed.
*
* RL_INT4 old_type;
*
* old_type = RL_GetErrorType("DIV_BY_ZERO");
* if (old_type < 0) RL_SetErrorType("DIV_BY_ZERO", -old_type);
* Math();
* RL_SetErrorType("DIV_BY_ZERO", old_type);
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters, plus final null character.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
*******************************************************************************/
RL_INT4 RL_GetErrorType(error_id)
RL_CHAR *error_id;
{
RL_ERRORNODE *node;
node = ZRL_FindNode(error_id, RL_TypeInfo + ZRL_Hash(error_id));
if (node == NULL) return RL_ABORT;
else return node->type;
}
/*
********************************************************************************
* INTERNAL ROUTINES
********************************************************************************
* RL_ERRORNODE *ZRL_FindNode(error_id, top)
*
* This internal function finds the node with matching error_id in a linked list
* of error nodes.
*
* Input:
* error_id error id to find in list.
* top pointer to a node whose "next" field points to the first
* entry in list.
*
* Return: pointer to the error node, or NULL if it was not found.
*******************************************************************************/
static RL_ERRORNODE *ZRL_FindNode(error_id, top)
RL_CHAR *error_id;
RL_ERRORNODE *top;
{
int index;
RL_ERRORNODE *node;
/* Walk down list looking for matching node */
for(node = top->next; node != NULL; node = node->next)
if (strcmp(error_id, node->id) == 0) return node;
/* If not found, return NULL */
return NULL;
}
/*
********************************************************************************
* RL_ERRORNODE *ZRL_MakeNode(error_id, top)
*
* This internal function finds the node with matching error_id in a linked list
* of error nodes. If it does not find a matching node, it creates one and
* adds it to the list.
*
* Input:
* error_id error id to find in list.
* top pointer to a node whose "next" field points to the first
* entry in list.
*
* Return: pointer to the error node.
*******************************************************************************/
static RL_ERRORNODE *ZRL_MakeNode(error_id, top)
RL_CHAR *error_id;
RL_ERRORNODE *top;
{
RL_ERRORNODE *node, *root;
/* Look for node and return it if found */
node = ZRL_FindNode(error_id, top);
if (node != NULL) return node;
/* Allocate a new node and put it at top of list
* Note that there is danger of infinite recursion here; if XRL_Malloc()
* fails but RL_MEMORY_ERROR is set to record without aborting, then it will
* recursively call this same routine ad infinitum. We therefore abort if
* this allocation fails. */
node = (RL_ERRORNODE *) XRL_MustAlloc(sizeof(RL_ERRORNODE));
node->next = top->next;
top->next = node;
/* Initialize node */
strncpy(node->id, error_id, RL_ERROR_ID_LEN);
node->id[RL_ERROR_ID_LEN] = '\0'; /* ensure null termination */
node->type = RL_ABORT;
return node;
}
/*
********************************************************************************
* RL_ERRORNODE *ZRL_UnlinkNode(error_id, top)
*
* This internal function finds the node giving error type for the specified
* error id. If found, the node is removed from the linked list.
*
* Input:
* error_id error id to find in list.
* top pointer to a node whose "next" field points to the first
* entry in list.
*
* Return: pointer to the error node, or NULL if it is not found.
*
* Side effects: node is unlinked from the list but is not freed.
*******************************************************************************/
static RL_ERRORNODE *ZRL_UnlinkNode(error_id, top)
RL_CHAR *error_id;
RL_ERRORNODE *top;
{
RL_ERRORNODE *parent, *node;
/* Walk down list looking for matching node */
for (parent = top; parent->next != NULL; parent = parent->next) {
if (strcmp(error_id, parent->next->id) == 0) {
/* Unlink node and return it */
node = parent->next;
parent->next = node->next;
return node;
}
}
/* Node was not found */
return NULL;
}
/*
********************************************************************************
* ZRL_Hash(error_id)
*
* This internal function calculates a quick hash value between 0 and 31 based on
* the given error id string.
*
* Inputs:
* error_id error id.
*
* Return: pointer to the error node, or NULL if it is not found.
*
* Side effects: node is unlinked from the list but is not freed.
*******************************************************************************/
static RL_INT4 ZRL_Hash(error_id)
RL_CHAR *error_id;
{
RL_INT4 hash, i;
hash = 0;
for (i = 0; i < 8; i++) {
if (error_id[i] == '\0') break;
hash = 5*hash + (RL_INT4) error_id[i];
}
return (hash & ERROR_TYPE_MASK);
}
/*
********************************************************************************
* FORTRAN INTERFACE ROUTINES
********************************************************************************
*$ Component_name:
* FRL_RaiseError (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine raises an error in the manner specified by the error type.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* subroutine FRL_RaiseError(error_id, message)
* character*(*) error_id, message
*$ Inputs:
* error_id string identifying the error id.
* message specific message relating to this particular error.
*$ Outputs:
* none
*$ Returns:
* none
*$ Detailed_description:
* This routine raises an error in the manner specified by the error type.
* The error may or may not print a message and it may or may not be
* recorded. The default action is for the error message to be printed on
* the stream specified by errfile and for the program to abort.
*
* The behavior depends on the value of the error_type parameter associated
* with the error code. Options are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* RL_ABORT is the default behavior. These constants are defined in the
* include file ringlib.h.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* Depending on the error type, an error may be pushed onto the top of the
* stack, a message may be printed, and the program may abort.
*$ Examples:
* This snippet of code raises a "DIV_BY_ZERO" error before the program
* attempts to divide by zero.
*
* if (x .eq. 0.) then
* call FRL_RaiseError('DIV_BY_ZERO',
* 'You're attempting to divide by x when x is zero!')
* y = 0.
* else
* y = 1. / x
* end if
*$ Error_handling:
* No error conditions are raised. If out of critical memory, the program
* prints a fatal error message and aborts.
*$ Limitations:
* Error ids are limited to 31 characters; messages are limited to 255
* characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_RaiseError() defined here is the intermediary routine between
* FRL_RaiseError() and RL_RaiseError(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* subroutine GRL_RaiseError(error_id, message)
* byte error_id(*), message(*)
*******************************************************************************/
void FORTRAN_NAME(grl_raiseerror) (error_id, message)
RL_CHAR *error_id, *message;
{
RL_RaiseError(error_id, message);
}
/*
********************************************************************************
*$ Component_name:
* FRL_PipeErrors (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine changes the file into which error messages are placed. By
* default, error messages are displayed on the terminal.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* subroutine FRL_PipeErrors(filename)
* character*(*) filename
*$ Inputs:
* filename file where error messages are to be recorded. Use a
* blank string to direct messages back to the terminal.
*$ Outputs:
* none
*$ Returns:
* none
*$ Detailed_description:
* This routine changes the file into which error messages are placed. By
* default, error messages are displayed on the terminal.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* A file is opened if necessary.
*$ Examples:
* This sends future error messages to file "errors.lis":
* call FRL_PipeErrors('errors.lis')
* This redirects future error messages to the terminal:
* call FRL_PipeErrors(' ')
*$ Error_handling:
* RingLib error handling is in effect. Conditions raised:
* RL_OPEN_FAILURE if file could not be opened for writing; in
* this case the terminal is used for this and
* future messages.
*$ Limitations:
* File names are limited to 255 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_PipeErrors() defined here is the intermediary routine between
* FRL_PipeErrors() and RL_PipeErrors(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* subroutine GRL_PipeErrors(filename)
* byte filename(*)
*******************************************************************************/
void FORTRAN_NAME(grl_pipeerrors) (filename)
RL_CHAR *filename;
{
RL_PipeErrors(filename);
}
/*
********************************************************************************
*$ Component_name:
* FRL_TestError (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine tests for the presence of an error on the top of the error
* stack and returns the error_id string.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* logical*4 function FRL_TestError(error_id)
* character*(*) error_id
*$ Inputs:
* none
*$ Outputs:
* error_id string containing the error id, or blank if no error
* condition is found.
*$ Returns:
* .TRUE. if an error condition was found on the stack; .FALSE. otherwise.
*$ Detailed_description:
* This routine tests for the presence of an error on the top of the error
* stack and returns the error_id string. If it does not find an error, it
* returns a blank string. It does not modify the error stack. It also
* returns .TRUE. if an error was found and .FALSE. otherwise.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose you call a routine Math() that might raise errors "DIV_BY_ZERO"
* or "SQRT_NEGATIVE". You wish to print your own error message if either
* of these errors occurred, and then to remove them from the error stack.
*
* character*40 id
*
* call FRL_SetErrorType('DIV_BY_ZERO', RL_RECORD)
* call FRL_SetErrorType('SQRT_NEGATIVE', RL_RECORD)
* call Math()
* if (FRL_TestError(id)) then
* write(*,*) 'Error ', id, ' occurred!'
* call FRL_ClearError(id)
* end if
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_TestError() defined here is the intermediary routine between
* FRL_TestError() and RL_TestError(), allowing for the fact that strings cannot
* be passed directly between FORTRAN and C. See fringlib.for for the rest of
* the code.
*
* logical*4 function GRL_TestError(buffer, lbuffer)
* byte buffer(*)
* integer*4 lbuffer
*******************************************************************************/
RL_INT4 FORTRAN_NAME(grl_testerror) (buffer, lbuffer)
RL_CHAR *buffer;
RL_INT4 *lbuffer;
{
RL_CHAR *error_id;
error_id = RL_TestError();
if (error_id == NULL) {
buffer[0] = '\0';
return FFALSE;
}
strncpy(buffer, error_id, *lbuffer-1);
buffer[*lbuffer-1] = '\0';
return FTRUE;
}
/*
********************************************************************************
*$ Component_name:
* FRL_ClearError (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine removes the most recent error from the top of the error
* stack and returns the error_id string.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* logical*4 function FRL_ClearError(error_id)
* character*(*) error_id
*$ Inputs:
* none
*$ Outputs:
* error_id string containing the error id, or blank if no error
* condition was found.
*$ Returns:
* .TRUE. if an error condition was found on the stack; .FALSE. otherwise.
*$ Detailed_description:
* This routine removes the most recent error from the top of the error
* stack and returns the error_id string. If it does not find an error,
* it returns a blank string. It also returns .TRUE. if an error was
* found and .FALSE. otherwise.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* The first error is removed from the stack and freed.
*$ Examples:
* Suppose you call a routine Math() that might raise errors "DIV_BY_ZERO"
* or "SQRT_NEGATIVE". You wish to print your own error message if either
* of these errors occurred, and then to remove them from the error stack.
*
* character*40 id
*
* call FRL_SetErrorType('DIV_BY_ZERO', RL_RECORD)
* call FRL_SetErrorType('SQRT_NEGATIVE', RL_RECORD)
* call Math()
* if (FRL_TestError(id)) then
* write(*,*) 'Error ', id, ' occurred!'
* call FRL_ClearError(id)
* end if
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_ClearError() defined here is the intermediary routine between
* FRL_ClearError() and RL_ClearError(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* logical*4 function GRL_ClearError(buffer, lbuffer)
* byte buffer(*)
* integer*4 lbuffer
*******************************************************************************/
RL_INT4 FORTRAN_NAME(grl_clearerror) (buffer, lbuffer)
RL_CHAR *buffer;
RL_INT4 *lbuffer;
{
RL_CHAR *error_id;
error_id = RL_ClearError();
if (error_id == NULL) {
buffer[0] = '\0';
return FFALSE;
}
strncpy(buffer, error_id, *lbuffer-1);
buffer[*lbuffer-1] = '\0';
return FTRUE;
}
/*
********************************************************************************
*$ Component_name:
* FRL_TestError1 (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine tests for the presence of a particular error on the error
* stack. It returns .TRUE. if it is found and .FALSE. otherwise.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* logical*4 function FRL_TestError1(error_id)
* character*(*) error_id
*$ Inputs:
* error_id string containing the error id to test.
*$ Outputs:
* none
*$ Returns:
* .TRUE. if the error was found on the stack; .FALSE. otherwise.
*$ Detailed_description:
* This routine tests for the presence of a particular error on the error
* stack. It returns .TRUE. if it is found and .FALSE. otherwise. It does
* not modify the error stack.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose you call a routine Math() that might raise error "DIV_BY_ZERO".
* You wish to print your own error message if this occurs, and then leave
* it on the error stack for another routine to check.
*
* call FRL_SetErrorType('DIV_BY_ZERO', RL_RECORD)
* call Math()
* if (FRL_TestError1('DIV_BY_ZERO')) then
* write(*,*) 'You tried to divide by zero!'
* end if
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_TestError1() defined here is the intermediary routine between
* FRL_TestError1() and RL_TestError1(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* logical*4 function GRL_TestError1(error_id)
* byte error_id(*)
*******************************************************************************/
RL_INT4 FORTRAN_NAME(grl_testerror1) (error_id)
RL_CHAR *error_id;
{
return (RL_TestError1(error_id) ? FTRUE : FFALSE);
}
/*
********************************************************************************
*$ Component_name:
* FRL_ClearError1 (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine removes a particular error from the error stack, if found.
* It returns .TRUE. if the error was found and .FALSE. otherwise.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* logical*4 function FRL_ClearError1(error_id)
* character*(*) error_id
*$ Inputs:
* error_id string containing the error id to clear.
*$ Outputs:
* none
*$ Returns:
* .TRUE. if the error was found; .FALSE. otherwise.
*$ Detailed_description:
* This routine removes a particular error from the error stack, if found.
* It returns .TRUE. if the error was found and .FALSE. otherwise.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* An error may be removed from the stack and freed.
*$ Examples:
* Suppose you call a routine Math() that might raise error "DIV_BY_ZERO".
* You wish to print your own error message if this occurs, and then
* remove this error from the stack.
*
* call FRL_SetErrorType('DIV_BY_ZERO', RL_RECORD)
* call Math()
* if (FRL_ClearError1('DIV_BY_ZERO')) then
* write(*,*) 'You tried to divide by zero!'
* end if
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_ClearError1() defined here is the intermediary routine between
* FRL_ClearError1() and RL_ClearError1(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* logical*4 function GRL_ClearError1(error_id)
* byte error_id(*)
*******************************************************************************/
RL_INT4 FORTRAN_NAME(grl_clearerror1) (error_id)
RL_CHAR *error_id;
{
return (RL_ClearError1(error_id) ? FTRUE : FFALSE);
}
/*
********************************************************************************
*$ Component_name:
* FRL_SetErrorType (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine sets the type for a particular error. It also returns the
* current value of the error type.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* integer*4 function FRL_SetErrorType(error_id, error_type)
* character*(*) error_id
* integer*4 error_type
*$ Inputs:
* error_id string identifying the error id.
* error_type value indicating how the error is to be handled.
*$ Outputs:
* none
*$ Returns:
* the previous error_type for this error_id.
*$ Detailed_description:
* This routine sets the type for a particular error. It also returns the
* current value of the error type.
*
* The error type controls what happens when RL_RaiseError() is called.
* Error type values are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* RL_ABORT is the default behavior. These constants are defined in the
* include file ringlib.h.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* Depending on the error type, an error may be removed from the stack and
* freed.
*$ Examples:
* Suppose you wish to change temporarily the method a program uses to
* handle DIV_BY_ZERO errors to RL_RECORD, and then to restore it to the
* previous method when you're done.
*
* integer*4 old_type
*
* old_type = FRL_SetErrorType('DIV_BY_ZERO', RL_RECORD)
* ... (DIV_BY_ZERO is now set to record)
*
* call FRL_SetErrorType('DIV_BY_ZERO', old_type)
* ... (previous type of DIV_BY_ZERO is restored)
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_SetErrorType() defined here is the intermediary routine between
* FRL_SetErrorType() and RL_SetErrorType(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* integer*4 function GRL_SetErrorType(error_id, error_type)
* byte error_id(*)
* integer*4 error_type
*******************************************************************************/
RL_INT4 FORTRAN_NAME(grl_seterrortype) (error_id, error_type)
RL_CHAR *error_id;
RL_INT4 *error_type;
{
return RL_SetErrorType(error_id, *error_type);
}
/*
********************************************************************************
*$ Component_name:
* FRL_GetErrorType (rlerrors.c, fringlib.for)
*$ Abstract:
* This routine returns the error type for a particular error id.
*$ Keywords:
* RINGLIB, ERRORS
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
integer*4 function FRL_GetErrorType(error_id)
character*(*) error_id
*$ Inputs:
* error_id string identifying the error id.
*$ Outputs:
* none
*$ Returns:
* the error type for the given error id.
*$ Detailed_description:
* This routine returns the error type for a particular error id.
*
* The error type controls what happens when RL_RaiseError() is called.
* Error type values are:
* RL_IGNORE = -1: don't print; don't record in stack.
* RL_INFORM = 1: print; don't record in stack.
* RL_RECORD = -2: don't print; record in stack.
* RL_SIGNAL = 2: print; record in stack.
* RL_ABORT = 3: print; abort program
* RL_ABORT is the default behavior. These constants are defined in the
* include file ringlib.h.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose you call a routine Math() that might raise error "DIV_BY_ZERO".
* Without changing the type of this error permanently, you wish to make
* sure a message is printed.
*
* integer*4 old_type
*
* old_type = FRL_GetErrorType('DIV_BY_ZERO')
* if (old_type .lt. 0) call FRL_SetErrorType('DIV_BY_ZERO', -old_type)
* call Math()
* call FRL_SetErrorType('DIV_BY_ZERO', old_type)
*$ Error_handling:
* No error conditions are raised.
*$ Limitations:
* Error ids are limited to 31 characters.
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
*$ Change_history:
* none
********************************************************************************
* Note: GRL_GetErrorType() defined here is the intermediary routine between
* FRL_GetErrorType() and RL_GetErrorType(), allowing for the fact that strings
* cannot be passed directly between FORTRAN and C. See fringlib.for for the
* rest of the code.
*
* integer*4 function GRL_GetErrorType(error_id)
* byte error_id(*)
*******************************************************************************/
RL_INT4 FORTRAN_NAME(grl_geterrortype) (error_id)
RL_CHAR *error_id;
{
return RL_GetErrorType(error_id);
}
/*******************************************************************************
*/