17 Ports

A port is an object that mediates data from an input or to a destination. In the former case, the port is an input port, in the latter case, an output port. The data itself can consist of either characters or bytes. In the former case the port is a textual port and in the latter case, a binary port.

There are three textual ports open, binded by dynamic variables, one for standard input, output, and error.

Although ports are not considered immutable, none of the operations on ports described in this section constitute mutation. Ports are equal? iff eq?. The port type is encapsulated.

An auxiliary data type used to signal the end of file was reached is eof. The eof type consists of a single immutable value, having an output only external representation (so that it can never be the normal result of a call to read). The eof type is encapsulated.

SOURCE NOTE: the eof type is not in the Kernel report, it is used in klisp and was taken from r7rs.

— Applicative: port? (port? . objects)

The primitive type predicate for type port. port? returns true iff all the objects in objects are of type port.

— Applicative: input-port? (input-port? . objects)
— Applicative: output-port? (output-port? . objects)

Applicative input-port? is a predicate that returns true unless one or more of its arguments is not an input port. Applicative output-port? is a predicate that returns true unless one or more of its arguments is not an output port.

Every port must be admitted by at least one of these two predicates.

— Applicative: textual-port? (textual-port? . objects)
— Applicative: binary-port? (binary-port? . objects)

Applicative textual-port? is a predicate that returns true unless one or more of its arguments is not a textual port. Applicative binary-port? is a predicate that returns true unless one or more of its arguments is not a binary port.

Every port must be admitted by at least one of these two predicates.

SOURCE NOTE: this is missing from Kernel, it is taken from r7rs.

— Applicative: file-port? (file-port? . objects)
— Applicative: string-port? (string-port? . objects)
— Applicative: bytevector-port? (bytevector-port? . objects)

These applictives are predicates that returns true unless one or more of its arguments is not a file, string or bytevector port, repectively.

Every port in klisp is be admitted by exactly one of these predicates.

SOURCE NOTE: this is missing from Kernel, but convenient in the face of the different port types admited by klisp.

— Applicative: port-open? (port-open? port)

Applicative port-open? returns true iff port is still open.

SOURCE NOTE: this is taken from r7rs.

— Applicative: with-input-from-file (with-input-from-file string combiner)
— Applicative: with-output-to-file (with-output-to-file string combiner)
— Applicative: with-error-to-file (with-error-to-file string combiner)

These three applicatives open the file named in string for textual input or output, an invoke the binder of either the input-port, the output-port or the error-port keyed dynamic variables respectively with the opened port & the passed combiner (this means that the combiner is called in a fresh, empty dynamic environment). When/if the binder normally returns, the port is closed. The result of the applicatives with-input-from-file and with-output-from-file is inert.

SOURCE NOTE: The first two are enumerated in the Kernel report but the text is still missing. The third applicative is from r7rs.

— Applicative: get-current-input-port (get-current-input-port)
— Applicative: get-current-output-port (get-current-output-port)
— Applicative: get-current-error-port (get-current-error-port)

These are the accessors for the input-port, output-port, and error-port keyed dynamic variables repectively.

SOURCE NOTE: The first two are enumerated in the Kernel report but the text is still missing. The third applicative is from r7rs.

— Applicative: open-input-file (open-input-file string)
— Applicative: open-binary-input-file (open-binary-input-file string)

string should be the name/path for an existing file.

Applicative open-input-file creates and returns a textual input port associated with the file represented with string. Applicative open-binary-input-file creates and returns a binary input port associated with the file represented with string. In either case, if the file can’t be opened (e.g. because it doesn’t exists, or there’s a permissions problem), an error is signaled.

SOURCE NOTE: open-input-file is enumerated in the Kernel report but the text is still missing. open-binary-input-file is from r7rs.

— Applicative: open-output-file (open-output-file string)
— Applicative: open-binary-output-file (open-binary-output-file string)

string should be the name/path for an existing file.

