0. Error Handling in SPICELIB





This Required Reading document details the use of SPICELIB error handling facilities.

NOTE

Most of this information in this document is OPTIONAL reading, not ``required'' reading. To get started using SPICELIB quickly, it suffices to read up through section 1.1, ``The First Thing You Should Know.''
About the organization of this Required Reading document:

The first chapter describes ``Using SPICELIB Error Handling.'' We begin with brief descriptions of the error handling features, and many examples of their use.

The second chapter describes ``Definitions and Concepts.'' This chapter provides a more detailed and complete discussion of the concepts used in describing the SPICELIB error handling mechanism, but generally does not give examples. Here we define what we mean by ``errors,'' describe error messages and their use, and describe the possible error processing ``actions'' -- ways of responding to error conditions.

The third chapter describes ``Advanced Programming With Error Handling.'' We discuss some further considerations, not discussed in chapter 1, pertaining to the extension of the error reporting scheme to your own application code.

The document covers the following topics:

Error handling topics beyond the scope of this document:

Before starting our discussion of how to use the SPICELIB error handling facilities, let's briefly answer the question, ``Why perform error handling at all?'' Here are a few reasons:



1. Using SPICELIB Error Handling





This chapter tells you how to use most of the features of the SPICELIB error handling mechanism. Many examples are given, but details are saved for chapter 2, ``Concepts and Definitions.''

The material in this chapter covers three areas:



1.1. The First Thing You Should Know




The first thing to know about SPICELIB error handling is, you don't HAVE to do anything to use it. As a default, when a SPICELIB routine detects an error, SPICELIB will print error messages to the default output device (the screen, on most systems), and then STOP.

This capability is built into SPICELIB software; you get it automatically when you link your program with SPICELIB. No additional action of any kind is needed to make it work.

If this behavior is adequate for your application, you don't need to read the rest of this document.



1.2. What SPICELIB Does About Errors, Automatically




When a SPICELIB routine detects an error (we call this ``signalling'' an error), the SPICELIB error handling mechanism will write a set of descriptive error messages to the default output device, which is the terminal screen on most systems. The messages are:

After writing these messages, the error handling mechanism will halt execution of the program.

See section 2.1, ``About Error Messages,'' for details about error messages.



1.3. Changing What SPICELIB Does About Errors




You can change the set of error messages written when an error occurs. You can re-direct the output to a file, or suppress it. You can choose to have your program continue after an detecting an error rather than stopping. Sections 1.4 -- 1.6 describe how to select these actions.



1.4. Choosing Where the Error Messages Are Sent




Suppose you want to have any error messages written to a file, rather than to the default output device (the screen, on most systems). You can do this by calling the SPICELIB routine, ERRDEV. The first argument should be 'SET'. The second should be the file specification.

For example, to have error messages go to the file, ERROR.DAT, you could use the following code:

   C
   C     Set the error output device for SPICELIB
   C     error messages to the file ERROR.DAT:
   C
         CALL ERRDEV ( 'SET', 'ERROR.DAT' )
This call should precede calls to other SPICELIB routines, except ERRACT and ERRPRT. If your program has an initialization portion, this call should go there.



1.5. Choosing Which Error Messages to Write




By default, when an error is detected by a SPICELIB routine, up to five different types (listed in section 1.2) of error messages are written. You can tell SPICELIB's error handling mechanism to write any combination, including ``all'' and ``none'' of these messages.

Change the set of written messages via a call to the SPICELIB routine, ERRPRT.

The first argument should be 'SET'.

The second argument is a list of message types that you want to ADD to the set of messages that currently are selected to be output when an error occurs.

The keywords which may be used in the list:

   SHORT
   LONG
   EXPLAIN
   TRACEBACK
   DEFAULT
   ALL         ( write all messages )
   NONE        ( write no messages  )
The list of message choices is read from left to right, with each word ADDING to the previous set of messages (except for the word NONE, which subtracts all of the messages from your selection).

Some examples may help clarify this.



Example 1



Suppose that currently, the short message has been selected for output. To ADD the long message, make the call:

   C
   C     Add the long message to the set selected for output
   C     when an error occurs:
   C
         CALL ERRPRT ( 'SET', 'LONG' )
Now the short and long messages will be output if SPICELIB detects an error.



Example 2



What if you want JUST the long message? Put the word NONE at the beginning of the list; this cancels the previous selection:

   C
   C     Just output the long message
   C     when an error occurs:
   C
         CALL ERRPRT (  'SET',   'NONE, LONG'  )


Example 3



What if you want just the traceback and long message? Put the word NONE at the beginning of the list; this cancels the previous selection:

   C
   C     Just output the long message and traceback
   C     on error:
   C
         CALL ERRPRT (  'SET',   'NONE, TRACEBACK, LONG'  )


Example 4



How about no messages?

   C
   C     Don't output ANY SPICELIB error messages
   C     on error:
   C
         CALL ERRPRT (  'SET',   'NONE'  )


Example 5



All messages?

   C
   C     Output ALL SPICELIB error messages
   C     when an error occurs:
   C
         CALL ERRPRT (  'SET',   'ALL'  )
For a detailed discussion of just what these error messages are, see section 2.1 below, ``About Error Messages.''



