INTERFACE IOErr; (***************************************************************************) (* Copyright (C) Olivetti 1989 *) (* All Rights reserved *) (* *) (* Use and copy of this software and preparation of derivative works based *) (* upon this software are permitted to any person, provided this same *) (* copyright notice and the following Olivetti warranty disclaimer are *) (* included in any copy of the software or any modification thereof or *) (* derivative work therefrom made by any person. *) (* *) (* This software is made available AS IS and Olivetti disclaims all *) (* warranties with respect to this software, whether expressed or implied *) (* under any law, including all implied warranties of merchantibility and *) (* fitness for any purpose. In no event shall Olivetti be liable for any *) (* damages whatsoever resulting from loss of use, data or profits or *) (* otherwise arising out of or in connection with the use or performance *) (* of this software. *) (***************************************************************************) IMPORT Text; IMPORT IO, Err; (* This interface is intended to provide a simple way of handling stream errors. For the most part, stream errors have these two properties: 1) They occur rarely 2) They cannot be corrected easily by the program using the stream. Consider a common stream - a stream to a file. Reads and writes from a file rarely fail. When they do fail most programs are not interested in trying to fix the problem. There is another class of stream errors which may occur - incorrect usage. Examples of this class of error are seeking to a negative position in a file or writing to a read only stream. These errors should also occur rarely and if they do occur no attempt should be made to correct them at runtime. They indicate a bug in the program which should be fixed by the programmer. This interface provides procedures which can be used to close down an errant stream and generate a helpful message describing the stream error. One of the procedures optionally terminates the program when the message has been printed. Here is an example of simple stream use: ... TRY s := SomeStream.Open(...); ...various stream operations... IO.Close(s); EXCEPT | IO.Error(s) => IOErr.Close(s); END; ... The stream is opened, used and then closed. If any stream error occurs during this process 'IO.Error' is raised and control is given to 'Close'. This procedure writes out a message describing the error and then terminates the program. Variations are possible; 'Close' takes a severity argument (see the interface to 'Err' for more details on severity) so it need not stop the program. 'DescribeAndClose' closes the stream and returns the message so the user can print it. For some programs the following structure may be more appropriate: ... s := NIL; TRY TRY ...various operations... s := SomeStream.Open(...); ...various stream operations... EXCEPT | IO.Error(errant) => s := errant; (* in case 'Open' raised the stream error and 's' was never set *) END; FINALLY IOErr.Close(s, Err.Severity.Warning); (* does nothing if 's' is NIL; closes 's' without comment if 's' is not errant; closes 's' with comment if 's' is errant *) END; ... This form is needed if the user needs 's' to be closed even if an exception other than 'IO.Error' is raised in the body of the inner TRY. Using 'Close' to routinely close the stream is ok because if used to close a stream on which no error has occured it will not write out a message or terminate the program. Similarly, 'DescribeAndClose' on a non errant stream will close the stream and return the null text (""). The procedure 'Describe' is provided to describe the current error on a stream without closing it. 'Describe' returns the null text if the stream is not errant. The message generated by the 'Close', 'DescribeAndClose' and 'Describe' procedures incorporates the stream name, a description of the type of error (error types are given by the enumeration 'IO.Fault') and any stream class specific error information which is available. The message may be more than one line long and is terminated by a newline. The helpfulness of the stream name and stream class specific information depend on the implementation of the stream class (note that some stream classes require the user to provide a name when the stream is opened). Some streams are extremely unlikely to raise errors; the implementor of such a stream may choose to be unhelpful. Implementors of widely used streams (such as file streams) should try to be as helpful as possible. The close procedures in this interface try very hard to close their stream argument - they keep calling 'IO.Close' until the stream dies! It is possible to try and close an errant stream and then get further errors. In this case the message generated will describe all the errors which occur. If the stream argument to 'Close' or 'DescribeAndClose' is NIL or has been closed already they behave as if the stream has been closed successfully (i.e. 'Close' does nothing and 'DescribeAndClose' returns the null text). It is a checked runtime error for the argument to 'Describe' to be NIL *) PROCEDURE Describe(s: IO.Stream): Text.T RAISES {}; (* Describe the error on 's'. Returns the null text if 's' is not errant. Causes a checked runtime error if 's' is NIL *) PROCEDURE DescribeAndClose(s: IO.Stream): Text.T RAISES {}; (* Close 's'. If 's' was errant or if an error occurs while closing 's' build an error message describing the problem. The result of the procedure is either the null text (no error) or the message describing the error(s). If 's' is NIL or has already been closed 'DescribeAndClose' returns the null text. *) PROCEDURE Close( s: IO.Stream; severity: Err.Severity := Err.Severity.Fatal) RAISES {}; (* A veneer on 'DescribeAndClose'. If the result of 'DescribeAndClose(s)' is not the null text calls 'Err.Print' to print it, with the given severity. See the 'Err' interface for more details on 'Err.Print' and 'Err.Severity'. Remember that 'Err.Print' is only called if the stream argument is errant or if closing the stream causes an error. If 's' is NIL 'Close' does nothing *) END IOErr.