The <error.h> Header File

Routines for error handling

Language Extensions

ENDFINAL
Terminates a TRY...FINALLY...ENDFINAL block.
ENDTRY
Terminates a TRY...ONERR...ENDTRY block.
FINALLY
Begins the termination handler in a TRY...FINALLY...ENDFINAL block.
ONERR
Begins the error handler in a TRY...ONERR...ENDTRY block.
PASS
Passes on unhandled errors to a higher level.
TRY
Starts a protected block of code.

Functions

ER_catch
Catches an error.
ER_success
Pops the state from the error stack.
ER_throw
Throws an error with a constant number.
ER_throwVar
Throws an error.
ERD_dialog
Displays an error dialog box.
ERD_process
Processes an error.
find_error_message
Returns a TI-Basic error message string.

Global Variables

errCode
Contains the error number in a TRY...ONERR...ENDTRY block.

Predefined Types

Bool
An enumeration to describe true or false values.
ERROR_FRAME
A type designed for capturing a task state.
ErrorCodes
An enumeration containing all error codes.

ENDFINAL

Terminates a TRY...FINALLY...ENDFINAL block.

The macro ENDFINAL terminates a TRY...FINALLY...ENDFINAL block. See TRY for more info.


ENDTRY

Terminates a TRY...ONERR...ENDTRY block.

The macro ENDTRY terminates a TRY...ONERR...ENDTRY block. See TRY for more info.


FINALLY

Begins the termination handler in a TRY...FINALLY...ENDFINAL block.

The macro FINALLY ends the protected block and begins the handler for code which always has to be executed (see TRY for more info). The 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, or 0 if there was no error. This variable is destroyed after the ENDFINAL statement.

Note: The macro FINALLY uses the ER_success function to end the protected block, and ENDFINAL uses PASS to throw the error signaled by errCode a second time.

Here is an example (called "Memory Error"), which demonstrates the use of this macro:

// Allocate memory as long as possible, then throw an error
// All allocated memory will be freed again!

#define USE_TI89              // Compile for TI-89
#define USE_TI92PLUS          // Compile for TI-92 Plus
#define USE_V200              // Compile for V200

#define MIN_AMS 100           // Compile for AMS 1.00 or higher
#define ENABLE_ERROR_RETURN   // Enable Returning Errors to TIOS

#include <tigcclib.h>         // Include All Header Files

#define BLOCK_SIZE 1024

void AllocRecursively(void)
{
  void *ptr = malloc_throw (BLOCK_SIZE);
  TRY
    // Could do something with ptr here...
    AllocRecursively ();
    // Could still do something with ptr...
  FINALLY
    free (ptr);
  ENDFINAL
}

// Main Function
void _main(void)
{
  AllocRecursively ();
}

ONERR

Begins the error handler in a TRY...ONERR...ENDTRY block.

The macro ONERR ends the protected block and begins the error handler (see TRY for more info). The 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 is destroyed after the ENDTRY statement.

Note: The macro ONERR uses the ER_success function to end the protected block.


PASS

Passes on unhandled errors to a higher level.

The macro PASS passes on any unhandled errors to a higher level error handler (see TRY for more info). In fact, it executes ER_throwVar with errCode as an argument.


TRY

Starts a protected block of code.

TRY, ONERR, ENDTRY, FINALLY, ENDFINAL, and PASS are macros which extend the C language to implement an error handling mechanism which is almost identical to the commonly-used exception handling as well as error handling in TI-Basic.

TRY begins the protected block. It is a macro which is implemented using the ER_catch function. If an error occurs in the protected block, program execution transfers to the block after the ONERR or FINALLY statement.

However, ONERR and FINALLY are entirely different. The ONERR block will not be executed if there was no error, and it is assumed to either handle the error or call PASS. The error is cleared, so if PASS is not called, the execution continues normally after the ENDTRY statement.

FINALLY, on the other hand, is not implemented to handle errors, but instead to create a block of code which will always be executed, regardless of whether there was an error or not. It does not clear the error (or more precisely, ENDFINAL throws it again). This can be used in a function which allocates memory, destroys the contents of the screen, or does something else which always needs cleaning up. If the function throws an error in a protected block, the memory should always be freed again, the screen should be restored, etc. But the error should not be handled at the same time; instead, it must be handled on a higher level (often even in the calling function).

The usage of ONERR is illustrated in the following example:

TRY
  // <protected code>