1.6. Choosing the Error Response Action




We've said (section 1.1) that SPICELIB's default response to error detection includes halting the program. What if you don't want that?

SPICELIB's error handling mechanism allows you to choose one of several different error response ``actions.''

Briefly, the choices are:

DEFAULT

The action you start with, automatically. This is the same as ``abort'' (below), except that all of the error messages, including the ``default'' message, are written.
ABORT

Print messages and halts the program. With this action, you can select the error messages that are written.
REPORT

Write messages and CONTINUE EXECUTION.
This action may be useful for debugging. Caution: Once an error has occurred, your program may not execute as expected.

RETURN

Write messages, AFTER WHICH ALL SPICELIB ROUTINES THAT DETECT ERRORS OR CALL OTHER ROUTINES WILL RETURN IMMEDIATELY UPON ENTRY.
This is the action to use if you want to perform error handling for SPICELIB errors in your own code.

This is a useful error handling action to know about, because using it allows you to write much simpler code with less error checking.

See section 1.14 for information about using the RETURN action.

IGNORE

DO NOTHING in response to errors. No error messages will be output; the SPICELIB status functions RETURN and FAILED will not indicate that an error has occurred.
These choices are mutually exclusive; only one action can be in effect at a given time.

You use ERRACT to set the error response action. The first argument should be 'SET'. The second argument should be one of the above choices. For example:

   C
   C     Set the CSPICE error response action
   C     to 'RETURN':
   C
         CALL ERRACT (  'SET',   'RETURN'  )


1.7. Handling SPICELIB Errors in Your Own Program




So far we've talked about how to control automatic reporting of errors detected in SPICELIB routines.

The automatic error reporting feature is meant to produce human- readable error diagnostic information. However, you may also wish to have your program respond to SPICELIB errors.

To do this, you will need to know about three more basic functions: testing and resetting the SPICELIB error status, and retrieving SPICELIB error messages. These are described in sections 1.8 -- 1.10.



1.8. Testing the Error Status




You use the SPICELIB function, FAILED, to tell if any SPICELIB routine has detected an error. FAILED is a function which returns a boolean. It takes the `true' value, if any SPICELIB routine has detected an error.

For example, suppose you call the SPICELIB routine, RDTEXT, to read a line of text from a file. You want your program to test whether an error occurred on the read. You can write:

   C
   C     Read a line from USERFILE.TXT; check for
   C     errors:
   C
         CALL RDTEXT ( 'USERFILE.TXT', LINE, EOF )
 
         IF (  FAILED()  )  THEN
 
   C        LINE is not valid, so quit:
 
            RETURN
 
         END IF
If you're used to routines that have error arguments, you might note that the code is similar to what you would write if FAILED were an output argument for RDTEXT, instead of a function.

However, there are a number of advantages to the SPICELIB method, one of which is that if you don't wish to write any error handling code to handle SPICELIB errors, you don't have to, and you'll still get helpful error messages automatically. Also, if you use SPICELIB error handling in your own code, you don't need error arguments, which makes for simpler code.



1.9. Retrieving Error Messages




SPICELIB provides routines to retrieve the error messages generated whenever a SPICELIB routine detects an error.

This feature is useful for two reasons. First, if you want your program to take different actions depending on what error occurred, it gives your program a way to find out. Second, if you want to generate your own error reports instead of using those generated by SPICELIB, you need to be able to retrieve the information SPICELIB has generated about the error.



Getting the short message



Because of its brief format, the short message is the one to use in your code in any logical tests you might want to do.

To retrieve the short error message, call GETSMS. For example:

   C
   C     Call GETFIL (Not a SPICELIB routine) to prompt
   C     user for the name of file to read from.  Read
   C     a line from it. Check for errors:
   C
         CALL GETFIL ( FILE1 )
 
         DO WHILE ( FILE1 .NE. ' ' )
 
            CALL RDTEXT ( FILE1, LINE, EOF )
 
            IF ( FAILED() ) THEN
 
   C
   C           An error occurred.
   C           Find out what the short message was:
   C
               CALL GETSMS ( SHRTMS )
 
               IF (  ( SHRTMS .EQ. 'SPICE(NOFREELOGICALUNIT)' )
 
        .         .OR.
 
        .            ( SHRTMS .EQ. 'SPICE(TOOMANYFILESOPEN)'  )
        .         )
        .      THEN
 
   C
   C              We won't succeed in reading any file.
   C              So, quit.
   C
                  RETURN
 
               ELSE
 
   C
   C              Get name of a different file:
   C
                  CALL GETFIL ( FILE2 )
 
               END IF
 
            END IF
 
         END DO


Getting the long message



The long error message and traceback aren't useful for program logic, but you may want them if you're going to produce error reports in your own format.

To get the long error message, call GETLMS. For example,

         CALL RDTEXT ( FILE, LINE, EOF )
 
            IF ( FAILED() ) THEN
 
   C
   C        Get long message and output it using USROUT
   C        (not a SPICELIB routine)
   C
            CALL GETLMS ( LONGMS )
            CALL USROUT ( LONGMS )
 
         END IF
The argument supplied to GETLMS should be declared CHARACTER*1840.



Getting the explanation for the short message



The SPICELIB routine EXPLN returns a line of text explaining each SPICELIB short error message. This text is an expansion of the short error message, since the short message is frequently abbreviated.

Here's an example:

   C
   C     After this call, EXPL will take the value:
   C
   C     'Invalid Radius--Equatorial or Polar Radius is Zero'
   C
         CALL EXPLN ( 'SPICE(ZERORADIUS)', EXPL )
 
         CALL STDIO ( EXPLN )


Getting the traceback



Two ways of getting the traceback are provided in SPICELIB:

Example: Suppose MAIN has called SUBA, which in turn has called SUBB. The following code is in SUBB:

   C
   C     Get traceback.  After the call to QCKTRC,
   C     TRACE should have the value,
   C
   C     'MAIN --> SUBA --> SUBB'
   C
         CALL QCKTRC ( TRACE )
 
         CALL STDIO( TRACE )
For example, you could print out the names of all of the modules in the active call chain with the following code:

    CALL TRCDEP ( DEPTH )
 
    DO I = 1, DEPTH
 
       CALL TRCNAM ( I, NAME )
 
       CALL STDIO( NAME )
 
    END DO


1.10. Re-setting the Error Status




If your program encounters a recoverable error, you may wish to have it report the error and continue processing.

An example would be the case where you have an interactive program that prompts the user for the name of a file to read. Your program uses the SPICELIB function RDTEXT to read the file. If the file isn't found, RDTEXT signals an error. The inability to locate the file need not stop the program; your program could just display a message saying the file wasn't found and ask for another file name.

The problem here is the the SPICELIB functions FAILED and RETURN (RETURN is discussed in section 1.14) will return the `true' value after RDTEXT signals the error, so any code whose logic depends on the value of those functions will behave as if an error has occurred, even though the error was recoverable. To solve this problem, SPICELIB provides the routine, RESET, which ``resets'' the error handling mechanism, so that it acts as if no error had occurred. Calling RESET has the following effects:

