The <error.h> header file


  
This header file contains the following functions:
ER_catch           ER_throwVar           ER_success           ERD_dialog
ERD_process        find_error_message
the following language extensions (implemented as macros):
ENDTRY             errCode               ONERR                PASS
TRY
and the following predefined types:
Bool               ERROR_FRAME

Functions


short ER_catch (void *ErrorFrame);

Catchs an error.

ER_catch setups an error handler (see also TRY, ONERR and ENDTRY). It saves the task state in ErrorFrame, which is usually a buffer of type ERROR_FRAME, and returns 0. The state consists of the values of A2-A7, D3-D7, and PC. It also records a pointer to the previously saved state, which makes it a linked list/stack, and yet another two system pointers.

If ER_throwVar is called later on (note that some TIOS routines may perform ER_throwVar in a case of error), it simulates a return from the previously called ER_catch, and the error code passed into ER_throwVar will become the result of ER_catch. The processor must be in User mode for this to work properly.

NOTE: Usually you should not call this function explicitely. Use TRY macro instead.

void ER_throwVar (short err_no);

Throws an error.

ER_throwVar restores the state previously saved by ER_catch. It then returns in such a way that ER_catch appears to have returned with the value err_no (see also PASS). See the TI-Basic manual for a meaning of the various error codes. ER_throwVar should not be called with a value 0 as err_no. Think of ER_throwVar as a long jump rather than a subroutine call. Execution does not return from the ER_throwVar call.

NOTE: It is not a good idea to use ER_throwVar to bail out to the TIOS from arbitrary place. ER_throwVar will return you to the system as expected, but your program will remain locked, and will throw "Invalid program reference" error on subsequent calls...

void ER_success (void);

Pops the state from the error stack

ER_success pops the state previously saved by ER_catch off the stack, i.e. removes the error frame from the linked list. You usually will not call this function explicitely: the macro ONERR will do this for you.

char *find_error_message (short err_no);

Gives a TI-Basic error message string.

find_error_message returns a pointer to the text of the TI-Basic error message string with code err_no. See TI-Basic manual for the list of various error codes. If err_no is not a valid error code, the routine returns a pointer to the string "Unknown ERROR code".

short ERD_dialog (short err_no, short prog_flag);

Displays an error dialog box.

ERD_dialog displays an error dialog box with a message corresponding to the error code err_no. See the TI manual for a meaning of the various error codes. ERD_dialog returns KEY_ENTER or KEY_ESC, depending of whether the user exits the dialog box by pressing ENTER or ESC key. This routine may cause heap compression.

prog_flag is a flag which may be FALSE or TRUE. Normally, it need to be FALSE, but when it is TRUE, in addition to the standard button whith message "Esc=CANCEL", another button with message "Enter=GOTO" will be added in the error dialog box. This is mostly useless, but error dialog boxes have this option (TIOS uses this when you break a BASIC program). Note, however, that pressing Enter will not perform the actual transfer to the program editor.

void ERD_process (short err_no);

Process an error.

ERD_process processes the error with error code err_no by calling ERD_dialog appropriately. Button "Enter=GOTO" will be displayed only if the routine concludes from some system flags that the routine is called from the TI-Basic interpreter (which will not be the case if you called it from C or ASM program). Then, ERD_process responds by starting appropriate application (for example text editor if the TI-Basic interpretter was active and if the user pressed button "Enter=GOTO"). Principally, there is no difference between ERD_process and ERD_dialog, except in event-driven applications (see events.h header file).


Language extensions


TRY

TRY, ONERR, ENDTRY and PASS are macros which extends the C language to implement the error handling mechanism which is almost identical like in TI-Basic.

TRY begins the protected block. It is a macro which is implemented using ER_catch function. If an error occurs in the protected block, program execution transfers to the block after ONERR statement, else this block will not be executed. In each case, the execution continues normally after ENDTRY statement. This is ilustrated in the following example:
TRY
   // protected code
ONERR
   // error handler
   if (errCode == some_specific_code)
      PASS; // pass on any unhandled errors to a higher level
ENDTRY
Variable errCode is automatically created in the error handler, and it contains the error number to allow the program to check what caused the error. This variable will be destroyed after ENDTRY statement.

It is important to say that you must not exit the protected block using goto or return statements, else the error frame will not be removed, so the further behaviour of the program will be unpredictable. If you really want to exit from the protected block before its natural end (i.e. before ONERR statement), call ER_success explicitely to remove the error frame before exiting, i.e. do something like
TRY
   ...
   if (I_really_must_exit_from_here)
      {
         ER_success ();
         return;
      }
   ...
ONERR
   ...
ENDTRY
There is also another possible caveat related to error handling. The TRY macro saves many of the CPU registers on its execution context stack. Consequently, when an error is thrown, all variables which reside in CPU registers are reset to their contents before the TRY macro was called. This is only a problem with auto variables — global and static variables are never kept in CPU registers. If code in an ONERR block needs the value of a variable set in the TRY block, the code must arrange to make sure the C code optimizer does not put that variable in a CPU register. This can be accomplished by declaring such variables to be volatile. So, remember this rule: Auto variables changed in a TRY block must be declared volatile if they are referenced in an ONERR block!!!

If you want to "protect" whole program, maybe the best method is to do something like
void _main (void)
{
  TRY
    main_prog ()
  ONERR
    // Do some error hanling, for example call simply ERD_process (errCode);
  ENDTRY
}

void main_prog (void)
{
  // Put your real code here
}

ONERR

Macro ONERR ends the protected block and begins the error handler (see TRY for more info). Variable errCode is automatically created in the error handler, and it contains the error number to allow the program to check what caused the error. This variable will be destroyed after ENDTRY statement.

NOTE: Macro ONERR uses ER_success function to end the protected block.

ENDTRY

Macro ENDTRY terminates TRY ... ONERR ... ENDTRY structure (see TRY for more info).

PASS

Macro PASS pass on any unhandled errors to a higher level of error handler (see TRY for more info). In fact, it exectutes ER_throwVar with errCode as an argument.

short errCode;

errCode is an automatic (local) variable which is automatically created in the error handler, and it contains the error number to allow the program to check what caused the error. This variable is automatically destroyed after ENDTRY statement, i.e. after execution of the error handler. Variable errCode, because it is local to the ONERR block, cannot be referenced outside the ONERR block.


Constants and predefined types


enum Bool

Bool is enumerated type for describing true or false values. It is defined as
enum Bool {FALSE, TRUE};

type ERROR_FRAME

ERROR_FRAME is a type designed for capturing a task state needed for catching errors using ER_catch command. It is defined here as
typedef struct ErrorFrameStruct
  {
    unsigned long A2, A3, A4, A5, A6, A7;
    unsigned long D3, D4, D5, D6, D7;
    unsigned long NG_Control;
    char *RetIndex;
    unsigned long PC;
    struct ErrorFrameStruct *Link;
  } ERROR_FRAME[1];

Return to the main index