If the computer's file system has a problem accessing a file or device (ie, stream), then REXX will put the stream into an error state.

Note: If the failure concerns an error not due to the file system, for example you pass bad arguments to LINEIN, then the stream won't be put into an error state. But SYNTAX condition will be raised instead.

What happens when a stream is put into an error state? No further calls to LINEIN, LINEOUT, CHAROUT, CHARIN, VALUEOUT, and VALUEIN will read/write data from/to that stream until the error state for the stream is cleared. Between the time that the stream is put into an error state, and when that error state is cleared, any attempt to read or write data to the stream will not actually read nor write data. Furthermore, while the stream is in an error state, sometimes certain Functions may return a value that seems to indicate that the operation was a success, although the operation was not actually performed.

Let's take an example. Let's assume that the file system has a problem in our following call to LINEIN:

line = LINEIN("mytext.txt", , 1)
Since there is a problem actually reading the line from "mytext.txt", then REXX puts "mytext.txt" into an error state. So what does LINEIN return? Well, if you are trapping NOTREADY via SIGNAL ON, then of course you will immediately jump to some other place in your script and therefore LINEIN will not get a chance to return anything. But if you are not trapping NOTREADY, or are trapping NOTREADY via CALL ON, then LINEIN returns an empty string.

In other words, LINEIN has to "fake the operation". After all, it must return something. LINEIN hasn't really read in an empty line. Because it has had a problem reading in another line, LINEIN lies to you and tells you that it successfully read another line which happens to be empty.

What happens if we make another call to LINEIN (while the stream is still in error state)? This will also return an empty line. LINEIN will not even attempt to read a line so long as the stream is in an error state.

For example, consider the following statement where we read and concatenate three lines from the stream:

line = LINEIN("mytext.txt", , 1) || LINEIN("mytext.txt", , 1) || LINEIN("mytext.txt", , 1)
If there is a problem reading the first line, then the second and third calls to LINEIN will both also return an empty string. (Of course, if you're using SIGNAL ON NOTREADY, then the second and third calls will not even be made since you'll have jumped out of the instruction precisely when the problem occurred).

Let's take another example. Assume we want to write Hello to "mytext.txt". But let's also assume that LINEOUT has a problem doing that:

err = LINEOUT("mytext.txt", "Hello")
Since there is a problem actually writing the line to "mytext.txt", then REXX puts "mytext.txt" into an error state. What does LINEOUT return? If you're trapping NOTREADY via CALL ON, LINEOUT returns a 0. In other words, LINEOUT has also lied to us and told us that it successfully wrote the line, even though no line may have been written. If you're not trapping NOTREADY, then LINEOUT will return a 1 to indicate that the line was not successfully written.

What happens if we make another call to LINEOUT (while the stream is still in error state)? This will also return a 0 or 1 depending upon whether you're using CALL ON NOTREADY or not trapping NOTREADY. LINEOUT will not even attempt to write a line so long as the stream is in an error state.

Let's examine one more example. Assume that CHARS() has some problem determining how many characters are in the stream:

howmany = CHARS("mytext.txt")
Since there is a problem actually counting the characters in "mytext.txt", then REXX puts "mytext.txt" into an error state. What does CHARS return? If you're trapping NOTREADY via CALL ON, or not trapping NOTREADY, CHARS returns a 0. In other words, CHARS has lied to us and told us that "mytext.txt" is an empty file, even though it may not be.

The implication is that, in order to definitively determine whether you've got an error with some stream, you need to either trap NOTREADY, or use STREAM's "D" command to retrieve any error message after each operation. Since some interpreters do not support the latter, then the former is the most compatible way to handle file system problems.


Clearing the error state

If you trap the NOTREADY condition, then REXX automatically clears a stream's error state on your behalf as soon as it SIGNALs or CALLs your NOTREADY handler. (But note that if using CALL ON, then REXX doesn't call your NOTREADY handler until it gets to the end of an instruction. So any calls made within the same instruction to read/write data will occur while the stream is still in an error state, and consequently not do anything).

So, you do not need to explicitly clear a stream's error state if you're trapping NOTREADY.

If you're not trapping NOTREADY, then you can explicitly clear a stream's error state with STREAM's 'RESET' command. This returns the string "READY" if the stream's error state is cleared.

IF STREAM("mytext.txt", "C", "RESET") == "READY" THEN SAY "No error state"

You can also clear a stream's error state by explicitly closing the stream.

A third way to clear a stream's error state (without needing to close it) is to change one of the read/write positions. If you are successful at doing this, then the error state is cleared. (Note that you can change a stream's current position in the same call to write/read data, and this will clear the error state if successful. In other words, passing a position arg to LINEIN, LINEOUT, CHARIN, or CHAROUT can clear the error state if the operation is successful).

Note: STREAM's 'S' option will return the string "ERROR" if the stream is in an error state.