When your program detects a recoverable error, it should respond to the error, and THEN call RESET. That way, the error messages generated in response to the error will be available for inspection.

RESET has use only if your program does not stop on an error signal. Use the RETURN or REPORT action (see section 1.6 for a discussion of error response actions) if you don't want the SPICELIB error handling mechanism to stop your program wheonn an error signal.



1.11. Handling Errors Detected in Your Own Program




When you use SPICELIB, you can use the error handling mechanism to respond to errors detected by your own code, as well as by SPICELIB code.

Some of the capabilities that you get with SPICELIB are:

In sections 1.12--1.17, we explain:



1.12. Signalling Errors




A routine calls SIGERR to signal an error condition to the SPICELIB error mechanism.

When SIGERR is called, all of the types of error messages that have been selected for automatic output are written out, and SPICELIB takes whatever additional actions are required by the current setting of the error response ``action.''

SIGERR takes one input argument, a short (25 character maximum) error message. This message will be output if the ``short message'' has been selected for output (see section 1.5 for details on selecting the messages to be output). It is strongly recommended that your code supply a descriptive (at least non-blank) error message when it calls SIGERR.

The short message, if used, indicates the type of error which occurred, so the program can respond appropriately. See section 1.9 to find out how to retrieve error messages.

A capability exists to set a long, human-readable, error message. The next section discusses setting the long message.

Here's an example in which the routine, DACOSH, signals an error.

   C
   C  DACOSH computes an arc hyperbolic cosine of X; X must
   C  be greater than or equal to 1 to be in the domain of
   C  DACOSH.
   C
   C  Check that X >= 1.
   C
 
         IF ( X .LT. 1.D0 ) THEN
 
            CALL SETMSG ( 'DACOSH: Invalid argument, ' //
        .                 'X is less than one.' )
 
            CALL SIGERR ( 'SPICE(INVALIDARGUMENT)' )
 
            RETURN
 
         END IF
You may note a call to the routine SETMSG precedes the call to SIGERR as SETMSG sets the long error message. SETMSG is discussed in the next section, but we'll note here that if you wish to call SETMSG, it should be called BEFORE calling SIGERR, since SIGERR causes the current long error message to be output.



1.13. Setting the Long Error Message




The long error message is intended to inform the human reader about an error that has occurred.

You may supply a character string of length up to 1840 characters as the input argument to SETMSG. Strictly speaking, the long message is optional, but it's recommended that you call SETMSG before every call to SIGERR, supplying a blank string if you don't wish to set a long message.

As an example, the calls to SETMSG and SIGERR from the example in the last section are repeated here:

    CALL SETMSG ( 'DACOSH: Invalid argument, ' //
   .                 'X is less than one.' )
 
 
    CALL SIGERR ( 'SPICE(INVALIDARGUMENT)' )
Frequently, one would like to insert variable strings into a long message. In the above example, it might be nice to convert X, a double precision number, to a character string and put it in the error message. SPICELIB provides the routine, ERRDP, for just this purpose.

ERRDP takes two arguments. The first is a character string to appear in the long error message. It marks the place where the result of the conversion is to be placed in the long error message.

The second argument is the value to be converted to a character string. The resulting string is substituted for the first occurrence of the first argument found in the long message.

