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.