Error Handling in jBC Programs

jBASE provides several mechanisms to monitor, control and display runtime errors.


Environment Variables

The following 3 environment variables control how jBC (BASIC) programs handle specific error conditions. Each variable is assigned a bit-mask to control what actions are performed when the corresponding error is encountered.

Environment Variable Error Message
JBASE_ERRMSG_DIVIDE_ZERO Divide by zero !!-- ZERO returned
JBASE_ERRMSG_NON_NUMERIC Non-numeric value -- ZERO USED
JBASE_ERRMSG_ZERO_USED Invalid or uninitialised variable -- ZERO USED

JBASE_ERRMSG_TRACE
Setting this variable will log all error and runtime messages to the $JBCRELEASEDIR/tmp/jbase_error_trace file. Be aware that this will cause the jbase_error_trace file to grow very large if left to its own devices.

JBC_STDERR
To redirect standard error to standard out in a jBC program set JBC_STDERR=1. This is useful with the EXECUTE statement for CAPTUREing output that would normally be sent to the screen.

JBCERRFILE
This environment variable is used to specify an alternate error message file. See Advanced Error Message Tracking.
 

Trapping I/O errors

Most jBC (BASIC) I/O statements have built-in syntax to trap errors. This is implemented by specifying the SETTING and ON ERROR clauses. For example:

READ record FROM filevar, id SETTING errornumber ON ERROR
  CRT "READ failed with error number ":errornumber
  STOP
END ELSE
  STOP 202,id
END
The SYSTEM(0) function can also be used to determine the outcome of I/O options. Operations like READ and WRITE will return non-zero error numbers if the operation fails in some way. Tape statements, like READT and WRITET, will store the reason code if an error occurs.

The SYSTEM(0) function does not automatically reset itself; it will hold on to the last error code until some other statement sets it. This can sometimes lead to a wrong conclusion when checking the value. To avoid this situation you can explicitly reset SYSTEM(0) with:
ASSIGN 0 TO SYSTEM(0)
 

Customizing Error Messages

There are two files, jbcinit.err and jbcmesssages, underneath JBCRELEASEDIR. The jbcinit.err file is used to build the jbcmessages file. The jbcinit.err file contains extensive documentation on how to add new and customize existing messages that display to the user. This is all explained in detail here.
 

Advanced Error Message Tracking

This section details how to track specific error messages.

The JBASE_ERRMSG_TRACE environment variable is message-agnostic. When it is set it logs all jBASE messages that are 'printable' (i.e. not marked 'NOPRINT') in the %JBCRELEASEDIR%\jbcmessages file. This can be problematic when all you want to do is log the occurrences of a few specific error messages. The log produced by JBASE_ERRMSG_TRACE will also not tell you what process produced the error, what time the error occurred, the port number, the username, etc.

For example, suppose we want to only log BASIC program errors that result from the 3 errors that are controlled by JBASE_ERRMSG_DIVIDE_ZERO, JBASE_ERRMSG_NON_NUMERIC and JBASE_ERRMSG_ZERO_USED. We don't want the program to drop to the debugger, nor do we want these error messages to display to the user. Setting JBASE_ERRMSG_TRACE=1 will certainly log these occurrences but they will be intermixed with all other messages making it difficult to determine what happened when.

The solution (details to follow) is to remove (unset) JBASE_ERRMSG_TRACE and place a POSTREAD trigger on your own version of the jbcmessages file. The trigger code will look for, and log, the 3 specific errors. Of course, you can add to this list as long as the error message is in the jbcmessages file.

There are two stages, Development and Implementation. The Development stage can be done at any time and will not affect the system in any way. The Implementation however must be done when there are no users on the system and no running jBASE processes.

Development
==========

1) Here is the trigger code. It assumes the existence of a file called ERRORLOG, in which the errors will be logged, and a different jbcmessages file. There are other things that need to be done to allow the trigger to fire and we will get to those shortly.

2) The first task is to create a custom jbcmessages file and then modify specific messages in this new file. For this example, we will use a directory named C:\custom. We will also assume that JBCRELEASEDIR is set to C:\jbase5\5.2. Here are the steps:

a) Copy the following files to the C:\custom directory (DO NOT use the jBASE COPY command):

C:\jbase5\5.2\jbcinit.err
C:\jbase5\5.2\jbcmessages]D
C:\jbase5\5.2\jbcmessages
b) Open the C:\custom\jbcinit.err file with any editor, then locate the line that starts with the string ZERO_USED: and replace the string WARNING with the string NOPRINT on that line. Note that the ^ characters you see are up-arrows (shift+6 on the keyboard). Make the same change on the lines that start with DIVIDE_ZERO: and NON_NUMERIC:. The final lines must look EXACTLY like this.

Be aware that, once this jbcmessages file is in use, these 3 errors will NEVER print to the screen, but instead will be captured by the trigger and logged to the ERRORLOG file.

c) Build the new jbcmessages file:
cd C:\custom
jmakeerr jbcinit.err (O
TO: C:\custom\jbcmessages
3) Create the ERRORLOG file (or whatever name you want to use, but if you change the name then you will then have to also change it in the trigger code). This is the file that the trigger will log the errors to rather than logging them to the jbase_error_trace file. The trigger code shows what information gets logged but you can, of course, add or remove elements as desired. Since the file is only going to contain 3 records it can be created with:
CREATE-FILE ERRORLOG 1 1

Feel free to create dictionary items as required.

Note: The ERRORLOG file must be available to your application so make sure that in is in HOME or is visible to JEDIFILEPATH.


Implementation
============

Ensure that there are no users on the system and that there are no running jBASE processes.

Any environment variable changes must be set system-wide. The changes should also be made in all remote.cmd (Windows) or .profile (Unix/Linux) files.

1) Compile the trigger code and catalog it so that it is available to your application. Remember to change the OPENs to reflect the locations and names of the files you are actually using.

Note: If you change the name of the trigger then remember to also change the name on the SUBROUTINE line.

2) Assign the trigger to your custom jbcmessages file:

CREATE-TRIGGER C:\custom\jbcmessages POSTREAD trackerrors
3) Add (or change) the environment settings for the 3 error scenarios:
JBASE_ERRMSG_DIVIDE_ZERO=2
JBASE_ERRMSG_NON_NUMERIC=2
JBASE_ERRMSG_ZERO_USED=2
Note: If the setting includes a bit mask value of 1 then the trigger will never fire because the jbcmessages file will never be read for that particular error condition.

4) Remove (unset) the JBASE_ERRMSG_TRACE environment variable.

5) Assign the environment variable that will point to your custom jbcmessages file:
JBCERRFILE=C:\custom\jbcmessages
Note: This setting is what actually activates the whole system.

If things don't work at first and you don't have time to debug it, then you can always:

a) remove (unset) JBCERRFILE. This will revert to the default jbcmessages file.
b) Optional: add JBASE_ERRMSG_TRACE=1 (do this only if it was set prior to Implementation)
c) Optional: change the value the JBASE_ERRMSG_xyz environment variables back to what they were prior to Implementation

Here is a simplistic program to test things out. After running it, if everything is working correctly, there will be 3 records in the ERRORLOG file, one record for each of the 3 error conditions.
0001   PROGRAM testerrors
0002   a = 1234
0003   b = 'xyz'
0004   CRT "Test1: use a non numeric --> ":a+b
0005   CRT "Test2: divide by 0 --> ":a/0
0006   CRT "Test3: invalid or uninitialised --> ":c  ;* variable c was never assigned


Knowledgebase Index