Here's the previous example, re-written using ERRDP.

   C
   C        Set long error message, with a MARKER where
   C        the value of X will go.  Our marker is '#'.
   C
            CALL SETMSG ( 'DACOSH: Invalid argument, ' //
        .                 'X is less than one.  The '  //
        .                 'value is #.'   )
 
   C
   C        Convert X to characters, and insert the result
   C        in the long message where the # is now:
   C
            CALL ERRDP  ( '#',  X )
 
   C
   C        If X happened to be -5.5D0, for example,
   C        the long message would now be:
   C
   C        'DACOSH: Invalid argument, X is less than one. '
   C        'The value is -5.5D0.'
   C
 
   C
   C         Signal the error:
   C
             CALL SIGERR ( 'SPICE(INVALIDARGUMENT)' )
In addition to ERRDP, ERRINT and ERRCH are provided for inserting integers and character strings into the long message.



1.14. Using the RETURN Action and the SPICELIB Function, RETURN




If you want your program to do any error handling in addition to SPICELIB's automatic error handling, you probably would like to prevent your program from crashing as a result of an error, since this unfortunate event may prevent control from ever being given to your error handling code.

SPICELIB solves this problem with the boolean function RETURN, and the RETURN error response action.

The first two lines of executable code of every SPICELIB routine that can detect errors, or that calls another routine, are:

   IF ( RETURN() ) THEN
      RETURN
   END IF
When the error action is RETURN (see section 1.6 for information about setting the error action), and an error has been signalled, RETURN takes the `true' value. So every SPICELIB routine that can detect errors, or that calls another routine, returns without doing anything. This greatly reduces the chance of an error causing a program crash.

You can use the function RETURN in your own code to achieve the same effect.

RETURN always takes the `false' value if the error action is not RETURN.

See the next section to find out what the rest of the IF block should be.



1.15. Maintaining Traceback Information -- Checking In and Checking Out




SPICELIB can give you a ``picture'' of your call chain at the time an error is signalled, and at any time before. We call this a ``traceback.'' A traceback is provided in the default selection of error messages. When an error is signalled, a traceback helps you find out what calls were made before the call to the routine which detected an error.

As an example, suppose the following figure shows the calling hierarchy for a program, and that currently, subroutine ``E'' is executing, after being called by ``C.''

 
        MAIN
      /  |  \
     B   C   D
    / \ /|   |
   E   F E   H
 
The active call chain would consist of ``MAIN,'' ``C,'' and ``E.'' The traceback message, if retrieved at this point, would be:

   MAIN --> C --> E
