5.13.7 Stream I/O in Regina 0.07a Regina implements stream I/O in a fashion that closely resembles how it is described in TRL2. The following list gives the relevant system-specific information. [Names for standard streams.] Regina uses <stdout> and <stdin> as names for the standard output and input streams. Note that the angle brackets are part of the names. You may also access the standard error stream (on systems supporting this stream) under the name <stderr>. In addition, the nullstring is taken to be equivalent to an empty first parameter in the I/O-related built-in functions. [Implicit opening.] Regina implicitly opens any file whenever it is first used. If the first operation is a read, it will be opened in read- only mode. If the first operation is a write, it is opened in read-write mode. In this case if the read-write opening does not succeed, the file is opened in write-only mode. If the file exists, the opening is non-destructive, i.e. that the file is not truncated or overwritten when opened, else it is created if opened in read-write mode. If you name a file currently open in read-only mode in a write operation, Regina closes the file, and reopens it in read-write mode. The only exception is when you call LINEOUT() with both second and third arguments unspecified, which always closes a file, both for reading and writing. Similarly, if the file was opened in write-only mode, and you use it in a read operation, Regina closes and reopens in read- write mode. This implicit reopening is enabled by default. You can turn it off by unsetting the extension ExplicitOpen. [Separate current positions.] The environment in which Regina operates (ANSI C and POSIX) does not allow separate read and write positions, but only supplies one position for both operations. Regina handles this by maintaining the two positions internally, and move the “real” current position back and forth depending on whether a read or write operation is next. [Swapping out file descriptors.] In order to defend itself against “open-many-close-none” programming, Regina tries to “swap out” files that have been unused for some time. Assume that your operating system limits Regina to 100 simultaneously open files; when your try to open your 101st file, Regina closes the least recently used stream, and recycles its descriptor for the new file. You can enable or disable this recycling with the SwapFilePtr extension. During this recycling, Regina only closes the file in the operating system, but retains all vital information about the file itself. If you re-access the file later, Regina reopens it, and positions the current read and write positions at the correct (i.e. previous) positions. This introduces some uncertainties into stream processing. Renaming a file affects it only if it gets swapped out. Since the swap operation is something the users do not see, it can cause some strange effects. Regina will not allow a transient stream to be swapped out, since they often are connected to some sort of active partner in the other end, and closing the file might kill the partner or make it impossible to reestablish the stream. So only persistent files are swapped out. Thus, you can still fill the file table in Regina. [Explicit opening and closing.] Regina allows streams to be explicitly opened or closed through the use of the built-in function STREAM(). The exact syntax of this function is described in section stream. Old versions of Regina supported two non-standard built-in functions OPEN() and CLOSE() for these operations. These functions are still supported for compatibility reasons, but might be removed in future releases. Their availability is controlled by the OpenBif and CloseBif extensions. [Truncation after writing lines.] If you reposition line-wise the current write position to the middle of a file, Regina truncates the file at the new position. This happens whether data is written during the LINEOUT() or not. If not, the file might contain half a line, some lines might disappear, and the linecount would in general be disrupted. The availability of this behavior is controlled by LineOutTrunc, which is turned on by default. Unfortunately, the operation of truncating a file is not part of POSIX, and it might not exist on all systems, so on some rare systems, this truncating will not occur. In order to be able to truncate a file, your machine must have the ftruncate() system call in C. If you don’t have this, the truncating functionality is not available. [Caching info on lines left.] When Regina executes the built-in function LINES() for a persistent stream, it caches the number of lines left as an attribute to the stream. In subsequent calls to LINEIN(), this number is updated, so that subsequent calls to LINES() can retrieve the cached number instead of having to re-scan the rest of the stream, provided that the number is still valid. Some operations will invalidate the count: repositioning the current read position; reading using the character oriented I/O, i.e. CHARIN(); and any write operation by the same interpreter on the stream. Ideally, any write operation should invalidate the count, but that might require a large overhead before any operation, in order to check whether the file has been written to by other programs. This functionality can be controlled by the extension called CacheLineNo, which is turned on by default. Note that if you turn that off, you can experience a serious decrease in performance. The following extra built-in functions relating to stream I/O are defined in Regina. They are provided for extra support and compatibility with other systems. Their support may be discontinued in later versions, and they are likely to be moved to a library of extra support. CLOSE(streamid) Closes the stream named by streamid. This stream must have been opened by implicit open or by the OPEN function call earlier. The function returns 1 if there was any file to close, and 0 if the file was not opened. Note that the return value does not indicate whether the closing was successful. You can use the extension named CloseBif with the OPTIONS instruction to select or remove this function. This function is now obsolete, instead you should use: STREAM( streamid, ‘Command’, ‘CLOSE’ ) CLOSE(myfile) 1 if stream was open CLOSE(‘NOSUCHFIL 0 if stream didn’t E’) exist OPEN(streamid,access) Opens the stream named streamid with the access access. If access is not specified, the access R will be used. access may be the following characters. Only the first character of the access is needed. [R] (Read) Open for read access. The file pointer will be positioned at the start of the file, and only read operations are allowed. [W] (Write) Open for write access and position the current write position at the end of the file. An error is returned if it was not possible to get appropriate access. The return value from this function is either 1 or 0, depending on whether the named stream is in opened state after the operation has been performed. Note that if you open the files “foobar” and “./foobar” they will point to the same physical file, but Regina interprets them as two different streams, and will open a internal file descriptor for each one. If you try to open an already open stream, using the same name, it will have no effect. You can use the extension OpenBif with the OPTIONS instruction to control the availability of this function. This function is now obsolete, but is still kept for compatibility with other interpreters and older versions of Regina. Instead, with Regina you should use: STREAM( streamid, ‘C’, ‘READ’|’WRITE’|’APPEND’|’UPDATE’ ) OPEN(myfile, 1 maybe, if successful ‘write’) OPEN(passwd, 0 maybe, if no write ‘Write’) access OPEN(‘DATA’, 0 maybe, if successful ‘READ’) The return value from this function is either 1 or 0, depending on whether the named stream is in opened state after the operation has been performed.