5.13.11 Stream I/O in BRexx 1.0b BRexx contains a set of I/O which shows very close relations with the C programming language I/O library. In fact, you should consider consulting the C library documentation for in-depth documentation on this functionality. BRexx contains a two-level naming scheme: in REXX, streams are referred to by a stream handle, which is an integer; in the operating system files are referred to by a file name, which is a normal string. The function OPEN() is used to bind a file name to a stream handle. However, BRexx I/O functions generally have the ability to get a reference either as a file name and a stream handle, and open the file if appropriate. However, if the name of a file is an integer which can be interpreted as a file descriptor number, it is interpreted as a descriptor rather than a name. Whenever you use BRexx and want to program robust code, always use OPEN() and the descriptor. If a file is opened by specifying the name in a I/O operation other than OPEN(), and the name is an integer and only one or two higher than the highest current file descriptor, strange things may happen. Five special streams are defined, having the pseudo file names: <STDIN>, <STDOUT>, <STDERR>, <STDAUX>, and <STDPRN>; and are assigned pre-defined stream handles from 0 to 4, respectively. These refer to the default input, default output, and default error output, default auxiliary output, and printer output. The two last generally refer to the COM1: and LPT1: devices under MS- DOS. Either upper or lower case letter can be used when referring to these four special names. However, note that if any of these five special files are closed, they can not be reopened again. The reopened file will be just a normal file, having the name e.g. <STDOUT>. There is a few things you should watch out for with the special files. I/O involving the <STDAUX> and <STDPRN> can cause the Abort, Retry, Ignore message to be shown once for each character that was attempted read or written. It can be boring and tedious to answer R or I if the text string is long. If A is answered, BRexx terminates. You should never write data to file descriptor 0 (<STDIN>), apparently, it will only disappear. Likewise, never read data to file descriptors 1 and 2 (<STDOUT> and <STDERR>), the former seems to terminate the program while the latter apparently just returns the nullstring. Also be careful with reading from file descriptors 3 and 4, since your program may hang if no data is available. OPEN(file,mode) The OPEN() built-in function opens a file named by file, in mode mode, and returns an integer which is the number of the stream handle assigned to the file. In general, the stream handle is a non-negative integer, where 0 to 4 are pre-defined for the default streams. If an error occurred during the open operation, the value -1 is returned. The mode parameter specifies the mode in which the file is opened. It consists of two parts: the access mode, and the file mode. The access mode part consists of one single character, which can be r for read, w for write, and a for append. In addition, the + character can be appended to open a file in both read and write mode. The file mode part can also have of one additional character which can be t for text files and b for binary files. The t mode is default. The following combinations of + and access mode are possible: r is non-destructive open for reading; w is destructive open for write-only mode; a is non-destructive open for in append-only mode, i.e. only write operations are allowed, and all write operations must be performed at the end-of-file; r+ is non- destructive open for reading and writing; w+ is destructive open for reading and writing; and a+ is non-destructive open in append update, i.e. reading is allowed anywhere, but writing is allowed only at end-of-file. Destructive mode means that the file is truncated to zero length when opened. In addition, the b and t characters can be appended in order to open the file in binary or text mode. These modes are the same as under C, although the t mode character is strictly not in ANSI C. Also note that r, w, and a are mutually exclusive, but one of them must always be present. The mode + is optional, but if present, it must always come immediately after r, w, or a. The t and b modes are optional and mutually exclusive; the default is t. If present, t or b must be the last character in the mode string. open(‘myfile’ 7 perhaps ,’w’) open(‘no.such - if non-existent .file’,’r’) 1 open(‘c:tmp’, 6 perhaps ‘r+b’) If two file descriptors are opened to the same file, only the most recently of them works. However, if the most recently descriptor is closed, the least recently starts working again. There may be other strange effects too, so try avoid reopening a file that is already open. CLOSE(file) The CLOSE() built-in function closes a file that is already open. The parameter file can be either a stream handle returned from OPEN() or a file name which has been opened (but for which you do not known the correct stream handle). The return value of this function seems to be the nullstring in all cases. close(6) if open close(7) if not open close(‘f perhaps oobar’) EOF(file) The EOF() built-in function checks the end-of-file state for the stream given by file, which can be either a stream descriptor or a file name. The value returned is 1 if the end-of-file status is set for the stream, and 0 if it is cleared. In addition, the value -1 is returned if an error occurred, for instance if the file is not open. The end-of-file indicator is set whenever an attempt was made to read at least one character past the last character of the file. Note that reading the last character itself will not set the end- of-file condition. eof(foo) 0 if not at eof eof(‘8’) 1 if at eof eof(‘no.su - if file isn’t open ch.file’) 1 READ([file][,length]) The READ() built-in function reads data from the file referred to by the file parameter, which can be either a file name or a stream descriptor. If it is a file name, and that file is not currently open, then BRexx opens the file in mode rt. The default value of the first parameter is the default input stream. The data is read from and including the current position. If the length parameter is not specified, a whole line is read, i.e. reading forwards to and including the first end-of-line sequence. However, the end-of-line sequence itself is not returned. If the length parameter is specified, it must be a non- negative integer, and specified the number of characters to read. The data returned is the data read, except that if length is not specified, the terminating end-of-line sequence is stripped off. If the last line of a file contains a string unterminated by the end-of-string character sequence, then the end-of-file is implicitly interpreted as an end-of-line. However, in this case the end-of-file state is entered, since the end-of-stream was found while looking for an end-of-line. read(‘ one reads a complete line foo’) line read(‘ anoth reads parts of a line foo’,5 ) read(6 er using a file descriptor ) line read() hello perhaps, reads line from there default input stream WRITE([file][,[string][,dummy]]) The WRITE() built-in function writes a string of data to the stream specified by the file parameter, or by default the default output stream. If specified, file can be either a file name or a stream descriptor. If it is a file name, and that file is not already open, it is opened using wt mode. The data written is specified by the string parameter. The return value is an integer, which is the number of bytes written during the operation. If the file is opened in text mode, all ASCII newline characters are translated into ASCII CRLF character sequences. However, the number returned is not affected by this translation; it remains independent of any text of binary mode. Unfortunately, errors while writing is seldom trapped, so the number returned is generally the number of character that was supposed to be written, independent of whether they was actually written or not. If a third parameter is specified, the data is written as a line, i.e. including the end-of-line sequence. Else, the data is written as-is, without any end-of-line sequence. Note that with BRexx, the third parameter is considered present if at least the comma in front of it—-the second comma—-is present. This is a bit inconsistent with the standard operations of the ARG() built-in function. The value of the third parameter is always ignored, only its presence is considered. If the second parameter is omitted, only an end-of-line action is written, independent of whether the third parameter is present or not. write(‘bar’, 4 writes four bytes ’data’) write(‘bar’, 4+ write a line ’data’,’nl’) ?? write(‘bar’, 4+ same as previous ’data’,) ?? SEEK(file[,[offset][,origin]]) The SEEK() built-in function moves the current position to a location in the file referred to by file. The parameter file can be either a file name (which must already be open) or a stream descriptor. This function does not implicitly open files that is not currently open. The parameter offset determines the location of the stream and must be an integer. It defaults to zero. Note that the addressing of bytes within the stream is zero-based. The third parameter can be any of TOF, CUR, or EOF, in order to set the reference point in which to recon the offset location. The three strings refer to top-of-file, current position, and end-of- file, and either upper or lower case can be used. The default value is ???. The return value of this function is the absolute position of the position in the file after the seek operation has been performed. The SEEK() function provides a very important additional feature. Whenever a file opened for both reading and writing has been used in a read operation and is to be used in a write operation next (or vice versa), then a call to SEEK() must be performed between the two I/O calls. In other words, after a read only a seeking and reading may occur; after a write, only seeking and writing may occur; and after a seek, reading, writing, and seeking may occur.