Applicative open-output-file creates and returns a textual output port associated with the file represented with string. Applicative open-binary-output-file creates and returns a binary output port associated with the file represented with string. In either case, if the file can’t be opened (e.g. if there’s a permissions problem), an error is signaled.

In klisp, for now, applicative open-output-file and open-binary-output-file truncate the file if it already exists, but that could change later (i.e. like in Scheme the behaviour should be considered unspecified).

SOURCE NOTE: open-output-file is enumerated in the Kernel report but the text is still missing. open-binary-output-file is from r7rs.

— Applicative: open-input-string (open-output-string string)
— Applicative: open-input-bytevector (open-output-bytevector bytevector)

These applicative return a fresh input port that reads characters or unsigned bytes from the passed sequence.

SOURCE NOTE: These are taken from r7rs.

— Applicative: open-output-string (open-output-string)

Applicative open-output-string returns a fresh textual output port that accumulates characters. The accumulated data can be obtained via applicative get-output-string.

SOURCE NOTE: This is taken from r7rs.

— Applicative: open-output-bytevector (open-output-bytevector)

Applicative open-output-bytevector returns a fresh binary output port that accumulates unsigned bytes. The accumulated data can be obtained via applicative get-output-bytevector.

SOURCE NOTE: This is taken from r7rs.

— Applicative: close-input-file (close-input-file input-port)
— Applicative: close-output-file (close-output-file output-port)

These applicatives close the port argument, so that no more input/output may be performed on them, and the resources can be freed. If the port was already closed these applicatives have no effect.

The result returned by applicatives close-input-file and close-output-file is inert.

SOURCE NOTE: this is enumerated in the Kernel report but the text is still missing. There’s probably a name error here. These should probably be called close-input-port & close-output-port.

— Applicative: close-input-port (close-input-port input-port)
— Applicative: close-output-port (close-output-port output-port)
— Applicative: close-port (close-port port)

These applicatives close the port argument, so that no more input/output may be performed on them, and the resources can be freed. If the port was already closed these applicatives have no effect. If at some time klisp provided input/output ports these could be used to selectively close only one direction of the port.

The result returned by applicatives close-input-portclose-output-port, and close-port is inert.

SOURCE NOTE: this is from r7rs. The equivalent close-input-file and close-output-file are probably name errors and only retained here till the draft standard rectifies them.

— Applicative: get-output-string (get-output-string port)

port should be a string output port.

Applicative get-output-string returns a freshly created mutable string representing the characters accumulated in port so far. port can be either open or closed.

SOURCE NOTE: This is taken from r7rs.

— Applicative: get-output-bytevector (get-output-bytevector port)

port should be a bytevector output port.

Applicative get-output-bytevector returns a freshly created mutable bytevector representing the unsigned bytes accumulated in port so far. port can be either open or closed.

SOURCE NOTE: This is taken from r7rs.

