Here's my proposal for Thing One ports and I/O facilities. It's fully upward compatible with R5RS, but takes ideas from R6RS, SRFI-91 and SRFI-6. Many of the concepts are present in R6RS under other names.
The new features beyond R5RS are:
In this proposal, there are two kinds of ports, binary ports and character ports. Unusually, every binary port is automatically a character port, though not vice versa. This implies that some character encoding must be associated with each binary port so that character I/O can be performed on it. The only encoding that implementations MUST support is ASCII, so this is relatively cost-free, since ASCII encoding does not require a separate character buffer or encoding translation table, only a few bits for newline translation and case sensitivity.
This proposal does not specify any way to create a bidirectional port, but allows for their possible existence in an implementation. Sockets, terminals, and pipes are all examples.
In this proposal, a filename may be specified either as a string or as a settings list, which is a list of alternating keys and values where every key is a symbol ending in a colon. For convenience, these symbols are also defined as identifiers. Implementations MUST support the following keys:
Implementations MAY support other keys.
All these procedures are required in a WG1 Scheme system and form part of the core module.
(input-port? obj)
(output-port? obj)
Same as R5RS, but also return true on input/output ports.
(port? obj)
Mentioned in R5RS section 3 but not in section 6.6. Part of R6RS.
(current-input-port)
(current-output-port)
Same as R5RS. These are binary ports whose character encoding is implementation-dependent.
(current-error-port)
From R6RS. This is a binary port whose character encoding is implementation-dependent.
(flush-output-port [ output-port ] [ character-only? ])
Same as R6RS, except that if the output-port is omitted, the default port is the current output port. Drains the character buffer of output-port, if any. Then, if the port is a binary port, drains the binary buffer, if any.
(close-input-port port)
(close-output-port port)
From R5RS. Close-output-port implicitly calls flush-output-port first.
(close-port)
Closes both sides of a bidirectional port; otherwise the same as close-input-port or close-output-port as the case may be.
(eof-object? obj)
Same as R5RS.
(character-port? obj)
Returns #t if obj is a character port. SRFI 91 calls this char-port. Implementations may define other kinds of character ports.
(read-char [ character-input-port ])
(write-char [ character-output-port ])
(newline [ character-output-port ])
(peek-char [ character-input-port ])
(char-ready? [ character-input-port ])
Same as R5RS. It is an error to output characters not present in the encoding of a character-output-port.
(read-line [ character-input-port ])
Same as R6RS. Reads a line from port (or the current input port) terminated by a #\newline character (which may be the result of newline conversion in the port). This is a convenience function.
(open-input-string string)
(open-output-string)
(get-output-string output-string-port)
Same as SRFI 6.
Note that string ports are character ports, but not binary ports, so these procedures do not apply to them. Implementations MAY support other kinds of binary ports such as process ports or stream socket ports.
(binary-port? obj)
Returns #t if obj is a binary port. SRFI 91 calls this byte-port?.
(read-u8 [ binary-input-port ])
(write-u8 [ binary-output-port ])
(peek-u8 [ binary-input-port ])
(u8-ready? [ binary-input-port ])
The direct binary analogues of read-char, write-char, newline, peek-char, and char-ready? respectively. They return an exact integer between 0 and 255 rather than a character. SRFI 91 talks of byte rather than u8.
(open-input-blob blob)
(open-output-blob)
(get-output-blob output-blob-port)
Blobs are (possibly specialized) vectors containing integers from 0 to 255 inclusive. These procedures are the binary analogues of the SRFI 6 string port procedures. The term blob is subject to change.
This is a separate module because some implementations will not have access to a file system.
(call-with-input-file filename proc)
(call-with-output-file filename proc)
(with-input-from file filename thunk)
(with-output-to-file filename thunk)
(open-input-file filename)
(open-output-file filename)
Same as R5RS, except that any filename argument may be a string or a settings list.
(delete-file filename)
(file-exists? filename)
Same as R6RS. Only string filenames are supported.
These procedures are not in the core because many systems, especially embedded ones, don't require the ability to read or write general Scheme objects, and very small implementations may not want the overhead of a Scheme parser. Writing may be useful even when reading is not, which is why there are two modules.
Note that implementations may provide ports that are not character ports, such as directory ports or vector ports, and extend these procedure to work on them.
(read [ input-port ])
Same as R5RS.
(write obj [ output-port ])
Same as R5RS, but specifies that only ASCII characters may be output (for re-readability). Non-ASCII characters in symbols, strings, and character literals MUST be escaped.
(display obj [ port ])
Same as R5RS. It is an error to output characters not present in the encoding of output-port.
Thanks to the R5RS and R6RS editors; to Marc Feeley, author of SRFI 91 and Gambit-C; and to Will Clinger, author of SRFI 6.