To make your own code participate in the traceback scheme, every routine in your program (except those that call nothing else and don't detect errors) should ``check in'' on entry and ``check out'' on exit. These actions tell the error handling mechanism whether your routine is in the active call chain or not.

To check in, call CHKIN, supplying the name of your routine. To check out, call CHKOUT, also supplying the name of your routine. The call to CHKIN should come immediately after each entry into your code. A call to CHKOUT should precede each exit made after checking in. For example:

   C
   C     Here's a skeleton of code for a mock routine, SUBA:
   C
   C     Executable code follows
   C
   C
         IF ( RETURN() ) THEN
 
   C        No check out here, since we haven't checked in.
 
            RETURN
         ELSE
            CALL CHKIN ( 'SUBA' )
         END IF
 
               .
               .
               .
 
         IF ( X .LT. 1 ) THEN
   C        First exit following check in:
            CALL CHKOUT ( 'SUBA' )
            RETURN
          END IF
               .
               .
               .
 
   C     Normal exit:
         CALL CHKOUT ( 'SUBA' )
         RETURN
         END
The traceback storage is 512 characters in length. There is no explicit limit on the depth of the call chain that can be handled, however, with 6-character module names, 73 names can be accommodated (there is a space between each name in the traceback string).



1.16. Clean Coding Using FAILED




A coding tip: If you use the RETURN error response action (see section 1.6), you can greatly simplify your error checking. When you set the action to RETURN, all SPICELIB routines that can detect errors simply RETURN UPON ENTRY. So, they can't cause a run-time error. Therefore, you may safely call a number of SPICELIB routines consecutively, and just test FAILED after the last call in the sequence.



Example 1



   C
   C     Read a line from USERFILE1.TXT, USERFILE2.TXT,
   C     and USERFILE3.TXT; check for errors:
   C
 
         CALL RDTEXT ( 'USERFILE1.TXT', LINE1, EOF )
         CALL RDTEXT ( 'USERFILE2.TXT', LINE2, EOF )
         CALL RDTEXT ( 'USERFILE3.TXT', LINE3, EOF )
 
         IF (  FAILED()  )  THEN
 
   C        Not all of LINE1, LINE2, LINE3 are valid, so quit:
 
            CALL CHKOUT ( 'MYSUB' )
            RETURN
 
         END IF


Example 2



   C
   C     In the following code, COPYC is used to copy the result
   C     of the union of two sets (ordered cells) from a temporary
   C     working set back into one of the original sets.
   C
         CALL UNIONC ( BODIES, PLANETS, TEMP )
         CALL COPYC  ( TEMP,   BODIES        )
 
         IF ( FAILED() ) THEN
 
            CALL CHKOUT ( 'MYSUB' )
            RETURN
 
         END IF
 
   C
   C     If the size of the temporary cell is greater than the size
   C     of the original set, FAILED should be checked to be
   C     sure that no overflow occurred. If BODIES is at least as
   C     large as TEMP, no such check is necessary.
   C
You can also use this coding technique with calls to your own routines, if your use the function RETURN. See section 1.14 for information about RETURN.



1.17. Finding Out What the Automatic Error Handling Settings Are




Sections 1.4 -- 1.6 explain how to set the error output device, the selection of error messages to output, and the error response action. You can retrieve the current settings of these items by calling the same routines you used to choose the settings, supplying the value ``GET'' as the first argument, instead of 'SET'.

For example, you find out which device error output is sent to:

         CALL ERRDEV ( 'GET', DEVICE )
 
   C
   C     DEVICE now contains the name of the output device.
   C
To find out what the current error response action is:

         CALL ERRACT ( 'GET', ACTION )
 
   C
   C     ACTION now contains the current error response action.
   C
To find out what the current error message selection is:

         CALL ERRPRT ( 'GET', LIST )
 
   C
   C     LIST now contains the last list of messages that
   C     was input by a call to ERRPRT.  If no call was made,
   C     LIST has the value 'DEFAULT'.
   C


2. Concepts and Definitions







2.1. About Errors




What do we mean by ``errors''? In general, we mean ``asking routines to do something they can't do.'' Examples include supplying invalid values of input arguments to a subroutine, exceeding program limits such as the maximum number of files open simultaneously, or trying to read from a file that doesn't exist.

When an error is detected because a routine has been used improperly, information about the context of the error is desirable. It's useful to know which routine the error was detected in, what the call chain was at the time of the error, and what the inputs to the routine that detected the error were. The SPICELIB error handling mechanism is designed to provide this type of information.

On the other hand, when it's the program's job to determine the correctness of data, information about the program is not what is wanted when an error occurs. In this case, information about the data is what's needed. SPICELIB's automatic error handling is not appropriate for dealing with this type of error. However, it is possible to shut off the automatic error handling, using the IGNORE error action, and use non-SPICELIB code to handle these errors.

In general, SPICELIB's automatic error handling is most useful for diagnosing programming errors.

The only errors that the SPICELIB error handling mechanism deals with are DETECTABLE ones. SPICELIB can test whether a calling routine has supplied an argument that's in the domain of a function, but it can't tell if the calling routine has the order of the arguments in a calling sequence reversed. By coincidence, an error may be detected in that case, but the diagnosis will point to the error in an indirect way, at best. And if an application uses a faulty algorithm, but nonetheless uses the SPICELIB routines correctly, SPICELIB can't tell you about it.

Some detectable errors exist which SPICELIB does not detect. While attempted division-by-zero errors are prevented, floating overflow is generally not prevented (because doing so is too inefficient).

When a SPICELIB routine detects an error, it may mean the routine is being used improperly. One of the most likely causes is an interface error: inputs may be supplied to the routine that it can't handle, or there may be an error in the coding of the call to the routine itself. It's a good idea to thoroughly understand the descriptions of inputs and outputs given in the module headers of each SPICELIB routine called by one's application.

Some other possible causes of errors may be: bugs in application software, bugs in SPICELIB software, or bad inputs to the application program. Errors can also occur due to problems with the program's environment. For example, an attempt to open a file could fail because the application program didn't have the privileges necessary to perform the open, or on some systems, because the file was in use by another user.



2.2. About Error Messages




SPICELIB uses error messages to inform both the application program using SPICELIB, and the user, about what type of error has occurred and where in the program it occurred.

SPICELIB provides routines for setting and retrieving error messages. When a routine detects an error, it may ``set,'' or store, error messages, which then can be retrieved and examined by other routines.

There are five types of error messages:



The short error message



This message is a character string containing a very terse, usually abbreviated, description of the problem. The message is a character string of length not more than 25 characters. It always has the form:

    SPICE(...)
where the message text goes between the parentheses. An example is:

    SPICE(FILEOPENFAILED)
The text is always composed of upper case letters and numbers.

Short error messages used in SPICELIB are CONSTANT, since they are intended to be used in code. That is, they don't contain any data which varies with the specific instance of the error they indicate.

Because of the brief format of the short error messages, it is practical to use them in a test to determine which type of error has occurred.

For example:

            CALL RDTEXT ( FILE, LINE, EOF )
 
            IF ( FAILED() ) THEN
 
   C
   C           An error occurred.
   C           Find out what the short message was:
   C
 
               CALL GETSMS ( SHRTMS )
 
               IF (  ( SHRTMS .EQ. 'SPICE(NOFREELOGICALUNIT)' )
 
        .         .OR.
 
        .            ( SHRTMS .EQ. 'SPICE(TOOMANYFILESOPEN)'  )
        .         )
        .      THEN
 
 
   C
   C              We won't succeed in reading any file.
   C              So, quit.
   C
                  RETURN
 
               ELSE
 
                        .
                        .
                        .
See section 1.9 for the complete version of the above example.

If you use the SPICELIB error mechanism to respond to errors detected in your own code, you may wish to use your own short error messages. The SPICELIB error handling mechanism doesn't make use of the actual content of the messages, so you may use any values that are practical. It may be of use to make up your own prefix (analogous to SPICELIB's ``SPICE'' ), to identify the errors as detected by your own code. Recall the 25-character limit; excess characters will be truncated.