— Applicative: read (read [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual input port.

Applicative read reads & returns the next parseable object from the given port, or the eof if no objects remain. If read finds and unparseable object in the port, an error is signaled. In that case, the remaining position in the port is unspecified.

SOURCE NOTE: this is enumerated in the Kernel report but the text is still missing.

— Applicative: write (write object [port])

If the port optional argument is not specified, then the value of the output-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual output port.

Applicative write writes an external representation of object to the specified port. This may be an output-only representation that can’t be read by applicative read in cases where the type of object doen’t have a parseable external representation (e.g. combiners and environments). The result returned by write is inert. write is guaranteed to terminate even in the case of objects with shared or cyclic structure. In those cases write will use special syntax to preserve sharing info.

SOURCE NOTE: this is enumerated in the Kernel report but the text is still missing.

— Applicative: write-simple (write-simple object [port])

Applicative write-simple is like write except that it doesn’t write sharing info. It will hang if handed a cyclic structure.

SOURCE NOTE: this is taken from r7rs.

— Applicative: eof-object? (eof-object? . objects)

The primitive type predicate for type eof. eof-object? returns true iff all the objects in objects are of type eof.

SOURCE NOTE: This is not in the report, the idea is from Scheme. The eof-object? name is also from Scheme, but this will probably be changed to just eof?, for consistency with the other primitive type predicates.

— Applicative: newline (newline [port])

If the port optional argument is not specified, then the value of the output-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual output port.

Applicative newline writes a newline to the specified port. The result returned by newline is inert.

SOURCE NOTE: this is missing from Kernel, it is taken from Scheme.

— Applicative: display (display object [port])

If the port optional argument is not specified, then the value of the output-port keyed dynamic variable is used. If the port is not a textual output port, or is closed, an error is signaled.

Applicative display behaves like write except that strings are not enclosed in double quotes and no character is escaped within those strings and character objects are output as if by write-char instead of write. The result returned by display is inert.

SOURCE NOTE: this is missing from Kernel, it is taken from Scheme.

— Applicative: read-line (read-line [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed or if it is not a textual input port, an error is signaled.

Applicative read-line

SOURCE NOTE: this is taken from r7rs.

— Applicative: flush-output-port (flush-output-port [port])

If the port optional argument is not specified, then the value of the output-port keyed dynamic variable is used. If the port is closed or if it is not an output port, an error is signaled.

Applicative flush-output-port flushes any buffered data in the output port to the underlying object (file, socket, pipe, memory sector, device, etc). The result returned by flush-output-port is inert.

SOURCE NOTE: this is missing from Kernel, it is taken from r7rs.

— Applicative: write-char (write-char char [port])

If the port optional argument is not specified, then the value of the output-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual output port.

Applicative write-char writes the char character (not an external representation of the character) to the specified port. The result returned by write-char is inert.

SOURCE NOTE: this is missing from Kernel, it is taken from Scheme.

— Applicative: read-char (read-char [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual input port.

Applicative read-char reads and returns a character (not an external representation of a character) from the specified port, or an eof if the end of file was reached.

SOURCE NOTE: this is missing from Kernel, it is taken from Scheme.

— Applicative: peek-char (peek-char [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual input port.

Applicative peek-char reads and returns a character (not an external representation of a character) from the specified port, or an eof if the end of file was reached. The position of the port remains unchanged so that new call to peek-char or read-char on the same port return the same character.

SOURCE NOTE: this is missing from Kernel, it is taken from Scheme.

— Applicative: char-ready? (char-ready? [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a textual input port.

Predicate char-ready? checks to see if a character is available in the specified port. If it returns true, then a read-char or peek-char on that port is guaranteed not to block/hang. For now in klisp this is hardcoded to #t because the code to do this is non-portable.

SOURCE NOTE: this is missing from Kernel, it is taken from Scheme.

— Applicative: write-u8 (write-u8 u8 [port])

If the port optional argument is not specified, then the value of the output-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a binary output port.

Applicative write-u8 writes the byte represented by the unsigned integer u8, that should be between 0 and 255 inclusive, (not an external representation of byte) to the specified port. The result returned by write-u8 is inert.

SOURCE NOTE: this is missing from Kernel, it is taken from r7rs.

— Applicative: read-u8 (read-u8 [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a binary input port.

Applicative read-u8 reads and returns a byte as an exact unsigned integer between 0 and 255 inclusive (not an external representation of a byte) from the specified port, or an eof if the end of file was reached.

SOURCE NOTE: this is missing from Kernel, it is taken from r7rs.

— Applicative: peek-u8 (peek-u8 [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a binary input port.

Applicative peek-u8 reads and returns a byte as an exact unsigned integer between 0 and 255 inclusive (not an external representation of a byte) from the specified port, or an eof if the end of file was reached. The position of the port remains unchanged so that new call to peek-u8 or read-u8 on the same port return the same byte.

SOURCE NOTE: this is missing from Kernel, it is taken from r7rs.

— Applicative: u8-ready? (u8-ready? [port])

If the port optional argument is not specified, then the value of the input-port keyed dynamic variable is used. If the port is closed, an error is signaled. The port should be a binary input port.

Predicate u8-ready? checks to see if a byte is available in the specified port. If it returns true, then a read-u8 or peek-u8 on that port is guaranteed not to block/hang. For now in klisp this is hardcoded to #t because the code to do this is non-portable.

SOURCE NOTE: this is missing from Kernel, it is taken from r7rs.

— Applicative: call-with-input-file (call-with-input-file string combiner)
— Applicative: call-with-output-file (call-with-output-file string combiner)

These applicatives open file named in string for textual input/output respectively and call their combiner argument in a fresh empty environment passing it as a sole operand the opened port. When/if the combiner normally returns a value the port is closed and that value is returned as the result of the applicative.

SOURCE NOTE: this is enumerated in the Kernel report but the text is still missing.

— Applicative: load (load string)

Applicative load opens the file named string for textual input; reads immutable objects from the file until the end of the file is reached; evaluates those objects consecutively in the created environment. The result from applicative load is inert.

Notice that if string is a relative path it is looked in the current directory (whatever that means in your OS, normally the directory from which the interpreted was run or the directory where the interpreter executable lives). klisp doesn’t track the directory from which the current code was read, so there’s in principle no way to load a file in the same directory as the currently executing code with a relative path. See find-required-filename for a way to look for a file in a number of directories.

SOURCE NOTE: load is enumerated in the Kernel report, but the description is not there yet. This seems like a sane way to define it, taking the description of get-module that there is in the report. The one detail that I think is still open, is whether to return #inert (as is the case with klisp currently) or rather return the value of the last evaluation.

— Applicative: require (require string)

Applicative require looks for string following the algorithm described in applicative find-required-filename. If an appropriate file can’t be found, and error is signaled. Otherwise, the file is opened for textual input; immutable objects are read and acumulated until the end of file is found; those objects are evaluated in a fresh standard environment; the results of evaluation are discarded and the result from applicative require is inert.

Applicative require also register string (as via applicative register-requirement!) so that subsequent calls to require with exactly the same string will not cause any search or evaluation. The mechanism used for this can also be manipulated directly by the programmer via applicatives registered-requirement?register-requirement!unregister-requirement!, and find-required-filename.

Applicative require is useful to load klisp libraries.

SOURCE NOTE: require is taken from lua and r7rs.

— Applicative: registered-requirement? (registered-requirement? string)
— Applicative: register-requirement! (register-requirement! string)
— Applicative: unregister-requirement! (unregister-requirement! string)
— Applicative: find-required-filename (find-required-filename string)

string should be non-empty.

These applicatives control the underlying facilities used by require to register already required files. Predicate registered-requirement? returns true iff string is already registered. register-requirement! marks string as registered (throws an error if it was already registered). unregister-requirement! marks string as not being registered (throws an error if it wasn’t registered). find-required-filename looks for an appropriate file for string using the algorithm described below.

filename search in controlled by environment variable KLISP_PATH. This environment variable should be a list of templates separated with semicolons (“;”). Each template is a string that may contain embedded question mark characters (“?”) to be replaced with string. After replacements, each template represents the path to a file. All templates are probed in order, and the first to name an existing readable file is returned. If no template corresponds to an existing readable file, an error is signaled.

NOTE: in the future there will be some mechanism to alter the search algorithm dinamically, in the meantime this environment variable is the only way to customize it.

SOURCE NOTE: this is not in Kernel, they are supplied per guideline G1b of the report (extensibility), so that klisp programs can easily duplicate the behaviour of require

— Applicative: get-module (get-module string [environment])

Applicative get-module creates a fresh standard environment; opens the file named string for textual input; reads objects from the file until the end of the file is reached; evaluates those objects consecutively in the created environment; and, lastly, returns the created environment. If the optional argument environment is specified, the freshly created standard environment is augmented, prior to evaluating read expressions, by binding symbol module-parameters to the environment argument.