Routines for error handling
Terminates a TRY...FINALLY...ENDFINAL block.
The macro ENDFINAL terminates a TRY...FINALLY...ENDFINAL block. See TRY for more info.
Terminates a TRY...ONERR...ENDTRY block.
The macro ENDTRY terminates a TRY...ONERR...ENDTRY block. See TRY for more info.
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 (); }
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.
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.
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.
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
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.
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
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
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.
void ERD_dismissNotice (void); |
Removes the error notice displayed by a prior call to ERD_notice.
This function causes the screen to be repainted, because it calls
WinClose.
CAUTION: calling this function without a prior call to
ERD_notice, or calling ERD_dismissNotice twice,
can leave the calculator in an unstable state !
short ERD_notice (unsigned char const *title, unsigned char const *message); |
Displays an error notice.
ERD_notice displays a dialog-looking window with title title, message message
(word-wrapped if necessary), without buttons, that will stay on the screen until
ERD_dismissNotice is called.
ERD_notice returns TRUE if the window was actually displayed, FALSE otherwise.
ERD_notice must be paired correctly with ERD_dismissNotice.
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).
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.
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
typedef struct ErrorFrameStruct {
|
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.
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