We recommend that you do NOT use blank short error messages. While the error handling mechanism allows it, the short error messages would no longer be useful for enabling code to determine the type of error that has occurred.

The short message is ``set'' by supplying it as an input argument to the SPICELIB routine SIGERR. It is retrieved by calling GETSMS. See sections 1.9 and 1.12 for more information on setting and retrieving the short message.



The explanation of the short error message



An 80-character expansion of the short message exists for each of SPICELIB's short messages. Each explanation message is constant. While the short message is meant to be used in code, the explanation is supposed to be easily interpreted by the human reader.

SPICELIB provides the routine EXPLN to map short error messages to their explanations. See section 1.9 for EXPLN usage information.

Currently, there is no provision to extend the mapping to user-defined short messages, but NAIF plans to support this extension in the future.

In future versions of SPICELIB, more space may be allocated for explanations. However, EXPLN will continue to return the first 80-character line of the explanation text in that case.

Here's an example of a short message and the corresponding explanation:

   Short message: 'SPICE(ZERORADIUS)'
 
   Explanation:   'Invalid Radius--Equatorial or Polar Radius is Zero'


The long error message



This message may be up to 1840 characters long. The SPICELIB error handling mechanism makes no use of its contents. Its purpose is to provide human-readable information about errors.

Long error messages generated by SPICELIB routines begin with the name of the routine that detected the error, followed by a colon (see the example below).

Here's an example of a long error message:

      'CONVRT: Neither the input units '
      // INU  //'nor the output units '
      // OUTU // 'were recognized.'
Note that INU and OUTU are variables of type CHARACTER. CONVRT is the name of the routine detecting the error.

The long message is ``set'' by supplying it as an input argument to the SPICELIB routine SETMSG. It may be retrieved by calling GETLMS. See sections 1.9 and 1.13 for more information on setting and retrieving the long message.

The routines, ERRDP, ERRINT, and ERRCH provide the capability to insert data into the long message. Their respective purposes are to insert DOUBLE PRECISION, INTEGER, and CHARACTER data into the long message. They (except ERRCH) convert the input data to a character string, and insert it in the current long message at a location indicated by a user-specified marker.

See section 1.13 for examples of use of these routines.

We strongly recommend that you DO NOT write code that tests for particular values of SPICELIB long error messages; this is a very error-prone practice.



The traceback



The purpose of this message is to represent the active call chain, that is, the set of subroutines in your program that have been called and have not yet returned. The traceback will always show the SPICELIB routines in the active call chain.

You can have your own code participate in the SPICELIB traceback scheme, so that the traceback will represent the entire active call chain. See section 1.15 for instructions on how to do this.

Knowledge of the active call chain can be a valuable debugging aid, because it helps you determine where in your program an error occurred. For example, if your program calls subroutine SUBX from ten different subroutines, it's not enough to know that SUBX detected an error; you want to know which subroutine made the offending call to SUBX. The traceback contains that information. Another example: suppose a SPICELIB routine in your program detects an error, but your own code does not call that routine. You need to know which call, made by your own code to a SPICELIB routine, eventually resulted in the call to the routine that detected the error. The traceback shows you this.

The SPICELIB error handling mechanism automatically keeps track of which SPICELIB routines are in the active call chain. In order for the SPICELIB error handling mechanism to represent the entire active call chain, including non-SPICELIB routines, it is necessary for each routine to tell the error handling mechanism: 1) when it has been called and 2) when it is about to return. In SPICELIB documentation, these two operations are called ``checking in'' and ``checking out.'' The set of routines that have checked in but have not yet checked out constitute the portion of the active call chain that the SPICELIB error handling mechanism can represent.

SPICELIB provides the two routines CHKIN and CHKOUT for this purpose; CHKIN for checking in, and CHKOUT for checking out. CHKIN and CHKOUT take one input argument: the name of the calling routine. See section 1.15 for information on the use of these routines.

The traceback message has the form of a list of subroutine names, delimited by arrows. The first name in the list is the highest-level routine in the portion of the active call chain that is known to the SPICELIB error handling mechanism.

As an example, suppose the following figure shows the calling hierarchy for a program, and that currently, subroutine ``E'' is executing, after being called by ``C.''

 
        MAIN
      /  |  \
     B   C   D
    / \ /|   |
   E   F E   H
 
The active call chain would consist of ``MAIN,'' ``C,'' and ``E.'' The traceback message, if retrieved at this point, would be:

   MAIN --> C --> E
The traceback storage is 512 characters in length. There is no explicit limit on the depth of the call chain that can be handled, however, with 6-character module names, 73 names can be accommodated (there is a space between each name in the traceback string).