ONERR
  if (errCode == some_specific_code)
    // <error handler>
  else
    // pass on any unhandled errors to a higher level
    PASS;
ENDTRY

The usage of FINALLY is illustrated in the following example:

TRY
  ...
  // <allocate memory>
  TRY
    // <protected code>
  FINALLY
    // <free the allocated memory>
  ENDFINAL
  ...
ONERR
  // <error handler>
ENDTRY

The 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 the ENDTRY/ENDFINAL 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 behavior of the program will be unpredictable. If you really want to exit from the protected block before its natural end (i.e. before the ONERR or FINALLY 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

But in general this is a very bad practice and should be avoided even if it requires some extra code. For example, you can rewrite the code like this:

TRY
  ...
  if (!I_really_must_exit_from_here)
  {
    ...
  }
ONERR
  ...
ENDTRY
if (I_really_must_exit_from_here)
  return;

There is also another possible caveat related to error handling. The TRY macro (or ER_catch, more precisely) saves many of the registers on its execution context stack, since ER_catch needs to simulate a return identical to the return of any normal function. Consequently, when an error is thrown, all variables which reside in registers are reset to their contents before the TRY macro was called. If code in an ONERR or FINALLY 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 register. This can be accomplished by declaring such variables to be volatile. So, remember this rule: Variables changed in a TRY block must be declared volatile if they are referenced in an ONERR or FINALLY block!

If you want to protect the whole program, passing all unhandled errors to the operating system, you can define ENABLE_ERROR_RETURN instead of using a TRY...ONERR...ENDTRY block. See the section Returning Errors for more information.


ER_catch

short ER_catch (void *ErrorFrame);

Catches an error.

ER_catch sets up an error handler. 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 the TRY macro instead.

See also: TRY, ONERR, ENDTRY, FINALLY, ENDFINAL, ER_throwVar, ER_throw, ER_success


ER_success

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.


ER_throw

void ER_throw (short err_no);

Throws an error with a constant number.

ER_throw works like ER_throwVar, but it produces much shorter code (only 2 bytes). This is done through the Line 1010 (A-Line) emulator, which emulates an assembly opcode for each error number. As a consequence, err_no must be constant.

See also: ER_throwVar, ErrorCodes


ER_throwVar

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 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: If you want to use ER_throwVar to bail out to the TIOS from an arbitrary place, you need to define ENABLE_ERROR_RETURN. See the section Returning Errors for more information.

See also: ER_throw, ErrorCodes, PASS


ERD_dialog

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 TRUE or FALSE, 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 needs 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.


ERD_process

void ERD_process (short err_no);

Processes 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 a C or ASM program). Then, ERD_process responds by starting the appropriate application (for example the text editor if the TI-Basic interpreter was active and if the user pressed the button "Enter=GOTO"). Principally, there is no difference between ERD_process and ERD_dialog, except in event-driven applications (see the events.h header file).


find_error_message

AMS 1.01 or higher

const char *find_error_message (short err_no);

Returns a TI-Basic error message string.

find_error_message returns a pointer to the text of the TI-Basic error message string with the code err_no. See the TI-Basic manual for a 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", or its localized version if a language localization is active (on AMS 2.xx).

find_error_message may return NULL.


errCode

unsigned short errCode;

Contains the error number in a TRY...ONERR...ENDTRY block.

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.

See also: ErrorCodes


ERROR_FRAME

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];

A type designed for capturing a task state.

ERROR_FRAME is a type designed for capturing a task state needed for catching errors using the ER_catch command.


ErrorCodes

