5.12. Errors: Discovery, Handling, and Recovery

TRL2 contains two important improvements over TRL1 in the area of
handling errors in stream I/O: the NOTREADY condition and the
STREAM() built-in function.  The NOTREADY condition is raised
whenever a stream I/O operation did not succeed. The STREAM()
function is used to retrieve status information about a particular
stream or to execute a particular operation for a stream.

You can discover that an error occurred during an I/O operation in
one of the following ways: a) it may trigger a SYNTAX condition;
b) it may trigger a NOTREADY condition; or c) it may just not
return that data it was supposed to.  There is no clear border
between which situations should trigger SYNTAX and which should
trigger NOTREADY. Errors in parameters to the I/O functions, like
a negative start position, is clearly a SYNTAX condition, while
reading off the end-of-file is equally clearly a NOTREADY
condition.  In between lay more uncertain situations like trying
to position the current write position after the end-of-file, or
trying to read a non-existent file, or using an illegal file name.

Some situations are likely to be differently handled in various
implementations, but you can assume that they are handled as
either SYNTAX or NOTREADY. Defensive, portable programming
requires you to check for both. Unfortunately, NOTREADY is not
allowed in TRL1, so you have to avoid that condition if you want
maximum compatibility. And due to the very lax restrictions on
implementations, you should always perform very strict
verification on all data returned from any file I/O built-in
function.

If neither are trapped, SYNTAX will terminate the program while
NOTREADY will be ignored, so the implementor’s decision about
which of these to use may even depend on the severity of the
problem (i.e. if the problem is small, raising SYNTAX may be a
little too strict). Personally, I think SYNTAX should be raised in
this context only if the value of a parameter is outside its valid
range for all contexts in which the function might be called.

Example: General NOTREADY condition handler

 Under TRL2 the “correct” way to handle NOTREADY conditions and
errors from I/O operations is unfortunately very complex. It is
shown in this example, in order to demonstrate the procedure:

     myfile = ‘MYFILE.DAT’
     signal on syntax name syn_handler
     call on notready name IO_handler
     do i=1 to 10 until res=0
          res = lineout(myfile, ‘line #’i)
          if (res=0) then
               say ‘Call to LINEOUT() didn”t manage to write out
     data’
     end
     exit
     
     IO_handler:
     syn_handler:
          file = condition(‘D’)
          say condition(‘C’) ‘raised for file’ file ‘at line’
     sigl’:’
          say ‘  ‘ sourceline(sigl)
          say ‘   State=’stream(file,’S’) ‘reason:’
     stream(file,’D’)
          call lineout( condition( ‘D’ ))   /* try to close */
          if condition(‘C’)==’SYNTAX’ then
               exit 1
          else
               return

Note the double checking in this example: first the condition
handler is set up to trap any NOTREADY conditions, and then the
return code from LINEOUT() is checked for each call.

As you can see, there is not really that much information that you
can retrieve about what went wrong. Some systems may have
additional sources from which you can get information, e.g.
special commands for the STREAM() built-in function, but these are
non-standard and should be avoided when writing compatible
programs.




PREV NEXT