The particular traceback information made available by SPICELIB is dependent on the error action and on whether an error has occurred. In general, the routines QCKTRC, TRCDEP, and TRCNAM (see section 1.9) return information about the current active call chain. But when the error response action is RETURN, and an error occurs, the error handling mechanism captures a ``frozen'' copy of the traceback; from this point on, the trace information provided by the above routines will be based on the frozen copy. The purpose of this behavior is to make the traceback that existed at the time the error occurred available to the application program. Changing the error action to a value other than RETURN, or resetting the error status, will cause the traceback routines QCKTRC, TRCDEP, and TRCNAM to return data based on the current traceback again.

The overhead of checking in and checking out may be prohibitive for some routines. An intermediate position between not using CHKIN and CHKOUT and using them in every routine is to use them only in routines that call other routines, or that detect errors. Routines which do neither would never appear in a traceback anyway. Note that absence of error detection in a routine is not sufficient grounds for exclusion from checking in and checking out, since a routine called by the routine in question could detect an error, and then the caller should appear in the traceback.

It is important to note that ONLY routines which have checked in can possibly have their names appear in the traceback. So the traceback will not be accurate if any routines in the active call chain have not ``checked in,'' when a traceback message is produced.

The traceback mechanism requires any ``checked-in'' routine to check out before exit.



The default message



This message is output when an error occurs, and the error response action is DEFAULT. It informs the user that the behavior of SPICELIB error handling is user-tailorable, and it refers the user to this document.



2.3. About Error Response Actions




The term ``error response action'' refers to the action that the SPICELIB error handling mechanism takes automatically when an error is signalled (see section 1.12 for information on signalling errors).

SPICELIB provides the routine ERRACT (see section 1.6) to enable you to select the error response action.

There are five different error response actions, each appropriate to a different type of programming situation:

DEFAULT

This is what you get if you don't choose an error response action. When the error action is DEFAULT, and an error is signalled, the SPICELIB error handling mechanism outputs all of the available types of error messages to the error output device, and then stops program execution.
The default action is probably acceptable as a response to detection of program bugs. However, if you wish to allow your own program to respond to errors, you must choose one of REPORT, RETURN, or IGNORE as the error response action.

ABORT

This action is the same as the default, except that the set of error messages is selectable. This action is useful for running programs in batch mode, to prevent them from continuing execution after encountering an error. The ABORT action is also useful if your program does not perform any error handling itself.
REPORT

This action can be useful for debugging. With the REPORT action, the SPICELIB error handling mechanism outputs error messages when an error is signalled, but doesn't stop your program. So, more information can be gained from a single run of your program than with the ABORT action. Using the SPICELIB routine ERRDEV (see section 1.4), you can direct the error messages output by the SPICELIB error handling mechanism to a file, thus creating a log of your errors.
However, the function FAILED (see section 1.8) will indicate an error condition after an error has been signalled. Therefore, any program logic that depends on the value returned by FAILED may be affected by an error. You can use the SPICELIB routine RESET (see section 1.10) to set the error status to ``no error,'' so that your program will attempt to follow a normal thread of execution, after an error is signalled.

RETURN

The RETURN action's intend use is in situations where you want your program to recover from errors detected by SPICELIB (or by your own code). Like the REPORT action, the RETURN action also includes writing error messages to the chosen output device. But with the RETURN action, the SPICELIB function RETURN takes the `true' value when an error is signalled. Any routine that tests the function RETURN on entry, and that returns immediately if RETURN takes the `true' value, will not crash in this case. All SPICELIB routines that can detect errors, or that call other routines, do test RETURN on entry and return if the `true' value. This behavior maximizes the chance that SPICELIB routines will return control to the application program using them, in the event of an error.
It is also possible to use the function RETURN in the same way in your own routines. See section 1.14 for more information on using the function RETURN. We note here that use of RETURN mode allows you to call multiple SPICELIB routines consecutively, without testing the error status until after the last call. This can greatly enhance the readability of your code, and increase its efficiency, as well.

Returning control to the non SPICELIB portion of the program allows for a response to the error condition. The nature of the response is application-dependent. However, in the case that the error does not preclude further successful operation of the program, it is necessary to instruct the SPICELIB error handling mechanism that normal operation is desired, after the error has been responded to. The SPICELIB function RESET (see section 1.10) is provided for this purpose. Calling RESET blanks out all stored error messages, and causes the functions FAILED (see section 1.8) and RETURN to take the `false' value.

IGNORE

This action is provided to allow you to completely ``shut off'' SPICELIB's automatic error handling. When this action is selected, and any routine signals an error, no action is taken by the SPICELIB error handling mechanism. The error messages cannot be updated by SIGERR and SETMSG, and RETURN and FAILED will not change their values.
This action may be useful in the case where you know exactly which errors will be detected by SPICELIB routines, and you know that no response is required.

Note that the IGNORE action is not appropriate for the case where you wish to suppress automatic output of SPICELIB error messages, and to handle SPICELIB errors in your own code. To do that, use the RETURN error action and set the selection of error messages to 'NONE', using ERRPRT (see section 1.5).



3. Advanced Programming with Error Handling





This chapter discusses some further error handling topics.

The reference for all of the SPICELIB routines mentioned below is sections 1.11--1.17 of this document.



3.1. Using the SPICELIB Functions FAILED and RETURN




Section 1.14 is prerequisite reading for this section.

First, note that the SPICELIB function RETURN takes the `false' value unless the error response action is RETURN, so all of the following discussion assumes that the error action has been set to RETURN.