enum ErrorCodes {ER_OK = 0, ER_OKAY = 0, ER_EXIT = 1, ER_STOP = 2, ER_OFF = 3, ER_PRGM_STOP = 4, ER_NO_MSG = 9, ER_FUNC_DID_NOT_RETURN_VALUE = 10, ER_TEST_NOT_TRUE_OR_FALSE = 20, ER_ARG_CANNOT_BE_FOLDER = 30, ER_ARGUMENT = 40, ER_ARG_MISMATCH = 50, ER_EXPECTED_BOOL_OR_AGG = 60, ER_ARG_MUST_BE_DECIMAL = 70, ER_ARG_MUST_BE_LABEL = 80, ER_ARGUMENT_MUST_BE_LIST = 90, ER_ARG_MUST_BE_MATRIX = 100, ER_ARG_MUST_BE_PIC = 110, ER_ARG_MUST_BE_PIC_OR_STR = 120, ER_ARG_MUST_BE_STRING = 130, ER_EXPECTED_VAR = 140, ER_ARG_MUST_BE_EMPTY_FOLDER = 150, ER_EXPECTED_ALGEBRAIC = 160, ER_ASAP_TOO_LONG = 161, ER_ATTRIBUTE_NOT_FOUND = 163, ER_BATT_LOW = 165, ER_BOUND = 170, ER_BREAK = 180, ER_CHECKSUM = 185, ER_CIRCULAR_DEFINITION = 190, ER_INVALID_SUCH_THAT = 200, ER_DATATYPE = 210, ER_DEPENDENT_LIMIT = 220, ER_DIFF_EQ_SETUP = 225, ER_DIMENSION = 230, ER_NOT_ENOUGH_ELEMENTS = 230, ER_NON_CONFORMING_LISTS = 240, ER_DIVBY0 = 250, ER_DOMAIN = 260, ER_DUPLICATE_VAR_NAME = 270, ER_ELSEIF_WITHOUT_IF = 280, ER_ELSE_WITHOUT_IF = 280, ER_ENDTRY_WITHOUT_ELSE = 290, ER_EXCESSIVE_ITERATION = 295, ER_EXPECTED_2OR3_ELEMENTS = 300, ER_EXPIRED = 305, ER_APP_EXT_NOT_FOUND = 307, ER_APP_NOT_FOUND = 308, ER_INVALID_NSOLVE_ARG1 = 310, ER_INVALID_SOLVE_ARG1 = 320, ER_FOLDER = 330, ER_FUNCS_IN_DIFF_EQ = 335, ER_INCONSISTENT_UNITS = 345, ER_INVALID_SUBSCRIPT = 350, ER_INVALID_INDIR_STRING = 360, ER_INDIR_STRING_NOT_VARNAME = 360, ER_INDIR_STRING_NOT_FUNNAME = 360, ER_INVALID_ANS = 380, ER_ILLEGAL_ASSIGNMENT = 390, ER_ILLEGAL_ASSIGNMENT_VALUE = 400, ER_INVALID_AXES = 405, ER_ILLEGAL_COMMAND = 410, ER_INVALID_FOLDER_NAME = 420, ER_GRAPH_MODE = 430, ER_INVALID_GUESS = 435, ER_INVALID_IMPLIED_MULT = 440, ER_ILLEGAL_IN_FUNC = 450, ER_ILLEGAL_IN_CUSTOM = 460, ER_ILLEGAL_IN_DIALOG = 470, ER_ILLEGAL_IN_TOOLBAR = 480, ER_CANNOT_EXIT_FROM_TRY = 490, ER_CANNOT_CYCLE_FROM_TRY = 490, ER_CANNOT_GOTO_FROM_TRY = 490, ER_CANNOT_GOTO_INTO_TRY = 490, ER_INVALID_LABEL = 500, ER_INVALID_LIST_OR_MATRIX = 510, ER_INVAL_OUTSIDE_TB_CM = 520, ER_INVAL_OUTSIDE_DG_TB_CM = 530, ER_INVALID_OUTSIDE_DIALOG = 540, ER_MUST_BE_IN_PRGM_OR_FUNC = 550, ER_CYCLE_NOT_IN_LOOP = 560, ER_EXIT_NOT_IN_LOOP = 560, ER_INVALID_PATHNAME = 570, ER_INVALID_POLAR_COMPLEX = 575, ER_ILLEGAL_PRGM_REF = 580, ER_INVALID_SYNTAX_BLOCK = 590, ER_INVALID_TABLE = 600, ER_INVALID_USE_OF_UNITS = 605, ER_INVALID_LOCAL_DECLARATION = 610, ER_EXPECTED_VAR_OR_FUNC = 620, ER_INVALID_VAR_REF = 630, ER_INVALID_VECTOR_SYNTAX = 640, ER_LINK_IO = 650, ER_MAT_NOT_DIAGONALIZABLE = 665, ER_MEMORY = 670, ER_MEMORY_EXHAUSTION = 670, ER_ESTACK_OVERFLOW = 670, ER_STACK_VIO = 673, ER_EXPECTED_LPAR = 680, ER_EXPECTED_RPAR = 690, ER_EXPECTED_DOUBLE_QUOTE = 700, ER_EXPECTED_RIGHT_BRACKET = 710, ER_EXPECTED_RIGHT_BRACE = 720, ER_INVALID_BLOCK_STRUCTURE = 730, ER_MISSING_THEN = 740, ER_NOT_FUNC_OR_PRGM = 750, ER_NO_FUNCS_SEL = 765, ER_NO_SOLUTION = 780, ER_NON_ALGEBRAIC_VARIABLE = 790, ER_UNREAL_RESULT = 800, ER_EXPECTED_REAL = 800, ER_MEMORY_DML = 810, ER_RATIONAL_NUMERIC_OVERFLOW = 830, ER_OVERFLOW = 830, ER_STAT_PLOT = 840, ER_PRGM_NOT_FOUND = 850, ER_RECURSION_TOO_DEEP = 860, ER_RESERVED = 870, ER_SYS_FUNC = 870, ER_ROM_ROUTINE_NOT_AVAILABLE = 875, ER_SEQUENCE_SETUP = 880, ER_SIGNATURE_ERR = 885, ER_SINGULARMAT = 890, ER_SLOPE_FIELD_FUNCS = 895, ER_WEIGHTS_SUM_NOT_POS = 900, ER_LISTS_CONTAIN_NEG = 900, ER_LISTS_NOT2DISCREET = 900, ER_EMPTY_GROUP_NOT_VALID = 900, ER_SYNTAX = 910, ER_UNEXPECTED_CHARACTER = 910, ER_EXPECTED_EQUAL = 910, ER_EXPECTED_FACTOR = 910, ER_TOO_FEW_ARGS = 930, ER_TOO_MANY_ARGS = 940, ER_TOO_MANY_SUBSCRIPTS = 950, ER_TOO_MANY_UNDEFINED = 955, ER_UNDEFINED_VAR = 960, ER_UNLICENSED = 965, ER_GRAPH_FUNC_IN_USE = 970, ER_PROG_OR_FUNC_IN_USE = 970, ER_VAR_IN_USE = 970, ER_LOCKED = 980, ER_PROTECTED = 980, ER_NAME_TOO_LONG = 990, ER_RANGE = 1000, ER_ZOOM = 1010, ER_ILLEGAL_TAG = 1020, ER_UNKNOWN_TAG = 1020, ER_DIVISION_BUG = 1020, ER_MEM_VIO = 1030, ER_FP_TEST_FAIL = 4094, EXPECTED_BOOL_OR_AGG_ERROR = 60, EXPECTED_VAR_ERROR = 140, EXPECTED_ALGEBRAIC_ERROR = 160, INVALID_SUCH_THAT_ERROR = 200, NON_CONFORMING_LISTS_ERROR = 240, EXPECTED_2OR3_ELEMENTS_ERROR = 300, INVALID_NSOLVE_ARG1_ERROR = 310, INVALID_SOLVE_ARG1_ERROR = 320, INVALID_PATHNAME_ERROR = 570, EXPECTED_VAR_OR_FUNC_ERROR = 620, MEMORY_EXHAUSTION_ERROR = 670, ESTACK_OVERFLOW_ERROR = 670, EXPECTED_LPAR_ERROR = 680, EXPECTED_RPAR_ERROR = 690, EXPECTED_DOUBLE_QUOTE_ERROR = 700, EXPECTED_RIGHT_BRACKET_ERROR = 710, EXPECTED_RIGHT_BRACE_ERROR = 720, UNREAL_RESULT_ERROR = 800, EXPECTED_REAL_ERROR = 800, RATIONAL_NUMERIC_OVERFLOW_ERROR = 830, RECURSION_TOO_DEEP_ERROR = 860, SYNTAX_ERROR = 910, UNEXPECTED_CHARACTER_ERROR = 910, EXPECTED_EQUAL_ERROR = 910, EXPECTED_FACTOR_ERROR = 910, TOO_FEW_ARGS_ERROR = 930, TOO_MANY_ARGS_ERROR = 940, TOO_MANY_SUBSCRIPTS_ERROR = 950, TOO_MANY_UNDEFINED_ERROR = 955, GRAPH_FUNC_IN_USE_ERROR = 970, NAME_TOO_LONG_ERROR = 990, ILLEGAL_TAG_ERROR = 1020, UNKNOWN_TAG_ERROR = 1020, DIVISION_BUG_ERROR = 1020};

An enumeration containing all error codes.

This enumeration contains all error codes used by the TIOS. Error names not starting with 'ER_' are deprecated and introduced only for compatibility. All of these errors can be passed on to the operating system. You can use your own numbers for errors which you handle in your program, if you want to use the error-handling system to write more stable programs.

See also: ER_throw, ER_throwVar, errCode


Return to the main index