Which routines should use the function RETURN, and where?

The ``which?'' question is somewhat tricky: there's a trade-off between speed and resistance to program crashes. It takes time (not much) to test RETURN, and in a very short routine, such as one that computes a dot product, the execution time can be increased by a substantial factor if RETURN is tested. In most routines, the percentage increase in execution time is small.

So, if you don't want to test RETURN in every routine, how do you decide? The SPICELIB answer to this question is, test RETURN in routines that call other routines or detect errors (SPICELIB routines that are specifically intended to perform error handling are exempt from testing RETURN). If a routine calls another routine already, it's unlikely that testing RETURN will slow its execution intolerably. Similarly for routines that test for error conditions.

Our final answer is still a hedge: the proper use of RETURN depends on your speed and reliability requirements. The SPICELIB method may be a good zero-order approximation to what's optimal.

NOTE: You must be very careful about using RETURN in application code that DOES error handling, otherwise your error handling code itself may not function when an error is signalled.

The ``where?'' question also eludes a straightforward answer. The idea behind the RETURN action is to ensure that control is returned to whatever part of your program handles errors, when an error is signalled. According to this idea, once an error has been signalled, you have to do something about the error before you can finish the job. So, routines that do use RETURN ought to test it at the very beginning of their executable code; there's no reason for them to proceed further until the error condition has been acted upon.

What about using the function RETURN in other parts of the code, for instance following calls to SPICELIB routines? The same speed vs crash resistance trade-off applies, but there is another consideration: RETURN has an effect only when the error action is RETURN. So, in cases where an error condition makes it likely that a portion of code won't work, it's usually better to test the function FAILED, rather than RETURN, since a program crash is usually undesirable, even when using the REPORT action for debugging. But if you do want to retain the option of executing the code when an error has already occurred, use RETURN.

We repeat here that the SPICELIB function FAILED indicates whether an error has been signalled, regardless of the error response action. It can be used to avoid executing any code that may cause a run-time error if an error has already occurred. Note that testing FAILED instead of RETURN means that whether the error response action is RETURN or REPORT doesn't affect the program logic in question; the logic depends on whether or not an error has been signalled.



3.2. Using the SPICELIB routines CHKIN and CHKOUT




Section 1.15 is prerequisite reading for this section.

The simplest approach to the use of these routines is to use them in every routine you write. But as with the case of RETURN, your routines will be slightly slower if they call CHKIN and CHKOUT, and for very short routines, the percentage difference may be great.

The SPICELIB approach is to call CHKIN and CHKOUT in routines which call other routines or which can detect errors. This way, every routine that can possibly be in the active call chain at the time an error is detected can appear in the traceback message.

As mentioned in the previous section, these routines are less likely to suffer a large percentage increase in execution time as a result of making extra calls.

We note that some routines that do make external references but do not signal errors may have no routines capable of signalling errors below them in the calling hierarchy; these routines won't appear in a traceback. Why should they call CHKIN and CHKOUT? They should do so for maintenance reasons, specifically, if any routine below them in the calling hierarchy is changed so as to be able to detect an error, the higher level routines don't need to be changed.



3.3. Using Multiple Settings of the Automatic Error Handling Features




In chapter 1, we suggested that you choose the error output device, error response action, and selection of error messages, during program initialization and leave them unchanged for the duration of the program run. This is probably a good procedure to stick to for inexperienced users. However, it's possible and reasonable to do some fancier things with these settings, in some cases:

a

When making a transition to a new action, the value of FAILED does not change. If FAILED has the `true' value, and you set the action to IGNORE, any NEW errors that are signalled will be ignored, but FAILED will remain `true'.
b

The value of the function RETURN depends on FAILED and the current action. Specifically, RETURN has the `true' value if and only if FAILED has the `true' value and the action is RETURN. Therefore, note that if FAILED has the `true' value and you change the action to RETURN, the function RETURN will now have the `true' value, regardless of its previous value. Setting the action to something other than RETURN will cause RETURN to take the `false' value, regardless of its previous value.
c

Changing the error action doesn't affect the stored short and long error messages, if any. If there are stored messages, they will still be available if the action is changed to IGNORE.
d

The traceback routines return information about the ``frozen'' traceback if and only if RETURN has the `true' value. So the rule about which traceback you get is the same as the rule for the value of RETURN.
e

Changing the action to ABORT or DEFAULT doesn't automatically abort your program if FAILED has the `true' value; an error must be signalled while the action is one of these values to achieve an abort.
For example:

   C
   C     All errors in the following section of code are
   C     fatal.  Temporarily set the error action to
   C     'ABORT'; restore old action after end of code
   C     section.
   C
 
         CALL ERRACT ( 'GET', SAVACT  )
 
         CALL ERRACT ( 'SET', 'ABORT' )
 
 
    { Section of code in which errors are fatal starts here }
 
                          .
                          .
                          .
 
 
    { Section of code in which errors are fatal ends here }
 
 
   C
   C     Restore old error action:
   C
         CALL ERRACT ( 'SET', SAVACT )
Changes to the error output device or error message selection can be made in the same way; both ERRDEV and ERRPRT accept the values ``GET'' and ``SET'' for their first argument.